1 // Copyright 2010-2018, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //     * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 //     * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 //     * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30 #include "renderer/window_util.h"
31 
32 #include "base/coordinates.h"
33 
34 namespace mozc {
35 namespace renderer {
36 namespace {
GetWindowRectForMainWindowFromPreeditRectHorizontal(const Point & target_point,const Rect & preedit_rect,const Size & window_size,const Point & zero_point_offset,const Rect & working_area)37 Rect GetWindowRectForMainWindowFromPreeditRectHorizontal(
38     const Point &target_point, const Rect &preedit_rect,
39     const Size &window_size, const Point &zero_point_offset,
40     const Rect &working_area) {
41   Rect window_rect(target_point, window_size);
42   window_rect.origin.x -= zero_point_offset.x;
43   window_rect.origin.y -= zero_point_offset.y;
44 
45   // If monitor_rect has erroneous value, it returns window_rect.
46   if (working_area.Height() == 0 || working_area.Width() == 0) {
47     return window_rect;
48   }
49 
50   // If the working area below the preedit does not have enough vertical space
51   // to display the candidate window, put the candidate window above
52   // the preedit.
53   if (working_area.Bottom() < window_rect.Bottom()) {
54     window_rect.origin.y -= (window_rect.Height() + preedit_rect.Height());
55     // We add zero_point_offset.y twice to keep the same distance
56     // above the preedit_rect.
57     window_rect.origin.y += zero_point_offset.y * 2;
58   }
59 
60   if (working_area.Bottom() < window_rect.Bottom()) {
61     window_rect.origin.y -= (window_rect.Bottom() - working_area.Bottom());
62   }
63 
64   if (window_rect.Top() < working_area.Top()) {
65     window_rect.origin.y += (working_area.Top() - window_rect.Top());
66   }
67 
68   if (working_area.Right() < window_rect.Right()) {
69     window_rect.origin.x -= (window_rect.Right() - working_area.Right());
70   }
71 
72   if (window_rect.Left() < working_area.Left()) {
73     window_rect.origin.x += (working_area.Left() - window_rect.Left());
74   }
75 
76   return window_rect;
77 }
78 
GetWindowRectForMainWindowFromPreeditRectVertical(const Point & target_point,const Rect & preedit_rect,const Size & window_size,const Point & zero_point_offset,const Rect & working_area)79 Rect GetWindowRectForMainWindowFromPreeditRectVertical(
80     const Point &target_point, const Rect &preedit_rect,
81     const Size &window_size, const Point &zero_point_offset,
82     const Rect &working_area) {
83   Rect window_rect(target_point, window_size);
84 
85   // Currently |zero_point_offset| is ignored because the candidate renderer
86   // has not supported vertical writing.
87 
88   // Since |target_point| is pointing the upper-left of the preedit, move the
89   // candidate window to the right side of the preedit.
90   window_rect.origin.x += preedit_rect.Width();
91 
92   // If monitor_rect has erroneous value, it returns window_rect.
93   if (working_area.Height() == 0 || working_area.Width() == 0) {
94     return window_rect;
95   }
96 
97   if (working_area.Right() < window_rect.Right()) {
98     window_rect.origin.x -= (window_rect.Width() + preedit_rect.Width());
99   }
100 
101   if (working_area.Right() < window_rect.Right()) {
102     window_rect.origin.x -= (window_rect.Right() - working_area.Right());
103   }
104 
105   if (window_rect.Left() < working_area.Left()) {
106     window_rect.origin.x += (working_area.Left() - window_rect.Left());
107   }
108 
109   if (working_area.Bottom() < window_rect.Bottom()) {
110     window_rect.origin.y -= (window_rect.Bottom() - working_area.Bottom());
111   }
112 
113   if (window_rect.Top() < working_area.Top()) {
114     window_rect.origin.y += (working_area.Top() - window_rect.Top());
115   }
116 
117   return window_rect;
118 }
119 }  // namespace
120 
GetWindowRectForMainWindowFromPreeditRect(const Rect & preedit_rect,const Size & window_size,const Point & zero_point_offset,const Rect & working_area)121 Rect WindowUtil::GetWindowRectForMainWindowFromPreeditRect(
122     const Rect &preedit_rect, const Size &window_size,
123     const Point &zero_point_offset, const Rect &working_area) {
124   const Point preedit_bottom_left(preedit_rect.Left(), preedit_rect.Bottom());
125 
126   return GetWindowRectForMainWindowFromPreeditRectHorizontal(
127       preedit_bottom_left, preedit_rect, window_size, zero_point_offset,
128       working_area);
129 }
130 
GetWindowRectForMainWindowFromTargetPoint(const Point & target_point,const Size & window_size,const Point & zero_point_offset,const Rect & working_area)131 Rect WindowUtil::GetWindowRectForMainWindowFromTargetPoint(
132     const Point &target_point, const Size &window_size,
133     const Point &zero_point_offset, const Rect &working_area) {
134   Rect window_rect(target_point, window_size);
135   window_rect.origin.x -= zero_point_offset.x;
136   window_rect.origin.y -= zero_point_offset.y;
137 
138   // If monitor_rect has erroneous value, it returns window_rect.
139   if (working_area.Height() == 0 || working_area.Width() == 0) {
140     return window_rect;
141   }
142 
143   if (working_area.Bottom() < window_rect.Bottom()) {
144     window_rect.origin.y -= (window_rect.Bottom() - working_area.Bottom());
145   }
146 
147   if (window_rect.Top() < working_area.Top()) {
148     window_rect.origin.y += (working_area.Top() - window_rect.Top());
149   }
150 
151   if (working_area.Right() < window_rect.Right()) {
152     window_rect.origin.x -= (window_rect.Right() - working_area.Right());
153   }
154 
155   if (window_rect.Left() < working_area.Left()) {
156     window_rect.origin.x += (working_area.Left() - window_rect.Left());
157   }
158 
159   return window_rect;
160 }
161 
GetWindowRectForMainWindowFromTargetPointAndPreedit(const Point & target_point,const Rect & preedit_rect,const Size & window_size,const Point & zero_point_offset,const Rect & working_area,bool vertical)162 Rect WindowUtil::GetWindowRectForMainWindowFromTargetPointAndPreedit(
163     const Point &target_point, const Rect &preedit_rect,
164     const Size &window_size, const Point &zero_point_offset,
165     const Rect &working_area, bool vertical) {
166   if (vertical) {
167     return GetWindowRectForMainWindowFromPreeditRectVertical(
168         target_point, preedit_rect, window_size, zero_point_offset,
169         working_area);
170   }
171 
172   return GetWindowRectForMainWindowFromPreeditRectHorizontal(
173       target_point, preedit_rect, window_size, zero_point_offset,
174       working_area);
175 }
176 
GetWindowRectForCascadingWindow(const Rect & selected_row,const Size & window_size,const Point & zero_point_offset,const Rect & working_area)177 Rect WindowUtil::GetWindowRectForCascadingWindow(
178     const Rect &selected_row, const Size &window_size,
179     const Point &zero_point_offset, const Rect &working_area) {
180   const Point row_top_right(selected_row.Right(), selected_row.Top());
181 
182   Rect window_rect(row_top_right, window_size);
183   window_rect.origin.x -= zero_point_offset.x;
184   window_rect.origin.y -= zero_point_offset.y;
185 
186   if (working_area.Height() == 0 || working_area.Width() == 0) {
187     return window_rect;
188   }
189 
190   // If the working area right to the specified candidate window does not have
191   // enough horizontal space to display the cascading window,
192   // put the cascading window left to the candidate window.
193   if (working_area.Right() < window_rect.Right()) {
194     window_rect.origin.x -= (window_rect.Width() + selected_row.Width());
195     // We add zero_point_offset.x twice to keep the same distance
196     // left of the selected_row.
197     window_rect.origin.x += zero_point_offset.x * 2;
198   }
199 
200   if (working_area.Bottom() < window_rect.Bottom()) {
201     window_rect.origin.y -= (window_rect.Bottom() - working_area.Bottom());
202   }
203 
204   if (window_rect.Top() < working_area.Top()) {
205     window_rect.origin.y += (working_area.Top() - window_rect.Top());
206   }
207 
208   if (window_rect.Left() < working_area.Left()) {
209     window_rect.origin.x += (working_area.Left() - window_rect.Left());
210   }
211 
212   return window_rect;
213 }
214 
GetWindowRectForInfolistWindow(const Size & window_size,const Rect & candidate_rect,const Rect & working_area)215 Rect WindowUtil::GetWindowRectForInfolistWindow(
216     const Size &window_size, const Rect &candidate_rect,
217     const Rect &working_area) {
218   Point infolist_pos;
219 
220   if (working_area.Height() == 0 || working_area.Width() == 0) {
221     infolist_pos.x = candidate_rect.Left() + candidate_rect.Width();
222     infolist_pos.y = candidate_rect.Top();
223     return Rect(infolist_pos, window_size);
224   }
225   if (candidate_rect.Left() + candidate_rect.Width() + window_size.width >
226       working_area.Right()) {
227     infolist_pos.x = candidate_rect.Left() - window_size.width;
228   } else {
229     infolist_pos.x = candidate_rect.Left() + candidate_rect.Width();
230   }
231   if (candidate_rect.Top() + window_size.height > working_area.Bottom()) {
232     infolist_pos.y = working_area.Bottom() - window_size.height;
233   } else {
234     infolist_pos.y = candidate_rect.Top();
235   }
236   return Rect(infolist_pos, window_size);
237 }
238 }  // namespace renderer
239 }  // namespace mozc
240