root_window_transformers.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. // Copyright (c) 2013 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. #include "ash/display/root_window_transformers.h"
  5. #include <cmath>
  6. #include "ash/accessibility/magnifier/fullscreen_magnifier_controller.h"
  7. #include "ash/display/display_util.h"
  8. #include "ash/host/root_window_transformer.h"
  9. #include "ash/shell.h"
  10. #include "ash/utility/transformer_util.h"
  11. #include "base/command_line.h"
  12. #include "base/memory/ptr_util.h"
  13. #include "base/system/sys_info.h"
  14. #include "ui/display/display.h"
  15. #include "ui/display/manager/display_manager.h"
  16. #include "ui/display/screen.h"
  17. #include "ui/gfx/geometry/insets.h"
  18. #include "ui/gfx/geometry/size_conversions.h"
  19. #include "ui/gfx/geometry/transform.h"
  20. namespace ash {
  21. namespace {
  22. // TODO(oshima): Transformers should be able to adjust itself
  23. // when the device scale factor is changed, instead of
  24. // precalculating the transform using fixed value.
  25. // Creates rotation transform for |root_window| to |new_rotation|. This will
  26. // call |CreateRotationTransform()|, the |old_rotation| will implicitly be
  27. // |display::Display::ROTATE_0|.
  28. gfx::Transform CreateRootWindowRotationTransform(
  29. const display::Display& display) {
  30. gfx::SizeF size(display.GetSizeInPixel());
  31. // Use SizeF so that the origin of translated layer will be
  32. // aligned when scaled back at pixels.
  33. size.Scale(1.f / display.device_scale_factor());
  34. return CreateRotationTransform(display::Display::ROTATE_0,
  35. display.panel_rotation(), size);
  36. }
  37. gfx::Transform CreateInsetsTransform(const gfx::Insets& insets,
  38. float device_scale_factor) {
  39. gfx::Transform transform;
  40. if (insets.top() != 0 || insets.left() != 0) {
  41. float x_offset = insets.left() / device_scale_factor;
  42. float y_offset = insets.top() / device_scale_factor;
  43. transform.Translate(x_offset, y_offset);
  44. }
  45. return transform;
  46. }
  47. // Returns a transform with rotation adjusted |insets_in_pixel|. The transform
  48. // is applied to the root window so that |insets_in_pixel| looks correct after
  49. // the rotation applied at the output.
  50. gfx::Transform CreateReverseRotatedInsetsTransform(
  51. display::Display::Rotation rotation,
  52. const gfx::Insets& insets_in_pixel,
  53. float device_scale_factor) {
  54. float x_offset = 0;
  55. float y_offset = 0;
  56. switch (rotation) {
  57. case display::Display::ROTATE_0:
  58. x_offset = insets_in_pixel.left();
  59. y_offset = insets_in_pixel.top();
  60. break;
  61. case display::Display::ROTATE_90:
  62. x_offset = insets_in_pixel.top();
  63. y_offset = insets_in_pixel.right();
  64. break;
  65. case display::Display::ROTATE_180:
  66. x_offset = insets_in_pixel.right();
  67. y_offset = insets_in_pixel.bottom();
  68. break;
  69. case display::Display::ROTATE_270:
  70. x_offset = insets_in_pixel.bottom();
  71. y_offset = insets_in_pixel.left();
  72. break;
  73. }
  74. gfx::Transform transform;
  75. if (x_offset != 0 || y_offset != 0) {
  76. x_offset /= device_scale_factor;
  77. y_offset /= device_scale_factor;
  78. transform.Translate(x_offset, y_offset);
  79. }
  80. return transform;
  81. }
  82. // RootWindowTransformer for ash environment.
  83. class AshRootWindowTransformer : public RootWindowTransformer {
  84. public:
  85. AshRootWindowTransformer(const display::Display& display) {
  86. initial_root_bounds_ = gfx::Rect(display.size());
  87. display::DisplayManager* display_manager = Shell::Get()->display_manager();
  88. display::ManagedDisplayInfo info =
  89. display_manager->GetDisplayInfo(display.id());
  90. host_insets_ = info.GetOverscanInsetsInPixel();
  91. gfx::Transform insets_and_rotation_transform =
  92. CreateInsetsTransform(host_insets_, display.device_scale_factor()) *
  93. CreateRootWindowRotationTransform(display);
  94. transform_ = insets_and_rotation_transform;
  95. insets_and_scale_transform_ = CreateReverseRotatedInsetsTransform(
  96. display.panel_rotation(), host_insets_, display.device_scale_factor());
  97. FullscreenMagnifierController* magnifier =
  98. Shell::Get()->fullscreen_magnifier_controller();
  99. if (magnifier) {
  100. gfx::Transform magnifier_scale = magnifier->GetMagnifierTransform();
  101. transform_ *= magnifier_scale;
  102. insets_and_scale_transform_ *= magnifier_scale;
  103. }
  104. CHECK(transform_.GetInverse(&invert_transform_));
  105. CHECK(insets_and_rotation_transform.GetInverse(
  106. &root_window_bounds_transform_));
  107. root_window_bounds_transform_.Scale(1.f / display.device_scale_factor(),
  108. 1.f / display.device_scale_factor());
  109. initial_host_size_ = info.bounds_in_native().size();
  110. }
  111. AshRootWindowTransformer(const AshRootWindowTransformer&) = delete;
  112. AshRootWindowTransformer& operator=(const AshRootWindowTransformer&) = delete;
  113. // aura::RootWindowTransformer overrides:
  114. gfx::Transform GetTransform() const override { return transform_; }
  115. gfx::Transform GetInverseTransform() const override {
  116. return invert_transform_;
  117. }
  118. gfx::Rect GetRootWindowBounds(const gfx::Size& host_size) const override {
  119. if (base::SysInfo::IsRunningOnChromeOS())
  120. return initial_root_bounds_;
  121. // If we're running on linux desktop for dev purpose, the host window
  122. // may be updated to new size. Recompute the root window bounds based
  123. // on the host size if the host size changed.
  124. if (initial_host_size_ == host_size)
  125. return initial_root_bounds_;
  126. gfx::RectF new_bounds = gfx::RectF(gfx::SizeF(host_size));
  127. new_bounds.Inset(gfx::InsetsF(host_insets_));
  128. root_window_bounds_transform_.TransformRect(&new_bounds);
  129. // Root window origin will be (0,0) except during bounds changes.
  130. // Set to exactly zero to avoid rounding issues.
  131. // Floor the size because the bounds is no longer aligned to
  132. // backing pixel when |root_window_scale_| is specified
  133. // (850 height at 1.25 scale becomes 1062.5 for example.)
  134. return gfx::Rect(gfx::ToFlooredSize(new_bounds.size()));
  135. }
  136. gfx::Insets GetHostInsets() const override { return host_insets_; }
  137. gfx::Transform GetInsetsAndScaleTransform() const override {
  138. return insets_and_scale_transform_;
  139. }
  140. private:
  141. ~AshRootWindowTransformer() override = default;
  142. gfx::Transform transform_;
  143. // The accurate representation of the inverse of the |transform_|.
  144. // This is used to avoid computation error caused by
  145. // |gfx::Transform::GetInverse|.
  146. gfx::Transform invert_transform_;
  147. // The transform of the root window bounds. This is used to calculate the size
  148. // of the root window. It is the composition of the following transforms
  149. // - inverse of insets. Insets position the content area within the display.
  150. // - inverse of rotation. Rotation changes orientation of the content area.
  151. // - inverse of device scale. Scaling up content shrinks the content area.
  152. //
  153. // Insets also shrink the content area but this happens prior to applying the
  154. // transformation in GetRootWindowBounds().
  155. //
  156. // Magnification does not affect the window size. Content is clipped in this
  157. // case, but the magnifier allows panning to reach clipped areas.
  158. //
  159. // The transforms are inverted because GetTransform() is the transform from
  160. // root window coordinates to host coordinates, but this transform is used in
  161. // the reverse direction (derives root window bounds from display bounds).
  162. gfx::Transform root_window_bounds_transform_;
  163. gfx::Insets host_insets_;
  164. gfx::Transform insets_and_scale_transform_;
  165. gfx::Rect initial_root_bounds_;
  166. gfx::Size initial_host_size_;
  167. };
  168. // RootWindowTransformer for mirror root window. We simply copy the
  169. // texture (bitmap) of the source display into the mirror window, so
  170. // the root window bounds is the same as the source display's
  171. // pixel size (excluding overscan insets).
  172. class MirrorRootWindowTransformer : public RootWindowTransformer {
  173. public:
  174. MirrorRootWindowTransformer(
  175. const display::ManagedDisplayInfo& source_display_info,
  176. const display::ManagedDisplayInfo& mirror_display_info) {
  177. root_bounds_ =
  178. gfx::Rect(source_display_info.GetSizeInPixelWithPanelOrientation());
  179. display::Display::Rotation active_root_rotation =
  180. source_display_info.GetActiveRotation();
  181. const bool should_undo_rotation = ShouldUndoRotationForMirror();
  182. gfx::Transform rotation_transform;
  183. if (should_undo_rotation) {
  184. // Calculate the transform to undo the rotation and apply it to the
  185. // source display. Use GetActiveRotation() because |source_bounds_|
  186. // includes panel rotation and we only need to revert active rotation.
  187. rotation_transform = CreateRotationTransform(
  188. source_display_info.GetActiveRotation(), display::Display::ROTATE_0,
  189. gfx::SizeF(root_bounds_.size()));
  190. gfx::RectF rotated_bounds(root_bounds_);
  191. rotation_transform.TransformRect(&rotated_bounds);
  192. root_bounds_ = gfx::ToNearestRect(rotated_bounds);
  193. active_root_rotation = display::Display::ROTATE_0;
  194. }
  195. gfx::Rect mirror_display_rect =
  196. gfx::Rect(mirror_display_info.bounds_in_native().size());
  197. // When logical rotation is 90 or 270 degree, transpose is needed to apply
  198. // reverse rotation to `root_bounds_` and `mirror_display_rect` to exclude
  199. // the rotation. This is because the rotation happens at viz output and
  200. // `transform_` needs to be calculated without the rotation.
  201. // E.g. host native size 1600x1200. Rotation 90 degree. `transform_` needs
  202. // to fit 1200x1600 rather than 1600x1200.
  203. const bool need_transpose =
  204. active_root_rotation == display::Display::ROTATE_90 ||
  205. active_root_rotation == display::Display::ROTATE_270;
  206. if (need_transpose) {
  207. root_bounds_.Transpose();
  208. mirror_display_rect.Transpose();
  209. }
  210. bool letterbox = root_bounds_.width() * mirror_display_rect.height() >
  211. root_bounds_.height() * mirror_display_rect.width();
  212. if (letterbox) {
  213. float mirror_scale_ratio =
  214. (static_cast<float>(root_bounds_.width()) /
  215. static_cast<float>(mirror_display_rect.width()));
  216. float inverted_scale = 1.0f / mirror_scale_ratio;
  217. int margin = static_cast<int>((mirror_display_rect.height() -
  218. root_bounds_.height() * inverted_scale) /
  219. 2);
  220. insets_ = gfx::Insets::TLBR(0, margin, 0, margin);
  221. transform_.Translate(0, margin);
  222. transform_.Scale(inverted_scale, inverted_scale);
  223. } else {
  224. float mirror_scale_ratio =
  225. (static_cast<float>(root_bounds_.height()) /
  226. static_cast<float>(mirror_display_rect.height()));
  227. float inverted_scale = 1.0f / mirror_scale_ratio;
  228. int margin = static_cast<int>((mirror_display_rect.width() -
  229. root_bounds_.width() * inverted_scale) /
  230. 2);
  231. insets_ = gfx::Insets::TLBR(margin, 0, margin, 0);
  232. transform_.Translate(margin, 0);
  233. transform_.Scale(inverted_scale, inverted_scale);
  234. }
  235. }
  236. MirrorRootWindowTransformer(const MirrorRootWindowTransformer&) = delete;
  237. MirrorRootWindowTransformer& operator=(const MirrorRootWindowTransformer&) =
  238. delete;
  239. // aura::RootWindowTransformer overrides:
  240. gfx::Transform GetTransform() const override { return transform_; }
  241. gfx::Transform GetInverseTransform() const override {
  242. gfx::Transform invert;
  243. CHECK(transform_.GetInverse(&invert));
  244. return invert;
  245. }
  246. gfx::Rect GetRootWindowBounds(const gfx::Size& host_size) const override {
  247. return root_bounds_;
  248. }
  249. gfx::Insets GetHostInsets() const override { return insets_; }
  250. gfx::Transform GetInsetsAndScaleTransform() const override {
  251. return transform_;
  252. }
  253. private:
  254. ~MirrorRootWindowTransformer() override = default;
  255. gfx::Transform transform_;
  256. gfx::Rect root_bounds_;
  257. gfx::Insets insets_;
  258. };
  259. class PartialBoundsRootWindowTransformer : public RootWindowTransformer {
  260. public:
  261. PartialBoundsRootWindowTransformer(const gfx::Rect& screen_bounds,
  262. const display::Display& display) {
  263. const display::DisplayManager* display_manager =
  264. Shell::Get()->display_manager();
  265. display::ManagedDisplayInfo display_info =
  266. display_manager->GetDisplayInfo(display.id());
  267. // Physical root bounds.
  268. root_bounds_ = gfx::Rect(display_info.bounds_in_native().size());
  269. display::Display::Rotation active_root_rotation =
  270. display_info.GetActiveRotation();
  271. const bool need_transpose =
  272. active_root_rotation == display::Display::ROTATE_90 ||
  273. active_root_rotation == display::Display::ROTATE_270;
  274. if (need_transpose)
  275. root_bounds_.Transpose();
  276. // |screen_bounds| is the unified desktop logical bounds.
  277. // Calculate the unified height scale value, and apply the same scale on the
  278. // row physical height to get the row logical height.
  279. display::Display unified_display =
  280. display::Screen::GetScreen()->GetPrimaryDisplay();
  281. const int unified_physical_height =
  282. unified_display.GetSizeInPixel().height();
  283. const int unified_logical_height = screen_bounds.height();
  284. const float unified_height_scale =
  285. static_cast<float>(unified_logical_height) / unified_physical_height;
  286. const int row_index =
  287. display_manager->GetMirroringDisplayRowIndexInUnifiedMatrix(
  288. display.id());
  289. const int row_physical_height =
  290. display_manager->GetUnifiedDesktopRowMaxHeight(row_index);
  291. const int row_logical_height = row_physical_height * unified_height_scale;
  292. const float dsf = unified_display.device_scale_factor();
  293. const float scale = root_bounds_.height() / (dsf * row_logical_height);
  294. transform_.Scale(scale, scale);
  295. transform_.Translate(-SkIntToScalar(display.bounds().x()),
  296. -SkIntToScalar(display.bounds().y()));
  297. // Scaling using physical root bounds here, because rotation is applied
  298. // before device_scale_factor is applied.
  299. gfx::Transform rotation = CreateRotationTransform(
  300. display::Display::ROTATE_0, display.panel_rotation(),
  301. gfx::SizeF(root_bounds_.size()));
  302. CHECK((rotation * transform_).GetInverse(&invert_transform_));
  303. }
  304. PartialBoundsRootWindowTransformer(
  305. const PartialBoundsRootWindowTransformer&) = delete;
  306. PartialBoundsRootWindowTransformer& operator=(
  307. const PartialBoundsRootWindowTransformer&) = delete;
  308. // RootWindowTransformer:
  309. gfx::Transform GetTransform() const override { return transform_; }
  310. gfx::Transform GetInverseTransform() const override {
  311. return invert_transform_;
  312. }
  313. gfx::Rect GetRootWindowBounds(const gfx::Size& host_size) const override {
  314. return root_bounds_;
  315. }
  316. gfx::Insets GetHostInsets() const override { return gfx::Insets(); }
  317. gfx::Transform GetInsetsAndScaleTransform() const override {
  318. return transform_;
  319. }
  320. private:
  321. ~PartialBoundsRootWindowTransformer() override = default;
  322. gfx::Transform transform_;
  323. gfx::Transform invert_transform_;
  324. gfx::Rect root_bounds_;
  325. };
  326. } // namespace
  327. std::unique_ptr<RootWindowTransformer> CreateRootWindowTransformerForDisplay(
  328. const display::Display& display) {
  329. return base::WrapUnique<RootWindowTransformer>(
  330. new AshRootWindowTransformer(display));
  331. }
  332. std::unique_ptr<RootWindowTransformer>
  333. CreateRootWindowTransformerForMirroredDisplay(
  334. const display::ManagedDisplayInfo& source_display_info,
  335. const display::ManagedDisplayInfo& mirror_display_info) {
  336. return base::WrapUnique<RootWindowTransformer>(
  337. new MirrorRootWindowTransformer(source_display_info,
  338. mirror_display_info));
  339. }
  340. std::unique_ptr<RootWindowTransformer>
  341. CreateRootWindowTransformerForUnifiedDesktop(const gfx::Rect& screen_bounds,
  342. const display::Display& display) {
  343. return base::WrapUnique<RootWindowTransformer>(
  344. new PartialBoundsRootWindowTransformer(screen_bounds, display));
  345. }
  346. } // namespace ash