| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chromeos/display/output_configurator.h" | 5 #include "ui/display/chromeos/output_configurator.h" |
| 6 | 6 |
| 7 #include <X11/Xlib.h> | 7 #include <X11/Xlib.h> |
| 8 #include <X11/extensions/Xrandr.h> | 8 #include <X11/extensions/Xrandr.h> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
| 13 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
| 14 #include "base/sys_info.h" | 14 #include "base/sys_info.h" |
| 15 #include "base/time/time.h" | 15 #include "base/time/time.h" |
| 16 #include "chromeos/display/native_display_delegate_x11.h" | 16 #include "ui/display/chromeos/x11/display_util.h" |
| 17 #include "chromeos/display/output_util.h" | 17 #include "ui/display/chromeos/x11/native_display_delegate_x11.h" |
| 18 #include "chromeos/display/touchscreen_delegate_x11.h" | 18 #include "ui/display/chromeos/x11/touchscreen_delegate_x11.h" |
| 19 | 19 |
| 20 namespace chromeos { | 20 namespace ui { |
| 21 | 21 |
| 22 namespace { | 22 namespace { |
| 23 | 23 |
| 24 // The delay to perform configuration after RRNotify. See the comment | 24 // The delay to perform configuration after RRNotify. See the comment |
| 25 // in |Dispatch()|. | 25 // in |Dispatch()|. |
| 26 const int64 kConfigureDelayMs = 500; | 26 const int64 kConfigureDelayMs = 500; |
| 27 | 27 |
| 28 // Returns a string describing |state|. | 28 // Returns a string describing |state|. |
| 29 std::string DisplayPowerStateToString(DisplayPowerState state) { | 29 std::string DisplayPowerStateToString(chromeos::DisplayPowerState state) { |
| 30 switch (state) { | 30 switch (state) { |
| 31 case DISPLAY_POWER_ALL_ON: | 31 case chromeos::DISPLAY_POWER_ALL_ON: |
| 32 return "ALL_ON"; | 32 return "ALL_ON"; |
| 33 case DISPLAY_POWER_ALL_OFF: | 33 case chromeos::DISPLAY_POWER_ALL_OFF: |
| 34 return "ALL_OFF"; | 34 return "ALL_OFF"; |
| 35 case DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON: | 35 case chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON: |
| 36 return "INTERNAL_OFF_EXTERNAL_ON"; | 36 return "INTERNAL_OFF_EXTERNAL_ON"; |
| 37 case DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF: | 37 case chromeos::DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF: |
| 38 return "INTERNAL_ON_EXTERNAL_OFF"; | 38 return "INTERNAL_ON_EXTERNAL_OFF"; |
| 39 default: | 39 default: |
| 40 return "unknown (" + base::IntToString(state) + ")"; | 40 return "unknown (" + base::IntToString(state) + ")"; |
| 41 } | 41 } |
| 42 } | 42 } |
| 43 | 43 |
| 44 // Returns a string describing |state|. | 44 // Returns a string describing |state|. |
| 45 std::string OutputStateToString(ui::OutputState state) { | 45 std::string OutputStateToString(OutputState state) { |
| 46 switch (state) { | 46 switch (state) { |
| 47 case ui::OUTPUT_STATE_INVALID: | 47 case OUTPUT_STATE_INVALID: |
| 48 return "INVALID"; | 48 return "INVALID"; |
| 49 case ui::OUTPUT_STATE_HEADLESS: | 49 case OUTPUT_STATE_HEADLESS: |
| 50 return "HEADLESS"; | 50 return "HEADLESS"; |
| 51 case ui::OUTPUT_STATE_SINGLE: | 51 case OUTPUT_STATE_SINGLE: |
| 52 return "SINGLE"; | 52 return "SINGLE"; |
| 53 case ui::OUTPUT_STATE_DUAL_MIRROR: | 53 case OUTPUT_STATE_DUAL_MIRROR: |
| 54 return "DUAL_MIRROR"; | 54 return "DUAL_MIRROR"; |
| 55 case ui::OUTPUT_STATE_DUAL_EXTENDED: | 55 case OUTPUT_STATE_DUAL_EXTENDED: |
| 56 return "DUAL_EXTENDED"; | 56 return "DUAL_EXTENDED"; |
| 57 } | 57 } |
| 58 NOTREACHED() << "Unknown state " << state; | 58 NOTREACHED() << "Unknown state " << state; |
| 59 return "INVALID"; | 59 return "INVALID"; |
| 60 } | 60 } |
| 61 | 61 |
| 62 // Returns a string representation of OutputSnapshot. | 62 // Returns a string representation of OutputSnapshot. |
| 63 std::string OutputSnapshotToString( | 63 std::string OutputSnapshotToString( |
| 64 const OutputConfigurator::OutputSnapshot* output) { | 64 const OutputConfigurator::OutputSnapshot* output) { |
| 65 return base::StringPrintf( | 65 return base::StringPrintf( |
| 66 "[type=%d, output=%ld, crtc=%ld, mode=%ld, dim=%dx%d]", | 66 "[type=%d, output=%ld, crtc=%ld, mode=%ld, dim=%dx%d]", |
| 67 output->type, | 67 output->type, |
| 68 output->output, | 68 output->output, |
| 69 output->crtc, | 69 output->crtc, |
| 70 output->current_mode, | 70 output->current_mode, |
| 71 static_cast<int>(output->width_mm), | 71 static_cast<int>(output->width_mm), |
| 72 static_cast<int>(output->height_mm)); | 72 static_cast<int>(output->height_mm)); |
| 73 } | 73 } |
| 74 | 74 |
| 75 // Returns a string representation of ModeInfo. | 75 // Returns a string representation of ModeInfo. |
| 76 std::string ModeInfoToString(const OutputConfigurator::ModeInfo* mode) { | 76 std::string ModeInfoToString(const OutputConfigurator::ModeInfo* mode) { |
| 77 return base::StringPrintf("[%dx%d %srate=%f]", | 77 return base::StringPrintf("[%dx%d %srate=%f]", |
| 78 mode->width, | 78 mode->width, |
| 79 mode->height, | 79 mode->height, |
| 80 mode->interlaced ? "interlaced " : "", | 80 mode->interlaced ? "interlaced " : "", |
| 81 mode->refresh_rate); | 81 mode->refresh_rate); |
| 82 | |
| 83 } | 82 } |
| 84 | 83 |
| 85 // Returns the number of outputs in |outputs| that should be turned on, per | 84 // Returns the number of outputs in |outputs| that should be turned on, per |
| 86 // |state|. If |output_power| is non-NULL, it is updated to contain the | 85 // |state|. If |output_power| is non-NULL, it is updated to contain the |
| 87 // on/off state of each corresponding entry in |outputs|. | 86 // on/off state of each corresponding entry in |outputs|. |
| 88 int GetOutputPower( | 87 int GetOutputPower( |
| 89 const std::vector<OutputConfigurator::OutputSnapshot>& outputs, | 88 const std::vector<OutputConfigurator::OutputSnapshot>& outputs, |
| 90 DisplayPowerState state, | 89 chromeos::DisplayPowerState state, |
| 91 std::vector<bool>* output_power) { | 90 std::vector<bool>* output_power) { |
| 92 int num_on_outputs = 0; | 91 int num_on_outputs = 0; |
| 93 if (output_power) | 92 if (output_power) |
| 94 output_power->resize(outputs.size()); | 93 output_power->resize(outputs.size()); |
| 95 | 94 |
| 96 for (size_t i = 0; i < outputs.size(); ++i) { | 95 for (size_t i = 0; i < outputs.size(); ++i) { |
| 97 bool internal = outputs[i].type == ui::OUTPUT_TYPE_INTERNAL; | 96 bool internal = outputs[i].type == OUTPUT_TYPE_INTERNAL; |
| 98 bool on = state == DISPLAY_POWER_ALL_ON || | 97 bool on = |
| 99 (state == DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON && !internal) || | 98 state == chromeos::DISPLAY_POWER_ALL_ON || |
| 100 (state == DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF && internal); | 99 (state == chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON && |
| 100 !internal) || |
| 101 (state == chromeos::DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF && internal); |
| 101 if (output_power) | 102 if (output_power) |
| 102 (*output_power)[i] = on; | 103 (*output_power)[i] = on; |
| 103 if (on) | 104 if (on) |
| 104 num_on_outputs++; | 105 num_on_outputs++; |
| 105 } | 106 } |
| 106 return num_on_outputs; | 107 return num_on_outputs; |
| 107 } | 108 } |
| 108 | 109 |
| 109 } // namespace | 110 } // namespace |
| 110 | 111 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 134 crtc(None), | 135 crtc(None), |
| 135 current_mode(None), | 136 current_mode(None), |
| 136 native_mode(None), | 137 native_mode(None), |
| 137 mirror_mode(None), | 138 mirror_mode(None), |
| 138 selected_mode(None), | 139 selected_mode(None), |
| 139 x(0), | 140 x(0), |
| 140 y(0), | 141 y(0), |
| 141 width_mm(0), | 142 width_mm(0), |
| 142 height_mm(0), | 143 height_mm(0), |
| 143 is_aspect_preserving_scaling(false), | 144 is_aspect_preserving_scaling(false), |
| 144 type(ui::OUTPUT_TYPE_UNKNOWN), | 145 type(OUTPUT_TYPE_UNKNOWN), |
| 145 touch_device_id(0), | 146 touch_device_id(0), |
| 146 display_id(0), | 147 display_id(0), |
| 147 has_display_id(false), | 148 has_display_id(false), |
| 148 index(0) {} | 149 index(0) {} |
| 149 | 150 |
| 150 OutputConfigurator::OutputSnapshot::~OutputSnapshot() {} | 151 OutputConfigurator::OutputSnapshot::~OutputSnapshot() {} |
| 151 | 152 |
| 152 bool OutputConfigurator::TestApi::TriggerConfigureTimeout() { | 153 bool OutputConfigurator::TestApi::TriggerConfigureTimeout() { |
| 153 if (configurator_->configure_timer_.get() && | 154 if (configurator_->configure_timer_.get() && |
| 154 configurator_->configure_timer_->IsRunning()) { | 155 configurator_->configure_timer_->IsRunning()) { |
| 155 configurator_->configure_timer_.reset(); | 156 configurator_->configure_timer_.reset(); |
| 156 configurator_->ConfigureOutputs(); | 157 configurator_->ConfigureOutputs(); |
| 157 return true; | 158 return true; |
| 158 } else { | 159 } else { |
| 159 return false; | 160 return false; |
| 160 } | 161 } |
| 161 } | 162 } |
| 162 | 163 |
| 163 // static | 164 // static |
| 164 const OutputConfigurator::ModeInfo* OutputConfigurator::GetModeInfo( | 165 const OutputConfigurator::ModeInfo* OutputConfigurator::GetModeInfo( |
| 165 const OutputSnapshot& output, | 166 const OutputSnapshot& output, |
| 166 RRMode mode) { | 167 RRMode mode) { |
| 167 if (mode == None) | 168 if (mode == None) |
| 168 return NULL; | 169 return NULL; |
| 169 | 170 |
| 170 ModeInfoMap::const_iterator it = output.mode_infos.find(mode); | 171 ModeInfoMap::const_iterator it = output.mode_infos.find(mode); |
| 171 if (it == output.mode_infos.end()) { | 172 if (it == output.mode_infos.end()) { |
| 172 LOG(WARNING) << "Unable to find info about mode " << mode | 173 LOG(WARNING) << "Unable to find info about mode " << mode << " for output " |
| 173 << " for output " << output.output; | 174 << output.output; |
| 174 return NULL; | 175 return NULL; |
| 175 } | 176 } |
| 176 return &it->second; | 177 return &it->second; |
| 177 } | 178 } |
| 178 | 179 |
| 179 // static | 180 // static |
| 180 RRMode OutputConfigurator::FindOutputModeMatchingSize( | 181 RRMode OutputConfigurator::FindOutputModeMatchingSize( |
| 181 const OutputSnapshot& output, | 182 const OutputSnapshot& output, |
| 182 int width, | 183 int width, |
| 183 int height) { | 184 int height) { |
| 184 RRMode found = None; | 185 RRMode found = None; |
| 185 float best_rate = 0; | 186 float best_rate = 0; |
| 186 bool non_interlaced_found = false; | 187 bool non_interlaced_found = false; |
| 187 for (ModeInfoMap::const_iterator it = output.mode_infos.begin(); | 188 for (ModeInfoMap::const_iterator it = output.mode_infos.begin(); |
| 188 it != output.mode_infos.end(); ++it) { | 189 it != output.mode_infos.end(); |
| 190 ++it) { |
| 189 RRMode mode = it->first; | 191 RRMode mode = it->first; |
| 190 const ModeInfo& info = it->second; | 192 const ModeInfo& info = it->second; |
| 191 | 193 |
| 192 if (info.width == width && info.height == height) { | 194 if (info.width == width && info.height == height) { |
| 193 if (info.interlaced) { | 195 if (info.interlaced) { |
| 194 if (non_interlaced_found) | 196 if (non_interlaced_found) |
| 195 continue; | 197 continue; |
| 196 } else { | 198 } else { |
| 197 // Reset the best rate if the non interlaced is | 199 // Reset the best rate if the non interlaced is |
| 198 // found the first time. | 200 // found the first time. |
| 199 if (!non_interlaced_found) | 201 if (!non_interlaced_found) |
| 200 best_rate = info.refresh_rate; | 202 best_rate = info.refresh_rate; |
| 201 non_interlaced_found = true; | 203 non_interlaced_found = true; |
| 202 } | 204 } |
| 203 if (info.refresh_rate < best_rate) | 205 if (info.refresh_rate < best_rate) |
| 204 continue; | 206 continue; |
| 205 | 207 |
| 206 found = mode; | 208 found = mode; |
| 207 best_rate = info.refresh_rate; | 209 best_rate = info.refresh_rate; |
| 208 } | 210 } |
| 209 } | 211 } |
| 210 return found; | 212 return found; |
| 211 } | 213 } |
| 212 | 214 |
| 213 OutputConfigurator::OutputConfigurator() | 215 OutputConfigurator::OutputConfigurator() |
| 214 : state_controller_(NULL), | 216 : state_controller_(NULL), |
| 215 mirroring_controller_(NULL), | 217 mirroring_controller_(NULL), |
| 216 is_panel_fitting_enabled_(false), | 218 is_panel_fitting_enabled_(false), |
| 217 configure_display_(base::SysInfo::IsRunningOnChromeOS()), | 219 configure_display_(base::SysInfo::IsRunningOnChromeOS()), |
| 218 output_state_(ui::OUTPUT_STATE_INVALID), | 220 output_state_(OUTPUT_STATE_INVALID), |
| 219 power_state_(DISPLAY_POWER_ALL_ON), | 221 power_state_(chromeos::DISPLAY_POWER_ALL_ON), |
| 220 next_output_protection_client_id_(1) {} | 222 next_output_protection_client_id_(1) {} |
| 221 | 223 |
| 222 OutputConfigurator::~OutputConfigurator() { | 224 OutputConfigurator::~OutputConfigurator() { |
| 223 if (native_display_delegate_) | 225 if (native_display_delegate_) |
| 224 native_display_delegate_->RemoveObserver(this); | 226 native_display_delegate_->RemoveObserver(this); |
| 225 } | 227 } |
| 226 | 228 |
| 227 void OutputConfigurator::SetNativeDisplayDelegateForTesting( | 229 void OutputConfigurator::SetNativeDisplayDelegateForTesting( |
| 228 scoped_ptr<NativeDisplayDelegate> delegate) { | 230 scoped_ptr<NativeDisplayDelegate> delegate) { |
| 229 DCHECK(!native_display_delegate_); | 231 DCHECK(!native_display_delegate_); |
| 230 | 232 |
| 231 native_display_delegate_ = delegate.Pass(); | 233 native_display_delegate_ = delegate.Pass(); |
| 232 native_display_delegate_->AddObserver(this); | 234 native_display_delegate_->AddObserver(this); |
| 233 configure_display_ = true; | 235 configure_display_ = true; |
| 234 } | 236 } |
| 235 | 237 |
| 236 void OutputConfigurator::SetTouchscreenDelegateForTesting( | 238 void OutputConfigurator::SetTouchscreenDelegateForTesting( |
| 237 scoped_ptr<TouchscreenDelegate> delegate) { | 239 scoped_ptr<TouchscreenDelegate> delegate) { |
| 238 DCHECK(!touchscreen_delegate_); | 240 DCHECK(!touchscreen_delegate_); |
| 239 | 241 |
| 240 touchscreen_delegate_ = delegate.Pass(); | 242 touchscreen_delegate_ = delegate.Pass(); |
| 241 } | 243 } |
| 242 | 244 |
| 243 void OutputConfigurator::SetInitialDisplayPower(DisplayPowerState power_state) { | 245 void OutputConfigurator::SetInitialDisplayPower( |
| 244 DCHECK_EQ(output_state_, ui::OUTPUT_STATE_INVALID); | 246 chromeos::DisplayPowerState power_state) { |
| 247 DCHECK_EQ(output_state_, OUTPUT_STATE_INVALID); |
| 245 power_state_ = power_state; | 248 power_state_ = power_state; |
| 246 } | 249 } |
| 247 | 250 |
| 248 void OutputConfigurator::Init(bool is_panel_fitting_enabled) { | 251 void OutputConfigurator::Init(bool is_panel_fitting_enabled) { |
| 249 is_panel_fitting_enabled_ = is_panel_fitting_enabled; | 252 is_panel_fitting_enabled_ = is_panel_fitting_enabled; |
| 250 if (!configure_display_) | 253 if (!configure_display_) |
| 251 return; | 254 return; |
| 252 | 255 |
| 253 if (!native_display_delegate_) { | 256 if (!native_display_delegate_) { |
| 254 native_display_delegate_.reset(new NativeDisplayDelegateX11()); | 257 native_display_delegate_.reset(new NativeDisplayDelegateX11()); |
| 255 native_display_delegate_->AddObserver(this); | 258 native_display_delegate_->AddObserver(this); |
| 256 } | 259 } |
| 257 | 260 |
| 258 if (!touchscreen_delegate_) | 261 if (!touchscreen_delegate_) |
| 259 touchscreen_delegate_.reset(new TouchscreenDelegateX11()); | 262 touchscreen_delegate_.reset(new TouchscreenDelegateX11()); |
| 260 } | 263 } |
| 261 | 264 |
| 262 void OutputConfigurator::ForceInitialConfigure(uint32 background_color_argb) { | 265 void OutputConfigurator::ForceInitialConfigure(uint32 background_color_argb) { |
| 263 if (!configure_display_) | 266 if (!configure_display_) |
| 264 return; | 267 return; |
| 265 | 268 |
| 266 native_display_delegate_->GrabServer(); | 269 native_display_delegate_->GrabServer(); |
| 267 native_display_delegate_->Initialize(); | 270 native_display_delegate_->Initialize(); |
| 268 | 271 |
| 269 UpdateCachedOutputs(); | 272 UpdateCachedOutputs(); |
| 270 if (cached_outputs_.size() > 1 && background_color_argb) | 273 if (cached_outputs_.size() > 1 && background_color_argb) |
| 271 native_display_delegate_->SetBackgroundColor(background_color_argb); | 274 native_display_delegate_->SetBackgroundColor(background_color_argb); |
| 272 const ui::OutputState new_state = ChooseOutputState(power_state_); | 275 const OutputState new_state = ChooseOutputState(power_state_); |
| 273 const bool success = EnterStateOrFallBackToSoftwareMirroring( | 276 const bool success = |
| 274 new_state, power_state_); | 277 EnterStateOrFallBackToSoftwareMirroring(new_state, power_state_); |
| 275 | 278 |
| 276 // Force the DPMS on chrome startup as the driver doesn't always detect | 279 // Force the DPMS on chrome startup as the driver doesn't always detect |
| 277 // that all displays are on when signing out. | 280 // that all displays are on when signing out. |
| 278 native_display_delegate_->ForceDPMSOn(); | 281 native_display_delegate_->ForceDPMSOn(); |
| 279 native_display_delegate_->UngrabServer(); | 282 native_display_delegate_->UngrabServer(); |
| 280 NotifyObservers(success, new_state); | 283 NotifyObservers(success, new_state); |
| 281 } | 284 } |
| 282 | 285 |
| 283 bool OutputConfigurator::ApplyProtections(const DisplayProtections& requests) { | 286 bool OutputConfigurator::ApplyProtections(const DisplayProtections& requests) { |
| 284 for (std::vector<OutputSnapshot>::const_iterator it = cached_outputs_.begin(); | 287 for (std::vector<OutputSnapshot>::const_iterator it = cached_outputs_.begin(); |
| 285 it != cached_outputs_.end(); ++it) { | 288 it != cached_outputs_.end(); |
| 289 ++it) { |
| 286 uint32_t all_desired = 0; | 290 uint32_t all_desired = 0; |
| 287 DisplayProtections::const_iterator request_it = requests.find( | 291 DisplayProtections::const_iterator request_it = |
| 288 it->display_id); | 292 requests.find(it->display_id); |
| 289 if (request_it != requests.end()) | 293 if (request_it != requests.end()) |
| 290 all_desired = request_it->second; | 294 all_desired = request_it->second; |
| 291 switch (it->type) { | 295 switch (it->type) { |
| 292 case ui::OUTPUT_TYPE_UNKNOWN: | 296 case OUTPUT_TYPE_UNKNOWN: |
| 293 return false; | 297 return false; |
| 294 // DisplayPort, DVI, and HDMI all support HDCP. | 298 // DisplayPort, DVI, and HDMI all support HDCP. |
| 295 case ui::OUTPUT_TYPE_DISPLAYPORT: | 299 case OUTPUT_TYPE_DISPLAYPORT: |
| 296 case ui::OUTPUT_TYPE_DVI: | 300 case OUTPUT_TYPE_DVI: |
| 297 case ui::OUTPUT_TYPE_HDMI: { | 301 case OUTPUT_TYPE_HDMI: { |
| 298 ui::HDCPState new_desired_state = | 302 HDCPState new_desired_state = |
| 299 (all_desired & ui::OUTPUT_PROTECTION_METHOD_HDCP) | 303 (all_desired & OUTPUT_PROTECTION_METHOD_HDCP) ? |
| 300 ? ui::HDCP_STATE_DESIRED | 304 HDCP_STATE_DESIRED : HDCP_STATE_UNDESIRED; |
| 301 : ui::HDCP_STATE_UNDESIRED; | |
| 302 if (!native_display_delegate_->SetHDCPState(*it, new_desired_state)) | 305 if (!native_display_delegate_->SetHDCPState(*it, new_desired_state)) |
| 303 return false; | 306 return false; |
| 304 break; | 307 break; |
| 305 } | 308 } |
| 306 case ui::OUTPUT_TYPE_INTERNAL: | 309 case OUTPUT_TYPE_INTERNAL: |
| 307 case ui::OUTPUT_TYPE_VGA: | 310 case OUTPUT_TYPE_VGA: |
| 308 case ui::OUTPUT_TYPE_NETWORK: | 311 case OUTPUT_TYPE_NETWORK: |
| 309 // No protections for these types. Do nothing. | 312 // No protections for these types. Do nothing. |
| 310 break; | 313 break; |
| 311 case ui::OUTPUT_TYPE_NONE: | 314 case OUTPUT_TYPE_NONE: |
| 312 NOTREACHED(); | 315 NOTREACHED(); |
| 313 break; | 316 break; |
| 314 } | 317 } |
| 315 } | 318 } |
| 316 | 319 |
| 317 return true; | 320 return true; |
| 318 } | 321 } |
| 319 | 322 |
| 320 OutputConfigurator::OutputProtectionClientId | 323 OutputConfigurator::OutputProtectionClientId |
| 321 OutputConfigurator::RegisterOutputProtectionClient() { | 324 OutputConfigurator::RegisterOutputProtectionClient() { |
| 322 if (!configure_display_) | 325 if (!configure_display_) |
| 323 return kInvalidClientId; | 326 return kInvalidClientId; |
| 324 | 327 |
| 325 return next_output_protection_client_id_++; | 328 return next_output_protection_client_id_++; |
| 326 } | 329 } |
| 327 | 330 |
| 328 void OutputConfigurator::UnregisterOutputProtectionClient( | 331 void OutputConfigurator::UnregisterOutputProtectionClient( |
| 329 OutputProtectionClientId client_id) { | 332 OutputProtectionClientId client_id) { |
| 330 client_protection_requests_.erase(client_id); | 333 client_protection_requests_.erase(client_id); |
| 331 | 334 |
| 332 DisplayProtections protections; | 335 DisplayProtections protections; |
| 333 for (ProtectionRequests::const_iterator it = | 336 for (ProtectionRequests::const_iterator it = |
| 334 client_protection_requests_.begin(); | 337 client_protection_requests_.begin(); |
| 335 it != client_protection_requests_.end(); | 338 it != client_protection_requests_.end(); |
| 336 ++it) { | 339 ++it) { |
| 337 for (DisplayProtections::const_iterator it2 = it->second.begin(); | 340 for (DisplayProtections::const_iterator it2 = it->second.begin(); |
| 338 it2 != it->second.end(); ++it2) { | 341 it2 != it->second.end(); |
| 342 ++it2) { |
| 339 protections[it2->first] |= it2->second; | 343 protections[it2->first] |= it2->second; |
| 340 } | 344 } |
| 341 } | 345 } |
| 342 | 346 |
| 343 ApplyProtections(protections); | 347 ApplyProtections(protections); |
| 344 } | 348 } |
| 345 | 349 |
| 346 bool OutputConfigurator::QueryOutputProtectionStatus( | 350 bool OutputConfigurator::QueryOutputProtectionStatus( |
| 347 OutputProtectionClientId client_id, | 351 OutputProtectionClientId client_id, |
| 348 int64 display_id, | 352 int64 display_id, |
| 349 uint32_t* link_mask, | 353 uint32_t* link_mask, |
| 350 uint32_t* protection_mask) { | 354 uint32_t* protection_mask) { |
| 351 if (!configure_display_) | 355 if (!configure_display_) |
| 352 return false; | 356 return false; |
| 353 | 357 |
| 354 uint32_t enabled = 0; | 358 uint32_t enabled = 0; |
| 355 uint32_t unfulfilled = 0; | 359 uint32_t unfulfilled = 0; |
| 356 *link_mask = 0; | 360 *link_mask = 0; |
| 357 for (std::vector<OutputSnapshot>::const_iterator it = cached_outputs_.begin(); | 361 for (std::vector<OutputSnapshot>::const_iterator it = cached_outputs_.begin(); |
| 358 it != cached_outputs_.end(); ++it) { | 362 it != cached_outputs_.end(); |
| 363 ++it) { |
| 359 if (it->display_id != display_id) | 364 if (it->display_id != display_id) |
| 360 continue; | 365 continue; |
| 361 *link_mask |= it->type; | 366 *link_mask |= it->type; |
| 362 switch (it->type) { | 367 switch (it->type) { |
| 363 case ui::OUTPUT_TYPE_UNKNOWN: | 368 case OUTPUT_TYPE_UNKNOWN: |
| 364 return false; | 369 return false; |
| 365 // DisplayPort, DVI, and HDMI all support HDCP. | 370 // DisplayPort, DVI, and HDMI all support HDCP. |
| 366 case ui::OUTPUT_TYPE_DISPLAYPORT: | 371 case OUTPUT_TYPE_DISPLAYPORT: |
| 367 case ui::OUTPUT_TYPE_DVI: | 372 case OUTPUT_TYPE_DVI: |
| 368 case ui::OUTPUT_TYPE_HDMI: { | 373 case OUTPUT_TYPE_HDMI: { |
| 369 ui::HDCPState state; | 374 HDCPState state; |
| 370 if (!native_display_delegate_->GetHDCPState(*it, &state)) | 375 if (!native_display_delegate_->GetHDCPState(*it, &state)) |
| 371 return false; | 376 return false; |
| 372 if (state == ui::HDCP_STATE_ENABLED) | 377 if (state == HDCP_STATE_ENABLED) |
| 373 enabled |= ui::OUTPUT_PROTECTION_METHOD_HDCP; | 378 enabled |= OUTPUT_PROTECTION_METHOD_HDCP; |
| 374 else | 379 else |
| 375 unfulfilled |= ui::OUTPUT_PROTECTION_METHOD_HDCP; | 380 unfulfilled |= OUTPUT_PROTECTION_METHOD_HDCP; |
| 376 break; | 381 break; |
| 377 } | 382 } |
| 378 case ui::OUTPUT_TYPE_INTERNAL: | 383 case OUTPUT_TYPE_INTERNAL: |
| 379 case ui::OUTPUT_TYPE_VGA: | 384 case OUTPUT_TYPE_VGA: |
| 380 case ui::OUTPUT_TYPE_NETWORK: | 385 case OUTPUT_TYPE_NETWORK: |
| 381 // No protections for these types. Do nothing. | 386 // No protections for these types. Do nothing. |
| 382 break; | 387 break; |
| 383 case ui::OUTPUT_TYPE_NONE: | 388 case OUTPUT_TYPE_NONE: |
| 384 NOTREACHED(); | 389 NOTREACHED(); |
| 385 break; | 390 break; |
| 386 } | 391 } |
| 387 } | 392 } |
| 388 | 393 |
| 389 // Don't reveal protections requested by other clients. | 394 // Don't reveal protections requested by other clients. |
| 390 ProtectionRequests::iterator it = client_protection_requests_.find(client_id); | 395 ProtectionRequests::iterator it = client_protection_requests_.find(client_id); |
| 391 if (it != client_protection_requests_.end()) { | 396 if (it != client_protection_requests_.end()) { |
| 392 uint32_t requested_mask = 0; | 397 uint32_t requested_mask = 0; |
| 393 if (it->second.find(display_id) != it->second.end()) | 398 if (it->second.find(display_id) != it->second.end()) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 405 uint32_t desired_method_mask) { | 410 uint32_t desired_method_mask) { |
| 406 if (!configure_display_) | 411 if (!configure_display_) |
| 407 return false; | 412 return false; |
| 408 | 413 |
| 409 DisplayProtections protections; | 414 DisplayProtections protections; |
| 410 for (ProtectionRequests::const_iterator it = | 415 for (ProtectionRequests::const_iterator it = |
| 411 client_protection_requests_.begin(); | 416 client_protection_requests_.begin(); |
| 412 it != client_protection_requests_.end(); | 417 it != client_protection_requests_.end(); |
| 413 ++it) { | 418 ++it) { |
| 414 for (DisplayProtections::const_iterator it2 = it->second.begin(); | 419 for (DisplayProtections::const_iterator it2 = it->second.begin(); |
| 415 it2 != it->second.end(); ++it2) { | 420 it2 != it->second.end(); |
| 421 ++it2) { |
| 416 if (it->first == client_id && it2->first == display_id) | 422 if (it->first == client_id && it2->first == display_id) |
| 417 continue; | 423 continue; |
| 418 protections[it2->first] |= it2->second; | 424 protections[it2->first] |= it2->second; |
| 419 } | 425 } |
| 420 } | 426 } |
| 421 protections[display_id] |= desired_method_mask; | 427 protections[display_id] |= desired_method_mask; |
| 422 | 428 |
| 423 if (!ApplyProtections(protections)) | 429 if (!ApplyProtections(protections)) |
| 424 return false; | 430 return false; |
| 425 | 431 |
| 426 if (desired_method_mask == ui::OUTPUT_PROTECTION_METHOD_NONE) { | 432 if (desired_method_mask == OUTPUT_PROTECTION_METHOD_NONE) { |
| 427 if (client_protection_requests_.find(client_id) != | 433 if (client_protection_requests_.find(client_id) != |
| 428 client_protection_requests_.end()) { | 434 client_protection_requests_.end()) { |
| 429 client_protection_requests_[client_id].erase(display_id); | 435 client_protection_requests_[client_id].erase(display_id); |
| 430 if (client_protection_requests_[client_id].size() == 0) | 436 if (client_protection_requests_[client_id].size() == 0) |
| 431 client_protection_requests_.erase(client_id); | 437 client_protection_requests_.erase(client_id); |
| 432 } | 438 } |
| 433 } else { | 439 } else { |
| 434 client_protection_requests_[client_id][display_id] = desired_method_mask; | 440 client_protection_requests_[client_id][display_id] = desired_method_mask; |
| 435 } | 441 } |
| 436 | 442 |
| 437 return true; | 443 return true; |
| 438 } | 444 } |
| 439 | 445 |
| 440 void OutputConfigurator::PrepareForExit() { | 446 void OutputConfigurator::PrepareForExit() { |
| 441 configure_display_ = false; | 447 configure_display_ = false; |
| 442 } | 448 } |
| 443 | 449 |
| 444 bool OutputConfigurator::SetDisplayPower(DisplayPowerState power_state, | 450 bool OutputConfigurator::SetDisplayPower( |
| 445 int flags) { | 451 chromeos::DisplayPowerState power_state, |
| 452 int flags) { |
| 446 if (!configure_display_) | 453 if (!configure_display_) |
| 447 return false; | 454 return false; |
| 448 | 455 |
| 449 VLOG(1) << "SetDisplayPower: power_state=" | 456 VLOG(1) << "SetDisplayPower: power_state=" |
| 450 << DisplayPowerStateToString(power_state) << " flags=" << flags | 457 << DisplayPowerStateToString(power_state) << " flags=" << flags |
| 451 << ", configure timer=" | 458 << ", configure timer=" |
| 452 << ((configure_timer_.get() && configure_timer_->IsRunning()) ? | 459 << ((configure_timer_.get() && configure_timer_->IsRunning()) ? |
| 453 "Running" : "Stopped"); | 460 "Running" : "Stopped"); |
| 454 if (power_state == power_state_ && !(flags & kSetDisplayPowerForceProbe)) | 461 if (power_state == power_state_ && !(flags & kSetDisplayPowerForceProbe)) |
| 455 return true; | 462 return true; |
| 456 | 463 |
| 457 native_display_delegate_->GrabServer(); | 464 native_display_delegate_->GrabServer(); |
| 458 UpdateCachedOutputs(); | 465 UpdateCachedOutputs(); |
| 459 | 466 |
| 460 const ui::OutputState new_state = ChooseOutputState(power_state); | 467 const OutputState new_state = ChooseOutputState(power_state); |
| 461 bool attempted_change = false; | 468 bool attempted_change = false; |
| 462 bool success = false; | 469 bool success = false; |
| 463 | 470 |
| 464 bool only_if_single_internal_display = | 471 bool only_if_single_internal_display = |
| 465 flags & kSetDisplayPowerOnlyIfSingleInternalDisplay; | 472 flags & kSetDisplayPowerOnlyIfSingleInternalDisplay; |
| 466 bool single_internal_display = | 473 bool single_internal_display = |
| 467 cached_outputs_.size() == 1 && | 474 cached_outputs_.size() == 1 && |
| 468 cached_outputs_[0].type == ui::OUTPUT_TYPE_INTERNAL; | 475 cached_outputs_[0].type == OUTPUT_TYPE_INTERNAL; |
| 469 if (single_internal_display || !only_if_single_internal_display) { | 476 if (single_internal_display || !only_if_single_internal_display) { |
| 470 success = EnterStateOrFallBackToSoftwareMirroring(new_state, power_state); | 477 success = EnterStateOrFallBackToSoftwareMirroring(new_state, power_state); |
| 471 attempted_change = true; | 478 attempted_change = true; |
| 472 | 479 |
| 473 // Force the DPMS on since the driver doesn't always detect that it | 480 // Force the DPMS on since the driver doesn't always detect that it |
| 474 // should turn on. This is needed when coming back from idle suspend. | 481 // should turn on. This is needed when coming back from idle suspend. |
| 475 if (success && power_state != DISPLAY_POWER_ALL_OFF) | 482 if (success && power_state != chromeos::DISPLAY_POWER_ALL_OFF) |
| 476 native_display_delegate_->ForceDPMSOn(); | 483 native_display_delegate_->ForceDPMSOn(); |
| 477 } | 484 } |
| 478 | 485 |
| 479 native_display_delegate_->UngrabServer(); | 486 native_display_delegate_->UngrabServer(); |
| 480 if (attempted_change) | 487 if (attempted_change) |
| 481 NotifyObservers(success, new_state); | 488 NotifyObservers(success, new_state); |
| 482 return true; | 489 return true; |
| 483 } | 490 } |
| 484 | 491 |
| 485 bool OutputConfigurator::SetDisplayMode(ui::OutputState new_state) { | 492 bool OutputConfigurator::SetDisplayMode(OutputState new_state) { |
| 486 if (!configure_display_) | 493 if (!configure_display_) |
| 487 return false; | 494 return false; |
| 488 | 495 |
| 489 VLOG(1) << "SetDisplayMode: state=" << OutputStateToString(new_state); | 496 VLOG(1) << "SetDisplayMode: state=" << OutputStateToString(new_state); |
| 490 if (output_state_ == new_state) { | 497 if (output_state_ == new_state) { |
| 491 // Cancel software mirroring if the state is moving from | 498 // Cancel software mirroring if the state is moving from |
| 492 // OUTPUT_STATE_DUAL_EXTENDED to OUTPUT_STATE_DUAL_EXTENDED. | 499 // OUTPUT_STATE_DUAL_EXTENDED to OUTPUT_STATE_DUAL_EXTENDED. |
| 493 if (mirroring_controller_ && new_state == ui::OUTPUT_STATE_DUAL_EXTENDED) | 500 if (mirroring_controller_ && new_state == OUTPUT_STATE_DUAL_EXTENDED) |
| 494 mirroring_controller_->SetSoftwareMirroring(false); | 501 mirroring_controller_->SetSoftwareMirroring(false); |
| 495 NotifyObservers(true, new_state); | 502 NotifyObservers(true, new_state); |
| 496 return true; | 503 return true; |
| 497 } | 504 } |
| 498 | 505 |
| 499 native_display_delegate_->GrabServer(); | 506 native_display_delegate_->GrabServer(); |
| 500 UpdateCachedOutputs(); | 507 UpdateCachedOutputs(); |
| 501 const bool success = EnterStateOrFallBackToSoftwareMirroring( | 508 const bool success = |
| 502 new_state, power_state_); | 509 EnterStateOrFallBackToSoftwareMirroring(new_state, power_state_); |
| 503 native_display_delegate_->UngrabServer(); | 510 native_display_delegate_->UngrabServer(); |
| 504 | 511 |
| 505 NotifyObservers(success, new_state); | 512 NotifyObservers(success, new_state); |
| 506 return success; | 513 return success; |
| 507 } | 514 } |
| 508 | 515 |
| 509 void OutputConfigurator::OnConfigurationChanged() { | 516 void OutputConfigurator::OnConfigurationChanged() { |
| 510 // Configure outputs with |kConfigureDelayMs| delay, | 517 // Configure outputs with |kConfigureDelayMs| delay, |
| 511 // so that time-consuming ConfigureOutputs() won't be called multiple times. | 518 // so that time-consuming ConfigureOutputs() won't be called multiple times. |
| 512 if (configure_timer_.get()) { | 519 if (configure_timer_.get()) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 528 void OutputConfigurator::RemoveObserver(Observer* observer) { | 535 void OutputConfigurator::RemoveObserver(Observer* observer) { |
| 529 observers_.RemoveObserver(observer); | 536 observers_.RemoveObserver(observer); |
| 530 } | 537 } |
| 531 | 538 |
| 532 void OutputConfigurator::SuspendDisplays() { | 539 void OutputConfigurator::SuspendDisplays() { |
| 533 // If the display is off due to user inactivity and there's only a single | 540 // If the display is off due to user inactivity and there's only a single |
| 534 // internal display connected, switch to the all-on state before | 541 // internal display connected, switch to the all-on state before |
| 535 // suspending. This shouldn't be very noticeable to the user since the | 542 // suspending. This shouldn't be very noticeable to the user since the |
| 536 // backlight is off at this point, and doing this lets us resume directly | 543 // backlight is off at this point, and doing this lets us resume directly |
| 537 // into the "on" state, which greatly reduces resume times. | 544 // into the "on" state, which greatly reduces resume times. |
| 538 if (power_state_ == DISPLAY_POWER_ALL_OFF) { | 545 if (power_state_ == chromeos::DISPLAY_POWER_ALL_OFF) { |
| 539 SetDisplayPower(DISPLAY_POWER_ALL_ON, | 546 SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON, |
| 540 kSetDisplayPowerOnlyIfSingleInternalDisplay); | 547 kSetDisplayPowerOnlyIfSingleInternalDisplay); |
| 541 | 548 |
| 542 // We need to make sure that the monitor configuration we just did actually | 549 // We need to make sure that the monitor configuration we just did actually |
| 543 // completes before we return, because otherwise the X message could be | 550 // completes before we return, because otherwise the X message could be |
| 544 // racing with the HandleSuspendReadiness message. | 551 // racing with the HandleSuspendReadiness message. |
| 545 native_display_delegate_->SyncWithServer(); | 552 native_display_delegate_->SyncWithServer(); |
| 546 } | 553 } |
| 547 } | 554 } |
| 548 | 555 |
| 549 void OutputConfigurator::ResumeDisplays() { | 556 void OutputConfigurator::ResumeDisplays() { |
| 550 // Force probing to ensure that we pick up any changes that were made | 557 // Force probing to ensure that we pick up any changes that were made |
| 551 // while the system was suspended. | 558 // while the system was suspended. |
| 552 SetDisplayPower(power_state_, kSetDisplayPowerForceProbe); | 559 SetDisplayPower(power_state_, kSetDisplayPowerForceProbe); |
| 553 } | 560 } |
| 554 | 561 |
| 555 void OutputConfigurator::UpdateCachedOutputs() { | 562 void OutputConfigurator::UpdateCachedOutputs() { |
| 556 cached_outputs_ = native_display_delegate_->GetOutputs(); | 563 cached_outputs_ = native_display_delegate_->GetOutputs(); |
| 557 touchscreen_delegate_->AssociateTouchscreens(&cached_outputs_); | 564 touchscreen_delegate_->AssociateTouchscreens(&cached_outputs_); |
| 558 | 565 |
| 559 // Set |selected_mode| fields. | 566 // Set |selected_mode| fields. |
| 560 for (size_t i = 0; i < cached_outputs_.size(); ++i) { | 567 for (size_t i = 0; i < cached_outputs_.size(); ++i) { |
| 561 OutputSnapshot* output = &cached_outputs_[i]; | 568 OutputSnapshot* output = &cached_outputs_[i]; |
| 562 if (output->has_display_id) { | 569 if (output->has_display_id) { |
| 563 int width = 0, height = 0; | 570 int width = 0, height = 0; |
| 564 if (state_controller_ && | 571 if (state_controller_ && state_controller_->GetResolutionForDisplayId( |
| 565 state_controller_->GetResolutionForDisplayId( | 572 output->display_id, &width, &height)) { |
| 566 output->display_id, &width, &height)) { | |
| 567 output->selected_mode = | 573 output->selected_mode = |
| 568 FindOutputModeMatchingSize(*output, width, height); | 574 FindOutputModeMatchingSize(*output, width, height); |
| 569 } | 575 } |
| 570 } | 576 } |
| 571 // Fall back to native mode. | 577 // Fall back to native mode. |
| 572 if (output->selected_mode == None) | 578 if (output->selected_mode == None) |
| 573 output->selected_mode = output->native_mode; | 579 output->selected_mode = output->native_mode; |
| 574 } | 580 } |
| 575 | 581 |
| 576 // Set |mirror_mode| fields. | 582 // Set |mirror_mode| fields. |
| 577 if (cached_outputs_.size() == 2) { | 583 if (cached_outputs_.size() == 2) { |
| 578 bool one_is_internal = cached_outputs_[0].type == ui::OUTPUT_TYPE_INTERNAL; | 584 bool one_is_internal = cached_outputs_[0].type == OUTPUT_TYPE_INTERNAL; |
| 579 bool two_is_internal = cached_outputs_[1].type == ui::OUTPUT_TYPE_INTERNAL; | 585 bool two_is_internal = cached_outputs_[1].type == OUTPUT_TYPE_INTERNAL; |
| 580 int internal_outputs = (one_is_internal ? 1 : 0) + | 586 int internal_outputs = |
| 581 (two_is_internal ? 1 : 0); | 587 (one_is_internal ? 1 : 0) + (two_is_internal ? 1 : 0); |
| 582 DCHECK_LT(internal_outputs, 2); | 588 DCHECK_LT(internal_outputs, 2); |
| 583 LOG_IF(WARNING, internal_outputs == 2) | 589 LOG_IF(WARNING, internal_outputs == 2) << "Two internal outputs detected."; |
| 584 << "Two internal outputs detected."; | |
| 585 | 590 |
| 586 bool can_mirror = false; | 591 bool can_mirror = false; |
| 587 for (int attempt = 0; !can_mirror && attempt < 2; ++attempt) { | 592 for (int attempt = 0; !can_mirror && attempt < 2; ++attempt) { |
| 588 // Try preserving external output's aspect ratio on the first attempt. | 593 // Try preserving external output's aspect ratio on the first attempt. |
| 589 // If that fails, fall back to the highest matching resolution. | 594 // If that fails, fall back to the highest matching resolution. |
| 590 bool preserve_aspect = attempt == 0; | 595 bool preserve_aspect = attempt == 0; |
| 591 | 596 |
| 592 if (internal_outputs == 1) { | 597 if (internal_outputs == 1) { |
| 593 if (one_is_internal) { | 598 if (one_is_internal) { |
| 594 can_mirror = FindMirrorMode(&cached_outputs_[0], &cached_outputs_[1], | 599 can_mirror = FindMirrorMode(&cached_outputs_[0], |
| 595 is_panel_fitting_enabled_, preserve_aspect); | 600 &cached_outputs_[1], |
| 601 is_panel_fitting_enabled_, |
| 602 preserve_aspect); |
| 596 } else { | 603 } else { |
| 597 DCHECK(two_is_internal); | 604 DCHECK(two_is_internal); |
| 598 can_mirror = FindMirrorMode(&cached_outputs_[1], &cached_outputs_[0], | 605 can_mirror = FindMirrorMode(&cached_outputs_[1], |
| 599 is_panel_fitting_enabled_, preserve_aspect); | 606 &cached_outputs_[0], |
| 607 is_panel_fitting_enabled_, |
| 608 preserve_aspect); |
| 600 } | 609 } |
| 601 } else { // if (internal_outputs == 0) | 610 } else { // if (internal_outputs == 0) |
| 602 // No panel fitting for external outputs, so fall back to exact match. | 611 // No panel fitting for external outputs, so fall back to exact match. |
| 603 can_mirror = FindMirrorMode(&cached_outputs_[0], &cached_outputs_[1], | 612 can_mirror = FindMirrorMode( |
| 604 false, preserve_aspect); | 613 &cached_outputs_[0], &cached_outputs_[1], false, preserve_aspect); |
| 605 if (!can_mirror && preserve_aspect) { | 614 if (!can_mirror && preserve_aspect) { |
| 606 // FindMirrorMode() will try to preserve aspect ratio of what it | 615 // FindMirrorMode() will try to preserve aspect ratio of what it |
| 607 // thinks is external display, so if it didn't succeed with one, maybe | 616 // thinks is external display, so if it didn't succeed with one, maybe |
| 608 // it will succeed with the other. This way we will have the correct | 617 // it will succeed with the other. This way we will have the correct |
| 609 // aspect ratio on at least one of them. | 618 // aspect ratio on at least one of them. |
| 610 can_mirror = FindMirrorMode(&cached_outputs_[1], &cached_outputs_[0], | 619 can_mirror = FindMirrorMode( |
| 611 false, preserve_aspect); | 620 &cached_outputs_[1], &cached_outputs_[0], false, preserve_aspect); |
| 612 } | 621 } |
| 613 } | 622 } |
| 614 } | 623 } |
| 615 } | 624 } |
| 616 } | 625 } |
| 617 | 626 |
| 618 bool OutputConfigurator::FindMirrorMode(OutputSnapshot* internal_output, | 627 bool OutputConfigurator::FindMirrorMode(OutputSnapshot* internal_output, |
| 619 OutputSnapshot* external_output, | 628 OutputSnapshot* external_output, |
| 620 bool try_panel_fitting, | 629 bool try_panel_fitting, |
| 621 bool preserve_aspect) { | 630 bool preserve_aspect) { |
| 622 const ModeInfo* internal_native_info = | 631 const ModeInfo* internal_native_info = |
| 623 GetModeInfo(*internal_output, internal_output->native_mode); | 632 GetModeInfo(*internal_output, internal_output->native_mode); |
| 624 const ModeInfo* external_native_info = | 633 const ModeInfo* external_native_info = |
| 625 GetModeInfo(*external_output, external_output->native_mode); | 634 GetModeInfo(*external_output, external_output->native_mode); |
| 626 if (!internal_native_info || !external_native_info) | 635 if (!internal_native_info || !external_native_info) |
| 627 return false; | 636 return false; |
| 628 | 637 |
| 629 // Check if some external output resolution can be mirrored on internal. | 638 // Check if some external output resolution can be mirrored on internal. |
| 630 // Prefer the modes in the order that X sorts them, assuming this is the order | 639 // Prefer the modes in the order that X sorts them, assuming this is the order |
| 631 // in which they look better on the monitor. | 640 // in which they look better on the monitor. |
| 632 for (ModeInfoMap::const_iterator external_it = | 641 for (ModeInfoMap::const_iterator external_it = |
| 633 external_output->mode_infos.begin(); | 642 external_output->mode_infos.begin(); |
| 634 external_it != external_output->mode_infos.end(); ++external_it) { | 643 external_it != external_output->mode_infos.end(); |
| 644 ++external_it) { |
| 635 const ModeInfo& external_info = external_it->second; | 645 const ModeInfo& external_info = external_it->second; |
| 636 bool is_native_aspect_ratio = | 646 bool is_native_aspect_ratio = |
| 637 external_native_info->width * external_info.height == | 647 external_native_info->width * external_info.height == |
| 638 external_native_info->height * external_info.width; | 648 external_native_info->height * external_info.width; |
| 639 if (preserve_aspect && !is_native_aspect_ratio) | 649 if (preserve_aspect && !is_native_aspect_ratio) |
| 640 continue; // Allow only aspect ratio preserving modes for mirroring. | 650 continue; // Allow only aspect ratio preserving modes for mirroring. |
| 641 | 651 |
| 642 // Try finding an exact match. | 652 // Try finding an exact match. |
| 643 for (ModeInfoMap::const_iterator internal_it = | 653 for (ModeInfoMap::const_iterator internal_it = |
| 644 internal_output->mode_infos.begin(); | 654 internal_output->mode_infos.begin(); |
| 645 internal_it != internal_output->mode_infos.end(); ++internal_it) { | 655 internal_it != internal_output->mode_infos.end(); |
| 656 ++internal_it) { |
| 646 const ModeInfo& internal_info = internal_it->second; | 657 const ModeInfo& internal_info = internal_it->second; |
| 647 if (internal_info.width == external_info.width && | 658 if (internal_info.width == external_info.width && |
| 648 internal_info.height == external_info.height && | 659 internal_info.height == external_info.height && |
| 649 internal_info.interlaced == external_info.interlaced) { | 660 internal_info.interlaced == external_info.interlaced) { |
| 650 internal_output->mirror_mode = internal_it->first; | 661 internal_output->mirror_mode = internal_it->first; |
| 651 external_output->mirror_mode = external_it->first; | 662 external_output->mirror_mode = external_it->first; |
| 652 return true; // Mirror mode found. | 663 return true; // Mirror mode found. |
| 653 } | 664 } |
| 654 } | 665 } |
| 655 | 666 |
| 656 // Try to create a matching internal output mode by panel fitting. | 667 // Try to create a matching internal output mode by panel fitting. |
| 657 if (try_panel_fitting) { | 668 if (try_panel_fitting) { |
| 658 // We can downscale by 1.125, and upscale indefinitely. Downscaling looks | 669 // We can downscale by 1.125, and upscale indefinitely. Downscaling looks |
| 659 // ugly, so, can fit == can upscale. Also, internal panels don't support | 670 // ugly, so, can fit == can upscale. Also, internal panels don't support |
| 660 // fitting interlaced modes. | 671 // fitting interlaced modes. |
| 661 bool can_fit = | 672 bool can_fit = internal_native_info->width >= external_info.width && |
| 662 internal_native_info->width >= external_info.width && | 673 internal_native_info->height >= external_info.height && |
| 663 internal_native_info->height >= external_info.height && | 674 !external_info.interlaced; |
| 664 !external_info.interlaced; | |
| 665 if (can_fit) { | 675 if (can_fit) { |
| 666 RRMode mode = external_it->first; | 676 RRMode mode = external_it->first; |
| 667 native_display_delegate_->AddMode(*internal_output, mode); | 677 native_display_delegate_->AddMode(*internal_output, mode); |
| 668 internal_output->mode_infos.insert(std::make_pair(mode, external_info)); | 678 internal_output->mode_infos.insert(std::make_pair(mode, external_info)); |
| 669 internal_output->mirror_mode = mode; | 679 internal_output->mirror_mode = mode; |
| 670 external_output->mirror_mode = mode; | 680 external_output->mirror_mode = mode; |
| 671 return true; // Mirror mode created. | 681 return true; // Mirror mode created. |
| 672 } | 682 } |
| 673 } | 683 } |
| 674 } | 684 } |
| 675 | 685 |
| 676 return false; | 686 return false; |
| 677 } | 687 } |
| 678 | 688 |
| 679 void OutputConfigurator::ConfigureOutputs() { | 689 void OutputConfigurator::ConfigureOutputs() { |
| 680 configure_timer_.reset(); | 690 configure_timer_.reset(); |
| 681 | 691 |
| 682 if (!configure_display_) | 692 if (!configure_display_) |
| 683 return; | 693 return; |
| 684 | 694 |
| 685 native_display_delegate_->GrabServer(); | 695 native_display_delegate_->GrabServer(); |
| 686 UpdateCachedOutputs(); | 696 UpdateCachedOutputs(); |
| 687 const ui::OutputState new_state = ChooseOutputState(power_state_); | 697 const OutputState new_state = ChooseOutputState(power_state_); |
| 688 const bool success = EnterStateOrFallBackToSoftwareMirroring( | 698 const bool success = |
| 689 new_state, power_state_); | 699 EnterStateOrFallBackToSoftwareMirroring(new_state, power_state_); |
| 690 native_display_delegate_->UngrabServer(); | 700 native_display_delegate_->UngrabServer(); |
| 691 | 701 |
| 692 NotifyObservers(success, new_state); | 702 NotifyObservers(success, new_state); |
| 693 } | 703 } |
| 694 | 704 |
| 695 void OutputConfigurator::NotifyObservers(bool success, | 705 void OutputConfigurator::NotifyObservers(bool success, |
| 696 ui::OutputState attempted_state) { | 706 OutputState attempted_state) { |
| 697 if (success) { | 707 if (success) { |
| 698 FOR_EACH_OBSERVER(Observer, observers_, | 708 FOR_EACH_OBSERVER( |
| 699 OnDisplayModeChanged(cached_outputs_)); | 709 Observer, observers_, OnDisplayModeChanged(cached_outputs_)); |
| 700 } else { | 710 } else { |
| 701 FOR_EACH_OBSERVER(Observer, observers_, | 711 FOR_EACH_OBSERVER( |
| 702 OnDisplayModeChangeFailed(attempted_state)); | 712 Observer, observers_, OnDisplayModeChangeFailed(attempted_state)); |
| 703 } | 713 } |
| 704 } | 714 } |
| 705 | 715 |
| 706 bool OutputConfigurator::EnterStateOrFallBackToSoftwareMirroring( | 716 bool OutputConfigurator::EnterStateOrFallBackToSoftwareMirroring( |
| 707 ui::OutputState output_state, | 717 OutputState output_state, |
| 708 DisplayPowerState power_state) { | 718 chromeos::DisplayPowerState power_state) { |
| 709 bool success = EnterState(output_state, power_state); | 719 bool success = EnterState(output_state, power_state); |
| 710 if (mirroring_controller_) { | 720 if (mirroring_controller_) { |
| 711 bool enable_software_mirroring = false; | 721 bool enable_software_mirroring = false; |
| 712 if (!success && output_state == ui::OUTPUT_STATE_DUAL_MIRROR) { | 722 if (!success && output_state == OUTPUT_STATE_DUAL_MIRROR) { |
| 713 if (output_state_ != ui::OUTPUT_STATE_DUAL_EXTENDED || | 723 if (output_state_ != OUTPUT_STATE_DUAL_EXTENDED || |
| 714 power_state_ != power_state) | 724 power_state_ != power_state) |
| 715 EnterState(ui::OUTPUT_STATE_DUAL_EXTENDED, power_state); | 725 EnterState(OUTPUT_STATE_DUAL_EXTENDED, power_state); |
| 716 enable_software_mirroring = success = | 726 enable_software_mirroring = success = |
| 717 output_state_ == ui::OUTPUT_STATE_DUAL_EXTENDED; | 727 output_state_ == OUTPUT_STATE_DUAL_EXTENDED; |
| 718 } | 728 } |
| 719 mirroring_controller_->SetSoftwareMirroring(enable_software_mirroring); | 729 mirroring_controller_->SetSoftwareMirroring(enable_software_mirroring); |
| 720 } | 730 } |
| 721 return success; | 731 return success; |
| 722 } | 732 } |
| 723 | 733 |
| 724 bool OutputConfigurator::EnterState(ui::OutputState output_state, | 734 bool OutputConfigurator::EnterState(OutputState output_state, |
| 725 DisplayPowerState power_state) { | 735 chromeos::DisplayPowerState power_state) { |
| 726 std::vector<bool> output_power; | 736 std::vector<bool> output_power; |
| 727 int num_on_outputs = GetOutputPower( | 737 int num_on_outputs = |
| 728 cached_outputs_, power_state, &output_power); | 738 GetOutputPower(cached_outputs_, power_state, &output_power); |
| 729 VLOG(1) << "EnterState: output=" << OutputStateToString(output_state) | 739 VLOG(1) << "EnterState: output=" << OutputStateToString(output_state) |
| 730 << " power=" << DisplayPowerStateToString(power_state); | 740 << " power=" << DisplayPowerStateToString(power_state); |
| 731 | 741 |
| 732 // Framebuffer dimensions. | 742 // Framebuffer dimensions. |
| 733 int width = 0, height = 0; | 743 int width = 0, height = 0; |
| 734 std::vector<OutputSnapshot> updated_outputs = cached_outputs_; | 744 std::vector<OutputSnapshot> updated_outputs = cached_outputs_; |
| 735 | 745 |
| 736 switch (output_state) { | 746 switch (output_state) { |
| 737 case ui::OUTPUT_STATE_INVALID: | 747 case OUTPUT_STATE_INVALID: |
| 738 NOTREACHED() << "Ignoring request to enter invalid state with " | 748 NOTREACHED() << "Ignoring request to enter invalid state with " |
| 739 << updated_outputs.size() << " connected output(s)"; | 749 << updated_outputs.size() << " connected output(s)"; |
| 740 return false; | 750 return false; |
| 741 case ui::OUTPUT_STATE_HEADLESS: | 751 case OUTPUT_STATE_HEADLESS: |
| 742 if (updated_outputs.size() != 0) { | 752 if (updated_outputs.size() != 0) { |
| 743 LOG(WARNING) << "Ignoring request to enter headless mode with " | 753 LOG(WARNING) << "Ignoring request to enter headless mode with " |
| 744 << updated_outputs.size() << " connected output(s)"; | 754 << updated_outputs.size() << " connected output(s)"; |
| 745 return false; | 755 return false; |
| 746 } | 756 } |
| 747 break; | 757 break; |
| 748 case ui::OUTPUT_STATE_SINGLE: { | 758 case OUTPUT_STATE_SINGLE: { |
| 749 // If there are multiple outputs connected, only one should be turned on. | 759 // If there are multiple outputs connected, only one should be turned on. |
| 750 if (updated_outputs.size() != 1 && num_on_outputs != 1) { | 760 if (updated_outputs.size() != 1 && num_on_outputs != 1) { |
| 751 LOG(WARNING) << "Ignoring request to enter single mode with " | 761 LOG(WARNING) << "Ignoring request to enter single mode with " |
| 752 << updated_outputs.size() << " connected outputs and " | 762 << updated_outputs.size() << " connected outputs and " |
| 753 << num_on_outputs << " turned on"; | 763 << num_on_outputs << " turned on"; |
| 754 return false; | 764 return false; |
| 755 } | 765 } |
| 756 | 766 |
| 757 for (size_t i = 0; i < updated_outputs.size(); ++i) { | 767 for (size_t i = 0; i < updated_outputs.size(); ++i) { |
| 758 OutputSnapshot* output = &updated_outputs[i]; | 768 OutputSnapshot* output = &updated_outputs[i]; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 773 << ", i=" << i | 783 << ", i=" << i |
| 774 << ", output=" << OutputSnapshotToString(output) | 784 << ", output=" << OutputSnapshotToString(output) |
| 775 << ", mode_info=" << ModeInfoToString(mode_info); | 785 << ", mode_info=" << ModeInfoToString(mode_info); |
| 776 } | 786 } |
| 777 width = mode_info->width; | 787 width = mode_info->width; |
| 778 height = mode_info->height; | 788 height = mode_info->height; |
| 779 } | 789 } |
| 780 } | 790 } |
| 781 break; | 791 break; |
| 782 } | 792 } |
| 783 case ui::OUTPUT_STATE_DUAL_MIRROR: { | 793 case OUTPUT_STATE_DUAL_MIRROR: { |
| 784 if (updated_outputs.size() != 2 || | 794 if (updated_outputs.size() != 2 || |
| 785 (num_on_outputs != 0 && num_on_outputs != 2)) { | 795 (num_on_outputs != 0 && num_on_outputs != 2)) { |
| 786 LOG(WARNING) << "Ignoring request to enter mirrored mode with " | 796 LOG(WARNING) << "Ignoring request to enter mirrored mode with " |
| 787 << updated_outputs.size() << " connected output(s) and " | 797 << updated_outputs.size() << " connected output(s) and " |
| 788 << num_on_outputs << " turned on"; | 798 << num_on_outputs << " turned on"; |
| 789 return false; | 799 return false; |
| 790 } | 800 } |
| 791 | 801 |
| 792 if (!updated_outputs[0].mirror_mode) | 802 if (!updated_outputs[0].mirror_mode) |
| 793 return false; | 803 return false; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 809 if (output->mirror_mode != output->native_mode && | 819 if (output->mirror_mode != output->native_mode && |
| 810 output->is_aspect_preserving_scaling) { | 820 output->is_aspect_preserving_scaling) { |
| 811 output->transform = GetMirrorModeCTM(*output); | 821 output->transform = GetMirrorModeCTM(*output); |
| 812 mirrored_display_area_ratio_map_[output->touch_device_id] = | 822 mirrored_display_area_ratio_map_[output->touch_device_id] = |
| 813 GetMirroredDisplayAreaRatio(*output); | 823 GetMirroredDisplayAreaRatio(*output); |
| 814 } | 824 } |
| 815 } | 825 } |
| 816 } | 826 } |
| 817 break; | 827 break; |
| 818 } | 828 } |
| 819 case ui::OUTPUT_STATE_DUAL_EXTENDED: { | 829 case OUTPUT_STATE_DUAL_EXTENDED: { |
| 820 if (updated_outputs.size() != 2 || | 830 if (updated_outputs.size() != 2 || |
| 821 (num_on_outputs != 0 && num_on_outputs != 2)) { | 831 (num_on_outputs != 0 && num_on_outputs != 2)) { |
| 822 LOG(WARNING) << "Ignoring request to enter extended mode with " | 832 LOG(WARNING) << "Ignoring request to enter extended mode with " |
| 823 << updated_outputs.size() << " connected output(s) and " | 833 << updated_outputs.size() << " connected output(s) and " |
| 824 << num_on_outputs << " turned on"; | 834 << num_on_outputs << " turned on"; |
| 825 return false; | 835 return false; |
| 826 } | 836 } |
| 827 | 837 |
| 828 for (size_t i = 0; i < updated_outputs.size(); ++i) { | 838 for (size_t i = 0; i < updated_outputs.size(); ++i) { |
| 829 OutputSnapshot* output = &updated_outputs[i]; | 839 OutputSnapshot* output = &updated_outputs[i]; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 851 } | 861 } |
| 852 } | 862 } |
| 853 | 863 |
| 854 // Finally, apply the desired changes. | 864 // Finally, apply the desired changes. |
| 855 DCHECK_EQ(cached_outputs_.size(), updated_outputs.size()); | 865 DCHECK_EQ(cached_outputs_.size(), updated_outputs.size()); |
| 856 bool all_succeeded = true; | 866 bool all_succeeded = true; |
| 857 if (!updated_outputs.empty()) { | 867 if (!updated_outputs.empty()) { |
| 858 native_display_delegate_->CreateFrameBuffer(width, height, updated_outputs); | 868 native_display_delegate_->CreateFrameBuffer(width, height, updated_outputs); |
| 859 for (size_t i = 0; i < updated_outputs.size(); ++i) { | 869 for (size_t i = 0; i < updated_outputs.size(); ++i) { |
| 860 const OutputSnapshot& output = updated_outputs[i]; | 870 const OutputSnapshot& output = updated_outputs[i]; |
| 861 bool configure_succeeded =false; | 871 bool configure_succeeded = false; |
| 862 | 872 |
| 863 while (true) { | 873 while (true) { |
| 864 if (native_display_delegate_->Configure(output, | 874 if (native_display_delegate_->Configure( |
| 865 output.current_mode, | 875 output, output.current_mode, output.x, output.y)) { |
| 866 output.x, | |
| 867 output.y)) { | |
| 868 configure_succeeded = true; | 876 configure_succeeded = true; |
| 869 break; | 877 break; |
| 870 } | 878 } |
| 871 | 879 |
| 872 LOG(WARNING) << "Unable to configure CRTC " << output.crtc << ":" | 880 LOG(WARNING) << "Unable to configure CRTC " << output.crtc << ":" |
| 873 << " mode=" << output.current_mode | 881 << " mode=" << output.current_mode |
| 874 << " output=" << output.output | 882 << " output=" << output.output << " x=" << output.x |
| 875 << " x=" << output.x | |
| 876 << " y=" << output.y; | 883 << " y=" << output.y; |
| 877 | 884 |
| 878 const ModeInfo* mode_info = GetModeInfo(output, output.current_mode); | 885 const ModeInfo* mode_info = GetModeInfo(output, output.current_mode); |
| 879 if (!mode_info) | 886 if (!mode_info) |
| 880 break; | 887 break; |
| 881 | 888 |
| 882 // Find the mode with the next-best resolution and see if that can | 889 // Find the mode with the next-best resolution and see if that can |
| 883 // be set. | 890 // be set. |
| 884 int best_mode_pixels = 0; | 891 int best_mode_pixels = 0; |
| 885 | 892 |
| 886 int current_mode_pixels = mode_info->width * mode_info->height; | 893 int current_mode_pixels = mode_info->width * mode_info->height; |
| 887 for (ModeInfoMap::const_iterator it = output.mode_infos.begin(); | 894 for (ModeInfoMap::const_iterator it = output.mode_infos.begin(); |
| 888 it != output.mode_infos.end(); it++) { | 895 it != output.mode_infos.end(); |
| 896 it++) { |
| 889 int pixel_count = it->second.width * it->second.height; | 897 int pixel_count = it->second.width * it->second.height; |
| 890 if ((pixel_count < current_mode_pixels) && | 898 if ((pixel_count < current_mode_pixels) && |
| 891 (pixel_count > best_mode_pixels)) { | 899 (pixel_count > best_mode_pixels)) { |
| 892 updated_outputs[i].current_mode = it->first; | 900 updated_outputs[i].current_mode = it->first; |
| 893 best_mode_pixels = pixel_count; | 901 best_mode_pixels = pixel_count; |
| 894 } | 902 } |
| 895 } | 903 } |
| 896 | 904 |
| 897 if (best_mode_pixels == 0) | 905 if (best_mode_pixels == 0) |
| 898 break; | 906 break; |
| 899 } | 907 } |
| 900 | 908 |
| 901 if (configure_succeeded) { | 909 if (configure_succeeded) { |
| 902 if (output.touch_device_id) | 910 if (output.touch_device_id) |
| 903 touchscreen_delegate_->ConfigureCTM(output.touch_device_id, | 911 touchscreen_delegate_->ConfigureCTM(output.touch_device_id, |
| 904 output.transform); | 912 output.transform); |
| 905 cached_outputs_[i] = updated_outputs[i]; | 913 cached_outputs_[i] = updated_outputs[i]; |
| 906 } else { | 914 } else { |
| 907 all_succeeded = false; | 915 all_succeeded = false; |
| 908 } | 916 } |
| 909 | 917 |
| 910 // If we are trying to set mirror mode and one of the modesets fails, | 918 // If we are trying to set mirror mode and one of the modesets fails, |
| 911 // then the two monitors will be mis-matched. In this case, return | 919 // then the two monitors will be mis-matched. In this case, return |
| 912 // false to let the observers be aware. | 920 // false to let the observers be aware. |
| 913 if (output_state == ui::OUTPUT_STATE_DUAL_MIRROR && output_power[i] && | 921 if (output_state == OUTPUT_STATE_DUAL_MIRROR && output_power[i] && |
| 914 output.current_mode != output.mirror_mode) | 922 output.current_mode != output.mirror_mode) |
| 915 all_succeeded = false; | 923 all_succeeded = false; |
| 916 | |
| 917 } | 924 } |
| 918 } | 925 } |
| 919 | 926 |
| 920 if (all_succeeded) { | 927 if (all_succeeded) { |
| 921 output_state_ = output_state; | 928 output_state_ = output_state; |
| 922 power_state_ = power_state; | 929 power_state_ = power_state; |
| 923 } | 930 } |
| 924 return all_succeeded; | 931 return all_succeeded; |
| 925 } | 932 } |
| 926 | 933 |
| 927 ui::OutputState OutputConfigurator::ChooseOutputState( | 934 OutputState OutputConfigurator::ChooseOutputState( |
| 928 DisplayPowerState power_state) const { | 935 chromeos::DisplayPowerState power_state) const { |
| 929 int num_on_outputs = GetOutputPower(cached_outputs_, power_state, NULL); | 936 int num_on_outputs = GetOutputPower(cached_outputs_, power_state, NULL); |
| 930 switch (cached_outputs_.size()) { | 937 switch (cached_outputs_.size()) { |
| 931 case 0: | 938 case 0: |
| 932 return ui::OUTPUT_STATE_HEADLESS; | 939 return OUTPUT_STATE_HEADLESS; |
| 933 case 1: | 940 case 1: |
| 934 return ui::OUTPUT_STATE_SINGLE; | 941 return OUTPUT_STATE_SINGLE; |
| 935 case 2: { | 942 case 2: { |
| 936 if (num_on_outputs == 1) { | 943 if (num_on_outputs == 1) { |
| 937 // If only one output is currently turned on, return the "single" | 944 // If only one output is currently turned on, return the "single" |
| 938 // state so that its native mode will be used. | 945 // state so that its native mode will be used. |
| 939 return ui::OUTPUT_STATE_SINGLE; | 946 return OUTPUT_STATE_SINGLE; |
| 940 } else { | 947 } else { |
| 941 // With either both outputs on or both outputs off, use one of the | 948 // With either both outputs on or both outputs off, use one of the |
| 942 // dual modes. | 949 // dual modes. |
| 943 std::vector<int64> display_ids; | 950 std::vector<int64> display_ids; |
| 944 for (size_t i = 0; i < cached_outputs_.size(); ++i) { | 951 for (size_t i = 0; i < cached_outputs_.size(); ++i) { |
| 945 // If display id isn't available, switch to extended mode. | 952 // If display id isn't available, switch to extended mode. |
| 946 if (!cached_outputs_[i].has_display_id) | 953 if (!cached_outputs_[i].has_display_id) |
| 947 return ui::OUTPUT_STATE_DUAL_EXTENDED; | 954 return OUTPUT_STATE_DUAL_EXTENDED; |
| 948 display_ids.push_back(cached_outputs_[i].display_id); | 955 display_ids.push_back(cached_outputs_[i].display_id); |
| 949 } | 956 } |
| 950 return state_controller_->GetStateForDisplayIds(display_ids); | 957 return state_controller_->GetStateForDisplayIds(display_ids); |
| 951 } | 958 } |
| 952 } | 959 } |
| 953 default: | 960 default: |
| 954 NOTREACHED(); | 961 NOTREACHED(); |
| 955 } | 962 } |
| 956 return ui::OUTPUT_STATE_INVALID; | 963 return OUTPUT_STATE_INVALID; |
| 957 } | 964 } |
| 958 | 965 |
| 959 OutputConfigurator::CoordinateTransformation | 966 OutputConfigurator::CoordinateTransformation |
| 960 OutputConfigurator::GetMirrorModeCTM( | 967 OutputConfigurator::GetMirrorModeCTM( |
| 961 const OutputConfigurator::OutputSnapshot& output) { | 968 const OutputConfigurator::OutputSnapshot& output) { |
| 962 CoordinateTransformation ctm; // Default to identity | 969 CoordinateTransformation ctm; // Default to identity |
| 963 const ModeInfo* native_mode_info = GetModeInfo(output, output.native_mode); | 970 const ModeInfo* native_mode_info = GetModeInfo(output, output.native_mode); |
| 964 const ModeInfo* mirror_mode_info = GetModeInfo(output, output.mirror_mode); | 971 const ModeInfo* mirror_mode_info = GetModeInfo(output, output.mirror_mode); |
| 965 | 972 |
| 966 if (!native_mode_info || !mirror_mode_info || | 973 if (!native_mode_info || !mirror_mode_info || native_mode_info->height == 0 || |
| 967 native_mode_info->height == 0 || mirror_mode_info->height == 0 || | 974 mirror_mode_info->height == 0 || native_mode_info->width == 0 || |
| 968 native_mode_info->width == 0 || mirror_mode_info->width == 0) | 975 mirror_mode_info->width == 0) |
| 969 return ctm; | 976 return ctm; |
| 970 | 977 |
| 971 float native_mode_ar = static_cast<float>(native_mode_info->width) / | 978 float native_mode_ar = static_cast<float>(native_mode_info->width) / |
| 972 static_cast<float>(native_mode_info->height); | 979 static_cast<float>(native_mode_info->height); |
| 973 float mirror_mode_ar = static_cast<float>(mirror_mode_info->width) / | 980 float mirror_mode_ar = static_cast<float>(mirror_mode_info->width) / |
| 974 static_cast<float>(mirror_mode_info->height); | 981 static_cast<float>(mirror_mode_info->height); |
| 975 | 982 |
| 976 if (mirror_mode_ar > native_mode_ar) { // Letterboxing | 983 if (mirror_mode_ar > native_mode_ar) { // Letterboxing |
| 977 ctm.x_scale = 1.0; | 984 ctm.x_scale = 1.0; |
| 978 ctm.x_offset = 0.0; | 985 ctm.x_offset = 0.0; |
| 979 ctm.y_scale = mirror_mode_ar / native_mode_ar; | 986 ctm.y_scale = mirror_mode_ar / native_mode_ar; |
| 980 ctm.y_offset = (native_mode_ar / mirror_mode_ar - 1.0) * 0.5; | 987 ctm.y_offset = (native_mode_ar / mirror_mode_ar - 1.0) * 0.5; |
| 981 return ctm; | 988 return ctm; |
| 982 } | 989 } |
| 983 if (native_mode_ar > mirror_mode_ar) { // Pillarboxing | 990 if (native_mode_ar > mirror_mode_ar) { // Pillarboxing |
| 984 ctm.y_scale = 1.0; | 991 ctm.y_scale = 1.0; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1029 ctm.y_offset = static_cast<float>(output.y) / (framebuffer_height - 1); | 1036 ctm.y_offset = static_cast<float>(output.y) / (framebuffer_height - 1); |
| 1030 return ctm; | 1037 return ctm; |
| 1031 } | 1038 } |
| 1032 | 1039 |
| 1033 float OutputConfigurator::GetMirroredDisplayAreaRatio( | 1040 float OutputConfigurator::GetMirroredDisplayAreaRatio( |
| 1034 const OutputConfigurator::OutputSnapshot& output) { | 1041 const OutputConfigurator::OutputSnapshot& output) { |
| 1035 float area_ratio = 1.0f; | 1042 float area_ratio = 1.0f; |
| 1036 const ModeInfo* native_mode_info = GetModeInfo(output, output.native_mode); | 1043 const ModeInfo* native_mode_info = GetModeInfo(output, output.native_mode); |
| 1037 const ModeInfo* mirror_mode_info = GetModeInfo(output, output.mirror_mode); | 1044 const ModeInfo* mirror_mode_info = GetModeInfo(output, output.mirror_mode); |
| 1038 | 1045 |
| 1039 if (!native_mode_info || !mirror_mode_info || | 1046 if (!native_mode_info || !mirror_mode_info || native_mode_info->height == 0 || |
| 1040 native_mode_info->height == 0 || mirror_mode_info->height == 0 || | 1047 mirror_mode_info->height == 0 || native_mode_info->width == 0 || |
| 1041 native_mode_info->width == 0 || mirror_mode_info->width == 0) | 1048 mirror_mode_info->width == 0) |
| 1042 return area_ratio; | 1049 return area_ratio; |
| 1043 | 1050 |
| 1044 float width_ratio = static_cast<float>(mirror_mode_info->width) / | 1051 float width_ratio = static_cast<float>(mirror_mode_info->width) / |
| 1045 static_cast<float>(native_mode_info->width); | 1052 static_cast<float>(native_mode_info->width); |
| 1046 float height_ratio = static_cast<float>(mirror_mode_info->height) / | 1053 float height_ratio = static_cast<float>(mirror_mode_info->height) / |
| 1047 static_cast<float>(native_mode_info->height); | 1054 static_cast<float>(native_mode_info->height); |
| 1048 | 1055 |
| 1049 area_ratio = width_ratio * height_ratio; | 1056 area_ratio = width_ratio * height_ratio; |
| 1050 return area_ratio; | 1057 return area_ratio; |
| 1051 } | 1058 } |
| 1052 | 1059 |
| 1053 } // namespace chromeos | 1060 } // namespace ui |
| OLD | NEW |