OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 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 "remoting/client/desktop_viewport.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/logging.h" | |
10 | |
11 namespace remoting { | |
12 | |
13 namespace { | |
14 | |
15 float MAX_ZOOM_LEVEL = 100.f; | |
16 | |
17 } // namespace | |
18 | |
19 DesktopViewport::DesktopViewport() : desktop_to_surface_(0.f, {0.f, 0.f}) {} | |
joedow
2017/04/28 21:29:52
Add a default c'tor to SimpleMatrix so you don't n
Yuwei
2017/04/28 23:53:40
Done.
| |
20 | |
21 DesktopViewport::~DesktopViewport() {} | |
22 | |
23 void DesktopViewport::SetDesktopSize(int desktop_width, int desktop_height) { | |
24 bool need_resize_to_fit = !desktop_size_ready_ && surface_size_ready_; | |
25 desktop_size_.x = desktop_width; | |
26 desktop_size_.y = desktop_height; | |
27 desktop_size_ready_ = true; | |
28 if (need_resize_to_fit) { | |
29 ResizeToFit(); | |
30 } else if (IsViewportReady()) { | |
31 UpdateViewport(); | |
32 } | |
33 } | |
34 | |
35 void DesktopViewport::SetSurfaceSize(int surface_width, int surface_height) { | |
36 bool need_resize_to_fit = desktop_size_ready_ && !surface_size_ready_; | |
37 surface_size_.x = surface_width; | |
38 surface_size_.y = surface_height; | |
39 surface_size_ready_ = true; | |
40 if (need_resize_to_fit) { | |
41 ResizeToFit(); | |
42 } else if (IsViewportReady()) { | |
43 UpdateViewport(); | |
44 } | |
45 } | |
46 | |
47 void DesktopViewport::ResizeToFit() { | |
48 if (!IsViewportReady()) { | |
49 LOG(ERROR) << "Viewport is not ready."; | |
joedow
2017/04/28 21:29:52
Should this be a DCHECK? It seems like this is un
Yuwei
2017/04/28 23:53:40
Done.
| |
50 return; | |
51 } | |
52 | |
53 // <---Desktop Width----> | |
joedow
2017/04/28 21:29:52
I like the ASCII art, I think it would be good to
Yuwei
2017/04/28 23:53:40
Done.
| |
54 // +==========+---------+ | |
55 // | | | | |
56 // | Viewport | Desktop | | |
57 // | | | | |
58 // +==========+---------+ | |
59 // | |
60 // +==========+ ^ | |
61 // | | | | |
62 // | Viewport | | | |
63 // | | | | |
64 // +==========+ | Desktop | |
65 // | | | Height | |
66 // | Desktop | | | |
67 // | | | | |
68 // +----------+ v | |
69 | |
70 float scale = std::max(surface_size_.x / desktop_size_.x, | |
71 surface_size_.y / desktop_size_.y); | |
72 desktop_to_surface_.SetScale(scale); | |
73 UpdateViewport(); | |
74 } | |
75 | |
76 void DesktopViewport::MoveDesktop(float dx, float dy) { | |
77 desktop_to_surface_.PostTranslate({dx, dy}); | |
78 UpdateViewport(); | |
79 } | |
80 | |
81 void DesktopViewport::ScaleDesktop(float px, float py, float scale) { | |
82 desktop_to_surface_.PostScale({px, py}, scale); | |
83 UpdateViewport(); | |
84 } | |
85 | |
86 void DesktopViewport::SetViewportCenter(float x, float y) { | |
87 Point old_center = GetViewportCenter(); | |
88 MoveViewportCenterWithoutUpdate(x - old_center.x, y - old_center.y); | |
89 UpdateViewport(); | |
90 } | |
91 | |
92 void DesktopViewport::RegisterOnTransformationChangedCallback( | |
93 const TransformationCallback& callback, | |
94 bool run_immediately) { | |
95 on_transformation_changed_ = callback; | |
96 if (IsViewportReady() && run_immediately) { | |
97 callback.Run(desktop_to_surface_.ToMatrixArray()); | |
98 } | |
99 } | |
100 | |
101 bool DesktopViewport::IsViewportReady() const { | |
102 return desktop_size_ready_ && surface_size_ready_; | |
103 } | |
104 | |
105 void DesktopViewport::UpdateViewport() { | |
106 // Adjust zoom level. | |
107 float zoom_level = desktop_to_surface_.GetScale(); | |
108 if (zoom_level > MAX_ZOOM_LEVEL) { | |
109 // TODO(yuweih): This doesn't account for the effect of the pivot point, | |
110 // which will shift the desktop closer to the origin. | |
111 desktop_to_surface_.SetScale(MAX_ZOOM_LEVEL); | |
112 } | |
113 | |
114 Vector2D desktop_size_on_surface_ = | |
115 desktop_to_surface_.MapVector(desktop_size_); | |
116 if (desktop_size_on_surface_.x < surface_size_.x && | |
117 desktop_size_on_surface_.y < surface_size_.y) { | |
118 // +==============+ | |
119 // | VP | +==========+ | |
120 // | | | VP | | |
121 // | +----------+ | +----------+ | |
122 // | | DP | | ==> | DP | | |
123 // | +----------+ | +----------+ | |
124 // | | | | | |
125 // | | +==========+ | |
126 // +==============+ | |
127 // Displayed desktop is too small in both directions, so apply the minimum | |
128 // zoom level needed to fit either the width or height. | |
129 float scale = std::min(surface_size_.x / desktop_size_.x, | |
130 surface_size_.y / desktop_size_.y); | |
131 desktop_to_surface_.SetScale(scale); | |
132 } | |
133 | |
134 // Adjust position. | |
135 // Scenarios: | |
136 // 1. If the viewport can fully fit inside the desktop (smaller or equal width | |
137 // and height), but it doesn't overlap with any non-desktop area, it will | |
138 // be moved in minimum distance to be fitted inside the desktop. | |
139 // | |
140 // +========+ | |
141 // | VP | | |
142 // | +----|--------+ +========+-----+ | |
143 // | | | | | | | | |
144 // +========+ | | VP | DP | | |
145 // | DP | ==> | | | | |
146 // | | +========+ | | |
147 // | | | | | |
148 // +-------------+ +--------------+ | |
149 // | |
150 // 2. If the viewport is larger than the desktop, the viewport will always | |
151 // share the same center as the desktop. | |
152 // | |
153 // +==========+------+==+ +======+------+======+ | |
154 // | VP | DP | | ==> | VP | DP | | | |
155 // +==========+------+==+ +======+------+======+ | |
156 // | |
157 // This is done on the desktop's reference frame to simplify things a bit. | |
158 Point old_center = GetViewportCenter(); | |
159 Point new_center = | |
160 ConstrainPointToBounds(GetViewportCenterBounds(), old_center); | |
161 MoveViewportCenterWithoutUpdate(new_center.x - old_center.x, | |
162 new_center.y - old_center.y); | |
163 | |
164 if (!on_transformation_changed_.is_null()) { | |
joedow
2017/04/28 21:29:52
nit: You don't need to call is_null():
if (on_tra
Yuwei
2017/04/28 23:53:40
Done.
| |
165 on_transformation_changed_.Run(desktop_to_surface_.ToMatrixArray()); | |
166 } | |
167 } | |
168 | |
169 Bounds DesktopViewport::GetViewportCenterBounds() const { | |
170 Bounds bounds; | |
171 | |
172 // Viewport size on the desktop space. | |
173 Vector2D viewport_size = | |
174 desktop_to_surface_.Invert().MapVector(surface_size_); | |
175 | |
176 // Scenario 1: If VP can fully fit inside the desktop, then VP's center can be | |
177 // anywhere inside the desktop as long as VP doesn't overlap with the border. | |
178 bounds.left = viewport_size.x * 0.5f; | |
joedow
2017/04/28 21:29:52
divide by 2? I think that is a more natural way t
Yuwei
2017/04/28 23:53:40
Done.
| |
179 bounds.right = desktop_size_.x - viewport_size.x * 0.5f; | |
180 bounds.top = viewport_size.y * 0.5f; | |
181 bounds.bottom = desktop_size_.y - viewport_size.y * 0.5f; | |
182 | |
183 // Scenario 2: If VP can't fully fit inside the desktop in dimension D, then | |
184 // its bounds in dimension D is tightly restricted to the center of the | |
185 // desktop. | |
186 if (bounds.left > bounds.right) { | |
187 float desktop_width_center = desktop_size_.x * 0.5f; | |
188 bounds.left = desktop_width_center; | |
189 bounds.right = desktop_width_center; | |
190 } | |
191 | |
192 if (bounds.top > bounds.bottom) { | |
193 float desktop_height_center = desktop_size_.y * 0.5f; | |
194 bounds.top = desktop_height_center; | |
195 bounds.bottom = desktop_height_center; | |
196 } | |
197 | |
198 return bounds; | |
199 } | |
200 | |
201 Point DesktopViewport::GetViewportCenter() const { | |
202 return desktop_to_surface_.Invert().MapPoint( | |
203 {surface_size_.x * 0.5f, surface_size_.y * 0.5f}); | |
204 } | |
205 | |
206 void DesktopViewport::MoveViewportCenterWithoutUpdate(float dx, float dy) { | |
207 // <dx, dy> is defined on desktop's reference frame. Translation must be | |
208 // flipped and scaled. | |
209 desktop_to_surface_.PostTranslate(desktop_to_surface_.MapVector({-dx, -dy})); | |
210 } | |
211 | |
212 } // namespace remoting | |
OLD | NEW |