Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(337)

Side by Side Diff: remoting/client/desktop_viewport.cc

Issue 2843373005: [Remoting Client] DesktopViewport Implementation (Closed)
Patch Set: Rename SimpleMatrix to ViewMatrix Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « remoting/client/desktop_viewport.h ('k') | remoting/client/desktop_viewport_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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_transform_() {}
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::MoveDesktop(float dx, float dy) {
48 desktop_to_surface_transform_.PostTranslate({dx, dy});
49 UpdateViewport();
50 }
51
52 void DesktopViewport::ScaleDesktop(float px, float py, float scale) {
53 desktop_to_surface_transform_.PostScale({px, py}, scale);
54 UpdateViewport();
55 }
56
57 void DesktopViewport::SetViewportCenter(float x, float y) {
58 ViewMatrix::Point old_center = GetViewportCenter();
59 MoveViewportCenterWithoutUpdate(x - old_center.x, y - old_center.y);
60 UpdateViewport();
61 }
62
63 void DesktopViewport::RegisterOnTransformationChangedCallback(
64 const TransformationCallback& callback,
65 bool run_immediately) {
66 on_transformation_changed_ = callback;
67 if (IsViewportReady() && run_immediately) {
68 callback.Run(desktop_to_surface_transform_);
69 }
70 }
71
72 void DesktopViewport::ResizeToFit() {
73 DCHECK(IsViewportReady());
74
75 // <---Desktop Width---->
76 // +==========+---------+
77 // | | |
78 // | Viewport | Desktop |
79 // | | |
80 // +==========+---------+
81 //
82 // +==========+ ^
83 // | | |
84 // | Viewport | |
85 // | | |
86 // +==========+ | Desktop
87 // | | | Height
88 // | Desktop | |
89 // | | |
90 // +----------+ v
91 // resize the desktop such that it fits the viewport in one dimension.
92
93 float scale = std::max(surface_size_.x / desktop_size_.x,
94 surface_size_.y / desktop_size_.y);
95 desktop_to_surface_transform_.SetScale(scale);
96 UpdateViewport();
97 }
98
99 bool DesktopViewport::IsViewportReady() const {
100 return desktop_size_ready_ && surface_size_ready_;
101 }
102
103 void DesktopViewport::UpdateViewport() {
104 if (!IsViewportReady()) {
105 // User may attempt to zoom and pan before the desktop image is received.
106 // This should be fine since the viewport will be reset once the image
107 // dimension is set.
108 VLOG(1) << "Viewport is not ready yet.";
109 return;
110 }
111
112 // Adjust zoom level.
113 float zoom_level = desktop_to_surface_transform_.GetScale();
114 if (zoom_level > MAX_ZOOM_LEVEL) {
115 // TODO(yuweih): This doesn't account for the effect of the pivot point,
116 // which will shift the desktop closer to the origin.
117 desktop_to_surface_transform_.SetScale(MAX_ZOOM_LEVEL);
118 }
119
120 ViewMatrix::Vector2D desktop_size_on_surface_ =
121 desktop_to_surface_transform_.MapVector(desktop_size_);
122 if (desktop_size_on_surface_.x < surface_size_.x &&
123 desktop_size_on_surface_.y < surface_size_.y) {
124 // +==============+
125 // | VP | +==========+
126 // | | | VP |
127 // | +----------+ | +----------+
128 // | | DP | | ==> | DP |
129 // | +----------+ | +----------+
130 // | | | |
131 // | | +==========+
132 // +==============+
133 // Displayed desktop is too small in both directions, so apply the minimum
134 // zoom level needed to fit either the width or height.
135 float scale = std::min(surface_size_.x / desktop_size_.x,
136 surface_size_.y / desktop_size_.y);
137 desktop_to_surface_transform_.SetScale(scale);
138 }
139
140 // Adjust position.
141 // Scenarios:
142 // 1. If the viewport can fully fit inside the desktop (smaller or equal width
143 // and height) but it overlaps with the border, it will be moved in minimum
144 // distance to be fitted inside the desktop.
145 //
146 // +========+
147 // | VP |
148 // | +----|--------+ +========+-----+
149 // | | | | | | |
150 // +========+ | | VP | DP |
151 // | DP | ==> | | |
152 // | | +========+ |
153 // | | | |
154 // +-------------+ +--------------+
155 //
156 // 2. If the viewport is larger than the desktop, the viewport will always
157 // share the same center as the desktop.
158 //
159 // +==========+------+==+ +======+------+======+
160 // | VP | DP | | ==> | VP | DP | |
161 // +==========+------+==+ +======+------+======+
162 //
163 // This is done on the desktop's reference frame to simplify things a bit.
164 ViewMatrix::Point old_center = GetViewportCenter();
165 ViewMatrix::Point new_center =
166 ConstrainPointToBounds(GetViewportCenterBounds(), old_center);
167 MoveViewportCenterWithoutUpdate(new_center.x - old_center.x,
168 new_center.y - old_center.y);
169
170 if (on_transformation_changed_) {
171 on_transformation_changed_.Run(desktop_to_surface_transform_);
172 }
173 }
174
175 DesktopViewport::Bounds DesktopViewport::GetViewportCenterBounds() const {
176 Bounds bounds;
177
178 // Viewport size on the desktop space.
179 ViewMatrix::Vector2D viewport_size =
180 desktop_to_surface_transform_.Invert().MapVector(surface_size_);
181
182 // Scenario 1: If VP can fully fit inside the desktop, then VP's center can be
183 // anywhere inside the desktop as long as VP doesn't overlap with the border.
184 bounds.left = viewport_size.x / 2.f;
185 bounds.right = desktop_size_.x - viewport_size.x / 2.f;
186 bounds.top = viewport_size.y / 2.f;
187 bounds.bottom = desktop_size_.y - viewport_size.y / 2.f;
188
189 // Scenario 2: If VP can't fully fit inside the desktop in dimension D, then
190 // its bounds in dimension D is tightly restricted to the center of the
191 // desktop.
192 if (bounds.left > bounds.right) {
193 float desktop_width_center = desktop_size_.x / 2.f;
194 bounds.left = desktop_width_center;
195 bounds.right = desktop_width_center;
196 }
197
198 if (bounds.top > bounds.bottom) {
199 float desktop_height_center = desktop_size_.y / 2.f;
200 bounds.top = desktop_height_center;
201 bounds.bottom = desktop_height_center;
202 }
203
204 return bounds;
205 }
206
207 ViewMatrix::Point DesktopViewport::GetViewportCenter() const {
208 return desktop_to_surface_transform_.Invert().MapPoint(
209 {surface_size_.x / 2.f, surface_size_.y / 2.f});
210 }
211
212 void DesktopViewport::MoveViewportCenterWithoutUpdate(float dx, float dy) {
213 // <dx, dy> is defined on desktop's reference frame. Translation must be
214 // flipped and scaled.
215 desktop_to_surface_transform_.PostTranslate(
216 desktop_to_surface_transform_.MapVector({-dx, -dy}));
217 }
218
219 // static
220 ViewMatrix::Point DesktopViewport::ConstrainPointToBounds(
221 const Bounds& bounds,
222 const ViewMatrix::Point& point) {
223 ViewMatrix::Point new_point = point;
224 if (new_point.x < bounds.left) {
225 new_point.x = bounds.left;
226 } else if (new_point.x > bounds.right) {
227 new_point.x = bounds.right;
228 }
229
230 if (new_point.y < bounds.top) {
231 new_point.y = bounds.top;
232 } else if (new_point.y > bounds.bottom) {
233 new_point.y = bounds.bottom;
234 }
235 return new_point;
236 }
237
238 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/client/desktop_viewport.h ('k') | remoting/client/desktop_viewport_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698