|  | // Copyright 2014 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "ui/display/chromeos/configure_displays_task.h" | 
|  |  | 
|  | #include "base/auto_reset.h" | 
|  | #include "base/bind.h" | 
|  | #include "ui/display/types/display_snapshot.h" | 
|  | #include "ui/display/types/native_display_delegate.h" | 
|  |  | 
|  | namespace ui { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Find the next best mode after |display_mode|. If none can be found return | 
|  | // nullptr. | 
|  | const DisplayMode* FindNextMode(const DisplaySnapshot& display_state, | 
|  | const DisplayMode* display_mode) { | 
|  | if (!display_mode) | 
|  | return nullptr; | 
|  |  | 
|  | int best_mode_pixels = 0; | 
|  | const DisplayMode* best_mode = nullptr; | 
|  | int current_mode_pixels = display_mode->size().GetArea(); | 
|  | for (const DisplayMode* mode : display_state.modes()) { | 
|  | int pixel_count = mode->size().GetArea(); | 
|  | if (pixel_count < current_mode_pixels && pixel_count > best_mode_pixels) { | 
|  | best_mode = mode; | 
|  | best_mode_pixels = pixel_count; | 
|  | } | 
|  | } | 
|  |  | 
|  | return best_mode; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | DisplayConfigureRequest::DisplayConfigureRequest(DisplaySnapshot* display, | 
|  | const DisplayMode* mode, | 
|  | const gfx::Point& origin) | 
|  | : display(display), mode(mode), origin(origin) { | 
|  | } | 
|  |  | 
|  | ConfigureDisplaysTask::ConfigureDisplaysTask( | 
|  | NativeDisplayDelegate* delegate, | 
|  | const std::vector<DisplayConfigureRequest>& requests, | 
|  | const ResponseCallback& callback) | 
|  | : delegate_(delegate), | 
|  | requests_(requests), | 
|  | callback_(callback), | 
|  | is_configuring_(false), | 
|  | num_displays_configured_(0), | 
|  | task_status_(SUCCESS), | 
|  | weak_ptr_factory_(this) { | 
|  | for (size_t i = 0; i < requests_.size(); ++i) | 
|  | pending_request_indexes_.push(i); | 
|  | } | 
|  |  | 
|  | ConfigureDisplaysTask::~ConfigureDisplaysTask() { | 
|  | } | 
|  |  | 
|  | void ConfigureDisplaysTask::Run() { | 
|  | // Synchronous configurators will recursively call Run(). In that case just | 
|  | // defer their call to the next iteration in the while-loop. This is done to | 
|  | // guard against stack overflows if the display has a large list of broken | 
|  | // modes. | 
|  | if (is_configuring_) | 
|  | return; | 
|  |  | 
|  | { | 
|  | base::AutoReset<bool> recursivity_guard(&is_configuring_, true); | 
|  | while (!pending_request_indexes_.empty()) { | 
|  | size_t index = pending_request_indexes_.front(); | 
|  | DisplayConfigureRequest* request = &requests_[index]; | 
|  | pending_request_indexes_.pop(); | 
|  | delegate_->Configure(*request->display, request->mode, request->origin, | 
|  | base::Bind(&ConfigureDisplaysTask::OnConfigured, | 
|  | weak_ptr_factory_.GetWeakPtr(), index)); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Nothing should be modified after the |callback_| is called since the | 
|  | // task may be deleted in the callback. | 
|  | if (num_displays_configured_ == requests_.size()) | 
|  | callback_.Run(task_status_); | 
|  | } | 
|  |  | 
|  | void ConfigureDisplaysTask::OnConfigured(size_t index, bool success) { | 
|  | DisplayConfigureRequest* request = &requests_[index]; | 
|  | VLOG(2) << "Configured status=" << success | 
|  | << " display=" << request->display->display_id() | 
|  | << " origin=" << request->origin.ToString() | 
|  | << " mode=" << (request->mode ? request->mode->ToString() : "null"); | 
|  | if (!success) { | 
|  | request->mode = FindNextMode(*request->display, request->mode); | 
|  | if (request->mode) { | 
|  | pending_request_indexes_.push(index); | 
|  | if (task_status_ == SUCCESS) | 
|  | task_status_ = PARTIAL_SUCCESS; | 
|  |  | 
|  | Run(); | 
|  | return; | 
|  | } | 
|  | } else { | 
|  | request->display->set_current_mode(request->mode); | 
|  | request->display->set_origin(request->origin); | 
|  | } | 
|  |  | 
|  | num_displays_configured_++; | 
|  | if (!success) | 
|  | task_status_ = ERROR; | 
|  |  | 
|  | Run(); | 
|  | } | 
|  |  | 
|  | }  // namespace ui |