| 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/gfx/win/scaling_util.h" |
| 6 |
| 7 #include <algorithm> |
| 8 |
| 9 #include "ui/gfx/geometry/rect.h" |
| 10 #include "ui/gfx/geometry/safe_integer_conversions.h" |
| 11 #include "ui/gfx/geometry/size.h" |
| 12 #include "ui/gfx/geometry/vector2d.h" |
| 13 #include "ui/gfx/range/range.h" |
| 14 |
| 15 namespace { |
| 16 |
| 17 enum class RelativePosition { |
| 18 BOTTOM = 0, |
| 19 LEFT = 1, |
| 20 TOP = 2, |
| 21 RIGHT = 3, |
| 22 }; |
| 23 |
| 24 // Returns the relative position of |test| with respect to |ref|. |
| 25 // If |test| is below |ref|, then the return value is RelativePosition::BOTTOM. |
| 26 // The precedence of relative position in order of highest to lowest is |
| 27 // BOTTOM, LEFT, TOP, and finally RIGHT. |
| 28 // In other words, if |test| is both below and to the left of |ref|, then the |
| 29 // RelativePosition is BOTTOM. |
| 30 RelativePosition RectRelativePosition(const gfx::Rect& ref, |
| 31 const gfx::Rect& test) { |
| 32 if (ref.bottom() <= test.y()) |
| 33 return RelativePosition::BOTTOM; |
| 34 if (test.right() <= ref.x()) |
| 35 return RelativePosition::LEFT; |
| 36 if (test.bottom() <= ref.y()) |
| 37 return RelativePosition::TOP; |
| 38 |
| 39 return RelativePosition::RIGHT; |
| 40 } |
| 41 |
| 42 gfx::Rect CoordinateRotateRectangle90(const gfx::Rect& rect) { |
| 43 return gfx::Rect(rect.y(), -rect.x() - rect.width(), |
| 44 rect.height(), rect.width()); |
| 45 } |
| 46 |
| 47 gfx::Rect CoordinateRotateRectangle180(const gfx::Rect& rect) { |
| 48 return gfx::Rect(-rect.x() - rect.width(), -rect.y() -rect.height(), |
| 49 rect.width(), rect.height()); |
| 50 } |
| 51 |
| 52 gfx::Rect CoordinateRotateRectangle270(const gfx::Rect& rect) { |
| 53 return gfx::Rect(-rect.y() - rect.height(), rect.x(), |
| 54 rect.height(), rect.width()); |
| 55 } |
| 56 |
| 57 gfx::Rect CoordinateReflectRectangleYAxis(const gfx::Rect& rect) { |
| 58 return gfx::Rect(-rect.x() - rect.width(), rect.y(), |
| 59 rect.width(), rect.height()); |
| 60 } |
| 61 |
| 62 gfx::Rect CanonicalizeRelativePosition(const gfx::Rect& rect, |
| 63 RelativePosition relative_position) { |
| 64 switch (relative_position) { |
| 65 case RelativePosition::LEFT: |
| 66 return CoordinateRotateRectangle90(rect); |
| 67 case RelativePosition::TOP: |
| 68 return CoordinateRotateRectangle180(rect); |
| 69 case RelativePosition::RIGHT: |
| 70 return CoordinateRotateRectangle270(rect); |
| 71 } |
| 72 return rect; |
| 73 } |
| 74 |
| 75 bool InRange(int target, int lower_bound, int upper_bound) { |
| 76 return lower_bound <= target && target <= upper_bound; |
| 77 } |
| 78 |
| 79 // Scales |val| within |old_min| and |old_max| to |new_min| and |new_max|. |
| 80 int ScaleValue(int new_min, int new_max, int old_min, int old_max, int val) { |
| 81 int old_delta = old_max - old_min; |
| 82 if (old_delta == 0) { |
| 83 DCHECK_EQ(new_min, new_max); |
| 84 return new_min; |
| 85 } |
| 86 float percent = |
| 87 static_cast<float>(val - old_min) / static_cast<float>(old_delta); |
| 88 return new_min + gfx::ToFlooredInt(percent * (float)(new_max - new_min)); |
| 89 } |
| 90 |
| 91 // Scaled |unscaled_offset| to the same relative position on |unscaled_length| |
| 92 // based off of |unscaled_length|'s |scale_factor|. |
| 93 int ScaleOffset(int unscaled_length, float scale_factor, int unscaled_offset) { |
| 94 float scaled_length = static_cast<float>(unscaled_length) / scale_factor; |
| 95 float percent = |
| 96 static_cast<float>(unscaled_offset) / static_cast<float>(unscaled_length); |
| 97 return gfx::ToFlooredInt(scaled_length * percent); |
| 98 } |
| 99 |
| 100 } // namespace |
| 101 |
| 102 namespace gfx { |
| 103 namespace win { |
| 104 |
| 105 bool DisplayInfosTouch(const gfx::win::DisplayInfo& a, |
| 106 const gfx::win::DisplayInfo& b) { |
| 107 const gfx::Rect& a_rect = a.screen_rect(); |
| 108 const gfx::Rect& b_rect = b.screen_rect(); |
| 109 int max_left = std::max(a_rect.x(), b_rect.x()); |
| 110 int max_top = std::max(a_rect.y(), b_rect.y()); |
| 111 int min_right = std::min(a_rect.right(), b_rect.right()); |
| 112 int min_bottom = std::min(a_rect.bottom(), b_rect.bottom()); |
| 113 return max_left == min_right || max_top == min_bottom; |
| 114 } |
| 115 |
| 116 gfx::DisplayPlacement::Position CalculateDisplayPosition( |
| 117 const gfx::win::DisplayInfo& parent, |
| 118 const gfx::win::DisplayInfo& current) { |
| 119 const gfx::Rect& parent_rect = parent.screen_rect(); |
| 120 const gfx::Rect& current_rect = current.screen_rect(); |
| 121 int max_left = std::max(parent_rect.x(), current_rect.x()); |
| 122 int max_top = std::max(parent_rect.y(), current_rect.y()); |
| 123 int min_right = std::min(parent_rect.right(), current_rect.right()); |
| 124 int min_bottom = std::min(parent_rect.bottom(), current_rect.bottom()); |
| 125 if (max_left == min_right && max_top == min_bottom) { |
| 126 // Corner touching. |
| 127 if (parent_rect.bottom() == max_top) |
| 128 return gfx::DisplayPlacement::Position::BOTTOM; |
| 129 if (parent_rect.x() == max_left) |
| 130 return gfx::DisplayPlacement::Position::LEFT; |
| 131 |
| 132 return gfx::DisplayPlacement::Position::TOP; |
| 133 } |
| 134 if (max_left == min_right) { |
| 135 // Vertical edge touching. |
| 136 return parent_rect.x() == max_left |
| 137 ? gfx::DisplayPlacement::Position::LEFT |
| 138 : gfx::DisplayPlacement::Position::RIGHT; |
| 139 } |
| 140 if (max_top == min_bottom) { |
| 141 // Horizontal edge touching. |
| 142 return parent_rect.y() == max_top |
| 143 ? gfx::DisplayPlacement::Position::TOP |
| 144 : gfx::DisplayPlacement::Position::BOTTOM; |
| 145 } |
| 146 NOTREACHED(); |
| 147 return gfx::DisplayPlacement::Position::RIGHT; |
| 148 } |
| 149 |
| 150 gfx::DisplayPlacement CalculateDisplayPlacement( |
| 151 const gfx::win::DisplayInfo& parent, |
| 152 const gfx::win::DisplayInfo& current) { |
| 153 DCHECK(DisplayInfosTouch(parent, current)) << "DisplayInfos must touch."; |
| 154 |
| 155 gfx::DisplayPlacement placement; |
| 156 placement.parent_display_id = parent.id(); |
| 157 placement.display_id = current.id(); |
| 158 placement.position = CalculateDisplayPosition(parent, current); |
| 159 |
| 160 int parent_begin = 0; |
| 161 int parent_end = 0; |
| 162 int current_begin = 0; |
| 163 int current_end = 0; |
| 164 |
| 165 switch (placement.position) { |
| 166 case gfx::DisplayPlacement::Position::TOP: |
| 167 case gfx::DisplayPlacement::Position::BOTTOM: |
| 168 parent_begin = parent.screen_rect().x(); |
| 169 parent_end = parent.screen_rect().right(); |
| 170 current_begin = current.screen_rect().x(); |
| 171 current_end = current.screen_rect().right(); |
| 172 break; |
| 173 case gfx::DisplayPlacement::Position::LEFT: |
| 174 case gfx::DisplayPlacement::Position::RIGHT: |
| 175 parent_begin = parent.screen_rect().y(); |
| 176 parent_end = parent.screen_rect().bottom(); |
| 177 current_begin = current.screen_rect().y(); |
| 178 current_end = current.screen_rect().bottom(); |
| 179 break; |
| 180 } |
| 181 |
| 182 // Since we're talking offsets, make everything relative to parent_begin. |
| 183 parent_end -= parent_begin; |
| 184 current_begin -= parent_begin; |
| 185 current_end -= parent_begin; |
| 186 parent_begin = 0; |
| 187 |
| 188 // There are a few ways lines can intersect: |
| 189 // End Aligned |
| 190 // CURRENT's offset is relative to the end (in our world, BOTTOM_RIGHT). |
| 191 // +-PARENT----------------+ |
| 192 // +-CURRENT------------+ |
| 193 // |
| 194 // Positioning based off of |current_begin|. |
| 195 // CURRENT's offset is simply a percentage of its position on PARENT. |
| 196 // +-PARENT----------------+ |
| 197 // +-CURRENT------------+ |
| 198 // |
| 199 // Positioning based off of |current_end|. |
| 200 // CURRENT's offset is dependent on the percentage of its end position on |
| 201 // PARENT. |
| 202 // +-PARENT----------------+ |
| 203 // +-CURRENT------------+ |
| 204 // |
| 205 // Positioning based off of |parent_begin| on current. |
| 206 // CURRENT's offset is dependent on the percentage of its end position on |
| 207 // PARENT. |
| 208 // +-PARENT----------------+ |
| 209 // +-CURRENT--------------------------+ |
| 210 if (parent_end == current_end) { |
| 211 // End aligned. |
| 212 placement.offset_reference = |
| 213 gfx::DisplayPlacement::OffsetReference::BOTTOM_RIGHT; |
| 214 placement.offset = 0; |
| 215 } else if (InRange(current_begin, parent_begin, parent_end)) { |
| 216 placement.offset = ScaleOffset(parent_end, |
| 217 parent.device_scale_factor(), |
| 218 current_begin); |
| 219 } else if (InRange(current_end, parent_begin, parent_end)) { |
| 220 placement.offset_reference = |
| 221 gfx::DisplayPlacement::OffsetReference::BOTTOM_RIGHT; |
| 222 placement.offset = ScaleOffset(parent_end, |
| 223 parent.device_scale_factor(), |
| 224 parent_end - current_end); |
| 225 } else { |
| 226 DCHECK(InRange(parent_begin, current_begin, current_end)); |
| 227 placement.offset = ScaleOffset(current_end - current_begin, |
| 228 current.device_scale_factor(), |
| 229 current_begin); |
| 230 } |
| 231 |
| 232 return placement; |
| 233 } |
| 234 |
| 235 // This function takes the same approach as ScaleAndPositionRect, transforming |
| 236 // the two input rects so that the relative positions are always the same. |
| 237 int64_t SquaredDistanceBetweenRects(const gfx::Rect& ref, |
| 238 const gfx::Rect& rect) { |
| 239 if (ref.Intersects(rect)) |
| 240 return 0; |
| 241 |
| 242 RelativePosition relative_position = RectRelativePosition(ref, rect); |
| 243 gfx::Rect ref_work(CanonicalizeRelativePosition(ref, relative_position)); |
| 244 gfx::Rect rect_work(CanonicalizeRelativePosition(rect, relative_position)); |
| 245 // Now that the ref is on top, we can concentrate ref bottom |
| 246 // and rect top calculations. |
| 247 if (rect_work.right() < ref_work.x()) |
| 248 return (rect_work.top_right() - ref_work.bottom_left()).LengthSquared(); |
| 249 else if (ref_work.right() < rect_work.x()) |
| 250 return (rect_work.origin() - ref_work.bottom_right()).LengthSquared(); |
| 251 |
| 252 int distance = rect_work.y() - ref_work.bottom(); |
| 253 return distance * distance; |
| 254 } |
| 255 |
| 256 } // namespace win |
| 257 } // namespace gfx |
| OLD | NEW |