| OLD | NEW | 
 | (Empty) | 
|    1 // Copyright 2016 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 "ui/display/manager/display_layout.h" |  | 
|    6  |  | 
|    7 #include <algorithm> |  | 
|    8 #include <set> |  | 
|    9 #include <sstream> |  | 
|   10  |  | 
|   11 #include "base/logging.h" |  | 
|   12 #include "base/strings/string_number_conversions.h" |  | 
|   13 #include "base/strings/stringprintf.h" |  | 
|   14 #include "base/values.h" |  | 
|   15 #include "ui/display/display.h" |  | 
|   16 #include "ui/gfx/geometry/insets.h" |  | 
|   17  |  | 
|   18 namespace display { |  | 
|   19 namespace  { |  | 
|   20  |  | 
|   21 // DisplayPlacement Positions |  | 
|   22 const char kTop[] = "top"; |  | 
|   23 const char kRight[] = "right"; |  | 
|   24 const char kBottom[] = "bottom"; |  | 
|   25 const char kLeft[] = "left"; |  | 
|   26 const char kUnknown[] = "unknown"; |  | 
|   27  |  | 
|   28 // The maximum value for 'offset' in DisplayLayout in case of outliers.  Need |  | 
|   29 // to change this value in case to support even larger displays. |  | 
|   30 const int kMaxValidOffset = 10000; |  | 
|   31  |  | 
|   32 bool IsIdInList(int64_t id, const DisplayIdList& list) { |  | 
|   33   const auto iter = |  | 
|   34       std::find_if(list.begin(), list.end(), |  | 
|   35                    [id](int64_t display_id) { return display_id == id; }); |  | 
|   36   return iter != list.end(); |  | 
|   37 } |  | 
|   38  |  | 
|   39 Display* FindDisplayById(Displays* display_list, int64_t id) { |  | 
|   40   auto iter = |  | 
|   41       std::find_if(display_list->begin(), display_list->end(), |  | 
|   42                    [id](const Display& display) { return display.id() == id; }); |  | 
|   43   return &(*iter); |  | 
|   44 } |  | 
|   45  |  | 
|   46 }  // namespace |  | 
|   47  |  | 
|   48 //////////////////////////////////////////////////////////////////////////////// |  | 
|   49 // DisplayPlacement |  | 
|   50  |  | 
|   51 DisplayPlacement::DisplayPlacement() |  | 
|   52     : DisplayPlacement(kInvalidDisplayId, |  | 
|   53                        kInvalidDisplayId, |  | 
|   54                        DisplayPlacement::RIGHT, |  | 
|   55                        0, |  | 
|   56                        DisplayPlacement::TOP_LEFT) {} |  | 
|   57  |  | 
|   58 DisplayPlacement::DisplayPlacement(Position position, int offset) |  | 
|   59     : DisplayPlacement(kInvalidDisplayId, |  | 
|   60                        kInvalidDisplayId, |  | 
|   61                        position, |  | 
|   62                        offset, |  | 
|   63                        DisplayPlacement::TOP_LEFT) {} |  | 
|   64  |  | 
|   65 DisplayPlacement::DisplayPlacement(Position position, |  | 
|   66                                    int offset, |  | 
|   67                                    OffsetReference offset_reference) |  | 
|   68     : DisplayPlacement(kInvalidDisplayId, |  | 
|   69                        kInvalidDisplayId, |  | 
|   70                        position, |  | 
|   71                        offset, |  | 
|   72                        offset_reference) {} |  | 
|   73  |  | 
|   74 DisplayPlacement::DisplayPlacement(int64_t display_id, |  | 
|   75                                    int64_t parent_display_id, |  | 
|   76                                    Position position, |  | 
|   77                                    int offset, |  | 
|   78                                    OffsetReference offset_reference) |  | 
|   79     : display_id(display_id), |  | 
|   80       parent_display_id(parent_display_id), |  | 
|   81       position(position), |  | 
|   82       offset(offset), |  | 
|   83       offset_reference(offset_reference) { |  | 
|   84   DCHECK_LE(TOP, position); |  | 
|   85   DCHECK_GE(LEFT, position); |  | 
|   86   // Set the default value to |position| in case position is invalid.  DCHECKs |  | 
|   87   // above doesn't stop in Release builds. |  | 
|   88   if (TOP > position || LEFT < position) |  | 
|   89     this->position = RIGHT; |  | 
|   90  |  | 
|   91   DCHECK_GE(kMaxValidOffset, abs(offset)); |  | 
|   92 } |  | 
|   93  |  | 
|   94 DisplayPlacement::DisplayPlacement(const DisplayPlacement& placement) |  | 
|   95     : display_id(placement.display_id), |  | 
|   96       parent_display_id(placement.parent_display_id), |  | 
|   97       position(placement.position), |  | 
|   98       offset(placement.offset), |  | 
|   99       offset_reference(placement.offset_reference) {} |  | 
|  100  |  | 
|  101 DisplayPlacement& DisplayPlacement::Swap() { |  | 
|  102   switch (position) { |  | 
|  103     case TOP: |  | 
|  104       position = BOTTOM; |  | 
|  105       break; |  | 
|  106     case BOTTOM: |  | 
|  107       position = TOP; |  | 
|  108       break; |  | 
|  109     case RIGHT: |  | 
|  110       position = LEFT; |  | 
|  111       break; |  | 
|  112     case LEFT: |  | 
|  113       position = RIGHT; |  | 
|  114       break; |  | 
|  115   } |  | 
|  116   offset = -offset; |  | 
|  117   std::swap(display_id, parent_display_id); |  | 
|  118   return *this; |  | 
|  119 } |  | 
|  120  |  | 
|  121 std::string DisplayPlacement::ToString() const { |  | 
|  122   std::stringstream s; |  | 
|  123   if (display_id != kInvalidDisplayId) |  | 
|  124     s << "id=" << display_id << ", "; |  | 
|  125   if (parent_display_id != kInvalidDisplayId) |  | 
|  126     s << "parent=" << parent_display_id << ", "; |  | 
|  127   s << PositionToString(position) << ", "; |  | 
|  128   s << offset; |  | 
|  129   return s.str(); |  | 
|  130 } |  | 
|  131  |  | 
|  132 // static |  | 
|  133 std::string DisplayPlacement::PositionToString(Position position) { |  | 
|  134   switch (position) { |  | 
|  135     case TOP: |  | 
|  136       return kTop; |  | 
|  137     case RIGHT: |  | 
|  138       return kRight; |  | 
|  139     case BOTTOM: |  | 
|  140       return kBottom; |  | 
|  141     case LEFT: |  | 
|  142       return kLeft; |  | 
|  143   } |  | 
|  144   return kUnknown; |  | 
|  145 } |  | 
|  146  |  | 
|  147 // static |  | 
|  148 bool DisplayPlacement::StringToPosition(const base::StringPiece& string, |  | 
|  149                                         Position* position) { |  | 
|  150   if (string == kTop) { |  | 
|  151     *position = TOP; |  | 
|  152     return true; |  | 
|  153   } |  | 
|  154  |  | 
|  155   if (string == kRight) { |  | 
|  156     *position = RIGHT; |  | 
|  157     return true; |  | 
|  158   } |  | 
|  159  |  | 
|  160   if (string == kBottom) { |  | 
|  161     *position = BOTTOM; |  | 
|  162     return true; |  | 
|  163   } |  | 
|  164  |  | 
|  165   if (string == kLeft) { |  | 
|  166     *position = LEFT; |  | 
|  167     return true; |  | 
|  168   } |  | 
|  169  |  | 
|  170   LOG(ERROR) << "Invalid position value:" << string; |  | 
|  171  |  | 
|  172   return false; |  | 
|  173 } |  | 
|  174  |  | 
|  175 //////////////////////////////////////////////////////////////////////////////// |  | 
|  176 // DisplayLayout |  | 
|  177  |  | 
|  178 DisplayLayout::DisplayLayout() |  | 
|  179     : mirrored(false), default_unified(true), primary_id(kInvalidDisplayId) {} |  | 
|  180  |  | 
|  181 DisplayLayout::~DisplayLayout() {} |  | 
|  182  |  | 
|  183 void DisplayLayout::ApplyToDisplayList(Displays* display_list, |  | 
|  184                                        std::vector<int64_t>* updated_ids, |  | 
|  185                                        int minimum_offset_overlap) const { |  | 
|  186   // Layout from primary, then dependent displays. |  | 
|  187   std::set<int64_t> parents; |  | 
|  188   parents.insert(primary_id); |  | 
|  189   while (parents.size()) { |  | 
|  190     int64_t parent_id = *parents.begin(); |  | 
|  191     parents.erase(parent_id); |  | 
|  192     for (const DisplayPlacement& placement : placement_list) { |  | 
|  193       if (placement.parent_display_id == parent_id) { |  | 
|  194         if (ApplyDisplayPlacement(placement, |  | 
|  195                                   display_list, |  | 
|  196                                   minimum_offset_overlap) && |  | 
|  197             updated_ids) { |  | 
|  198           updated_ids->push_back(placement.display_id); |  | 
|  199         } |  | 
|  200         parents.insert(placement.display_id); |  | 
|  201       } |  | 
|  202     } |  | 
|  203   } |  | 
|  204 } |  | 
|  205  |  | 
|  206 // static |  | 
|  207 bool DisplayLayout::Validate(const DisplayIdList& list, |  | 
|  208                              const DisplayLayout& layout) { |  | 
|  209   // The primary display should be in the list. |  | 
|  210   DCHECK(IsIdInList(layout.primary_id, list)); |  | 
|  211  |  | 
|  212   // Unified mode, or mirror mode switched from unified mode, |  | 
|  213   // may not have the placement yet. |  | 
|  214   if (layout.placement_list.size() == 0u) |  | 
|  215     return true; |  | 
|  216  |  | 
|  217   bool has_primary_as_parent = false; |  | 
|  218   int64_t prev_id = std::numeric_limits<int64_t>::min(); |  | 
|  219   for (const auto& placement : layout.placement_list) { |  | 
|  220     // Placements are sorted by display_id. |  | 
|  221     if (prev_id >= placement.display_id) { |  | 
|  222       LOG(ERROR) << "PlacementList must be sorted by display_id"; |  | 
|  223       return false; |  | 
|  224     } |  | 
|  225     prev_id = placement.display_id; |  | 
|  226     if (placement.display_id == kInvalidDisplayId) { |  | 
|  227       LOG(ERROR) << "display_id is not initialized"; |  | 
|  228       return false; |  | 
|  229     } |  | 
|  230     if (placement.parent_display_id == kInvalidDisplayId) { |  | 
|  231       LOG(ERROR) << "display_parent_id is not initialized"; |  | 
|  232       return false; |  | 
|  233     } |  | 
|  234     if (placement.display_id == placement.parent_display_id) { |  | 
|  235       LOG(ERROR) << "display_id must not be same as parent_display_id"; |  | 
|  236       return false; |  | 
|  237     } |  | 
|  238     if (!IsIdInList(placement.display_id, list)) { |  | 
|  239       LOG(ERROR) << "display_id is not in the id list:" << placement.ToString(); |  | 
|  240       return false; |  | 
|  241     } |  | 
|  242  |  | 
|  243     if (!IsIdInList(placement.parent_display_id, list)) { |  | 
|  244       LOG(ERROR) << "parent_display_id is not in the id list:" |  | 
|  245                  << placement.ToString(); |  | 
|  246       return false; |  | 
|  247     } |  | 
|  248     has_primary_as_parent |= layout.primary_id == placement.parent_display_id; |  | 
|  249   } |  | 
|  250   if (!has_primary_as_parent) |  | 
|  251     LOG(ERROR) << "At least, one placement must have the primary as a parent."; |  | 
|  252   return has_primary_as_parent; |  | 
|  253 } |  | 
|  254  |  | 
|  255 std::unique_ptr<DisplayLayout> DisplayLayout::Copy() const { |  | 
|  256   std::unique_ptr<DisplayLayout> copy(new DisplayLayout); |  | 
|  257   for (const auto& placement : placement_list) |  | 
|  258     copy->placement_list.push_back(placement); |  | 
|  259   copy->mirrored = mirrored; |  | 
|  260   copy->default_unified = default_unified; |  | 
|  261   copy->primary_id = primary_id; |  | 
|  262   return copy; |  | 
|  263 } |  | 
|  264  |  | 
|  265 bool DisplayLayout::HasSamePlacementList(const DisplayLayout& layout) const { |  | 
|  266   if (placement_list.size() != layout.placement_list.size()) |  | 
|  267     return false; |  | 
|  268   for (size_t index = 0; index < placement_list.size(); index++) { |  | 
|  269     const DisplayPlacement& placement1 = placement_list[index]; |  | 
|  270     const DisplayPlacement& placement2 = layout.placement_list[index]; |  | 
|  271     if (placement1.position != placement2.position || |  | 
|  272         placement1.offset != placement2.offset || |  | 
|  273         placement1.display_id != placement2.display_id || |  | 
|  274         placement1.parent_display_id != placement2.parent_display_id) { |  | 
|  275       return false; |  | 
|  276     } |  | 
|  277   } |  | 
|  278   return true; |  | 
|  279 } |  | 
|  280  |  | 
|  281 std::string DisplayLayout::ToString() const { |  | 
|  282   std::stringstream s; |  | 
|  283   s << "primary=" << primary_id; |  | 
|  284   if (mirrored) |  | 
|  285     s << ", mirrored"; |  | 
|  286   if (default_unified) |  | 
|  287     s << ", default_unified"; |  | 
|  288   bool added = false; |  | 
|  289   for (const auto& placement : placement_list) { |  | 
|  290     s << (added ? "),(" : " [("); |  | 
|  291     s << placement.ToString(); |  | 
|  292     added = true; |  | 
|  293   } |  | 
|  294   if (added) |  | 
|  295     s << ")]"; |  | 
|  296   return s.str(); |  | 
|  297 } |  | 
|  298  |  | 
|  299 DisplayPlacement DisplayLayout::FindPlacementById(int64_t display_id) const { |  | 
|  300   const auto iter = |  | 
|  301       std::find_if(placement_list.begin(), placement_list.end(), |  | 
|  302                    [display_id](const DisplayPlacement& placement) { |  | 
|  303                      return placement.display_id == display_id; |  | 
|  304                    }); |  | 
|  305   return (iter == placement_list.end()) ? DisplayPlacement() |  | 
|  306                                         : DisplayPlacement(*iter); |  | 
|  307 } |  | 
|  308  |  | 
|  309 // static |  | 
|  310 bool DisplayLayout::ApplyDisplayPlacement(const DisplayPlacement& placement, |  | 
|  311                                           Displays* display_list, |  | 
|  312                                           int minimum_offset_overlap) { |  | 
|  313   const Display& parent_display = |  | 
|  314       *FindDisplayById(display_list, placement.parent_display_id); |  | 
|  315   DCHECK(parent_display.is_valid()); |  | 
|  316   Display* target_display = FindDisplayById(display_list, placement.display_id); |  | 
|  317   gfx::Rect old_bounds(target_display->bounds()); |  | 
|  318   DCHECK(target_display); |  | 
|  319  |  | 
|  320   const gfx::Rect& parent_bounds = parent_display.bounds(); |  | 
|  321   const gfx::Rect& target_bounds = target_display->bounds(); |  | 
|  322   gfx::Point new_target_origin = parent_bounds.origin(); |  | 
|  323  |  | 
|  324   DisplayPlacement::Position position = placement.position; |  | 
|  325  |  | 
|  326   // Ignore the offset in case the target display doesn't share edges with |  | 
|  327   // the parent display. |  | 
|  328   int offset = placement.offset; |  | 
|  329   if (position == DisplayPlacement::TOP || |  | 
|  330       position == DisplayPlacement::BOTTOM) { |  | 
|  331     if (placement.offset_reference == DisplayPlacement::BOTTOM_RIGHT) |  | 
|  332       offset = parent_bounds.width() - offset - target_bounds.width(); |  | 
|  333  |  | 
|  334     offset = std::min( |  | 
|  335         offset, parent_bounds.width() - minimum_offset_overlap); |  | 
|  336     offset = std::max( |  | 
|  337         offset, -target_bounds.width() + minimum_offset_overlap); |  | 
|  338   } else { |  | 
|  339     if (placement.offset_reference == DisplayPlacement::BOTTOM_RIGHT) |  | 
|  340       offset = parent_bounds.height() - offset - target_bounds.height(); |  | 
|  341  |  | 
|  342     offset = std::min( |  | 
|  343         offset, parent_bounds.height() - minimum_offset_overlap); |  | 
|  344     offset = std::max( |  | 
|  345         offset, -target_bounds.height() + minimum_offset_overlap); |  | 
|  346   } |  | 
|  347   switch (position) { |  | 
|  348     case DisplayPlacement::TOP: |  | 
|  349       new_target_origin.Offset(offset, -target_bounds.height()); |  | 
|  350       break; |  | 
|  351     case DisplayPlacement::RIGHT: |  | 
|  352       new_target_origin.Offset(parent_bounds.width(), offset); |  | 
|  353       break; |  | 
|  354     case DisplayPlacement::BOTTOM: |  | 
|  355       new_target_origin.Offset(offset, parent_bounds.height()); |  | 
|  356       break; |  | 
|  357     case DisplayPlacement::LEFT: |  | 
|  358       new_target_origin.Offset(-target_bounds.width(), offset); |  | 
|  359       break; |  | 
|  360   } |  | 
|  361  |  | 
|  362   gfx::Insets insets = target_display->GetWorkAreaInsets(); |  | 
|  363   target_display->set_bounds( |  | 
|  364       gfx::Rect(new_target_origin, target_bounds.size())); |  | 
|  365   target_display->UpdateWorkAreaFromInsets(insets); |  | 
|  366  |  | 
|  367   return old_bounds != target_display->bounds(); |  | 
|  368 } |  | 
|  369  |  | 
|  370 }  // namespace display |  | 
| OLD | NEW |