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/win32/win32_renderer_util.h"
31 
32 #define _ATL_NO_AUTOMATIC_NAMESPACE
33 #define _WTL_NO_AUTOMATIC_NAMESPACE
34 #include <atlbase.h>
35 #include <atlapp.h>
36 #include <atlgdi.h>
37 #include <atlmisc.h>
38 
39 #include "base/logging.h"
40 #include "base/mmap.h"
41 #include "base/util.h"
42 #include "base/win_font_test_helper.h"
43 #include "protocol/renderer_command.pb.h"
44 #include "renderer/win32/win32_font_util.h"
45 #include "testing/base/public/gunit.h"
46 
47 // Following functions should be placed in global namespace for Koenig look-up
48 // trick used in GTest.
PrintTo(const POINT & point,::std::ostream * os)49 void PrintTo(const POINT &point, ::std::ostream* os) {
50   *os << "(" << point.x << ", " << point.y << ")";
51 }
PrintTo(const RECT & rect,::std::ostream * os)52 void PrintTo(const RECT &rect, ::std::ostream* os) {
53   *os << "(" << rect.left << ", " << rect.top << ", " << rect.right << ", "
54     << rect.bottom << ")";
55 }
56 
57 namespace WTL {
58 
59 // These functions should be placed in WTL namespace for Koenig look-up
60 // trick used in GTest.
PrintTo(const CPoint & point,::std::ostream * os)61 void PrintTo(const CPoint &point, ::std::ostream* os) {
62   *os << "(" << point.x << ", " << point.y << ")";
63 }
PrintTo(const CRect & rect,::std::ostream * os)64 void PrintTo(const CRect &rect, ::std::ostream* os) {
65   *os << "(" << rect.left << ", " << rect.top << ", " << rect.right << ", "
66       << rect.bottom << ")";
67 }
68 
69 }  // namespace WTL
70 
71 namespace mozc {
72 namespace renderer {
73 namespace win32 {
74 typedef mozc::commands::Annotation Annotation;
75 typedef mozc::commands::CandidateList CandidateList;
76 typedef mozc::commands::CandidateWord CandidateWord;
77 typedef mozc::commands::Candidates Candidates;
78 typedef mozc::commands::Candidates::Candidate Candidate;
79 typedef mozc::commands::Footer Footer;
80 typedef mozc::commands::Output Output;
81 typedef mozc::commands::Preedit Preedit;
82 typedef mozc::commands::Preedit_Segment Segment;
83 typedef mozc::commands::RendererCommand RendererCommand;
84 typedef mozc::commands::RendererCommand_ApplicationInfo ApplicationInfo;
85 typedef mozc::commands::RendererCommand_CandidateForm CandidateForm;
86 typedef mozc::commands::RendererCommand_CaretInfo CaretInfo;
87 typedef mozc::commands::RendererCommand_CharacterPosition CharacterPosition;
88 typedef mozc::commands::RendererCommand_CompositionForm CompositionForm;
89 typedef mozc::commands::RendererCommand_Point Point;
90 typedef mozc::commands::RendererCommand_Rectangle Rectangle;
91 typedef mozc::commands::RendererCommand_WinLogFont WinLogFont;
92 typedef mozc::commands::Status Status;
93 
94 namespace {
95 
96 using WTL::CDC;
97 using WTL::CFont;
98 using WTL::CFontHandle;
99 using WTL::CLogFont;
100 using WTL::CPoint;
101 using WTL::CRect;
102 using WTL::CSize;
103 using WTL::PrintTo;
104 
105 const int kDefaultFontHeightInPixel = 18;
106 const wchar_t kWindowClassName[] = L"Mozc: Default Window Class Name";
107 
108 #define EXPECT_COMPOSITION_WINDOW_LAYOUT(                                   \
109     window_pos_left, window_pos_top, window_pos_right,  window_pos_bottom,  \
110     text_left, text_top, text_right, text_bottom, base_x, base_y,           \
111     caret_left, caret_top, caret_right, caret_bottom, font, window_layout)  \
112   do {                                                                      \
113     EXPECT_EQ(CRect((window_pos_left), (window_pos_top),                    \
114                     (window_pos_right), (window_pos_bottom)),               \
115               (window_layout).window_position_in_screen_coordinate);        \
116     EXPECT_EQ((font), layout.log_font);                                     \
117     EXPECT_EQ(CRect((text_left), (text_top),                                \
118                     (text_right), (text_bottom)),                           \
119               (window_layout).text_area);                                   \
120     EXPECT_EQ(CPoint((base_x), (base_y)), (window_layout).base_position);   \
121     EXPECT_EQ(CRect((caret_left), (caret_top),                              \
122                     (caret_right), (caret_bottom)),                         \
123               (window_layout).caret_rect);                                  \
124   } while (false)
125 
126 #define EXPECT_NON_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(                         \
127     target_x, target_y, layout)                                             \
128   do {                                                                      \
129      EXPECT_TRUE((layout).initialized());                                   \
130      EXPECT_FALSE((layout).has_exclude_region());                           \
131      EXPECT_EQ(CPoint((target_x), (target_y)), (layout).position());        \
132   } while (false)
133 
134 #define EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(                             \
135     target_x, target_y, exclude_rect_left, exclude_rect_top,                \
136     exclude_rect_right, exclude_rect_bottom, layout)                        \
137   do {                                                                      \
138      EXPECT_TRUE((layout).initialized());                                   \
139      EXPECT_TRUE((layout).has_exclude_region());                            \
140      EXPECT_EQ(CPoint((target_x), (target_y)), (layout).position());        \
141      EXPECT_EQ(CRect((exclude_rect_left), (exclude_rect_top),               \
142                      (exclude_rect_right), (exclude_rect_bottom)),          \
143                (layout).exclude_region());                                  \
144   } while (false)
145 
CreateWindowEmulator(const std::wstring & class_name,const RECT & window_rect,const POINT & client_area_offset,const SIZE & client_area_size,double scale_factor,HWND * hwnd)146 WindowPositionEmulator *CreateWindowEmulator(
147     const std::wstring &class_name, const RECT &window_rect,
148     const POINT &client_area_offset, const SIZE &client_area_size,
149     double scale_factor, HWND *hwnd) {
150   WindowPositionEmulator *emulator = WindowPositionEmulator::Create();
151   *hwnd = emulator->RegisterWindow(
152       class_name, window_rect, client_area_offset,
153       client_area_size, scale_factor);
154   return emulator;
155 }
156 
CreateWindowEmulatorWithDPIScaling(double scale_factor,HWND * hwnd)157 WindowPositionEmulator *CreateWindowEmulatorWithDPIScaling(
158     double scale_factor, HWND *hwnd) {
159   const CPoint kClientOffset(8, 42);
160   const CSize kClientSize(2000, 1000);
161   const CRect kWindowRect(500, 500, 2516, 1550);
162 
163   return CreateWindowEmulator(kWindowClassName, kWindowRect,
164                               kClientOffset, kClientSize, scale_factor, hwnd);
165 }
166 
CreateWindowEmulatorWithClassName(const std::wstring & class_name,HWND * hwnd)167 WindowPositionEmulator *CreateWindowEmulatorWithClassName(
168     const std::wstring &class_name, HWND *hwnd) {
169   const CPoint kClientOffset(8, 42);
170   const CSize kClientSize(2000, 1000);
171   const CRect kWindowRect(500, 500, 2516, 1550);
172   const double kScaleFactor = 1.0;
173 
174   return CreateWindowEmulator(class_name, kWindowRect,
175                               kClientOffset, kClientSize, kScaleFactor, hwnd);
176 }
177 
178 class AppInfoUtil {
179  public:
SetBasicApplicationInfo(ApplicationInfo * app_info,HWND hwnd,int visibility)180   static void SetBasicApplicationInfo(
181       ApplicationInfo *app_info, HWND hwnd, int visibility) {
182     app_info->set_ui_visibilities(visibility);
183     app_info->set_process_id(1234);
184     app_info->set_thread_id(5678);
185     app_info->set_target_window_handle(
186         reinterpret_cast<uint32>(hwnd));
187     app_info->set_input_framework(ApplicationInfo::IMM32);
188   }
189 
SetCompositionFont(ApplicationInfo * app_info,int height,int width,int escapement,int orientation,int weight,int char_set,int out_precision,int clip_precision,int quality,int pitch_and_family,const char * face_name)190   static void SetCompositionFont(
191       ApplicationInfo *app_info, int height, int width, int escapement,
192       int orientation, int weight, int char_set, int out_precision,
193       int clip_precision, int quality, int pitch_and_family,
194       const char *face_name) {
195     WinLogFont *font = app_info->mutable_composition_font();
196     font->set_height(height);
197     font->set_width(width);
198     font->set_escapement(escapement);
199     font->set_orientation(orientation);
200     font->set_weight(weight);
201     font->set_italic(false);
202     font->set_underline(false);
203     font->set_strike_out(false);
204     font->set_char_set(char_set);
205     font->set_out_precision(out_precision);
206     font->set_clip_precision(clip_precision);
207     font->set_quality(quality);
208     font->set_pitch_and_family(pitch_and_family);
209     font->set_face_name(face_name);
210   }
211 
SetCompositionForm(ApplicationInfo * app_info,uint32 style_bits,int x,int y,int left,int top,int right,int bottom)212   static void SetCompositionForm(
213       ApplicationInfo *app_info, uint32 style_bits,
214       int x, int y, int left, int top, int right, int bottom) {
215     CompositionForm *form = app_info->mutable_composition_form();
216     form->set_style_bits(style_bits);
217     Point *current_position = form->mutable_current_position();
218     Rectangle *area = form->mutable_area();
219     current_position->set_x(x);
220     current_position->set_y(y);
221     area->set_left(left);
222     area->set_top(top);
223     area->set_right(right);
224     area->set_bottom(bottom);
225   }
226 
SetCandidateForm(ApplicationInfo * app_info,uint32 style_bits,int x,int y,int left,int top,int right,int bottom)227   static void SetCandidateForm(
228       ApplicationInfo *app_info, uint32 style_bits,
229       int x, int y, int left, int top, int right, int bottom) {
230     CandidateForm *form = app_info->mutable_candidate_form();
231     form->set_style_bits(style_bits);
232     Point *current_pos = form->mutable_current_position();
233     current_pos->set_x(x);
234     current_pos->set_y(y);
235     Rectangle *area = form->mutable_area();
236     area->set_left(left);
237     area->set_top(top);
238     area->set_right(right);
239     area->set_bottom(bottom);
240   }
241 
SetCaretInfo(ApplicationInfo * app_info,bool blinking,int left,int top,int right,int bottom,HWND target_window_handle)242   static void SetCaretInfo(
243       ApplicationInfo *app_info, bool blinking, int left, int top,
244       int right, int bottom, HWND target_window_handle) {
245     CaretInfo *info = app_info->mutable_caret_info();
246     info->set_blinking(blinking);
247     info->set_target_window_handle(
248         reinterpret_cast<uint32>(target_window_handle));
249     Rectangle *rect = info->mutable_caret_rect();
250     rect->set_left(left);
251     rect->set_top(top);
252     rect->set_right(right);
253     rect->set_bottom(bottom);
254   }
255 
SetCompositionTarget(ApplicationInfo * app_info,int position,int x,int y,uint32 line_height,int left,int top,int right,int bottom)256   static void SetCompositionTarget(
257       ApplicationInfo *app_info, int position, int x, int y,
258       uint32 line_height, int left, int top, int right, int bottom) {
259     CharacterPosition *char_pos = app_info->mutable_composition_target();
260     char_pos->set_position(position);
261     char_pos->mutable_top_left()->set_x(x);
262     char_pos->mutable_top_left()->set_y(y);
263     char_pos->set_line_height(line_height);
264     Rectangle *area = char_pos->mutable_document_area();
265     area->set_left(left);
266     area->set_top(top);
267     area->set_right(right);
268     area->set_bottom(bottom);
269   }
270 
271  private:
272   DISALLOW_IMPLICIT_CONSTRUCTORS(AppInfoUtil);
273 };
274 
275 }  // namespace
276 
277 class Win32RendererUtilTest : public testing::Test {
278  public:
GetMonospacedFontFaceForTest()279   static string GetMonospacedFontFaceForTest() {
280     return WinFontTestHelper::GetIPAexGothicFontName();
281   }
282 
GetPropotionalFontFaceForTest()283   static string GetPropotionalFontFaceForTest() {
284     return WinFontTestHelper::GetIPAexMinchoFontName();
285   }
286 
GetFont(bool is_proportional,bool is_vertical)287   static CLogFont GetFont(bool is_proportional, bool is_vertical) {
288     std::wstring font_face;
289     Util::UTF8ToWide((is_proportional ? GetPropotionalFontFaceForTest()
290                                       : GetMonospacedFontFaceForTest()),
291                      &font_face);
292     if (is_vertical) {
293       font_face = L"@" + font_face;
294     }
295 
296     CLogFont font;
297     font.lfWeight = FW_NORMAL;
298     font.lfCharSet = DEFAULT_CHARSET;
299 
300     // We use negative value here to specify absolute font height in pixel,
301     // assuming the mapping mode is MM_TEXT.
302     // http://msdn.microsoft.com/en-us/library/ms901140.aspx
303     font.lfHeight = -kDefaultFontHeightInPixel;
304 
305     const errno_t error = wcscpy_s(font.lfFaceName, font_face.c_str());
306     CHECK_EQ(0, error) << "wcscpy_s failed";
307 
308     if (is_vertical) {
309       // 2700 means the text grows from top to bottom.
310       font.lfEscapement = 2700;
311       font.lfOrientation = 2700;
312     }
313 
314     return font;
315   }
316 
CreateDefaultGUIFontEmulator()317   static SystemPreferenceInterface *CreateDefaultGUIFontEmulator() {
318     CLogFont font = GetFont(true, false);
319     font.lfHeight = 18;
320     font.lfWidth = 0;
321     return SystemPreferenceFactory::CreateMock(font);
322   }
323 
GetTestMessageWithCompositeGlyph(int num_repeat)324   static std::wstring GetTestMessageWithCompositeGlyph(int num_repeat) {
325     std::wstring message;
326     for (size_t i = 0; i < num_repeat; ++i) {
327       // "ぱ"
328       message += L'\u3071';
329       message += L'\u309a';
330     }
331     return message;
332   }
333 
GetTestMessageForMonospaced()334   static std::wstring GetTestMessageForMonospaced() {
335     std::wstring w_path;
336     const char kMessage[] = "熊本県阿蘇郡南阿蘇村大字中松南阿蘇水の生まれる里白水高原駅";
337     std::wstring w_message;
338     Util::UTF8ToWide(kMessage, &w_message);
339     return w_message;
340   }
341 
GetTestMessageForProportional()342   static std::wstring GetTestMessageForProportional() {
343     std::wstring w_path;
344     const char kMessage[] =
345         "This open-source project originates from Google 日本語入力.";
346     std::wstring w_message;
347     Util::UTF8ToWide(kMessage, &w_message);
348     return w_message;
349   }
350 
351   // Initializes |command| for unit test.  Parameters to be set are based on
352   // an actual application which supports both horizontal and vertical writing.
SetRenderereCommandForTest(bool use_proportional_font,bool has_candidates,bool is_vertical,int cursor_offset,HWND hwnd,RendererCommand * command)353   static void SetRenderereCommandForTest(
354       bool use_proportional_font, bool has_candidates,
355       bool is_vertical, int cursor_offset, HWND hwnd,
356       RendererCommand *command) {
357     command->Clear();
358     command->set_type(RendererCommand::UPDATE);
359     command->set_visible(true);
360     {
361       Output *output = command->mutable_output();
362       output->set_id(123456789);
363       output->set_mode(commands::HIRAGANA);
364       output->set_consumed(true);
365       Preedit *preedit = output->mutable_preedit();
366       preedit->set_cursor(22);
367       {
368         Segment *segment = preedit->add_segment();
369         segment->set_annotation(Segment::UNDERLINE);
370         segment->set_value("これは");
371         segment->set_value_length(3);
372         segment->set_key("これは");
373       }
374       {
375         Segment *segment = preedit->add_segment();
376         segment->set_annotation(Segment::UNDERLINE);
377         segment->set_value("、");
378         segment->set_value_length(1);
379         segment->set_key("、");
380       }
381       {
382         Segment *segment = preedit->add_segment();
383         segment->set_annotation(Segment::HIGHLIGHT);
384         segment->set_value("Google");
385         segment->set_value_length(6);
386         segment->set_key("Google");
387       }
388       {
389         Segment *segment = preedit->add_segment();
390         segment->set_annotation(Segment::UNDERLINE);
391         segment->set_value("日本語入力の");
392         segment->set_value_length(6);
393         segment->set_key("にほんごにゅうりょくの");
394       }
395       {
396         Segment *segment = preedit->add_segment();
397         segment->set_annotation(Segment::UNDERLINE);
398         segment->set_value("Testです");
399         segment->set_value_length(6);
400         segment->set_key("Testです");
401       }
402       preedit->set_highlighted_position(3);
403 
404       if (has_candidates) {
405         Candidates *candidates = output->mutable_candidates();
406         candidates->set_focused_index(0);
407         candidates->set_size(2);
408         {
409           Candidate *candidate = candidates->add_candidate();
410           candidate->set_index(0);
411           candidate->set_value("Google");
412           Annotation *annotation = candidate->mutable_annotation();
413           annotation->set_description("[半] アルファベット");
414           annotation->set_shortcut("1");
415           candidate->set_id(0);
416         }
417         {
418           Candidate *candidate = candidates->add_candidate();
419           candidate->set_index(1);
420           candidate->set_value("そのほかの文字種");
421           Annotation *annotation = candidate->mutable_annotation();
422           annotation->set_shortcut("2");
423           candidate->set_id(-11);
424         }
425         candidates->set_position(4);
426         candidates->set_category(commands::CONVERSION);
427         candidates->set_display_type(commands::MAIN);
428         Footer *footer = candidates->mutable_footer();
429         footer->set_index_visible(true);
430         footer->set_logo_visible(true);
431         footer->set_sub_label("build 000");
432       }
433     }
434 
435     SetApplicationInfoForTest(
436         use_proportional_font, is_vertical, cursor_offset, hwnd, command);
437   }
438 
439   // Initializes |command| for unit test.  Parameters to be set are based on
440   // an actual application which supports both horizontal and vertical writing.
SetRenderereCommandForSuggestTest(bool use_proportional_font,bool is_vertical,int cursor_offset,HWND hwnd,RendererCommand * command)441   static void SetRenderereCommandForSuggestTest(
442       bool use_proportional_font, bool is_vertical, int cursor_offset,
443       HWND hwnd, RendererCommand *command) {
444     command->Clear();
445     command->set_type(RendererCommand::UPDATE);
446     command->set_visible(true);
447     {
448       Output *output = command->mutable_output();
449       output->set_id(123456789);
450       output->set_mode(commands::HIRAGANA);
451       output->set_consumed(true);
452       {
453         Preedit *preedit = output->mutable_preedit();
454         preedit->set_cursor(7);
455         {
456           Segment *segment = preedit->add_segment();
457           segment->set_annotation(Segment::UNDERLINE);
458           segment->set_value("ねこをかいたい");
459           segment->set_value_length(7);
460           segment->set_key("ねこをかいたい");
461         }
462       }
463       {
464         Candidates *candidates = output->mutable_candidates();
465         candidates->set_size(1);
466         {
467           Candidate *candidate = candidates->add_candidate();
468           candidate->set_index(0);
469           candidate->set_value("猫を飼いたい");
470           {
471             Annotation *annotation = candidate->mutable_annotation();
472             annotation->set_description("Real-time Conversion");
473             candidate->set_id(0);
474           }
475         }
476         candidates->set_position(0);
477         candidates->set_category(commands::SUGGESTION);
478         candidates->set_display_type(commands::MAIN);
479         {
480           Footer *footer = candidates->mutable_footer();
481           footer->set_sub_label("build 754");
482         }
483       }
484     }
485 
486     SetApplicationInfoForTest(
487         use_proportional_font, is_vertical, cursor_offset, hwnd, command);
488   }
489 
490   // Initializes |command| for unit tests of caret.  Parameters to be set are
491   // based on an actual application which supports both horizontal and vertical
492   // writing.
SetRenderereCommandForCaretTest(bool use_proportional_font,bool is_vertical,int num_characters,int cursor_position_in_preedit,int cursor_offset,HWND hwnd,RendererCommand * command)493   static void SetRenderereCommandForCaretTest(
494       bool use_proportional_font, bool is_vertical, int num_characters,
495       int cursor_position_in_preedit, int cursor_offset, HWND hwnd,
496       RendererCommand *command) {
497     command->Clear();
498     command->set_type(RendererCommand::UPDATE);
499     command->set_visible(true);
500     {
501       Output *output = command->mutable_output();
502       output->set_id(123456789);
503       output->set_mode(commands::HIRAGANA);
504       output->set_consumed(true);
505       Preedit *preedit = output->mutable_preedit();
506       preedit->set_cursor(cursor_position_in_preedit);
507       {
508         Segment *segment = preedit->add_segment();
509         segment->set_annotation(Segment::UNDERLINE);
510         string value;
511         for (size_t i = 0; i < num_characters; ++i) {
512           value.append("あ");
513         }
514         segment->set_value(value);
515         segment->set_value_length(num_characters);
516         segment->set_key(value);
517       }
518     }
519 
520     SetApplicationInfoForTest(
521         use_proportional_font, is_vertical, cursor_offset, hwnd, command);
522   }
523 
524   // Initializes |command| for unit tests of caret.  Parameters to be set are
525   // based on an actual application which supports both horizontal and vertical
526   // writing.
SetRenderereCommandForSurrogatePair(bool use_proportional_font,bool is_vertical,int cursor_offset,HWND hwnd,RendererCommand * command)527   static void SetRenderereCommandForSurrogatePair(bool use_proportional_font,
528                                                   bool is_vertical,
529                                                   int cursor_offset, HWND hwnd,
530                                                   RendererCommand *command) {
531     command->Clear();
532     command->set_type(RendererCommand::UPDATE);
533     command->set_visible(true);
534     {
535       Output *output = command->mutable_output();
536       output->set_id(123456789);
537       output->set_mode(commands::HIRAGANA);
538       output->set_consumed(true);
539       {
540         Preedit *preedit = output->mutable_preedit();
541         preedit->set_cursor(8);
542         {
543           Segment *segment = preedit->add_segment();
544           segment->set_annotation(Segment::UNDERLINE);
545           segment->set_value("��咤");
546           segment->set_value_length(2);
547           segment->set_key("しった");
548         }
549         {
550           Segment *segment = preedit->add_segment();
551           segment->set_annotation(Segment::UNDERLINE);
552           segment->set_value("��咤");
553           segment->set_value_length(2);
554           segment->set_key("しった");
555         }
556         {
557           Segment *segment = preedit->add_segment();
558           segment->set_annotation(Segment::HIGHLIGHT);
559           segment->set_value("��咤");
560           segment->set_value_length(2);
561           segment->set_key("しった");
562         }
563         {
564           Segment *segment = preedit->add_segment();
565           segment->set_annotation(Segment::UNDERLINE);
566           segment->set_value("��咤");
567           segment->set_value_length(2);
568           segment->set_key("しった");
569         }
570         preedit->set_highlighted_position(4);
571       }
572       {
573         Candidates *candidates = output->mutable_candidates();
574         candidates->set_focused_index(0);
575         candidates->set_size(5);
576         {
577           Candidate *candidate = candidates->add_candidate();
578           candidate->set_index(0);
579           candidate->set_value("��咤");
580           {
581             Annotation *annotation = candidate->mutable_annotation();
582             annotation->set_shortcut("1");
583           }
584           candidate->set_id(0);
585         }
586         {
587           Candidate *candidate = candidates->add_candidate();
588           candidate->set_index(1);
589           candidate->set_value("知った");
590           {
591             Annotation *annotation = candidate->mutable_annotation();
592             annotation->set_shortcut("2");
593           }
594           candidate->set_id(1);
595         }
596         {
597           Candidate *candidate = candidates->add_candidate();
598           candidate->set_index(2);
599           candidate->set_value("知った");
600           {
601             Annotation *annotation = candidate->mutable_annotation();
602             annotation->set_description("ひらがな");
603             annotation->set_shortcut("3");
604           }
605           candidate->set_id(2);
606         }
607         {
608           Candidate *candidate = candidates->add_candidate();
609           candidate->set_index(3);
610           candidate->set_value("知った");
611           {
612             Annotation *annotation = candidate->mutable_annotation();
613             annotation->set_description("[全] カタカナ");
614             annotation->set_shortcut("4");
615           }
616           candidate->set_id(4);
617         }
618         {
619           Candidate *candidate = candidates->add_candidate();
620           candidate->set_index(4);
621           candidate->set_value("そのほかの文字種");
622           {
623             Annotation *annotation = candidate->mutable_annotation();
624             annotation->set_shortcut("5");
625           }
626           candidate->set_id(-1);
627         }
628         candidates->set_position(4);
629         candidates->set_category(commands::CONVERSION);
630         candidates->set_display_type(commands::MAIN);
631         {
632           Footer *footer = candidates->mutable_footer();
633           footer->set_index_visible(true);
634           footer->set_logo_visible(true);
635           footer->set_sub_label("build 670");
636         }
637       }
638       {
639         Status *status = output->mutable_status();
640         status->set_activated(true);
641         status->set_mode(commands::HIRAGANA);
642       }
643       {
644         CandidateList *all_candidate_words =
645             output->mutable_all_candidate_words();
646         all_candidate_words->set_focused_index(0);
647         {
648           CandidateWord *candidate_word = all_candidate_words->add_candidates();
649           candidate_word->set_id(0);
650           candidate_word->set_index(0);
651           candidate_word->set_value("��咤");
652         }
653         {
654           CandidateWord *candidate_word = all_candidate_words->add_candidates();
655           candidate_word->set_id(1);
656           candidate_word->set_index(1);
657           candidate_word->set_value("知った");
658         }
659         {
660           CandidateWord *candidate_word = all_candidate_words->add_candidates();
661           candidate_word->set_id(2);
662           candidate_word->set_index(2);
663           candidate_word->set_key("しっ");
664           candidate_word->set_value("しった");
665         }
666         {
667           CandidateWord *candidate_word = all_candidate_words->add_candidates();
668           candidate_word->set_id(4);
669           candidate_word->set_index(3);
670           candidate_word->set_value("シッタ");
671         }
672         {
673           CandidateWord *candidate_word = all_candidate_words->add_candidates();
674           candidate_word->set_id(-1);
675           candidate_word->set_index(4);
676           candidate_word->set_value("しった");
677         }
678         {
679           CandidateWord *candidate_word = all_candidate_words->add_candidates();
680           candidate_word->set_id(-2);
681           candidate_word->set_index(5);
682           candidate_word->set_value("シッタ");
683         }
684         {
685           CandidateWord *candidate_word = all_candidate_words->add_candidates();
686           candidate_word->set_id(-3);
687           candidate_word->set_index(6);
688           candidate_word->set_value("shitta");
689         }
690         {
691           CandidateWord *candidate_word = all_candidate_words->add_candidates();
692           candidate_word->set_id(-4);
693           candidate_word->set_index(7);
694           candidate_word->set_value("SHITTA");
695         }
696         {
697           CandidateWord *candidate_word = all_candidate_words->add_candidates();
698           candidate_word->set_id(-6);
699           candidate_word->set_index(8);
700           candidate_word->set_value("Shitta");
701         }
702         {
703           CandidateWord *candidate_word = all_candidate_words->add_candidates();
704           candidate_word->set_id(-7);
705           candidate_word->set_index(9);
706           candidate_word->set_value("shitta");
707         }
708         {
709           CandidateWord *candidate_word = all_candidate_words->add_candidates();
710           candidate_word->set_id(-8);
711           candidate_word->set_index(10);
712           candidate_word->set_value("SHITTA");
713         }
714         {
715           CandidateWord *candidate_word = all_candidate_words->add_candidates();
716           candidate_word->set_id(-10);
717           candidate_word->set_index(11);
718           candidate_word->set_value("Shitta");
719         }
720         {
721           CandidateWord *candidate_word = all_candidate_words->add_candidates();
722           candidate_word->set_id(-11);
723           candidate_word->set_index(12);
724           candidate_word->set_value("シッタ");
725         }
726         all_candidate_words->set_category(commands::CONVERSION);
727       }
728     }
729 
730     SetApplicationInfoForTest(
731         use_proportional_font, is_vertical, cursor_offset, hwnd, command);
732   }
733 
734  protected:
SetUpTestCase()735   static void SetUpTestCase() {
736     // On Windows XP, the availability of typical Japanese fonts such are as
737     // MS Gothic depends on the language edition and language packs.
738     // So we will register a private font for unit test.
739     EXPECT_TRUE(WinFontTestHelper::Initialize());
740   }
741 
TearDownTestCase()742   static void TearDownTestCase() {
743     // Free private fonts although the system automatically frees them when
744     // this process is terminated.
745     WinFontTestHelper::Uninitialize();
746   }
747 
748  private:
SetApplicationInfoForTest(bool use_proportional_font,bool is_vertical,int cursor_offset,HWND hwnd,RendererCommand * command)749   static void SetApplicationInfoForTest(
750       bool use_proportional_font, bool is_vertical, int cursor_offset,
751       HWND hwnd, RendererCommand *command) {
752     ApplicationInfo *app = command->mutable_application_info();
753     app->set_process_id(1234);
754     app->set_thread_id(5678);
755     app->set_target_window_handle(reinterpret_cast<uint32>(hwnd));
756     WinLogFont *font = app->mutable_composition_font();
757     font->set_height(-45);
758     font->set_width(0);
759     font->set_escapement(0);
760     font->set_orientation(0);
761     font->set_weight(FW_NORMAL);
762     font->set_italic(false);
763     font->set_underline(false);
764     font->set_strike_out(false);
765     font->set_char_set(SHIFTJIS_CHARSET);
766     font->set_out_precision(0);
767     font->set_clip_precision(0);
768     font->set_quality(0);
769     if (use_proportional_font) {
770       // Use proportional font
771       font->set_pitch_and_family(VARIABLE_PITCH | FF_ROMAN | FF_SWISS);
772       font->set_face_name(GetPropotionalFontFaceForTest());
773     } else {
774       // Use monospaced font
775       font->set_pitch_and_family(FIXED_PITCH | FF_ROMAN | FF_SWISS);
776       font->set_face_name(GetMonospacedFontFaceForTest());
777     }
778 
779     if (is_vertical) {
780       font->set_escapement(2700);
781       font->set_face_name("@" + font->face_name());
782     }
783 
784     app->set_input_framework(ApplicationInfo::IMM32);
785     {
786       CompositionForm *composition_form = app->mutable_composition_form();
787       composition_form->set_style_bits(CompositionForm::RECT);
788       Point *current_position = composition_form->mutable_current_position();
789       Rectangle *area = composition_form->mutable_area();
790       if (is_vertical) {
791         current_position->set_x(1526);
792         current_position->set_y(385 + cursor_offset);
793         area->set_left(567);
794         area->set_top(170);
795         area->set_right(1540);
796         area->set_bottom(563);
797       } else {
798         current_position->set_x(1360 + cursor_offset);
799         current_position->set_y(57);
800         area->set_left(685);
801         area->set_top(47);
802         area->set_right(1523);
803         area->set_bottom(580);
804       }
805     }
806 
807     {
808       CandidateForm *candidate_layout = app->mutable_candidate_form();
809       candidate_layout->set_style_bits(CandidateForm::CANDIDATEPOS);
810       Rectangle *area = candidate_layout->mutable_area();
811       area->set_left(567);
812       area->set_top(67);
813       area->set_right(1983755732);
814       area->set_bottom(-781021488);
815     }
816   }
817 };
818 
TEST_F(Win32RendererUtilTest,GetPointInPhysicalCoordsTest)819 TEST_F(Win32RendererUtilTest, GetPointInPhysicalCoordsTest) {
820   const CPoint kClientOffset(8, 42);
821   const CSize kClientSize(100, 200);
822   const CRect kWindowRect(1000, 500, 1116, 750);
823 
824   const CPoint kInnerPoint(1100, 600);
825   const CPoint kOuterPoint(10, 300);
826 
827   // Check DPI scale: 100%
828   {
829     HWND hwnd = nullptr;
830     LayoutManager layout_mgr(
831         CreateDefaultGUIFontEmulator(),
832         CreateWindowEmulator(kWindowClassName, kWindowRect,
833                              kClientOffset, kClientSize, 1.0, &hwnd));
834 
835     // Conversion from an outer point should be calculated by emulation.
836     CPoint dest;
837     layout_mgr.GetPointInPhysicalCoords(hwnd, kOuterPoint, &dest);
838 
839     // Should be the same position because DPI scaling is 100%.
840     EXPECT_EQ(kOuterPoint, dest);
841 
842     // Conversion from an inner point should be calculated by API.
843     layout_mgr.GetPointInPhysicalCoords(hwnd, kInnerPoint, &dest);
844 
845     // Should be the same position because DPI scaling is 100%.
846     EXPECT_EQ(kInnerPoint, dest);
847   }
848 
849   // Check DPI scale: 200%
850   {
851     HWND hwnd = nullptr;
852     LayoutManager layout_mgr(
853         CreateDefaultGUIFontEmulator(),
854         CreateWindowEmulator(kWindowClassName, kWindowRect, kClientOffset,
855                              kClientSize, 2.0, &hwnd));
856 
857     // Conversion from an outer point should be calculated by emulation.
858     CPoint dest;
859     layout_mgr.GetPointInPhysicalCoords(hwnd, kOuterPoint, &dest);
860 
861     // Should be doubled because DPI scaling is 200%.
862     EXPECT_EQ(CPoint(20, 600), dest);
863 
864     // Conversion from an inner point should be calculated by API.
865     layout_mgr.GetPointInPhysicalCoords(hwnd, kInnerPoint, &dest);
866 
867     // Should be doubled because DPI scaling is 200%.
868     EXPECT_EQ(CPoint(2200, 1200), dest);
869   }
870 }
871 
TEST_F(Win32RendererUtilTest,GetRectInPhysicalCoordsTest)872 TEST_F(Win32RendererUtilTest, GetRectInPhysicalCoordsTest) {
873   const CPoint kClientOffset(8, 42);
874   const CSize kClientSize(100, 200);
875   const CRect kWindowRect(1000, 500, 1116, 750);
876 
877   const CRect kInnerRect(1100, 600, 1070, 630);
878   const CRect kOuterRect(10, 300, 1110, 630);
879 
880   // Check DPI scale: 100%
881   {
882     HWND hwnd = nullptr;
883     LayoutManager layout_mgr(
884         CreateDefaultGUIFontEmulator(),
885         CreateWindowEmulator(kWindowClassName, kWindowRect,
886                              kClientOffset, kClientSize, 1.0, &hwnd));
887 
888     // Conversion from an outer rectangle should be calculated by emulation.
889     CRect dest;
890     layout_mgr.GetRectInPhysicalCoords(hwnd, kOuterRect, &dest);
891 
892     // Should be the same rectangle because DPI scaling is 100%.
893     EXPECT_EQ(kOuterRect, dest);
894 
895     // Conversion from an inner rectangle should be calculated by API.
896     layout_mgr.GetRectInPhysicalCoords(hwnd, kInnerRect, &dest);
897 
898     // Should be the same rectangle because DPI scaling is 100%.
899     EXPECT_EQ(kInnerRect, dest);
900   }
901 
902   // Check DPI scale: 200%
903   {
904     HWND hwnd = nullptr;
905     LayoutManager layout_mgr(
906         CreateDefaultGUIFontEmulator(),
907         CreateWindowEmulator(kWindowClassName, kWindowRect,
908                              kClientOffset, kClientSize, 2.0, &hwnd));
909 
910     // Conversion from an outer rectangle should be calculated by emulation.
911     CRect dest;
912     layout_mgr.GetRectInPhysicalCoords(hwnd, kOuterRect, &dest);
913 
914     // Should be doubled because DPI scaling is 200%.
915     EXPECT_EQ(CRect(20, 600, 2220, 1260), dest);
916 
917     // Conversion from an inner rectangle should be calculated by API.
918     layout_mgr.GetRectInPhysicalCoords(hwnd, kInnerRect, &dest);
919 
920     // Should be doubled because DPI scaling is 200%.
921     EXPECT_EQ(CRect(2200, 1200, 2140, 1260), dest);
922   }
923 }
924 
TEST_F(Win32RendererUtilTest,GetScalingFactorTest)925 TEST_F(Win32RendererUtilTest, GetScalingFactorTest) {
926   const double kScalingFactor = 1.5;
927 
928   {
929     const CPoint kClientOffset(0, 0);
930     const CSize kClientSize(100, 200);
931     const CRect kWindowRect(1000, 500, 1100, 700);
932     HWND hwnd = nullptr;
933     LayoutManager layout_mgr(
934         CreateDefaultGUIFontEmulator(),
935         CreateWindowEmulator(kWindowClassName, kWindowRect,
936                              kClientOffset, kClientSize,
937                              kScalingFactor, &hwnd));
938 
939     ASSERT_DOUBLE_EQ(kScalingFactor, layout_mgr.GetScalingFactor(hwnd));
940   }
941 
942   // Zero Width
943   {
944     const CPoint kClientOffset(0, 0);
945     const CSize kClientSize(0, 200);
946     const CRect kWindowRect(1000, 500, 1000, 700);
947 
948     HWND hwnd = nullptr;
949     LayoutManager layout_mgr(
950         CreateDefaultGUIFontEmulator(),
951         CreateWindowEmulator(kWindowClassName, kWindowRect,
952                              kClientOffset, kClientSize,
953                              kScalingFactor, &hwnd));
954 
955     ASSERT_DOUBLE_EQ(kScalingFactor, layout_mgr.GetScalingFactor(hwnd));
956   }
957 
958   // Zero Height
959   {
960     const CPoint kClientOffset(0, 0);
961     const CSize kClientSize(100, 0);
962     const CRect kWindowRect(1000, 500, 1100, 500);
963     HWND hwnd = nullptr;
964     LayoutManager layout_mgr(
965         CreateDefaultGUIFontEmulator(),
966         CreateWindowEmulator(kWindowClassName, kWindowRect,
967                              kClientOffset, kClientSize,
968                              kScalingFactor, &hwnd));
969 
970     ASSERT_DOUBLE_EQ(kScalingFactor, layout_mgr.GetScalingFactor(hwnd));
971   }
972 
973   // Zero Size
974   {
975     const CPoint kClientOffset(0, 0);
976     const CSize kClientSize(0, 0);
977     const CRect kWindowRect(1000, 500, 1000, 500);
978     HWND hwnd = nullptr;
979     LayoutManager layout_mgr(
980         CreateDefaultGUIFontEmulator(),
981         CreateWindowEmulator(kWindowClassName, kWindowRect,
982                              kClientOffset, kClientSize,
983                              kScalingFactor, &hwnd));
984 
985     // If the window size is zero, the result should be fallen back 1.0.
986     ASSERT_DOUBLE_EQ(1.0, layout_mgr.GetScalingFactor(hwnd));
987   }
988 }
989 
TEST_F(Win32RendererUtilTest,WindowPositionEmulatorTest)990 TEST_F(Win32RendererUtilTest, WindowPositionEmulatorTest) {
991   const CPoint kClientOffset(8, 42);
992   const CSize kClientSize(100, 200);
993   const CRect kWindowRect(1000, 500, 1116, 750);
994 
995   const CPoint kInnerPoint(1100, 600);
996   const CPoint kOuterPoint(10, 300);
997   const CRect kInnerRect(1100, 600, 1070, 630);
998   const CRect kOuterRect(10, 300, 1110, 630);
999 
1000   // Check DPI scale: 100%
1001   {
1002     std::unique_ptr<WindowPositionEmulator> emulator(
1003         WindowPositionEmulator::Create());
1004     const HWND hwnd = emulator->RegisterWindow(
1005         kWindowClassName, kWindowRect, kClientOffset, kClientSize, 1.0);
1006 
1007     CRect rect;
1008     CPoint point;
1009 
1010     // You cannot pass nullptr to |window_handle|.
1011     EXPECT_FALSE(emulator->IsWindow(nullptr));
1012     EXPECT_FALSE(emulator->GetWindowRect(nullptr, &rect));
1013     EXPECT_FALSE(emulator->GetClientRect(nullptr, &rect));
1014     EXPECT_FALSE(emulator->ClientToScreen(nullptr, &point));
1015 
1016     EXPECT_TRUE(emulator->GetWindowRect(hwnd, &rect));
1017     EXPECT_EQ(kWindowRect, rect);
1018 
1019     EXPECT_TRUE(emulator->GetClientRect(hwnd, &rect));
1020     EXPECT_EQ(CRect(CPoint(0, 0), kClientSize), rect);
1021 
1022     point = CPoint(0, 0);
1023     EXPECT_TRUE(emulator->ClientToScreen(hwnd, &point));
1024     EXPECT_EQ(kWindowRect.TopLeft() + kClientOffset, point);
1025 
1026     std::wstring class_name;
1027     EXPECT_TRUE(emulator->GetWindowClassName(hwnd, &class_name));
1028     EXPECT_EQ(kWindowClassName, class_name);
1029   }
1030 
1031   // Interestingly, the following results are independent of DPI scaling.
1032   {
1033     std::unique_ptr<WindowPositionEmulator> emulator(
1034         WindowPositionEmulator::Create());
1035     const HWND hwnd = emulator->RegisterWindow(
1036         kWindowClassName, kWindowRect, kClientOffset, kClientSize, 10.0);
1037 
1038     CRect rect;
1039     CPoint point;
1040 
1041     // You cannot pass nullptr to |window_handle|.
1042     EXPECT_FALSE(emulator->IsWindow(nullptr));
1043     EXPECT_FALSE(emulator->GetWindowRect(nullptr, &rect));
1044     EXPECT_FALSE(emulator->GetClientRect(nullptr, &rect));
1045     EXPECT_FALSE(emulator->ClientToScreen(nullptr, &point));
1046 
1047     EXPECT_TRUE(emulator->GetWindowRect(hwnd, &rect));
1048     EXPECT_EQ(kWindowRect, rect);
1049 
1050     EXPECT_TRUE(emulator->GetClientRect(hwnd, &rect));
1051     EXPECT_EQ(CRect(CPoint(0, 0), kClientSize), rect);
1052 
1053     point = CPoint(0, 0);
1054     EXPECT_TRUE(emulator->ClientToScreen(hwnd, &point));
1055     EXPECT_EQ(kWindowRect.TopLeft() + kClientOffset, point);
1056 
1057     std::wstring class_name;
1058     EXPECT_TRUE(emulator->GetWindowClassName(hwnd, &class_name));
1059     EXPECT_EQ(kWindowClassName, class_name);
1060   }
1061 }
1062 
TEST_F(Win32RendererUtilTest,HorizontalProportional)1063 TEST_F(Win32RendererUtilTest, HorizontalProportional) {
1064   const CLogFont &logfont = GetFont(true, false);
1065 
1066   std::vector<mozc::renderer::win32::LineLayout> line_layouts;
1067   bool result = true;
1068 
1069   const std::wstring &message = GetTestMessageForProportional();
1070 
1071   // Check if the |initial_offset| works as expected.
1072   result = LayoutManager::CalcLayoutWithTextWrapping(
1073       logfont, message, 200, 100, &line_layouts);
1074   EXPECT_TRUE(result);
1075   EXPECT_EQ(4, line_layouts.size());
1076   EXPECT_EQ(line_layouts[0].line_width, line_layouts[1].line_width);
1077   EXPECT_EQ(line_layouts[1].line_width, line_layouts[2].line_width);
1078   EXPECT_EQ(line_layouts[2].line_width, line_layouts[3].line_width);
1079 
1080   // Check if the text wrapping occurs in the first line when
1081   // |initial_offset| > 0.  In this case, the line height of first line is
1082   // expected to be the same to that of the second line.
1083   result = LayoutManager::CalcLayoutWithTextWrapping(
1084       logfont, message, 200, 199, &line_layouts);
1085   EXPECT_TRUE(result);
1086   EXPECT_EQ(4, line_layouts.size());
1087   EXPECT_EQ(0, line_layouts[0].line_length);
1088   EXPECT_EQ(0, line_layouts[0].text.size());
1089   EXPECT_EQ(0, line_layouts[0].character_positions.size());
1090   EXPECT_EQ(line_layouts[0].line_width, line_layouts[1].line_width);
1091   EXPECT_EQ(line_layouts[1].line_width, line_layouts[2].line_width);
1092   EXPECT_EQ(line_layouts[2].line_width, line_layouts[3].line_width);
1093 
1094   // Check if this function fails when there is no enough space for text
1095   // wrapping.
1096   result = LayoutManager::CalcLayoutWithTextWrapping(
1097       logfont, message, 2, 1, &line_layouts);
1098   EXPECT_FALSE(result);
1099 
1100   // Check if an invalid |initial_offset| is detected as expected.
1101   result = LayoutManager::CalcLayoutWithTextWrapping(
1102       logfont, message, 200, -100, &line_layouts);
1103   EXPECT_FALSE(result);
1104 
1105   // Check if an invalid |initial_offset| is detected as expected.
1106   result = LayoutManager::CalcLayoutWithTextWrapping(
1107       logfont, message, 200, 201, &line_layouts);
1108   EXPECT_FALSE(result);
1109 
1110   // Check if an invalid |maximum_line_length| is detected as expected.
1111   result = LayoutManager::CalcLayoutWithTextWrapping(
1112       logfont, message, -1, 0, &line_layouts);
1113   EXPECT_FALSE(result);
1114 
1115   // Check if an invalid |maximum_line_length| is detected as expected.
1116   result = LayoutManager::CalcLayoutWithTextWrapping(
1117       logfont, message, 0, 0, &line_layouts);
1118   EXPECT_FALSE(result);
1119 }
1120 
TEST_F(Win32RendererUtilTest,VerticalProportional)1121 TEST_F(Win32RendererUtilTest, VerticalProportional) {
1122   const CLogFont &logfont = GetFont(true, true);
1123 
1124   std::vector<mozc::renderer::win32::LineLayout> line_layouts;
1125   bool result = true;
1126 
1127   const std::wstring &message = GetTestMessageForProportional();
1128 
1129   // Check if the |initial_offset| works as expected.
1130   result = LayoutManager::CalcLayoutWithTextWrapping(
1131       logfont, message, 200, 100, &line_layouts);
1132   EXPECT_TRUE(result);
1133   EXPECT_EQ(4, line_layouts.size());
1134   EXPECT_EQ(line_layouts[0].line_width, line_layouts[1].line_width);
1135   EXPECT_EQ(line_layouts[1].line_width, line_layouts[2].line_width);
1136   EXPECT_EQ(line_layouts[2].line_width, line_layouts[3].line_width);
1137 
1138   // Check if the text wrapping occurs in the first line when
1139   // |initial_offset| > 0.  In this case, the line height of first line is
1140   // expected to be the same to that of the second line.
1141   result = LayoutManager::CalcLayoutWithTextWrapping(
1142       logfont, message, 200, 199, &line_layouts);
1143   EXPECT_TRUE(result);
1144   EXPECT_EQ(4, line_layouts.size());
1145   EXPECT_EQ(0, line_layouts[0].line_length);
1146   EXPECT_EQ(0, line_layouts[0].text.size());
1147   EXPECT_EQ(0, line_layouts[0].character_positions.size());
1148   EXPECT_EQ(line_layouts[0].line_width, line_layouts[1].line_width);
1149   EXPECT_EQ(line_layouts[1].line_width, line_layouts[2].line_width);
1150   EXPECT_EQ(line_layouts[2].line_width, line_layouts[3].line_width);
1151 
1152   // Check if this function fails when there is no enough space for text
1153   // wrapping.
1154   result = LayoutManager::CalcLayoutWithTextWrapping(
1155       logfont, message, 2, 1, &line_layouts);
1156   EXPECT_FALSE(result);
1157 
1158   // Check if an invalid |initial_offset| is detected as expected.
1159   result = LayoutManager::CalcLayoutWithTextWrapping(
1160       logfont, message, 200, -100, &line_layouts);
1161   EXPECT_FALSE(result);
1162 
1163   // Check if an invalid |initial_offset| is detected as expected.
1164   result = LayoutManager::CalcLayoutWithTextWrapping(
1165       logfont, message, 200, 201, &line_layouts);
1166   EXPECT_FALSE(result);
1167 
1168   // Check if an invalid |maximum_line_length| is detected as expected.
1169   result = LayoutManager::CalcLayoutWithTextWrapping(
1170       logfont, message, -1, 0, &line_layouts);
1171   EXPECT_FALSE(result);
1172 
1173   // Check if an invalid |maximum_line_length| is detected as expected.
1174   result = LayoutManager::CalcLayoutWithTextWrapping(
1175       logfont, message, 0, 0, &line_layouts);
1176   EXPECT_FALSE(result);
1177 }
1178 
TEST_F(Win32RendererUtilTest,HorizontalMonospaced)1179 TEST_F(Win32RendererUtilTest, HorizontalMonospaced) {
1180   const CLogFont &logfont = GetFont(false, false);
1181 
1182   std::vector<mozc::renderer::win32::LineLayout> line_layouts;
1183   bool result = true;
1184 
1185   const std::wstring &message = GetTestMessageForMonospaced();
1186 
1187   // Check if the |initial_offset| works as expected.
1188   result = LayoutManager::CalcLayoutWithTextWrapping(
1189       logfont, message, 200, 100, &line_layouts);
1190   EXPECT_TRUE(result);
1191   EXPECT_EQ(4, line_layouts.size());
1192   EXPECT_EQ(line_layouts[0].line_width, line_layouts[1].line_width);
1193   EXPECT_EQ(line_layouts[1].line_width, line_layouts[2].line_width);
1194   EXPECT_EQ(line_layouts[2].line_width, line_layouts[3].line_width);
1195 
1196   // Check if the text wrapping occurs in the first line when
1197   // |initial_offset| > 0.  In this case, the line height of first line is
1198   // expected to be the same to that of the second line.
1199   result = LayoutManager::CalcLayoutWithTextWrapping(
1200       logfont, message, 200, 199, &line_layouts);
1201   EXPECT_TRUE(result);
1202   EXPECT_EQ(4, line_layouts.size());
1203   EXPECT_EQ(0, line_layouts[0].line_length);
1204   EXPECT_EQ(0, line_layouts[0].text.size());
1205   EXPECT_EQ(0, line_layouts[0].character_positions.size());
1206   EXPECT_EQ(line_layouts[0].line_width, line_layouts[1].line_width);
1207   EXPECT_EQ(line_layouts[1].line_width, line_layouts[2].line_width);
1208   EXPECT_EQ(line_layouts[2].line_width, line_layouts[3].line_width);
1209 
1210   // Check if this function fails when there is no enough space for text
1211   // wrapping.
1212   result = LayoutManager::CalcLayoutWithTextWrapping(
1213       logfont, message, 2, 1, &line_layouts);
1214   EXPECT_FALSE(result);
1215 
1216   // Check if an invalid |initial_offset| is detected as expected.
1217   result = LayoutManager::CalcLayoutWithTextWrapping(
1218       logfont, message, 200, -100, &line_layouts);
1219   EXPECT_FALSE(result);
1220 
1221   // Check if an invalid |initial_offset| is detected as expected.
1222   result = LayoutManager::CalcLayoutWithTextWrapping(
1223       logfont, message, 200, 201, &line_layouts);
1224   EXPECT_FALSE(result);
1225 
1226   // Check if an invalid |maximum_line_length| is detected as expected.
1227   result = LayoutManager::CalcLayoutWithTextWrapping(
1228       logfont, message, -1, 0, &line_layouts);
1229   EXPECT_FALSE(result);
1230 
1231   // Check if an invalid |maximum_line_length| is detected as expected.
1232   result = LayoutManager::CalcLayoutWithTextWrapping(
1233       logfont, message, 0, 0, &line_layouts);
1234   EXPECT_FALSE(result);
1235 }
1236 
TEST_F(Win32RendererUtilTest,VerticalMonospaced)1237 TEST_F(Win32RendererUtilTest, VerticalMonospaced) {
1238   const CLogFont &logfont = GetFont(false, true);
1239 
1240   std::vector<mozc::renderer::win32::LineLayout> line_layouts;
1241   bool result = true;
1242 
1243   const std::wstring &message = GetTestMessageForMonospaced();
1244 
1245   // Check if the |initial_offset| works as expected.
1246   result = LayoutManager::CalcLayoutWithTextWrapping(
1247       logfont, message, 200, 100, &line_layouts);
1248   EXPECT_TRUE(result);
1249   EXPECT_EQ(4, line_layouts.size());
1250   EXPECT_EQ(line_layouts[0].line_width, line_layouts[1].line_width);
1251   EXPECT_EQ(line_layouts[1].line_width, line_layouts[2].line_width);
1252   EXPECT_EQ(line_layouts[2].line_width, line_layouts[3].line_width);
1253 
1254   // Check if the text wrapping occurs in the first line when
1255   // |initial_offset| > 0.  In this case, the line height of first line is
1256   // expected to be the same to that of the second line.
1257   result = LayoutManager::CalcLayoutWithTextWrapping(
1258       logfont, message, 200, 199, &line_layouts);
1259   EXPECT_TRUE(result);
1260   EXPECT_EQ(4, line_layouts.size());
1261   EXPECT_EQ(0, line_layouts[0].line_length);
1262   EXPECT_EQ(0, line_layouts[0].text.size());
1263   EXPECT_EQ(0, line_layouts[0].character_positions.size());
1264   EXPECT_EQ(line_layouts[0].line_width, line_layouts[1].line_width);
1265   EXPECT_EQ(line_layouts[1].line_width, line_layouts[2].line_width);
1266   EXPECT_EQ(line_layouts[2].line_width, line_layouts[3].line_width);
1267 
1268   // Check if this function fails when there is no enough space for text
1269   // wrapping.
1270   result = LayoutManager::CalcLayoutWithTextWrapping(
1271       logfont, message, 2, 1, &line_layouts);
1272   EXPECT_FALSE(result);
1273 
1274   // Check if an invalid |initial_offset| is detected as expected.
1275   result = LayoutManager::CalcLayoutWithTextWrapping(
1276       logfont, message, 200, -100, &line_layouts);
1277   EXPECT_FALSE(result);
1278 
1279   // Check if an invalid |initial_offset| is detected as expected.
1280   result = LayoutManager::CalcLayoutWithTextWrapping(
1281       logfont, message, 200, 201, &line_layouts);
1282   EXPECT_FALSE(result);
1283 
1284   // Check if an invalid |maximum_line_length| is detected as expected.
1285   result = LayoutManager::CalcLayoutWithTextWrapping(
1286       logfont, message, -1, 0, &line_layouts);
1287   EXPECT_FALSE(result);
1288 
1289   // Check if an invalid |maximum_line_length| is detected as expected.
1290   result = LayoutManager::CalcLayoutWithTextWrapping(
1291       logfont, message, 0, 0, &line_layouts);
1292   EXPECT_FALSE(result);
1293 }
1294 
TEST_F(Win32RendererUtilTest,HorizontalProportionalCompositeGlyph)1295 TEST_F(Win32RendererUtilTest, HorizontalProportionalCompositeGlyph) {
1296   const CLogFont &logfont = GetFont(true, false);
1297 
1298   std::vector<mozc::renderer::win32::LineLayout> line_layouts;
1299   bool result = true;
1300 
1301   const std::wstring &message = GetTestMessageWithCompositeGlyph(1);
1302 
1303   result = LayoutManager::CalcLayoutWithTextWrapping(
1304       logfont, message, 200, 100, &line_layouts);
1305   EXPECT_TRUE(result);
1306   EXPECT_EQ(1, line_layouts.size());
1307 
1308   // CalcLayoutWithTextWrapping does not support composition glyph.
1309   EXPECT_GT(line_layouts[0].character_positions[0].length, 0);
1310   EXPECT_EQ(line_layouts[0].character_positions[1].begin +
1311             line_layouts[0].character_positions[1].length,
1312             line_layouts[0].line_length);
1313 }
1314 
TEST_F(Win32RendererUtilTest,VerticalProportionalCompositeGlyph)1315 TEST_F(Win32RendererUtilTest, VerticalProportionalCompositeGlyph) {
1316   const CLogFont &logfont = GetFont(true, true);
1317 
1318   std::vector<mozc::renderer::win32::LineLayout> line_layouts;
1319   bool result = true;
1320 
1321   const std::wstring &message = GetTestMessageWithCompositeGlyph(1);
1322   result = LayoutManager::CalcLayoutWithTextWrapping(
1323       logfont, message, 200, 100, &line_layouts);
1324   EXPECT_TRUE(result);
1325   EXPECT_EQ(1, line_layouts.size());
1326 
1327   // CalcLayoutWithTextWrapping does not support composition glyph.
1328   EXPECT_GT(line_layouts[0].character_positions[0].length, 0);
1329   EXPECT_EQ(line_layouts[0].character_positions[1].begin +
1330             line_layouts[0].character_positions[1].length,
1331             line_layouts[0].line_length);
1332 }
1333 
TEST_F(Win32RendererUtilTest,HorizontalMonospacedCompositeGlyph)1334 TEST_F(Win32RendererUtilTest, HorizontalMonospacedCompositeGlyph) {
1335   const CLogFont &logfont = GetFont(false, false);
1336 
1337   std::vector<mozc::renderer::win32::LineLayout> line_layouts;
1338   bool result = true;
1339 
1340   const std::wstring &message = GetTestMessageWithCompositeGlyph(1);
1341 
1342   result = LayoutManager::CalcLayoutWithTextWrapping(
1343       logfont, message, 200, 100, &line_layouts);
1344   EXPECT_TRUE(result);
1345   EXPECT_EQ(1, line_layouts.size());
1346 
1347   // CalcLayoutWithTextWrapping does not support composition glyph.
1348   EXPECT_GT(line_layouts[0].character_positions[0].length, 0);
1349   EXPECT_EQ(line_layouts[0].character_positions[1].begin +
1350             line_layouts[0].character_positions[1].length,
1351             line_layouts[0].line_length);
1352 }
1353 
TEST_F(Win32RendererUtilTest,VerticalMonospacedCompositeGlyph)1354 TEST_F(Win32RendererUtilTest, VerticalMonospacedCompositeGlyph) {
1355   const CLogFont &logfont = GetFont(false, true);
1356 
1357   std::vector<mozc::renderer::win32::LineLayout> line_layouts;
1358   bool result = true;
1359 
1360   const std::wstring &message = GetTestMessageWithCompositeGlyph(1);
1361 
1362   result = LayoutManager::CalcLayoutWithTextWrapping(
1363       logfont, message, 200, 100, &line_layouts);
1364   EXPECT_TRUE(result);
1365   EXPECT_EQ(1, line_layouts.size());
1366 
1367   // CalcLayoutWithTextWrapping does not support composition glyph.
1368   EXPECT_GT(line_layouts[0].character_positions[0].length, 0);
1369   EXPECT_EQ(line_layouts[0].character_positions[1].begin +
1370             line_layouts[0].character_positions[1].length,
1371             line_layouts[0].line_length);
1372 }
1373 
TEST_F(Win32RendererUtilTest,CompositionHorizontalNoAdditionalSegmentationWithMonospacedFont)1374 TEST_F(Win32RendererUtilTest,
1375        CompositionHorizontalNoAdditionalSegmentationWithMonospacedFont) {
1376   const int kCursorOffsetX = 0;
1377 
1378   RendererCommand command;
1379 
1380   HWND hwnd = nullptr;
1381   LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
1382                            CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
1383   std::vector<CompositionWindowLayout> layouts;
1384   CandidateWindowLayout candidate_layout;
1385 
1386   CLogFont logfont;
1387 
1388   bool result = false;
1389 
1390   // w/ candidates, monospaced, horizontal
1391   SetRenderereCommandForTest(
1392       false, true, false, kCursorOffsetX, hwnd, &command);
1393   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
1394       command.application_info().composition_font(), &logfont));
1395   layouts.clear();
1396   candidate_layout.Clear();
1397   result = layout_mgr.LayoutCompositionWindow(
1398       command, &layouts, &candidate_layout);
1399   EXPECT_TRUE(result);
1400 
1401   ASSERT_EQ(2, layouts.size());
1402 
1403   // The first line
1404   {
1405     const CompositionWindowLayout &layout = layouts.at(0);
1406     EXPECT_COMPOSITION_WINDOW_LAYOUT(1868, 599, 2003, 648, 0, 0, 135, 49,
1407                                      0, 0, 0, 0, 0, 0, logfont, layout);
1408     {
1409       const char kMsg[] = "これは";
1410       std::wstring msg;
1411       mozc::Util::UTF8ToWide(kMsg, &msg);
1412       EXPECT_EQ(msg, layout.text);
1413     }
1414     ASSERT_EQ(1, layout.marker_layouts.size());
1415 
1416     EXPECT_EQ(CPoint(0, 48), layout.marker_layouts[0].from);
1417     EXPECT_EQ(CPoint(126, 48), layout.marker_layouts[0].to);
1418     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
1419   }
1420 
1421   // The second line
1422   {
1423     const CompositionWindowLayout &layout = layouts.at(1);
1424     EXPECT_COMPOSITION_WINDOW_LAYOUT(1193, 648, 1840, 697, 0, 0, 646, 49,
1425                                      0, 0, 646, 0, 647, 49, logfont, layout);
1426     {
1427       const char kMsg[] = "、Google日本語入力のTestです";
1428       std::wstring msg;
1429       mozc::Util::UTF8ToWide(kMsg, &msg);
1430       EXPECT_EQ(msg, layout.text);
1431     }
1432     ASSERT_EQ(4, layout.marker_layouts.size());
1433 
1434     EXPECT_EQ(CPoint(0, 48), layout.marker_layouts[0].from);
1435     EXPECT_EQ(CPoint(36, 48), layout.marker_layouts[0].to);
1436     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
1437     EXPECT_EQ(CPoint(45, 48), layout.marker_layouts[1].from);
1438     EXPECT_EQ(CPoint(190, 48), layout.marker_layouts[1].to);
1439     EXPECT_TRUE(layout.marker_layouts[1].highlighted);
1440     EXPECT_EQ(CPoint(196, 48), layout.marker_layouts[2].from);
1441     EXPECT_EQ(CPoint(457, 48), layout.marker_layouts[2].to);
1442     EXPECT_FALSE(layout.marker_layouts[2].highlighted);
1443     EXPECT_EQ(CPoint(466, 48), layout.marker_layouts[3].from);
1444     EXPECT_EQ(CPoint(646, 48), layout.marker_layouts[3].to);
1445     EXPECT_FALSE(layout.marker_layouts[3].highlighted);
1446   }
1447   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1448       1238, 697, 1238, 648, 1839, 697, candidate_layout);
1449 
1450   // Check other candidate positions.
1451   command.mutable_output()->mutable_candidates()->set_position(0);
1452   layouts.clear();
1453   candidate_layout.Clear();
1454   result = layout_mgr.LayoutCompositionWindow(
1455       command, &layouts, &candidate_layout);
1456   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1457       1868, 648, 1868, 599, 2003, 648, candidate_layout);
1458 
1459   command.mutable_output()->mutable_candidates()->set_position(3);
1460   layouts.clear();
1461   candidate_layout.Clear();
1462   result = layout_mgr.LayoutCompositionWindow(
1463       command, &layouts, &candidate_layout);
1464   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1465       1193, 697, 1193, 648, 1839, 697, candidate_layout);
1466 
1467   command.mutable_output()->mutable_candidates()->set_position(10);
1468   layouts.clear();
1469   candidate_layout.Clear();
1470   result = layout_mgr.LayoutCompositionWindow(
1471       command, &layouts, &candidate_layout);
1472   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1473       1389, 697, 1389, 648, 1839, 697, candidate_layout);
1474 
1475   command.mutable_output()->mutable_candidates()->set_position(16);
1476   layouts.clear();
1477   candidate_layout.Clear();
1478   result = layout_mgr.LayoutCompositionWindow(
1479       command, &layouts, &candidate_layout);
1480   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1481       1659, 697, 1659, 648, 1839, 697, candidate_layout);
1482 
1483   // w/o candidates, monospaced, horizontal
1484   SetRenderereCommandForTest(false, false, false, 0, hwnd, &command);
1485   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
1486       command.application_info().composition_font(), &logfont));
1487   layouts.clear();
1488   candidate_layout.Clear();
1489   result = layout_mgr.LayoutCompositionWindow(
1490       command, &layouts, &candidate_layout);
1491   EXPECT_TRUE(result);
1492   EXPECT_FALSE(candidate_layout.initialized());
1493 }
1494 
TEST_F(Win32RendererUtilTest,CompositionHorizontalAdditionalSegmentationWithMonospacedFont)1495 TEST_F(Win32RendererUtilTest,
1496        CompositionHorizontalAdditionalSegmentationWithMonospacedFont) {
1497   const int kCursorOffsetX = -90;
1498 
1499   RendererCommand command;
1500 
1501   HWND hwnd = nullptr;
1502   LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
1503                            CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
1504   std::vector<CompositionWindowLayout> layouts;
1505   CandidateWindowLayout candidate_layout;
1506   CLogFont logfont;
1507 
1508   bool result = false;
1509 
1510   // w/ candidates, monospaced, horizontal
1511   SetRenderereCommandForTest(
1512       false, true, false, kCursorOffsetX, hwnd, &command);
1513   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
1514       command.application_info().composition_font(), &logfont));
1515   layouts.clear();
1516   candidate_layout.Clear();
1517   result = layout_mgr.LayoutCompositionWindow(
1518       command, &layouts, &candidate_layout);
1519   EXPECT_TRUE(result);
1520 
1521   ASSERT_EQ(2, layouts.size());
1522 
1523   // The first line
1524   {
1525     const CompositionWindowLayout &layout = layouts.at(0);
1526     EXPECT_COMPOSITION_WINDOW_LAYOUT(1778, 599, 2019, 648, 0, 0, 241, 49,
1527                                      0, 0, 0, 0, 0, 0, logfont, layout);
1528     {
1529       const char kMsg[] = "これは、Go";
1530       std::wstring msg;
1531       mozc::Util::UTF8ToWide(kMsg, &msg);
1532       EXPECT_EQ(msg, layout.text);
1533     }
1534     ASSERT_EQ(3, layout.marker_layouts.size());
1535 
1536     EXPECT_EQ(CPoint(0, 48), layout.marker_layouts[0].from);
1537     EXPECT_EQ(CPoint(126, 48), layout.marker_layouts[0].to);
1538     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
1539     EXPECT_EQ(CPoint(135, 48), layout.marker_layouts[1].from);
1540     EXPECT_EQ(CPoint(171, 48), layout.marker_layouts[1].to);
1541     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
1542     EXPECT_EQ(CPoint(180, 48), layout.marker_layouts[2].from);
1543     EXPECT_EQ(CPoint(241, 48), layout.marker_layouts[2].to);
1544     EXPECT_TRUE(layout.marker_layouts[2].highlighted);
1545   }
1546 
1547   // The second line
1548   {
1549     const CompositionWindowLayout &layout = layouts.at(1);
1550     EXPECT_COMPOSITION_WINDOW_LAYOUT(1193, 648, 1734, 697, 0, 0, 540, 49,
1551                                      0, 0, 540, 0, 541, 49, logfont, layout);
1552     {
1553       const char kMsg[] = "ogle日本語入力のTestです";
1554       std::wstring msg;
1555       mozc::Util::UTF8ToWide(kMsg, &msg);
1556       EXPECT_EQ(msg, layout.text);
1557     }
1558     ASSERT_EQ(3, layout.marker_layouts.size());
1559 
1560     EXPECT_EQ(CPoint(0, 48), layout.marker_layouts[0].from);
1561     EXPECT_EQ(CPoint(84, 48), layout.marker_layouts[0].to);
1562     EXPECT_TRUE(layout.marker_layouts[0].highlighted);
1563     EXPECT_EQ(CPoint(90, 48), layout.marker_layouts[1].from);
1564     EXPECT_EQ(CPoint(351, 48), layout.marker_layouts[1].to);
1565     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
1566     EXPECT_EQ(CPoint(360, 48), layout.marker_layouts[2].from);
1567     EXPECT_EQ(CPoint(540, 48), layout.marker_layouts[2].to);
1568     EXPECT_FALSE(layout.marker_layouts[2].highlighted);
1569   }
1570 
1571   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1572       1958, 648, 1958, 599, 2019, 648, candidate_layout);
1573 
1574   // Check other candidate positions.
1575   command.mutable_output()->mutable_candidates()->set_position(0);
1576   layouts.clear();
1577   candidate_layout.Clear();
1578   result = layout_mgr.LayoutCompositionWindow(
1579       command, &layouts, &candidate_layout);
1580   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1581       1778, 648, 1778, 599, 2019, 648, candidate_layout);
1582 
1583   command.mutable_output()->mutable_candidates()->set_position(3);
1584   layouts.clear();
1585   candidate_layout.Clear();
1586   result = layout_mgr.LayoutCompositionWindow(
1587       command, &layouts, &candidate_layout);
1588   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1589       1913, 648, 1913, 599, 2019, 648, candidate_layout);
1590 
1591   command.mutable_output()->mutable_candidates()->set_position(10);
1592   layouts.clear();
1593   candidate_layout.Clear();
1594   result = layout_mgr.LayoutCompositionWindow(
1595       command, &layouts, &candidate_layout);
1596   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1597       1283, 697, 1283, 648, 1733, 697, candidate_layout);
1598 
1599   command.mutable_output()->mutable_candidates()->set_position(16);
1600   layouts.clear();
1601   candidate_layout.Clear();
1602   result = layout_mgr.LayoutCompositionWindow(
1603       command, &layouts, &candidate_layout);
1604   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1605       1553, 697, 1553, 648, 1733, 697, candidate_layout);
1606 
1607   // w/o candidates, monospaced, horizontal
1608   SetRenderereCommandForTest(false, false, false, 0, hwnd, &command);
1609   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
1610       command.application_info().composition_font(), &logfont));
1611   layouts.clear();
1612   candidate_layout.Clear();
1613   result = layout_mgr.LayoutCompositionWindow(
1614       command, &layouts, &candidate_layout);
1615   EXPECT_TRUE(result);
1616   EXPECT_FALSE(candidate_layout.initialized());
1617 }
1618 
TEST_F(Win32RendererUtilTest,CompositionVerticalNoAdditionalSegmentationWithMonospacedFont)1619 TEST_F(Win32RendererUtilTest,
1620        CompositionVerticalNoAdditionalSegmentationWithMonospacedFont) {
1621   const int kCursorOffsetY = 0;
1622 
1623   RendererCommand command;
1624 
1625   HWND hwnd = nullptr;
1626   LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
1627                            CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
1628   std::vector<CompositionWindowLayout> layouts;
1629   CandidateWindowLayout candidate_layout;
1630   CLogFont logfont;
1631 
1632   bool result = false;
1633 
1634   // w/ candidates, monospaced, vertical
1635   SetRenderereCommandForTest(
1636       false, true, true, kCursorOffsetY, hwnd, &command);
1637   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
1638       command.application_info().composition_font(), &logfont));
1639   logfont.lfOrientation = 2700;
1640 
1641   layouts.clear();
1642   candidate_layout.Clear();
1643   result = layout_mgr.LayoutCompositionWindow(
1644       command, &layouts, &candidate_layout);
1645   EXPECT_TRUE(result);
1646 
1647   ASSERT_EQ(3, layouts.size());
1648 
1649   // The first line
1650   {
1651     const CompositionWindowLayout &layout = layouts.at(0);
1652     EXPECT_COMPOSITION_WINDOW_LAYOUT(1983, 927, 2034, 1062, 0, 0, 51, 135,
1653                                      51, 0, 0, 0, 0, 0, logfont, layout);
1654     {
1655       const char kMsg[] = "これは";
1656       std::wstring msg;
1657       mozc::Util::UTF8ToWide(kMsg, &msg);
1658       EXPECT_EQ(msg, layout.text);
1659     }
1660     ASSERT_EQ(1, layout.marker_layouts.size());
1661 
1662     EXPECT_EQ(CPoint(50, 0), layout.marker_layouts[0].from);
1663     EXPECT_EQ(CPoint(50, 126), layout.marker_layouts[0].to);
1664     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
1665   }
1666 
1667   // The second line
1668   {
1669     const CompositionWindowLayout &layout = layouts.at(1);
1670     EXPECT_COMPOSITION_WINDOW_LAYOUT(1932, 712, 1983, 1088, 0, 0, 51, 376,
1671                                      51, 0, 0, 0, 0, 0, logfont, layout);
1672     {
1673       const char kMsg[] = "、Google日本語入";
1674       std::wstring msg;
1675       mozc::Util::UTF8ToWide(kMsg, &msg);
1676       EXPECT_EQ(msg, layout.text);
1677     }
1678     ASSERT_EQ(3, layout.marker_layouts.size());
1679 
1680     EXPECT_EQ(CPoint(50, 0), layout.marker_layouts[0].from);
1681     EXPECT_EQ(CPoint(50, 36), layout.marker_layouts[0].to);
1682     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
1683     EXPECT_EQ(CPoint(50, 45), layout.marker_layouts[1].from);
1684     EXPECT_EQ(CPoint(50, 190), layout.marker_layouts[1].to);
1685     EXPECT_TRUE(layout.marker_layouts[1].highlighted);
1686     EXPECT_EQ(CPoint(50, 196), layout.marker_layouts[2].from);
1687     EXPECT_EQ(CPoint(50, 376), layout.marker_layouts[2].to);
1688     EXPECT_FALSE(layout.marker_layouts[2].highlighted);
1689   }
1690 
1691   // The third line
1692   {
1693     const CompositionWindowLayout &layout = layouts.at(2);
1694     EXPECT_COMPOSITION_WINDOW_LAYOUT(1881, 712, 1932, 983, 0, 0, 51, 270,
1695                                      51, 0, 0, 270, 51, 271, logfont, layout);
1696     {
1697       const char kMsg[] = "力のTestです";
1698       std::wstring msg;
1699       mozc::Util::UTF8ToWide(kMsg, &msg);
1700       EXPECT_EQ(msg, layout.text);
1701     }
1702     ASSERT_EQ(2, layout.marker_layouts.size());
1703 
1704     EXPECT_EQ(CPoint(50, 0), layout.marker_layouts[0].from);
1705     EXPECT_EQ(CPoint(50, 81), layout.marker_layouts[0].to);
1706     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
1707     EXPECT_EQ(CPoint(50, 90), layout.marker_layouts[1].from);
1708     EXPECT_EQ(CPoint(50, 270), layout.marker_layouts[1].to);
1709     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
1710   }
1711 
1712   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1713       1932, 757, 1932, 757, 1983, 1088, candidate_layout);
1714 
1715   // Check other candidate positions.
1716   command.mutable_output()->mutable_candidates()->set_position(0);
1717   layouts.clear();
1718   candidate_layout.Clear();
1719   result = layout_mgr.LayoutCompositionWindow(
1720       command, &layouts, &candidate_layout);
1721   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1722       1983, 927, 1983, 927, 2034, 1062, candidate_layout);
1723 
1724   command.mutable_output()->mutable_candidates()->set_position(3);
1725   layouts.clear();
1726   candidate_layout.Clear();
1727   result = layout_mgr.LayoutCompositionWindow(
1728       command, &layouts, &candidate_layout);
1729   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1730       1932, 712, 1932, 712, 1983, 1088, candidate_layout);
1731 
1732   command.mutable_output()->mutable_candidates()->set_position(10);
1733   layouts.clear();
1734   candidate_layout.Clear();
1735   result = layout_mgr.LayoutCompositionWindow(
1736       command, &layouts, &candidate_layout);
1737   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1738       1932, 908, 1932, 908, 1983, 1088, candidate_layout);
1739 
1740   command.mutable_output()->mutable_candidates()->set_position(16);
1741   layouts.clear();
1742   candidate_layout.Clear();
1743   result = layout_mgr.LayoutCompositionWindow(
1744       command, &layouts, &candidate_layout);
1745   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1746       1881, 802, 1881, 802, 1932, 982, candidate_layout);
1747 
1748   // w/o candidates, monospaced, vertical
1749   SetRenderereCommandForTest(false, false, true, 0, hwnd, &command);
1750   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
1751       command.application_info().composition_font(), &logfont));
1752   layouts.clear();
1753   candidate_layout.Clear();
1754   result = layout_mgr.LayoutCompositionWindow(
1755       command, &layouts, &candidate_layout);
1756   EXPECT_TRUE(result);
1757   EXPECT_FALSE(candidate_layout.initialized());
1758 }
1759 
TEST_F(Win32RendererUtilTest,CompositionVerticalAdditionalSegmentationWithMonospacedFont)1760 TEST_F(Win32RendererUtilTest,
1761        CompositionVerticalAdditionalSegmentationWithMonospacedFont) {
1762   const int kCursorOffsetY = -90;
1763 
1764   RendererCommand command;
1765 
1766   HWND hwnd = nullptr;
1767   LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
1768                            CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
1769   std::vector<CompositionWindowLayout> layouts;
1770   CandidateWindowLayout candidate_layout;
1771   CLogFont logfont;
1772 
1773   bool result = false;
1774 
1775   // w/ candidates, monospaced, vertical
1776   SetRenderereCommandForTest(
1777       false, true, true, kCursorOffsetY, hwnd, &command);
1778   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
1779       command.application_info().composition_font(), &logfont));
1780   logfont.lfOrientation = 2700;
1781 
1782   layouts.clear();
1783   candidate_layout.Clear();
1784   result = layout_mgr.LayoutCompositionWindow(
1785       command, &layouts, &candidate_layout);
1786   EXPECT_TRUE(result);
1787 
1788   ASSERT_EQ(3, layouts.size());
1789 
1790   // The first line
1791   {
1792     const CompositionWindowLayout &layout = layouts.at(0);
1793     EXPECT_COMPOSITION_WINDOW_LAYOUT(1983, 837, 2034, 1105, 0, 0, 51, 268,
1794                                      51, 0, 0, 0, 0, 0, logfont, layout);
1795     {
1796       const char kMsg[] = "これは、Goo";
1797       std::wstring msg;
1798       mozc::Util::UTF8ToWide(kMsg, &msg);
1799       EXPECT_EQ(msg, layout.text);
1800     }
1801     ASSERT_EQ(3, layout.marker_layouts.size());
1802 
1803     EXPECT_EQ(CPoint(50, 0), layout.marker_layouts[0].from);
1804     EXPECT_EQ(CPoint(50, 126), layout.marker_layouts[0].to);
1805     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
1806     EXPECT_EQ(CPoint(50, 135), layout.marker_layouts[1].from);
1807     EXPECT_EQ(CPoint(50, 171), layout.marker_layouts[1].to);
1808     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
1809     EXPECT_EQ(CPoint(50, 180), layout.marker_layouts[2].from);
1810     EXPECT_EQ(CPoint(50, 268), layout.marker_layouts[2].to);
1811     EXPECT_TRUE(layout.marker_layouts[2].highlighted);
1812   }
1813 
1814   // The second line
1815   {
1816     const CompositionWindowLayout &layout = layouts.at(1);
1817     EXPECT_COMPOSITION_WINDOW_LAYOUT(1932, 712, 1983, 1098, 0, 0, 51, 386,
1818                                      51, 0, 0, 0, 0, 0, logfont, layout);
1819     {
1820       const char kMsg[] = "gle日本語入力のTe";
1821       std::wstring msg;
1822       mozc::Util::UTF8ToWide(kMsg, &msg);
1823       EXPECT_EQ(msg, layout.text);
1824     }
1825     ASSERT_EQ(3, layout.marker_layouts.size());
1826 
1827     EXPECT_EQ(CPoint(50, 0), layout.marker_layouts[0].from);
1828     EXPECT_EQ(CPoint(50, 57), layout.marker_layouts[0].to);
1829     EXPECT_TRUE(layout.marker_layouts[0].highlighted);
1830     EXPECT_EQ(CPoint(50, 63), layout.marker_layouts[1].from);
1831     EXPECT_EQ(CPoint(50, 324), layout.marker_layouts[1].to);
1832     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
1833     EXPECT_EQ(CPoint(50, 333), layout.marker_layouts[2].from);
1834     EXPECT_EQ(CPoint(50, 386), layout.marker_layouts[2].to);
1835     EXPECT_FALSE(layout.marker_layouts[2].highlighted);
1836   }
1837 
1838   // The third line
1839   {
1840     const CompositionWindowLayout &layout = layouts.at(2);
1841     EXPECT_COMPOSITION_WINDOW_LAYOUT(1881, 712, 1932, 840, 0, 0, 51, 127,
1842                                      51, 0, 0, 127, 51, 128, logfont, layout);
1843     {
1844       const char kMsg[] = "stです";
1845       std::wstring msg;
1846       mozc::Util::UTF8ToWide(kMsg, &msg);
1847       EXPECT_EQ(msg, layout.text);
1848     }
1849     ASSERT_EQ(1, layout.marker_layouts.size());
1850 
1851     EXPECT_EQ(CPoint(50, 0), layout.marker_layouts[0].from);
1852     EXPECT_EQ(CPoint(50, 127), layout.marker_layouts[0].to);
1853     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
1854   }
1855 
1856   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1857       1983, 1017, 1983, 1017, 2034, 1105, candidate_layout);
1858 
1859   // Check other candidate positions.
1860   command.mutable_output()->mutable_candidates()->set_position(0);
1861   layouts.clear();
1862   candidate_layout.Clear();
1863   result = layout_mgr.LayoutCompositionWindow(
1864       command, &layouts, &candidate_layout);
1865   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1866       1983, 837, 1983, 837, 2034, 1105, candidate_layout);
1867 
1868   command.mutable_output()->mutable_candidates()->set_position(3);
1869   layouts.clear();
1870   candidate_layout.Clear();
1871   result = layout_mgr.LayoutCompositionWindow(
1872       command, &layouts, &candidate_layout);
1873   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1874       1983, 972, 1983, 972, 2034, 1105, candidate_layout);
1875 
1876   command.mutable_output()->mutable_candidates()->set_position(10);
1877   layouts.clear();
1878   candidate_layout.Clear();
1879   result = layout_mgr.LayoutCompositionWindow(
1880       command, &layouts, &candidate_layout);
1881   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1882       1932, 775, 1932, 775, 1983, 1098, candidate_layout);
1883 
1884   command.mutable_output()->mutable_candidates()->set_position(16);
1885   layouts.clear();
1886   candidate_layout.Clear();
1887   result = layout_mgr.LayoutCompositionWindow(
1888       command, &layouts, &candidate_layout);
1889   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1890       1932, 1045, 1932, 1045, 1983, 1098, candidate_layout);
1891 
1892   // w/o candidates, monospaced, vertical
1893   SetRenderereCommandForTest(false, false, true, 0, hwnd, &command);
1894   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
1895       command.application_info().composition_font(), &logfont));
1896   layouts.clear();
1897   candidate_layout.Clear();
1898   result = layout_mgr.LayoutCompositionWindow(
1899       command, &layouts, &candidate_layout);
1900   EXPECT_TRUE(result);
1901   EXPECT_FALSE(candidate_layout.initialized());
1902 }
1903 
TEST_F(Win32RendererUtilTest,CompositionHorizontalNoAdditionalSegmentationWithProportionalFont)1904 TEST_F(Win32RendererUtilTest,
1905        CompositionHorizontalNoAdditionalSegmentationWithProportionalFont) {
1906   const int kCursorOffsetX = 0;
1907 
1908   RendererCommand command;
1909 
1910   HWND hwnd = nullptr;
1911   LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
1912                            CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
1913   std::vector<CompositionWindowLayout> layouts;
1914   CandidateWindowLayout candidate_layout;
1915   CLogFont logfont;
1916 
1917   bool result = false;
1918 
1919   // w/ candidates, proportional, horizontal
1920   SetRenderereCommandForTest(
1921       true, true, false, kCursorOffsetX, hwnd, &command);
1922   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
1923       command.application_info().composition_font(), &logfont));
1924   layouts.clear();
1925   candidate_layout.Clear();
1926   result = layout_mgr.LayoutCompositionWindow(
1927       command, &layouts, &candidate_layout);
1928   EXPECT_TRUE(result);
1929 
1930   ASSERT_EQ(2, layouts.size());
1931 
1932   // The first line
1933   {
1934     const CompositionWindowLayout &layout = layouts.at(0);
1935     EXPECT_COMPOSITION_WINDOW_LAYOUT(1868, 599, 2003, 653, 0, 0, 135, 54,
1936                                      0, 0, 0, 0, 0, 0, logfont, layout);
1937     {
1938       const char kMsg[] = "これは";
1939       std::wstring msg;
1940       mozc::Util::UTF8ToWide(kMsg, &msg);
1941       EXPECT_EQ(msg, layout.text);
1942     }
1943     ASSERT_EQ(1, layout.marker_layouts.size());
1944 
1945     EXPECT_EQ(CPoint(0, 53), layout.marker_layouts[0].from);
1946     EXPECT_EQ(CPoint(126, 53), layout.marker_layouts[0].to);
1947     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
1948   }
1949 
1950   // The second line
1951   {
1952     const CompositionWindowLayout &layout = layouts.at(1);
1953     EXPECT_COMPOSITION_WINDOW_LAYOUT(1193, 653, 1840, 707, 0, 0, 646, 54,
1954                                      0, 0, 646, 0, 647, 54, logfont, layout);
1955     {
1956       const char kMsg[] = "、Google日本語入力のTestです";
1957       std::wstring msg;
1958       mozc::Util::UTF8ToWide(kMsg, &msg);
1959       EXPECT_EQ(msg, layout.text);
1960     }
1961     ASSERT_EQ(4, layout.marker_layouts.size());
1962 
1963     EXPECT_EQ(CPoint(0, 53), layout.marker_layouts[0].from);
1964     EXPECT_EQ(CPoint(36, 53), layout.marker_layouts[0].to);
1965     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
1966     EXPECT_EQ(CPoint(45, 53), layout.marker_layouts[1].from);
1967     EXPECT_EQ(CPoint(192, 53), layout.marker_layouts[1].to);
1968     EXPECT_TRUE(layout.marker_layouts[1].highlighted);
1969     EXPECT_EQ(CPoint(197, 53), layout.marker_layouts[2].from);
1970     EXPECT_EQ(CPoint(458, 53), layout.marker_layouts[2].to);
1971     EXPECT_FALSE(layout.marker_layouts[2].highlighted);
1972     EXPECT_EQ(CPoint(467, 53), layout.marker_layouts[3].from);
1973     EXPECT_EQ(CPoint(646, 53), layout.marker_layouts[3].to);
1974     EXPECT_FALSE(layout.marker_layouts[3].highlighted);
1975   }
1976 
1977   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1978       1238, 707, 1238, 653, 1839, 707, candidate_layout);
1979 
1980   // Check other candidate positions.
1981   command.mutable_output()->mutable_candidates()->set_position(0);
1982   layouts.clear();
1983   candidate_layout.Clear();
1984   result = layout_mgr.LayoutCompositionWindow(
1985       command, &layouts, &candidate_layout);
1986   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1987       1868, 653, 1868, 599, 2003, 653, candidate_layout);
1988 
1989   command.mutable_output()->mutable_candidates()->set_position(3);
1990   layouts.clear();
1991   candidate_layout.Clear();
1992   result = layout_mgr.LayoutCompositionWindow(
1993       command, &layouts, &candidate_layout);
1994   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1995       1193, 707, 1193, 653, 1839, 707, candidate_layout);
1996 
1997   command.mutable_output()->mutable_candidates()->set_position(10);
1998   layouts.clear();
1999   candidate_layout.Clear();
2000   result = layout_mgr.LayoutCompositionWindow(
2001       command, &layouts, &candidate_layout);
2002   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
2003       1390, 707, 1390, 653, 1839, 707, candidate_layout);
2004 
2005   command.mutable_output()->mutable_candidates()->set_position(16);
2006   layouts.clear();
2007   candidate_layout.Clear();
2008   result = layout_mgr.LayoutCompositionWindow(
2009       command, &layouts, &candidate_layout);
2010   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
2011       1660, 707, 1660, 653, 1839, 707, candidate_layout);
2012 
2013   // w/o candidates, proportional, horizontal
2014   SetRenderereCommandForTest(true, false, false, 0, hwnd, &command);
2015   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
2016       command.application_info().composition_font(), &logfont));
2017   layouts.clear();
2018   candidate_layout.Clear();
2019   result = layout_mgr.LayoutCompositionWindow(
2020       command, &layouts, &candidate_layout);
2021   EXPECT_TRUE(result);
2022   EXPECT_FALSE(candidate_layout.initialized());
2023 }
2024 
TEST_F(Win32RendererUtilTest,CompositionHorizontalAdditionalSegmentationWithProportionalFont)2025 TEST_F(Win32RendererUtilTest,
2026        CompositionHorizontalAdditionalSegmentationWithProportionalFont) {
2027   const int kCursorOffsetX = -90;
2028 
2029   RendererCommand command;
2030 
2031   HWND hwnd = nullptr;
2032   LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
2033                            CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
2034   std::vector<CompositionWindowLayout> layouts;
2035   CandidateWindowLayout candidate_layout;
2036   CLogFont logfont;
2037 
2038   bool result = false;
2039 
2040   // w/ candidates, proportional, horizontal
2041   SetRenderereCommandForTest(
2042       true, true, false, kCursorOffsetX, hwnd, &command);
2043   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
2044       command.application_info().composition_font(), &logfont));
2045   layouts.clear();
2046   candidate_layout.Clear();
2047   result = layout_mgr.LayoutCompositionWindow(
2048       command, &layouts, &candidate_layout);
2049   EXPECT_TRUE(result);
2050 
2051   ASSERT_EQ(2, layouts.size());
2052 
2053   // The first line
2054   {
2055     const CompositionWindowLayout &layout = layouts.at(0);
2056     EXPECT_COMPOSITION_WINDOW_LAYOUT(1778, 599, 2020, 653, 0, 0, 242, 54,
2057                                      0, 0, 0, 0, 0, 0, logfont, layout);
2058     {
2059       const char kMsg[] = "これは、Go";
2060       std::wstring msg;
2061       mozc::Util::UTF8ToWide(kMsg, &msg);
2062       EXPECT_EQ(msg, layout.text);
2063     }
2064     ASSERT_EQ(3, layout.marker_layouts.size());
2065 
2066     EXPECT_EQ(CPoint(0, 53), layout.marker_layouts[0].from);
2067     EXPECT_EQ(CPoint(126, 53), layout.marker_layouts[0].to);
2068     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
2069     EXPECT_EQ(CPoint(135, 53), layout.marker_layouts[1].from);
2070     EXPECT_EQ(CPoint(171, 53), layout.marker_layouts[1].to);
2071     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
2072     EXPECT_EQ(CPoint(180, 53), layout.marker_layouts[2].from);
2073     EXPECT_EQ(CPoint(242, 53), layout.marker_layouts[2].to);
2074     EXPECT_TRUE(layout.marker_layouts[2].highlighted);
2075   }
2076 
2077   // The second line
2078   {
2079     const CompositionWindowLayout &layout = layouts.at(1);
2080     EXPECT_COMPOSITION_WINDOW_LAYOUT(1193, 653, 1733, 707, 0, 0, 539, 54,
2081                                      0, 0, 539, 0, 540, 54, logfont, layout);
2082     {
2083       const char kMsg[] = "ogle日本語入力のTestです";
2084       std::wstring msg;
2085       mozc::Util::UTF8ToWide(kMsg, &msg);
2086       EXPECT_EQ(msg, layout.text);
2087     }
2088     ASSERT_EQ(3, layout.marker_layouts.size());
2089 
2090     EXPECT_EQ(CPoint(0, 53), layout.marker_layouts[0].from);
2091     EXPECT_EQ(CPoint(85, 53), layout.marker_layouts[0].to);
2092     EXPECT_TRUE(layout.marker_layouts[0].highlighted);
2093     EXPECT_EQ(CPoint(90, 53), layout.marker_layouts[1].from);
2094     EXPECT_EQ(CPoint(351, 53), layout.marker_layouts[1].to);
2095     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
2096     EXPECT_EQ(CPoint(360, 53), layout.marker_layouts[2].from);
2097     EXPECT_EQ(CPoint(539, 53), layout.marker_layouts[2].to);
2098     EXPECT_FALSE(layout.marker_layouts[2].highlighted);
2099   }
2100 
2101   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
2102       1958, 653, 1958, 599, 2020, 653, candidate_layout);
2103 
2104   // Check other candidate positions.
2105   command.mutable_output()->mutable_candidates()->set_position(0);
2106   layouts.clear();
2107   candidate_layout.Clear();
2108   result = layout_mgr.LayoutCompositionWindow(
2109       command, &layouts, &candidate_layout);
2110   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
2111       1778, 653, 1778, 599, 2020, 653, candidate_layout);
2112 
2113   command.mutable_output()->mutable_candidates()->set_position(3);
2114   layouts.clear();
2115   candidate_layout.Clear();
2116   result = layout_mgr.LayoutCompositionWindow(
2117       command, &layouts, &candidate_layout);
2118   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
2119       1913, 653, 1913, 599, 2020, 653, candidate_layout);
2120 
2121   command.mutable_output()->mutable_candidates()->set_position(10);
2122   layouts.clear();
2123   candidate_layout.Clear();
2124   result = layout_mgr.LayoutCompositionWindow(
2125       command, &layouts, &candidate_layout);
2126   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
2127       1283, 707, 1283, 653, 1732, 707, candidate_layout);
2128 
2129   command.mutable_output()->mutable_candidates()->set_position(16);
2130   layouts.clear();
2131   candidate_layout.Clear();
2132   result = layout_mgr.LayoutCompositionWindow(
2133       command, &layouts, &candidate_layout);
2134   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
2135       1553, 707, 1553, 653, 1732, 707, candidate_layout);
2136 
2137   // w/o candidates, proportional, horizontal
2138   SetRenderereCommandForTest(true, false, false, 0, hwnd, &command);
2139   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
2140       command.application_info().composition_font(), &logfont));
2141   layouts.clear();
2142   candidate_layout.Clear();
2143   result = layout_mgr.LayoutCompositionWindow(
2144       command, &layouts, &candidate_layout);
2145   EXPECT_TRUE(result);
2146   EXPECT_FALSE(candidate_layout.initialized());
2147 }
2148 
TEST_F(Win32RendererUtilTest,CompositionVerticalNoAdditionalSegmentationWithProportionalFont)2149 TEST_F(Win32RendererUtilTest,
2150        CompositionVerticalNoAdditionalSegmentationWithProportionalFont) {
2151   const int kCursorOffsetY = 0;
2152 
2153   RendererCommand command;
2154 
2155   HWND hwnd = nullptr;
2156   LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
2157                            CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
2158   std::vector<CompositionWindowLayout> layouts;
2159   CandidateWindowLayout candidate_layout;
2160   CLogFont logfont;
2161 
2162   bool result = false;
2163 
2164   // w/ candidates, proportional, vertical
2165   SetRenderereCommandForTest(
2166       true, true, true, kCursorOffsetY, hwnd, &command);
2167   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
2168       command.application_info().composition_font(), &logfont));
2169   logfont.lfOrientation = 2700;
2170 
2171   layouts.clear();
2172   candidate_layout.Clear();
2173   result = layout_mgr.LayoutCompositionWindow(
2174       command, &layouts, &candidate_layout);
2175   EXPECT_TRUE(result);
2176 
2177   ASSERT_EQ(3, layouts.size());
2178 
2179   // The first line
2180   {
2181     const CompositionWindowLayout &layout = layouts.at(0);
2182     EXPECT_COMPOSITION_WINDOW_LAYOUT(1978, 927, 2034, 1062, 0, 0, 56, 135,
2183                                      56, 0, 0, 0, 0, 0, logfont, layout);
2184     {
2185       const char kMsg[] = "これは";
2186       std::wstring msg;
2187       mozc::Util::UTF8ToWide(kMsg, &msg);
2188       EXPECT_EQ(msg, layout.text);
2189     }
2190     ASSERT_EQ(1, layout.marker_layouts.size());
2191 
2192     EXPECT_EQ(CPoint(55, 0), layout.marker_layouts[0].from);
2193     EXPECT_EQ(CPoint(55, 126), layout.marker_layouts[0].to);
2194     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
2195   }
2196 
2197   // The second line
2198   {
2199     const CompositionWindowLayout &layout = layouts.at(1);
2200     EXPECT_COMPOSITION_WINDOW_LAYOUT(1922, 712, 1978, 1089, 0, 0, 56, 377,
2201                                      56, 0, 0, 0, 0, 0, logfont, layout);
2202     {
2203       const char kMsg[] = "、Google日本語入";
2204       std::wstring msg;
2205       mozc::Util::UTF8ToWide(kMsg, &msg);
2206       EXPECT_EQ(msg, layout.text);
2207     }
2208     ASSERT_EQ(3, layout.marker_layouts.size());
2209 
2210     EXPECT_EQ(CPoint(55, 0), layout.marker_layouts[0].from);
2211     EXPECT_EQ(CPoint(55, 36), layout.marker_layouts[0].to);
2212     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
2213     EXPECT_EQ(CPoint(55, 45), layout.marker_layouts[1].from);
2214     EXPECT_EQ(CPoint(55, 192), layout.marker_layouts[1].to);
2215     EXPECT_TRUE(layout.marker_layouts[1].highlighted);
2216     EXPECT_EQ(CPoint(55, 197), layout.marker_layouts[2].from);
2217     EXPECT_EQ(CPoint(55, 377), layout.marker_layouts[2].to);
2218     EXPECT_FALSE(layout.marker_layouts[2].highlighted);
2219   }
2220 
2221   // The third line
2222   {
2223     const CompositionWindowLayout &layout = layouts.at(2);
2224     EXPECT_COMPOSITION_WINDOW_LAYOUT(1866, 712, 1922, 982, 0, 0, 56, 269,
2225                                      56, 0, 0, 269, 56, 270, logfont, layout);
2226     {
2227       const char kMsg[] = "力のTestです";
2228       std::wstring msg;
2229       mozc::Util::UTF8ToWide(kMsg, &msg);
2230       EXPECT_EQ(msg, layout.text);
2231     }
2232     ASSERT_EQ(2, layout.marker_layouts.size());
2233 
2234     EXPECT_EQ(CPoint(55, 0), layout.marker_layouts[0].from);
2235     EXPECT_EQ(CPoint(55, 81), layout.marker_layouts[0].to);
2236     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
2237     EXPECT_EQ(CPoint(55, 90), layout.marker_layouts[1].from);
2238     EXPECT_EQ(CPoint(55, 269), layout.marker_layouts[1].to);
2239     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
2240   }
2241 
2242   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
2243       1922, 757, 1922, 757, 1978, 1089, candidate_layout);
2244 
2245   // Check other candidate positions.
2246   command.mutable_output()->mutable_candidates()->set_position(0);
2247   layouts.clear();
2248   candidate_layout.Clear();
2249   result = layout_mgr.LayoutCompositionWindow(
2250       command, &layouts, &candidate_layout);
2251   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
2252       1978, 927, 1978, 927, 2034, 1062, candidate_layout);
2253 
2254   command.mutable_output()->mutable_candidates()->set_position(3);
2255   layouts.clear();
2256   candidate_layout.Clear();
2257   result = layout_mgr.LayoutCompositionWindow(
2258       command, &layouts, &candidate_layout);
2259   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
2260       1922, 712, 1922, 712, 1978, 1089, candidate_layout);
2261 
2262   command.mutable_output()->mutable_candidates()->set_position(10);
2263   layouts.clear();
2264   candidate_layout.Clear();
2265   result = layout_mgr.LayoutCompositionWindow(
2266       command, &layouts, &candidate_layout);
2267   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
2268       1922, 909, 1922, 909, 1978, 1089, candidate_layout);
2269 
2270   command.mutable_output()->mutable_candidates()->set_position(16);
2271   layouts.clear();
2272   candidate_layout.Clear();
2273   result = layout_mgr.LayoutCompositionWindow(
2274       command, &layouts, &candidate_layout);
2275   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
2276       1866, 802, 1866, 802, 1922, 981, candidate_layout);
2277 
2278   // w/o candidates, proportional, vertical
2279   SetRenderereCommandForTest(true, false, true, 0, hwnd, &command);
2280   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
2281       command.application_info().composition_font(), &logfont));
2282   layouts.clear();
2283   candidate_layout.Clear();
2284   result = layout_mgr.LayoutCompositionWindow(
2285       command, &layouts, &candidate_layout);
2286   EXPECT_TRUE(result);
2287   EXPECT_FALSE(candidate_layout.initialized());
2288 }
2289 
TEST_F(Win32RendererUtilTest,CompositionVerticalAdditionalSegmentationWithProportionalFont)2290 TEST_F(Win32RendererUtilTest,
2291        CompositionVerticalAdditionalSegmentationWithProportionalFont) {
2292   const int kCursorOffsetY = -90;
2293 
2294   RendererCommand command;
2295 
2296   HWND hwnd = nullptr;
2297   LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
2298                            CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
2299   std::vector<CompositionWindowLayout> layouts;
2300   CandidateWindowLayout candidate_layout;
2301   CLogFont logfont;
2302 
2303   bool result = false;
2304 
2305   // w/ candidates, proportional, vertical
2306   SetRenderereCommandForTest(
2307       true, true, true, kCursorOffsetY, hwnd, &command);
2308   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
2309       command.application_info().composition_font(), &logfont));
2310   logfont.lfOrientation = 2700;
2311 
2312   layouts.clear();
2313   candidate_layout.Clear();
2314   result = layout_mgr.LayoutCompositionWindow(
2315       command, &layouts, &candidate_layout);
2316   EXPECT_TRUE(result);
2317 
2318   ASSERT_EQ(3, layouts.size());
2319 
2320   // The first line
2321   {
2322     const CompositionWindowLayout &layout = layouts.at(0);
2323     EXPECT_COMPOSITION_WINDOW_LAYOUT(1978, 837, 2034, 1079, 0, 0, 56, 242,
2324                                      56, 0, 0, 0, 0, 0, logfont, layout);
2325     {
2326       const char kMsg[] = "これは、Go";
2327       std::wstring msg;
2328       mozc::Util::UTF8ToWide(kMsg, &msg);
2329       EXPECT_EQ(msg, layout.text);
2330     }
2331     ASSERT_EQ(3, layout.marker_layouts.size());
2332 
2333     EXPECT_EQ(CPoint(55, 0), layout.marker_layouts[0].from);
2334     EXPECT_EQ(CPoint(55, 126), layout.marker_layouts[0].to);
2335     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
2336     EXPECT_EQ(CPoint(55, 135), layout.marker_layouts[1].from);
2337     EXPECT_EQ(CPoint(55, 171), layout.marker_layouts[1].to);
2338     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
2339     EXPECT_EQ(CPoint(55, 180), layout.marker_layouts[2].from);
2340     EXPECT_EQ(CPoint(55, 242), layout.marker_layouts[2].to);
2341     EXPECT_TRUE(layout.marker_layouts[2].highlighted);
2342   }
2343 
2344   // The second line
2345   {
2346     const CompositionWindowLayout &layout = layouts.at(1);
2347     EXPECT_COMPOSITION_WINDOW_LAYOUT(1922, 712, 1978, 1100, 0, 0, 56, 388,
2348                                      56, 0, 0, 0, 0, 0, logfont, layout);
2349     {
2350       const char kMsg[] = "ogle日本語入力のT";
2351       std::wstring msg;
2352       mozc::Util::UTF8ToWide(kMsg, &msg);
2353       EXPECT_EQ(msg, layout.text);
2354     }
2355     ASSERT_EQ(3, layout.marker_layouts.size());
2356 
2357     EXPECT_EQ(CPoint(55, 0), layout.marker_layouts[0].from);
2358     EXPECT_EQ(CPoint(55, 85), layout.marker_layouts[0].to);
2359     EXPECT_TRUE(layout.marker_layouts[0].highlighted);
2360     EXPECT_EQ(CPoint(55, 90), layout.marker_layouts[1].from);
2361     EXPECT_EQ(CPoint(55, 351), layout.marker_layouts[1].to);
2362     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
2363     EXPECT_EQ(CPoint(55, 360), layout.marker_layouts[2].from);
2364     EXPECT_EQ(CPoint(55, 388), layout.marker_layouts[2].to);
2365     EXPECT_FALSE(layout.marker_layouts[2].highlighted);
2366   }
2367 
2368   // The third line
2369   {
2370     const CompositionWindowLayout &layout = layouts.at(2);
2371     EXPECT_COMPOSITION_WINDOW_LAYOUT(1866, 712, 1922, 864, 0, 0, 56, 151,
2372                                      56, 0, 0, 151, 56, 152, logfont, layout);
2373     {
2374       const char kMsg[] = "estです";
2375       std::wstring msg;
2376       mozc::Util::UTF8ToWide(kMsg, &msg);
2377       EXPECT_EQ(msg, layout.text);
2378     }
2379     ASSERT_EQ(1, layout.marker_layouts.size());
2380 
2381     EXPECT_EQ(CPoint(55, 0), layout.marker_layouts[0].from);
2382     EXPECT_EQ(CPoint(55, 151), layout.marker_layouts[0].to);
2383     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
2384   }
2385 
2386   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
2387       1978, 1017, 1978, 1017, 2034, 1079, candidate_layout);
2388 
2389   // Check other candidate positions.
2390   command.mutable_output()->mutable_candidates()->set_position(0);
2391   layouts.clear();
2392   candidate_layout.Clear();
2393   result = layout_mgr.LayoutCompositionWindow(
2394       command, &layouts, &candidate_layout);
2395   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
2396       1978, 837, 1978, 837, 2034, 1079, candidate_layout);
2397 
2398   command.mutable_output()->mutable_candidates()->set_position(3);
2399   layouts.clear();
2400   candidate_layout.Clear();
2401   result = layout_mgr.LayoutCompositionWindow(
2402       command, &layouts, &candidate_layout);
2403   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
2404       1978, 972, 1978, 972, 2034, 1079, candidate_layout);
2405 
2406   command.mutable_output()->mutable_candidates()->set_position(10);
2407   layouts.clear();
2408   candidate_layout.Clear();
2409   result = layout_mgr.LayoutCompositionWindow(
2410       command, &layouts, &candidate_layout);
2411   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
2412       1922, 802, 1922, 802, 1978, 1100, candidate_layout);
2413 
2414   command.mutable_output()->mutable_candidates()->set_position(16);
2415   layouts.clear();
2416   candidate_layout.Clear();
2417   result = layout_mgr.LayoutCompositionWindow(
2418       command, &layouts, &candidate_layout);
2419   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
2420       1922, 1072, 1922, 1072, 1978, 1100, candidate_layout);
2421 
2422   // w/o candidates, proportional, vertical
2423   SetRenderereCommandForTest(false, false, true, 0, hwnd, &command);
2424   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
2425       command.application_info().composition_font(), &logfont));
2426   layouts.clear();
2427   candidate_layout.Clear();
2428   result = layout_mgr.LayoutCompositionWindow(
2429       command, &layouts, &candidate_layout);
2430   EXPECT_TRUE(result);
2431   EXPECT_FALSE(candidate_layout.initialized());
2432 }
2433 
TEST_F(Win32RendererUtilTest,CompositionHorizontalFirstLineIsEmptyWithMonospacedFont)2434 TEST_F(Win32RendererUtilTest,
2435        CompositionHorizontalFirstLineIsEmptyWithMonospacedFont) {
2436   const int kCursorOffsetX = 120;
2437 
2438   RendererCommand command;
2439 
2440   HWND hwnd = nullptr;
2441   LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
2442                            CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
2443   std::vector<CompositionWindowLayout> layouts;
2444   CandidateWindowLayout candidate_layout;
2445   CLogFont logfont;
2446 
2447   bool result = false;
2448 
2449   // w/ candidates, monospaced, horizontal
2450   SetRenderereCommandForTest(
2451       false, true, false, kCursorOffsetX, hwnd, &command);
2452   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
2453       command.application_info().composition_font(), &logfont));
2454   layouts.clear();
2455   candidate_layout.Clear();
2456   result = layout_mgr.LayoutCompositionWindow(
2457       command, &layouts, &candidate_layout);
2458   EXPECT_TRUE(result);
2459 
2460   ASSERT_EQ(1, layouts.size());
2461 
2462   // The first line
2463   {
2464     const CompositionWindowLayout &layout = layouts.at(0);
2465     EXPECT_COMPOSITION_WINDOW_LAYOUT(1193, 648, 1975, 697, 0, 0, 781, 49,
2466                                      0, 0, 781, 0, 782, 49, logfont, layout);
2467     {
2468       const char kMsg[] = "これは、Google日本語入力のTestです";
2469       std::wstring msg;
2470       mozc::Util::UTF8ToWide(kMsg, &msg);
2471       EXPECT_EQ(msg, layout.text);
2472     }
2473     ASSERT_EQ(5, layout.marker_layouts.size());
2474 
2475     EXPECT_EQ(CPoint(0, 48), layout.marker_layouts[0].from);
2476     EXPECT_EQ(CPoint(126, 48), layout.marker_layouts[0].to);
2477     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
2478     EXPECT_EQ(CPoint(135, 48), layout.marker_layouts[1].from);
2479     EXPECT_EQ(CPoint(171, 48), layout.marker_layouts[1].to);
2480     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
2481     EXPECT_EQ(CPoint(180, 48), layout.marker_layouts[2].from);
2482     EXPECT_EQ(CPoint(325, 48), layout.marker_layouts[2].to);
2483     EXPECT_TRUE(layout.marker_layouts[2].highlighted);
2484     EXPECT_EQ(CPoint(331, 48), layout.marker_layouts[3].from);
2485     EXPECT_EQ(CPoint(592, 48), layout.marker_layouts[3].to);
2486     EXPECT_FALSE(layout.marker_layouts[3].highlighted);
2487     EXPECT_EQ(CPoint(601, 48), layout.marker_layouts[4].from);
2488     EXPECT_EQ(CPoint(781, 48), layout.marker_layouts[4].to);
2489     EXPECT_FALSE(layout.marker_layouts[4].highlighted);
2490   }
2491 }
2492 
TEST_F(Win32RendererUtilTest,CompositionHorizontalFirstLineIsEmptyWithProportionalFont)2493 TEST_F(Win32RendererUtilTest,
2494        CompositionHorizontalFirstLineIsEmptyWithProportionalFont) {
2495   const int kCursorOffsetX = 120;
2496 
2497   RendererCommand command;
2498 
2499   HWND hwnd = nullptr;
2500   LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
2501                            CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
2502   std::vector<CompositionWindowLayout> layouts;
2503   CandidateWindowLayout candidate_layout;
2504   CLogFont logfont;
2505 
2506   bool result = false;
2507 
2508   // w/ candidates, proportional, horizontal
2509   SetRenderereCommandForTest(
2510       true, true, false, kCursorOffsetX, hwnd, &command);
2511   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
2512       command.application_info().composition_font(), &logfont));
2513   layouts.clear();
2514   candidate_layout.Clear();
2515   result = layout_mgr.LayoutCompositionWindow(
2516       command, &layouts, &candidate_layout);
2517   EXPECT_TRUE(result);
2518 
2519   ASSERT_EQ(1, layouts.size());
2520 
2521   // The first line
2522   {
2523     const CompositionWindowLayout &layout = layouts.at(0);
2524     EXPECT_COMPOSITION_WINDOW_LAYOUT(1193, 653, 1975, 707, 0, 0, 781, 54,
2525                                      0, 0, 781, 0, 782, 54, logfont, layout);
2526     {
2527       const char kMsg[] = "これは、Google日本語入力のTestです";
2528       std::wstring msg;
2529       mozc::Util::UTF8ToWide(kMsg, &msg);
2530       EXPECT_EQ(msg, layout.text);
2531     }
2532     ASSERT_EQ(5, layout.marker_layouts.size());
2533 
2534     EXPECT_EQ(CPoint(0, 53), layout.marker_layouts[0].from);
2535     EXPECT_EQ(CPoint(126, 53), layout.marker_layouts[0].to);
2536     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
2537     EXPECT_EQ(CPoint(135, 53), layout.marker_layouts[1].from);
2538     EXPECT_EQ(CPoint(171, 53), layout.marker_layouts[1].to);
2539     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
2540     EXPECT_EQ(CPoint(180, 53), layout.marker_layouts[2].from);
2541     EXPECT_EQ(CPoint(327, 53), layout.marker_layouts[2].to);
2542     EXPECT_TRUE(layout.marker_layouts[2].highlighted);
2543     EXPECT_EQ(CPoint(332, 53), layout.marker_layouts[3].from);
2544     EXPECT_EQ(CPoint(593, 53), layout.marker_layouts[3].to);
2545     EXPECT_FALSE(layout.marker_layouts[3].highlighted);
2546     EXPECT_EQ(CPoint(602, 53), layout.marker_layouts[4].from);
2547     EXPECT_EQ(CPoint(781, 53), layout.marker_layouts[4].to);
2548     EXPECT_FALSE(layout.marker_layouts[4].highlighted);
2549   }
2550 }
2551 
TEST_F(Win32RendererUtilTest,CompositionVerticalFirstLineIsEmptyWithMonospacedFont)2552 TEST_F(Win32RendererUtilTest,
2553        CompositionVerticalFirstLineIsEmptyWithMonospacedFont) {
2554   const int kCursorOffsetY = 170;
2555 
2556   RendererCommand command;
2557 
2558   HWND hwnd = nullptr;
2559   LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
2560                            CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
2561   std::vector<CompositionWindowLayout> layouts;
2562   CandidateWindowLayout candidate_layout;
2563   CLogFont logfont;
2564 
2565   bool result = false;
2566 
2567   // w/ candidates, monospaced, vertical
2568   SetRenderereCommandForTest(
2569       false, true, true, kCursorOffsetY, hwnd, &command);
2570   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
2571       command.application_info().composition_font(), &logfont));
2572   logfont.lfOrientation = 2700;
2573 
2574   layouts.clear();
2575   candidate_layout.Clear();
2576   result = layout_mgr.LayoutCompositionWindow(
2577       command, &layouts, &candidate_layout);
2578   EXPECT_TRUE(result);
2579 
2580   ASSERT_EQ(3, layouts.size());
2581 
2582   // The first line
2583   {
2584     const CompositionWindowLayout &layout = layouts.at(0);
2585     EXPECT_COMPOSITION_WINDOW_LAYOUT(1932, 712, 1983, 1088, 0, 0, 51, 376,
2586                                      51, 0, 0, 0, 0, 0, logfont, layout);
2587     {
2588       const char kMsg[] = "これは、Google日";
2589       std::wstring msg;
2590       mozc::Util::UTF8ToWide(kMsg, &msg);
2591       EXPECT_EQ(msg, layout.text);
2592     }
2593     ASSERT_EQ(4, layout.marker_layouts.size());
2594 
2595     EXPECT_EQ(CPoint(50, 0), layout.marker_layouts[0].from);
2596     EXPECT_EQ(CPoint(50, 126), layout.marker_layouts[0].to);
2597     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
2598     EXPECT_EQ(CPoint(50, 135), layout.marker_layouts[1].from);
2599     EXPECT_EQ(CPoint(50, 171), layout.marker_layouts[1].to);
2600     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
2601     EXPECT_EQ(CPoint(50, 180), layout.marker_layouts[2].from);
2602     EXPECT_EQ(CPoint(50, 325), layout.marker_layouts[2].to);
2603     EXPECT_TRUE(layout.marker_layouts[2].highlighted);
2604     EXPECT_EQ(CPoint(50, 331), layout.marker_layouts[3].from);
2605     EXPECT_EQ(CPoint(50, 376), layout.marker_layouts[3].to);
2606     EXPECT_FALSE(layout.marker_layouts[3].highlighted);
2607   }
2608 
2609   // The second line
2610   {
2611     const CompositionWindowLayout &layout = layouts.at(1);
2612     EXPECT_COMPOSITION_WINDOW_LAYOUT(1881, 712, 1932, 1072, 0, 0, 51, 360,
2613                                      51, 0, 0, 0, 0, 0, logfont, layout);
2614     {
2615       const char kMsg[] = "本語入力のTestで";
2616       std::wstring msg;
2617       mozc::Util::UTF8ToWide(kMsg, &msg);
2618       EXPECT_EQ(msg, layout.text);
2619     }
2620     ASSERT_EQ(2, layout.marker_layouts.size());
2621 
2622     EXPECT_EQ(CPoint(50, 0), layout.marker_layouts[0].from);
2623     EXPECT_EQ(CPoint(50, 216), layout.marker_layouts[0].to);
2624     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
2625     EXPECT_EQ(CPoint(50, 225), layout.marker_layouts[1].from);
2626     EXPECT_EQ(CPoint(50, 360), layout.marker_layouts[1].to);
2627     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
2628   }
2629 
2630   // The third line
2631   {
2632     const CompositionWindowLayout &layout = layouts.at(2);
2633     EXPECT_COMPOSITION_WINDOW_LAYOUT(1830, 712, 1881, 758, 0, 0, 51, 45,
2634                                      51, 0, 0, 45, 51, 46, logfont, layout);
2635     {
2636       const char kMsg[] = "す";
2637       std::wstring msg;
2638       mozc::Util::UTF8ToWide(kMsg, &msg);
2639       EXPECT_EQ(msg, layout.text);
2640     }
2641     ASSERT_EQ(1, layout.marker_layouts.size());
2642 
2643     EXPECT_EQ(CPoint(50, 0), layout.marker_layouts[0].from);
2644     EXPECT_EQ(CPoint(50, 45), layout.marker_layouts[0].to);
2645     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
2646   }
2647 }
2648 
TEST_F(Win32RendererUtilTest,CompositionVerticalFirstLineIsEmptyWithProportionalFont)2649 TEST_F(Win32RendererUtilTest,
2650        CompositionVerticalFirstLineIsEmptyWithProportionalFont) {
2651   const int kCursorOffsetY = 170;
2652 
2653   RendererCommand command;
2654 
2655   HWND hwnd = nullptr;
2656   LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
2657                            CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
2658   std::vector<CompositionWindowLayout> layouts;
2659   CandidateWindowLayout candidate_layout;
2660   CLogFont logfont;
2661 
2662   bool result = false;
2663 
2664   // w/ candidates, proportional, vertical
2665   SetRenderereCommandForTest(
2666       true, true, true, kCursorOffsetY, hwnd, &command);
2667   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
2668       command.application_info().composition_font(), &logfont));
2669   logfont.lfOrientation = 2700;
2670 
2671   layouts.clear();
2672   candidate_layout.Clear();
2673   result = layout_mgr.LayoutCompositionWindow(
2674       command, &layouts, &candidate_layout);
2675   EXPECT_TRUE(result);
2676 
2677   ASSERT_EQ(3, layouts.size());
2678 
2679   // The first line
2680   {
2681     const CompositionWindowLayout &layout = layouts.at(0);
2682     EXPECT_COMPOSITION_WINDOW_LAYOUT(1922, 712, 1978, 1089, 0, 0, 56, 377,
2683                                      56, 0, 0, 0, 0, 0, logfont, layout);
2684     {
2685       const char kMsg[] = "これは、Google日";
2686       std::wstring msg;
2687       mozc::Util::UTF8ToWide(kMsg, &msg);
2688       EXPECT_EQ(msg, layout.text);
2689     }
2690     ASSERT_EQ(4, layout.marker_layouts.size());
2691 
2692     EXPECT_EQ(CPoint(55, 0), layout.marker_layouts[0].from);
2693     EXPECT_EQ(CPoint(55, 126), layout.marker_layouts[0].to);
2694     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
2695     EXPECT_EQ(CPoint(55, 135), layout.marker_layouts[1].from);
2696     EXPECT_EQ(CPoint(55, 171), layout.marker_layouts[1].to);
2697     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
2698     EXPECT_EQ(CPoint(55, 180), layout.marker_layouts[2].from);
2699     EXPECT_EQ(CPoint(55, 327), layout.marker_layouts[2].to);
2700     EXPECT_TRUE(layout.marker_layouts[2].highlighted);
2701     EXPECT_EQ(CPoint(55, 332), layout.marker_layouts[3].from);
2702     EXPECT_EQ(CPoint(55, 377), layout.marker_layouts[3].to);
2703     EXPECT_FALSE(layout.marker_layouts[3].highlighted);
2704   }
2705 
2706   // The second line
2707   {
2708     const CompositionWindowLayout &layout = layouts.at(1);
2709     EXPECT_COMPOSITION_WINDOW_LAYOUT(1866, 712, 1922, 1071, 0, 0, 56, 359,
2710                                      56, 0, 0, 0, 0, 0, logfont, layout);
2711     {
2712       const char kMsg[] = "本語入力のTestで";
2713       std::wstring msg;
2714       mozc::Util::UTF8ToWide(kMsg, &msg);
2715       EXPECT_EQ(msg, layout.text);
2716     }
2717     ASSERT_EQ(2, layout.marker_layouts.size());
2718 
2719     EXPECT_EQ(CPoint(55, 0), layout.marker_layouts[0].from);
2720     EXPECT_EQ(CPoint(55, 216), layout.marker_layouts[0].to);
2721     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
2722     EXPECT_EQ(CPoint(55, 225), layout.marker_layouts[1].from);
2723     EXPECT_EQ(CPoint(55, 359), layout.marker_layouts[1].to);
2724     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
2725   }
2726 
2727   // The third line
2728   {
2729     const CompositionWindowLayout &layout = layouts.at(2);
2730     EXPECT_COMPOSITION_WINDOW_LAYOUT(1810, 712, 1866, 758, 0, 0, 56, 45,
2731                                      56, 0, 0, 45, 56, 46, logfont, layout);
2732     {
2733       const char kMsg[] = "す";
2734       std::wstring msg;
2735       mozc::Util::UTF8ToWide(kMsg, &msg);
2736       EXPECT_EQ(msg, layout.text);
2737     }
2738     ASSERT_EQ(1, layout.marker_layouts.size());
2739 
2740     EXPECT_EQ(CPoint(55, 0), layout.marker_layouts[0].from);
2741     EXPECT_EQ(CPoint(55, 45), layout.marker_layouts[0].to);
2742     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
2743   }
2744 }
2745 
TEST_F(Win32RendererUtilTest,CheckCaretPosInHorizontalComposition)2746 TEST_F(Win32RendererUtilTest, CheckCaretPosInHorizontalComposition) {
2747   // Check the caret points the first character.
2748   {
2749     const int kCursorOffsetX = -300;
2750     HWND hwnd = nullptr;
2751     LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
2752                              CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
2753     std::vector<CompositionWindowLayout> layouts;
2754 
2755     RendererCommand command;
2756     CandidateWindowLayout candidate_layout;
2757     CLogFont logfont;
2758     bool result = false;
2759     SetRenderereCommandForCaretTest(
2760         false, false, 10, 0, kCursorOffsetX, hwnd, &command);
2761     EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
2762         command.application_info().composition_font(), &logfont));
2763     layouts.clear();
2764     candidate_layout.Clear();
2765     result = layout_mgr.LayoutCompositionWindow(
2766         command, &layouts, &candidate_layout);
2767     EXPECT_TRUE(result);
2768 
2769     ASSERT_EQ(1, layouts.size());
2770 
2771     {
2772       const CompositionWindowLayout &layout = layouts.at(0);
2773       EXPECT_COMPOSITION_WINDOW_LAYOUT(1568, 599, 2018, 648, 0, 0, 450, 49,
2774                                        0, 0, 0, 0, 1, 49, logfont, layout);
2775     }
2776   }
2777 
2778   // Check the caret points the middle character.
2779   {
2780     const int kCursorOffsetX = -300;
2781     HWND hwnd = nullptr;
2782     LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
2783                              CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
2784     std::vector<CompositionWindowLayout> layouts;
2785 
2786     RendererCommand command;
2787     CandidateWindowLayout candidate_layout;
2788     CLogFont logfont;
2789     bool result = false;
2790     SetRenderereCommandForCaretTest(
2791         false, false, 10, 5, kCursorOffsetX, hwnd, &command);
2792     EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
2793         command.application_info().composition_font(), &logfont));
2794     layouts.clear();
2795     candidate_layout.Clear();
2796     result = layout_mgr.LayoutCompositionWindow(
2797         command, &layouts, &candidate_layout);
2798     EXPECT_TRUE(result);
2799 
2800     ASSERT_EQ(1, layouts.size());
2801 
2802     {
2803       const CompositionWindowLayout &layout = layouts.at(0);
2804       EXPECT_COMPOSITION_WINDOW_LAYOUT(1568, 599, 2018, 648, 0, 0, 450, 49,
2805                                        0, 0, 225, 0, 226, 49, logfont, layout);
2806     }
2807   }
2808 
2809   // Check the caret points the next to the last character.
2810   // In this case, composition window should have an extra space to draw the
2811   // caret except that there is no room to extend.
2812   {
2813     const int kCursorOffsetX = -300;
2814     HWND hwnd = nullptr;
2815     LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
2816                              CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
2817     std::vector<CompositionWindowLayout> layouts;
2818 
2819     RendererCommand command;
2820     CandidateWindowLayout candidate_layout;
2821     CLogFont logfont;
2822     bool result = false;
2823     SetRenderereCommandForCaretTest(
2824         false, false, 10, 10, kCursorOffsetX, hwnd, &command);
2825     EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
2826         command.application_info().composition_font(), &logfont));
2827     layouts.clear();
2828     candidate_layout.Clear();
2829     result = layout_mgr.LayoutCompositionWindow(
2830         command, &layouts, &candidate_layout);
2831     EXPECT_TRUE(result);
2832 
2833     ASSERT_EQ(1, layouts.size());
2834 
2835     {
2836       const CompositionWindowLayout &layout = layouts.at(0);
2837       EXPECT_COMPOSITION_WINDOW_LAYOUT(1568, 599, 2019, 648, 0, 0, 450, 49,
2838                                        0, 0, 450, 0, 451, 49, logfont, layout);
2839     }
2840   }
2841 
2842   // To emulate built-in edit control, we will adjust caret position to be
2843   // inside of the line if it exceeds the end of line.
2844   {
2845     const int kCursorOffsetX = -287;
2846     HWND hwnd = nullptr;
2847     LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
2848                              CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
2849     std::vector<CompositionWindowLayout> layouts;
2850 
2851     RendererCommand command;
2852     CandidateWindowLayout candidate_layout;
2853     CLogFont logfont;
2854     bool result = false;
2855     SetRenderereCommandForCaretTest(
2856         false, false, 10, 10, kCursorOffsetX, hwnd, &command);
2857     EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
2858         command.application_info().composition_font(), &logfont));
2859     layouts.clear();
2860     candidate_layout.Clear();
2861     result = layout_mgr.LayoutCompositionWindow(
2862         command, &layouts, &candidate_layout);
2863     EXPECT_TRUE(result);
2864 
2865     ASSERT_EQ(1, layouts.size());
2866 
2867     {
2868       const CompositionWindowLayout &layout = layouts.at(0);
2869       EXPECT_COMPOSITION_WINDOW_LAYOUT(1581, 599, 2031, 648, 0, 0, 450, 49,
2870                                        0, 0, 449, 0, 450, 49, logfont, layout);
2871     }
2872   }
2873 
2874   // If there exists other characters in the next line, caret position should
2875   // not be adjusted.
2876   {
2877     const int kCursorOffsetX = -287;
2878     HWND hwnd = nullptr;
2879     LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
2880                              CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
2881     std::vector<CompositionWindowLayout> layouts;
2882 
2883     RendererCommand command;
2884     CandidateWindowLayout candidate_layout;
2885     CLogFont logfont;
2886     bool result = false;
2887     SetRenderereCommandForCaretTest(
2888         false, false, 11, 10, kCursorOffsetX, hwnd, &command);
2889     EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
2890         command.application_info().composition_font(), &logfont));
2891     layouts.clear();
2892     candidate_layout.Clear();
2893     result = layout_mgr.LayoutCompositionWindow(
2894         command, &layouts, &candidate_layout);
2895     EXPECT_TRUE(result);
2896 
2897     ASSERT_EQ(2, layouts.size());
2898 
2899     {
2900       const CompositionWindowLayout &layout = layouts.at(0);
2901       EXPECT_COMPOSITION_WINDOW_LAYOUT(1581, 599, 2031, 648, 0, 0, 450, 49,
2902                                        0, 0, 0, 0, 0, 0, logfont, layout);
2903     }
2904 
2905     {
2906       const CompositionWindowLayout &layout = layouts.at(1);
2907       EXPECT_COMPOSITION_WINDOW_LAYOUT(1193, 648, 1238, 697, 0, 0, 45, 49,
2908                                        0, 0, 0, 0, 1, 49, logfont, layout);
2909     }
2910   }
2911 }
2912 
TEST_F(Win32RendererUtilTest,CheckCaretPosInVerticalComposition)2913 TEST_F(Win32RendererUtilTest, CheckCaretPosInVerticalComposition) {
2914   // Check the caret points the first character.
2915   {
2916     const int kCursorOffsetY = -10;
2917     HWND hwnd = nullptr;
2918     LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
2919                              CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
2920     std::vector<CompositionWindowLayout> layouts;
2921 
2922     RendererCommand command;
2923     CandidateWindowLayout candidate_layout;
2924     CLogFont logfont;
2925     bool result = false;
2926     SetRenderereCommandForCaretTest(
2927         false, true, 4, 0, kCursorOffsetY, hwnd, &command);
2928     EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
2929         command.application_info().composition_font(), &logfont));
2930     logfont.lfOrientation = 2700;
2931 
2932     layouts.clear();
2933     candidate_layout.Clear();
2934     result = layout_mgr.LayoutCompositionWindow(
2935         command, &layouts, &candidate_layout);
2936     EXPECT_TRUE(result);
2937 
2938     ASSERT_EQ(1, layouts.size());
2939 
2940     {
2941       const CompositionWindowLayout &layout = layouts.at(0);
2942       EXPECT_COMPOSITION_WINDOW_LAYOUT(1983, 917, 2034, 1097, 0, 0, 51, 180,
2943                                        51, 0, 0, 0, 51, 1, logfont, layout);
2944     }
2945   }
2946 
2947   // Check the caret points the middle character.
2948   {
2949     const int kCursorOffsetY = -10;
2950     HWND hwnd = nullptr;
2951     LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
2952                              CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
2953     std::vector<CompositionWindowLayout> layouts;
2954 
2955     RendererCommand command;
2956     CandidateWindowLayout candidate_layout;
2957     CLogFont logfont;
2958     bool result = false;
2959     SetRenderereCommandForCaretTest(
2960         false, true, 4, 2, kCursorOffsetY, hwnd, &command);
2961     EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
2962         command.application_info().composition_font(), &logfont));
2963     logfont.lfOrientation = 2700;
2964 
2965     layouts.clear();
2966     candidate_layout.Clear();
2967     result = layout_mgr.LayoutCompositionWindow(
2968         command, &layouts, &candidate_layout);
2969     EXPECT_TRUE(result);
2970 
2971     ASSERT_EQ(1, layouts.size());
2972 
2973     {
2974       const CompositionWindowLayout &layout = layouts.at(0);
2975       EXPECT_COMPOSITION_WINDOW_LAYOUT(1983, 917, 2034, 1097, 0, 0, 51, 180,
2976                                        51, 0, 0, 90, 51, 91, logfont, layout);
2977     }
2978   }
2979 
2980   // Check the caret points the next to the last character.
2981   // In this case, composition window should have an extra space to draw the
2982   // caret except that there is no room to extend.
2983   {
2984     const int kCursorOffsetY = -10;
2985     HWND hwnd = nullptr;
2986     LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
2987                              CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
2988     std::vector<CompositionWindowLayout> layouts;
2989 
2990     RendererCommand command;
2991     CandidateWindowLayout candidate_layout;
2992     CLogFont logfont;
2993     bool result = false;
2994     SetRenderereCommandForCaretTest(
2995         false, true, 4, 4, kCursorOffsetY, hwnd, &command);
2996     EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
2997         command.application_info().composition_font(), &logfont));
2998     logfont.lfOrientation = 2700;
2999 
3000     layouts.clear();
3001     candidate_layout.Clear();
3002     result = layout_mgr.LayoutCompositionWindow(
3003         command, &layouts, &candidate_layout);
3004     EXPECT_TRUE(result);
3005 
3006     ASSERT_EQ(1, layouts.size());
3007 
3008     {
3009       const CompositionWindowLayout &layout = layouts.at(0);
3010       EXPECT_COMPOSITION_WINDOW_LAYOUT(1983, 917, 2034, 1098, 0, 0, 51, 180,
3011                                        51, 0, 0, 180, 51, 181, logfont, layout);
3012     }
3013   }
3014 
3015   // To emulate built-in edit control, we will adjust caret position to be
3016   // inside of the line if it exceeds the end of line.
3017   {
3018     const int kCursorOffsetY = -2;
3019     HWND hwnd = nullptr;
3020     LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
3021                              CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
3022     std::vector<CompositionWindowLayout> layouts;
3023 
3024     RendererCommand command;
3025     CandidateWindowLayout candidate_layout;
3026     CLogFont logfont;
3027     bool result = false;
3028     SetRenderereCommandForCaretTest(
3029         false, true, 4, 4, kCursorOffsetY, hwnd, &command);
3030     EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
3031         command.application_info().composition_font(), &logfont));
3032     logfont.lfOrientation = 2700;
3033 
3034     layouts.clear();
3035     candidate_layout.Clear();
3036     result = layout_mgr.LayoutCompositionWindow(
3037         command, &layouts, &candidate_layout);
3038     EXPECT_TRUE(result);
3039 
3040     ASSERT_EQ(1, layouts.size());
3041 
3042     {
3043       const CompositionWindowLayout &layout = layouts.at(0);
3044       EXPECT_COMPOSITION_WINDOW_LAYOUT(1983, 925, 2034, 1105, 0, 0, 51, 180,
3045                                        51, 0, 0, 179, 51, 180, logfont, layout);
3046     }
3047   }
3048 
3049   // If there exists other characters in the next line, caret position should
3050   // not be adjusted.
3051   {
3052     const int kCursorOffsetY = -2;
3053     HWND hwnd = nullptr;
3054     LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
3055                              CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
3056     std::vector<CompositionWindowLayout> layouts;
3057 
3058     RendererCommand command;
3059     CandidateWindowLayout candidate_layout;
3060     CLogFont logfont;
3061     bool result = false;
3062     SetRenderereCommandForCaretTest(
3063         false, true, 5, 4, kCursorOffsetY, hwnd, &command);
3064     EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
3065         command.application_info().composition_font(), &logfont));
3066     logfont.lfOrientation = 2700;
3067 
3068     layouts.clear();
3069     candidate_layout.Clear();
3070     result = layout_mgr.LayoutCompositionWindow(
3071         command, &layouts, &candidate_layout);
3072     EXPECT_TRUE(result);
3073 
3074     ASSERT_EQ(2, layouts.size());
3075 
3076     {
3077       const CompositionWindowLayout &layout = layouts.at(0);
3078       EXPECT_COMPOSITION_WINDOW_LAYOUT(1983, 925, 2034, 1105, 0, 0, 51, 180,
3079                                        51, 0, 0, 0, 0, 0, logfont, layout);
3080     }
3081 
3082     {
3083       const CompositionWindowLayout &layout = layouts.at(1);
3084       EXPECT_COMPOSITION_WINDOW_LAYOUT(1932, 712, 1983, 757, 0, 0, 51, 45,
3085                                        51, 0, 0, 0, 51, 1, logfont, layout);
3086     }
3087   }
3088 }
3089 
3090 // Check if suggest window does not hide preedit.
3091 // See b/4317753 for details.
TEST_F(Win32RendererUtilTest,SuggestWindowNeverHidesHorizontalPreedit)3092 TEST_F(Win32RendererUtilTest, SuggestWindowNeverHidesHorizontalPreedit) {
3093   const int kCursorOffsetX = 0;
3094 
3095   RendererCommand command;
3096 
3097   HWND hwnd = nullptr;
3098   LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
3099                            CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
3100   std::vector<CompositionWindowLayout> layouts;
3101   CandidateWindowLayout candidate_layout;
3102   CLogFont logfont;
3103 
3104   bool result = false;
3105 
3106   // w/ candidates, proportional, horizontal
3107   SetRenderereCommandForSuggestTest(true, false, kCursorOffsetX,
3108                                     hwnd, &command);
3109   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
3110       command.application_info().composition_font(), &logfont));
3111   layouts.clear();
3112   candidate_layout.Clear();
3113   result = layout_mgr.LayoutCompositionWindow(
3114       command, &layouts, &candidate_layout);
3115   EXPECT_TRUE(result);
3116 
3117   // Suggest window should be aligned to the last composition window.
3118   EXPECT_EQ(layouts.rbegin()->window_position_in_screen_coordinate.left,
3119             candidate_layout.position().x);
3120   EXPECT_EQ(layouts.rbegin()->window_position_in_screen_coordinate.bottom,
3121             candidate_layout.position().y);
3122   EXPECT_EQ(CRect(1193, 599, 2003, 707), candidate_layout.exclude_region());
3123 }
3124 
3125 // Check if suggest window does not hide preedit.
3126 // See b/4317753 for details.
TEST_F(Win32RendererUtilTest,SuggestWindowNeverHidesVerticalPreedit)3127 TEST_F(Win32RendererUtilTest, SuggestWindowNeverHidesVerticalPreedit) {
3128   const int kCursorOffsetY = 0;
3129 
3130   RendererCommand command;
3131 
3132   HWND hwnd = nullptr;
3133   LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
3134                            CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
3135   std::vector<CompositionWindowLayout> layouts;
3136   CandidateWindowLayout candidate_layout;
3137   CLogFont logfont;
3138 
3139   bool result = false;
3140 
3141   // w/ candidates, proportional, horizontal
3142   SetRenderereCommandForSuggestTest(true, true, kCursorOffsetY,
3143                                     hwnd, &command);
3144   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
3145       command.application_info().composition_font(), &logfont));
3146   layouts.clear();
3147   candidate_layout.Clear();
3148   result = layout_mgr.LayoutCompositionWindow(
3149       command, &layouts, &candidate_layout);
3150   EXPECT_TRUE(result);
3151 
3152   // Suggest window should be aligned to the first composition window.
3153   // TODO(yukawa): Use the last composition window when vertical candidate
3154   //   window is implemented.
3155   EXPECT_EQ(layouts.begin()->window_position_in_screen_coordinate.left,
3156             candidate_layout.position().x);
3157   EXPECT_EQ(layouts.begin()->window_position_in_screen_coordinate.top,
3158             candidate_layout.position().y);
3159   EXPECT_EQ(CRect(1978, 927, 2034, 1062), candidate_layout.exclude_region());
3160 }
3161 
TEST_F(Win32RendererUtilTest,RemoveUnderlineFromFont_Issue2935480)3162 TEST_F(Win32RendererUtilTest, RemoveUnderlineFromFont_Issue2935480) {
3163   const int kCursorOffsetY = 0;
3164   HWND hwnd = nullptr;
3165   LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
3166                            CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
3167   std::vector<CompositionWindowLayout> layouts;
3168 
3169   RendererCommand command;
3170   CandidateWindowLayout candidate_layout;
3171   CLogFont logfont;
3172   bool result = false;
3173   SetRenderereCommandForCaretTest(
3174       false, true, 4, 0, kCursorOffsetY, hwnd, &command);
3175   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
3176       command.application_info().composition_font(), &logfont));
3177   logfont.lfOrientation = 0;
3178   // Assume underline is enabled in the application.
3179   logfont.lfUnderline = 1;
3180 
3181   layouts.clear();
3182   candidate_layout.Clear();
3183   result = layout_mgr.LayoutCompositionWindow(
3184       command, &layouts, &candidate_layout);
3185   EXPECT_TRUE(result);
3186 
3187   // Underline should be stripped.
3188   ASSERT_EQ(2, layouts.size());
3189   EXPECT_EQ(0, layouts[0].log_font.lfUnderline);
3190   EXPECT_EQ(0, layouts[1].log_font.lfUnderline);
3191 }
3192 
3193 // Some applications such as MIEFS use CompositionForm::RECT as a bit flag.
3194 // We should consider the case where two or more style bits are specified
3195 // at the same time.
TEST_F(Win32RendererUtilTest,CompositionFormRECTAsBitFlag_Issue3200425)3196 TEST_F(Win32RendererUtilTest, CompositionFormRECTAsBitFlag_Issue3200425) {
3197   const uint32 kStyleBit = CompositionForm::RECT | CompositionForm::POINT;
3198 
3199   const int kCursorOffsetX = 0;
3200 
3201   RendererCommand command;
3202 
3203   HWND hwnd = nullptr;
3204   LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
3205                            CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
3206   std::vector<CompositionWindowLayout> layouts;
3207   CandidateWindowLayout candidate_layout;
3208 
3209   CLogFont logfont;
3210 
3211   bool result = false;
3212 
3213   // w/ candidates, monospaced, horizontal
3214   SetRenderereCommandForTest(
3215       false, true, false, kCursorOffsetX, hwnd, &command);
3216   command.mutable_application_info()->mutable_composition_form()
3217       ->set_style_bits(kStyleBit);
3218 
3219   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
3220       command.application_info().composition_font(), &logfont));
3221   layouts.clear();
3222   candidate_layout.Clear();
3223   result = layout_mgr.LayoutCompositionWindow(
3224       command, &layouts, &candidate_layout);
3225   EXPECT_TRUE(result);
3226 
3227   ASSERT_EQ(2, layouts.size());
3228 
3229   // The first line
3230   {
3231     const CompositionWindowLayout &layout = layouts.at(0);
3232     EXPECT_COMPOSITION_WINDOW_LAYOUT(1868, 599, 2003, 648, 0, 0, 135, 49,
3233                                      0, 0, 0, 0, 0, 0, logfont, layout);
3234     {
3235       const char kMsg[] = "これは";
3236       std::wstring msg;
3237       mozc::Util::UTF8ToWide(kMsg, &msg);
3238       EXPECT_EQ(msg, layout.text);
3239     }
3240     ASSERT_EQ(1, layout.marker_layouts.size());
3241 
3242     EXPECT_EQ(CPoint(0, 48), layout.marker_layouts[0].from);
3243     EXPECT_EQ(CPoint(126, 48), layout.marker_layouts[0].to);
3244     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
3245   }
3246 
3247   // The second line
3248   {
3249     const CompositionWindowLayout &layout = layouts.at(1);
3250     EXPECT_COMPOSITION_WINDOW_LAYOUT(1193, 648, 1840, 697, 0, 0, 646, 49,
3251                                      0, 0, 646, 0, 647, 49, logfont, layout);
3252     {
3253       const char kMsg[] = "、Google日本語入力のTestです";
3254       std::wstring msg;
3255       mozc::Util::UTF8ToWide(kMsg, &msg);
3256       EXPECT_EQ(msg, layout.text);
3257     }
3258     ASSERT_EQ(4, layout.marker_layouts.size());
3259 
3260     EXPECT_EQ(CPoint(0, 48), layout.marker_layouts[0].from);
3261     EXPECT_EQ(CPoint(36, 48), layout.marker_layouts[0].to);
3262     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
3263     EXPECT_EQ(CPoint(45, 48), layout.marker_layouts[1].from);
3264     EXPECT_EQ(CPoint(190, 48), layout.marker_layouts[1].to);
3265     EXPECT_TRUE(layout.marker_layouts[1].highlighted);
3266     EXPECT_EQ(CPoint(196, 48), layout.marker_layouts[2].from);
3267     EXPECT_EQ(CPoint(457, 48), layout.marker_layouts[2].to);
3268     EXPECT_FALSE(layout.marker_layouts[2].highlighted);
3269     EXPECT_EQ(CPoint(466, 48), layout.marker_layouts[3].from);
3270     EXPECT_EQ(CPoint(646, 48), layout.marker_layouts[3].to);
3271     EXPECT_FALSE(layout.marker_layouts[3].highlighted);
3272   }
3273   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
3274       1238, 697, 1238, 648, 1839, 697, candidate_layout);
3275 
3276   // Check other candidate positions.
3277   command.mutable_output()->mutable_candidates()->set_position(0);
3278   layouts.clear();
3279   candidate_layout.Clear();
3280   result = layout_mgr.LayoutCompositionWindow(
3281       command, &layouts, &candidate_layout);
3282   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
3283       1868, 648, 1868, 599, 2003, 648, candidate_layout);
3284 
3285   command.mutable_output()->mutable_candidates()->set_position(3);
3286   layouts.clear();
3287   candidate_layout.Clear();
3288   result = layout_mgr.LayoutCompositionWindow(
3289       command, &layouts, &candidate_layout);
3290   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
3291       1193, 697, 1193, 648, 1839, 697, candidate_layout);
3292 
3293   command.mutable_output()->mutable_candidates()->set_position(10);
3294   layouts.clear();
3295   candidate_layout.Clear();
3296   result = layout_mgr.LayoutCompositionWindow(
3297       command, &layouts, &candidate_layout);
3298   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
3299       1389, 697, 1389, 648, 1839, 697, candidate_layout);
3300 
3301   command.mutable_output()->mutable_candidates()->set_position(16);
3302   layouts.clear();
3303   candidate_layout.Clear();
3304   result = layout_mgr.LayoutCompositionWindow(
3305       command, &layouts, &candidate_layout);
3306   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
3307       1659, 697, 1659, 648, 1839, 697, candidate_layout);
3308 
3309   // w/o candidates, monospaced, horizontal
3310   SetRenderereCommandForTest(false, false, false, 0, hwnd, &command);
3311   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
3312       command.application_info().composition_font(), &logfont));
3313   layouts.clear();
3314   candidate_layout.Clear();
3315   result = layout_mgr.LayoutCompositionWindow(
3316       command, &layouts, &candidate_layout);
3317   EXPECT_TRUE(result);
3318   EXPECT_FALSE(candidate_layout.initialized());
3319 }
3320 
3321 // Evernote Windows Client 4.0.0.2880 (107102) / Editor component
TEST_F(Win32RendererUtilTest,EvernoteEditorComposition)3322 TEST_F(Win32RendererUtilTest, EvernoteEditorComposition) {
3323   const wchar_t kClassName[] = L"WebViewHost";
3324   const UINT kClassStyle = CS_DBLCLKS;
3325   const DWORD kWindowStyle =
3326       WS_CHILDWINDOW | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
3327   static_assert(kWindowStyle == 0x56000000, "Check actual value");
3328   const DWORD kWindowExStyle =
3329       WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
3330   static_assert(kWindowExStyle == 0, "Check actual value");
3331 
3332   const CRect kWindowRect(1548, 879, 1786, 1416);
3333   const CPoint kClientOffset(0, 0);
3334   const CSize kClientSize(238, 537);
3335   const double kScaleFactor = 1.0;
3336 
3337   HWND hwnd = nullptr;
3338   LayoutManager layout_mgr(
3339       CreateDefaultGUIFontEmulator(),
3340       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
3341                            kScaleFactor, &hwnd));
3342 
3343   RendererCommand command;
3344   SetRenderereCommandForTest(
3345       false, true, false, 0, hwnd, &command);
3346 
3347   // Clear the default ApplicationInfo and update it for Evernote.
3348   command.clear_application_info();
3349   AppInfoUtil::SetBasicApplicationInfo(
3350       command.mutable_application_info(), hwnd,
3351       (ApplicationInfo::ShowCandidateWindow |
3352        ApplicationInfo::ShowSuggestWindow |
3353        ApplicationInfo::ShowCompositionWindow));
3354 
3355   AppInfoUtil::SetCaretInfo(
3356       command.mutable_application_info(), false, 0, 0, 0, 0, hwnd);
3357 
3358   CandidateWindowLayout candidate_layout;
3359   std::vector<CompositionWindowLayout> layouts;
3360   bool result = false;
3361 
3362   layouts.clear();
3363   candidate_layout.Clear();
3364   result = layout_mgr.LayoutCompositionWindow(
3365       command, &layouts, &candidate_layout);
3366   EXPECT_TRUE(result);
3367 
3368   // Default GUI font should be selected.
3369   CLogFont default_font = GetFont(true, false);
3370   default_font.lfHeight = 18;
3371   default_font.lfWidth = 0;
3372 
3373   ASSERT_EQ(2, layouts.size());
3374 
3375   // The first line
3376   {
3377     const CompositionWindowLayout &layout = layouts.at(0);
3378     EXPECT_COMPOSITION_WINDOW_LAYOUT(1548, 1416, 1777, 1434, 0, 0, 229, 18,
3379                                      0, 0, 0, 0, 0, 0, default_font, layout);
3380     {
3381       const char kMsg[] = "これは、Google日本語入力のTest";
3382       std::wstring msg;
3383       mozc::Util::UTF8ToWide(kMsg, &msg);
3384       EXPECT_EQ(msg, layout.text);
3385     }
3386     ASSERT_EQ(5, layout.marker_layouts.size());
3387 
3388     EXPECT_EQ(CPoint(0, 17), layout.marker_layouts[0].from);
3389     EXPECT_EQ(CPoint(42, 17), layout.marker_layouts[0].to);
3390     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
3391     EXPECT_EQ(CPoint(45, 17), layout.marker_layouts[1].from);
3392     EXPECT_EQ(CPoint(57, 17), layout.marker_layouts[1].to);
3393     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
3394     EXPECT_EQ(CPoint(60, 17), layout.marker_layouts[2].from);
3395     EXPECT_EQ(CPoint(108, 17), layout.marker_layouts[2].to);
3396     EXPECT_TRUE(layout.marker_layouts[2].highlighted);
3397     EXPECT_EQ(CPoint(110, 17), layout.marker_layouts[3].from);
3398     EXPECT_EQ(CPoint(197, 17), layout.marker_layouts[3].to);
3399     EXPECT_FALSE(layout.marker_layouts[3].highlighted);
3400     EXPECT_EQ(CPoint(200, 17), layout.marker_layouts[4].from);
3401     EXPECT_EQ(CPoint(229, 17), layout.marker_layouts[4].to);
3402     EXPECT_FALSE(layout.marker_layouts[4].highlighted);
3403   }
3404 
3405   // The second line
3406   {
3407     const CompositionWindowLayout &layout = layouts.at(1);
3408     EXPECT_COMPOSITION_WINDOW_LAYOUT(1548, 1434, 1579, 1452, 0, 0, 30, 18,
3409                                      0, 0, 30, 0, 31, 18, default_font, layout);
3410     {
3411       const char kMsg[] = "です";
3412       std::wstring msg;
3413       mozc::Util::UTF8ToWide(kMsg, &msg);
3414       EXPECT_EQ(msg, layout.text);
3415     }
3416     ASSERT_EQ(1, layout.marker_layouts.size());
3417 
3418     EXPECT_EQ(CPoint(0, 17), layout.marker_layouts[0].from);
3419     EXPECT_EQ(CPoint(30, 17), layout.marker_layouts[0].to);
3420     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
3421   }
3422 
3423   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
3424       1608, 1434, 1608, 1416, 1777, 1434, candidate_layout);
3425 }
3426 
3427 // Crescent Eve 0.82a / Apr 24 2010.
3428 // Crescent Eve sets larger composition form area than its client area.
3429 // DPI virtualization API may fail in this case.  See b/3239031.
TEST_F(Win32RendererUtilTest,CrescentEveComposition_Issue3239031)3430 TEST_F(Win32RendererUtilTest, CrescentEveComposition_Issue3239031) {
3431   const wchar_t kClassName[] = L"CrescentEditer";
3432   const UINT kClassStyle = CS_DBLCLKS | CS_BYTEALIGNCLIENT;
3433   static_assert(kClassStyle == 0x00001008, "Check actual value");
3434   const DWORD kWindowStyle = WS_CHILDWINDOW | WS_VISIBLE | WS_VSCROLL;
3435   static_assert(kWindowStyle == 0x50200000, "Check actual value");
3436   const DWORD kWindowExStyle =
3437       WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR |
3438       WS_EX_ACCEPTFILES | WS_EX_CLIENTEDGE;
3439   static_assert(kWindowExStyle == 0x00000210, "Check actual value");
3440 
3441   const CRect kWindowRect(184, 192, 1312, 1426);
3442   const CPoint kClientOffset(2, 2);
3443   const CSize kClientSize(1107, 1230);
3444   const double kScaleFactor = 1.0;
3445 
3446   HWND hwnd = nullptr;
3447   LayoutManager layout_mgr(
3448       CreateDefaultGUIFontEmulator(),
3449       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
3450                            kScaleFactor, &hwnd));
3451 
3452   RendererCommand command;
3453   SetRenderereCommandForTest(
3454       false, true, false, 0, hwnd, &command);
3455 
3456   // Replace the default values with those of Crescent Eve.
3457   command.clear_application_info();
3458   AppInfoUtil::SetBasicApplicationInfo(
3459       command.mutable_application_info(), hwnd,
3460       (ApplicationInfo::ShowCandidateWindow |
3461        ApplicationInfo::ShowSuggestWindow |
3462        ApplicationInfo::ShowCompositionWindow));
3463 
3464   AppInfoUtil::SetCompositionForm(
3465      command.mutable_application_info(),
3466      CompositionForm::POINT | CompositionForm::RECT,
3467       35, 0, 35, 0, 1106, 1624);
3468 
3469   AppInfoUtil::SetCaretInfo(
3470       command.mutable_application_info(),
3471       false, 34, 0, 36, 14, hwnd);
3472 
3473   CandidateWindowLayout candidate_layout;
3474   std::vector<CompositionWindowLayout> layouts;
3475   bool result = false;
3476 
3477   layouts.clear();
3478   candidate_layout.Clear();
3479   result = layout_mgr.LayoutCompositionWindow(
3480       command, &layouts, &candidate_layout);
3481   EXPECT_TRUE(result);
3482 
3483   // Default GUI font should be selected.
3484   CLogFont default_font = GetFont(true, false);
3485   default_font.lfHeight = 18;
3486   default_font.lfWidth = 0;
3487 
3488   ASSERT_EQ(1, layouts.size());
3489 
3490   // The first line
3491   {
3492     const CompositionWindowLayout &layout = layouts.at(0);
3493     EXPECT_COMPOSITION_WINDOW_LAYOUT(221, 194, 481, 212, 0, 0, 259, 18, 0, 0,
3494                                      259, 0, 260, 18, default_font, layout);
3495     {
3496       const char kMsg[] = "これは、Google日本語入力のTestです";
3497       std::wstring msg;
3498       mozc::Util::UTF8ToWide(kMsg, &msg);
3499       EXPECT_EQ(msg, layout.text);
3500     }
3501     ASSERT_EQ(5, layout.marker_layouts.size());
3502 
3503     EXPECT_EQ(CPoint(0, 17), layout.marker_layouts[0].from);
3504     EXPECT_EQ(CPoint(42, 17), layout.marker_layouts[0].to);
3505     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
3506     EXPECT_EQ(CPoint(45, 17), layout.marker_layouts[1].from);
3507     EXPECT_EQ(CPoint(57, 17), layout.marker_layouts[1].to);
3508     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
3509     EXPECT_EQ(CPoint(60, 17), layout.marker_layouts[2].from);
3510     EXPECT_EQ(CPoint(108, 17), layout.marker_layouts[2].to);
3511     EXPECT_TRUE(layout.marker_layouts[2].highlighted);
3512     EXPECT_EQ(CPoint(110, 17), layout.marker_layouts[3].from);
3513     EXPECT_EQ(CPoint(197, 17), layout.marker_layouts[3].to);
3514     EXPECT_FALSE(layout.marker_layouts[3].highlighted);
3515     EXPECT_EQ(CPoint(200, 17), layout.marker_layouts[4].from);
3516     EXPECT_EQ(CPoint(259, 17), layout.marker_layouts[4].to);
3517     EXPECT_FALSE(layout.marker_layouts[4].highlighted);
3518   }
3519 
3520   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
3521       281, 212, 281, 194, 480, 212, candidate_layout);
3522 }
3523 
3524 // MSInfo32.exe 6.1.7600 on Windows 7.  (b/3433099)
3525 // The composition window and candidate window must be shown even when the
3526 // client sets Composition/CandidateForm outside of the top-level window.
3527 // Note that LogicalToPhysicalPoint API may return FALSE in this situation.
TEST_F(Win32RendererUtilTest,MSInfo32Composition_Issue3433099)3528 TEST_F(Win32RendererUtilTest, MSInfo32Composition_Issue3433099) {
3529   const double kScaleFactor = 1.0;
3530 
3531   WindowPositionEmulator *window_emulator = nullptr;
3532   HWND root_window = nullptr;
3533   HWND child_window = nullptr;
3534 
3535   {
3536     const wchar_t kRootClassName[] = L"#32770 (Dialog)";
3537     const UINT kRootClassStyle = CS_DBLCLKS | CS_SAVEBITS;
3538     const DWORD kRootWindowStyle = 0x96CF0044;
3539     const DWORD kRootWindowExStyle = 0x00010100;
3540     const CRect kRootWindowRect(838, 651, 1062, 1157);
3541     const CPoint kRootClientOffset(8, 71);
3542     const CSize kRootClientSize(208, 427);
3543     window_emulator = CreateWindowEmulator(
3544         kRootClassName, kRootWindowRect, kRootClientOffset, kRootClientSize,
3545         kScaleFactor, &root_window);
3546   }
3547   {
3548     const wchar_t kChildClassName[] = L"Edit";
3549     const UINT kChildClassStyle = CS_DBLCLKS | CS_PARENTDC | CS_GLOBALCLASS;
3550     const DWORD kChildWindowStyle = 0x50010080;
3551     const DWORD kChildWindowExStyle = 0x00000204;
3552     const CRect kChildWindowRect(951, 1071, 1072, 1098);
3553     const CPoint kChildClientOffset(2, 2);
3554     const CSize kChildClientSize(117, 23);
3555     child_window = window_emulator->RegisterWindow(
3556         kChildClassName, kChildWindowRect, kChildClientOffset,
3557         kChildClientSize, kScaleFactor);
3558 
3559     window_emulator->SetRoot(child_window, root_window);
3560   }
3561 
3562   LayoutManager layout_mgr(
3563       CreateDefaultGUIFontEmulator(),
3564       window_emulator);
3565 
3566   ApplicationInfo app_info;
3567 
3568   RendererCommand command;
3569   SetRenderereCommandForTest(
3570       false, true, false, 0, child_window, &command);
3571 
3572   // Replace the default values with those of MSInfo32.
3573   command.clear_application_info();
3574   AppInfoUtil::SetBasicApplicationInfo(
3575       command.mutable_application_info(), child_window,
3576       (ApplicationInfo::ShowCandidateWindow |
3577        ApplicationInfo::ShowSuggestWindow |
3578        ApplicationInfo::ShowCompositionWindow));
3579 
3580   AppInfoUtil::SetCompositionForm(
3581      command.mutable_application_info(),
3582      CompositionForm::POINT, 2, 1, 0, 0, 0, 0);
3583 
3584   AppInfoUtil::SetCaretInfo(
3585       command.mutable_application_info(),
3586       true, 2, 1, 3, 19, child_window);
3587 
3588   CandidateWindowLayout candidate_layout;
3589   std::vector<CompositionWindowLayout> layouts;
3590   bool result = false;
3591 
3592   layouts.clear();
3593   candidate_layout.Clear();
3594   result = layout_mgr.LayoutCompositionWindow(
3595       command, &layouts, &candidate_layout);
3596   EXPECT_TRUE(result);
3597 
3598   // Default GUI font should be selected.
3599   CLogFont default_font = GetFont(true, false);
3600   default_font.lfHeight = 18;
3601   default_font.lfWidth = 0;
3602 
3603   ASSERT_EQ(3, layouts.size());
3604 
3605   // The first line
3606   {
3607     const CompositionWindowLayout &layout = layouts.at(0);
3608     EXPECT_COMPOSITION_WINDOW_LAYOUT(955, 1074, 1065, 1092, 0, 0, 110, 18, 0, 0,
3609                                      0, 0, 0, 0, default_font, layout);
3610     {
3611       const char kMsg[] = "これは、Google";
3612       std::wstring msg;
3613       mozc::Util::UTF8ToWide(kMsg, &msg);
3614       EXPECT_EQ(msg, layout.text);
3615     }
3616     ASSERT_EQ(3, layout.marker_layouts.size());
3617 
3618     EXPECT_EQ(CPoint(0, 17), layout.marker_layouts[0].from);
3619     EXPECT_EQ(CPoint(42, 17), layout.marker_layouts[0].to);
3620     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
3621     EXPECT_EQ(CPoint(45, 17), layout.marker_layouts[1].from);
3622     EXPECT_EQ(CPoint(57, 17), layout.marker_layouts[1].to);
3623     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
3624     EXPECT_EQ(CPoint(60, 17), layout.marker_layouts[2].from);
3625     EXPECT_EQ(CPoint(108, 17), layout.marker_layouts[2].to);
3626     EXPECT_TRUE(layout.marker_layouts[2].highlighted);
3627   }
3628 
3629   // The second line
3630   {
3631     const CompositionWindowLayout &layout = layouts.at(1);
3632     EXPECT_COMPOSITION_WINDOW_LAYOUT(953, 1092, 1067, 1110, 0, 0, 114, 18, 0, 0,
3633                                      0, 0, 0, 0, default_font, layout);
3634     {
3635       const char kMsg[] = "日本語入力のTes";
3636       std::wstring msg;
3637       mozc::Util::UTF8ToWide(kMsg, &msg);
3638       EXPECT_EQ(msg, layout.text);
3639     }
3640     ASSERT_EQ(2, layout.marker_layouts.size());
3641 
3642     EXPECT_EQ(CPoint(0, 17), layout.marker_layouts[0].from);
3643     EXPECT_EQ(CPoint(87, 17), layout.marker_layouts[0].to);
3644     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
3645     EXPECT_EQ(CPoint(90, 17), layout.marker_layouts[1].from);
3646     EXPECT_EQ(CPoint(114, 17), layout.marker_layouts[1].to);
3647     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
3648   }
3649 
3650   // The third line
3651   {
3652     const CompositionWindowLayout &layout = layouts.at(2);
3653     EXPECT_COMPOSITION_WINDOW_LAYOUT(953, 1110, 989, 1128, 0, 0, 35, 18, 0, 0,
3654                                      35, 0, 36, 18, default_font, layout);
3655     {
3656       const char kMsg[] = "tです";
3657       std::wstring msg;
3658       mozc::Util::UTF8ToWide(kMsg, &msg);
3659       EXPECT_EQ(msg, layout.text);
3660     }
3661     ASSERT_EQ(1, layout.marker_layouts.size());
3662 
3663     EXPECT_EQ(CPoint(0, 17), layout.marker_layouts[0].from);
3664     EXPECT_EQ(CPoint(35, 17), layout.marker_layouts[0].to);
3665     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
3666   }
3667 
3668   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
3669       1015, 1092, 1015, 1074, 1065, 1092, candidate_layout);
3670 }
3671 
3672 // Check if LayoutManager can handle preedits which contains surrogate pair.
3673 // See b/4159275 for details.
TEST_F(Win32RendererUtilTest,CheckSurrogatePairInHorizontalComposition_Issue4159275)3674 TEST_F(Win32RendererUtilTest,
3675        CheckSurrogatePairInHorizontalComposition_Issue4159275) {
3676   const int kCursorOffsetX = 150;
3677 
3678   HWND hwnd = nullptr;
3679   LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
3680                            CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
3681 
3682   RendererCommand command;
3683   SetRenderereCommandForSurrogatePair(
3684         false, false, kCursorOffsetX, hwnd, &command);
3685 
3686   CLogFont logfont;
3687   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
3688       command.application_info().composition_font(), &logfont));
3689 
3690   std::vector<CompositionWindowLayout> layouts;
3691   CandidateWindowLayout candidate_layout;
3692   EXPECT_TRUE(layout_mgr.LayoutCompositionWindow(
3693       command, &layouts, &candidate_layout));
3694 
3695   ASSERT_EQ(1, layouts.size());
3696 
3697   // The first line
3698   {
3699     const CompositionWindowLayout &layout = layouts.at(0);
3700     EXPECT_COMPOSITION_WINDOW_LAYOUT(1193, 648, 1554, 697, 0, 0, 360, 49,
3701                                      0, 0, 360, 0, 361, 49, logfont,
3702                                      layout);
3703     {
3704       const char kMsg[] = "��咤��咤��咤��咤";
3705       std::wstring msg;
3706       mozc::Util::UTF8ToWide(kMsg, &msg);
3707       EXPECT_EQ(msg, layout.text);
3708     }
3709     ASSERT_EQ(4, layout.marker_layouts.size());
3710 
3711     EXPECT_EQ(CPoint(0, 48), layout.marker_layouts[0].from);
3712     EXPECT_EQ(CPoint(81, 48), layout.marker_layouts[0].to);
3713     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
3714     EXPECT_EQ(CPoint(90, 48), layout.marker_layouts[1].from);
3715     EXPECT_EQ(CPoint(171, 48), layout.marker_layouts[1].to);
3716     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
3717     EXPECT_EQ(CPoint(180, 48), layout.marker_layouts[2].from);
3718     EXPECT_EQ(CPoint(261, 48), layout.marker_layouts[2].to);
3719     EXPECT_TRUE(layout.marker_layouts[2].highlighted);
3720     EXPECT_EQ(CPoint(270, 48), layout.marker_layouts[3].from);
3721     EXPECT_EQ(CPoint(360, 48), layout.marker_layouts[3].to);
3722     EXPECT_FALSE(layout.marker_layouts[3].highlighted);
3723   }
3724 
3725   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
3726       1373, 697, 1373, 648, 1553, 697, candidate_layout);
3727 }
3728 
3729 // Check if LayoutManager can handle preedits which contains surrogate pair.
3730 // See b/4159275 for details.
TEST_F(Win32RendererUtilTest,CheckSurrogatePairInVerticalComposition_Issue4159275)3731 TEST_F(Win32RendererUtilTest,
3732        CheckSurrogatePairInVerticalComposition_Issue4159275) {
3733   const int kCursorOffsetY = 175;
3734 
3735   HWND hwnd = nullptr;
3736   LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
3737                            CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
3738 
3739   RendererCommand command;
3740   SetRenderereCommandForSurrogatePair(
3741         false, true, kCursorOffsetY, hwnd, &command);
3742 
3743   CLogFont logfont;
3744   EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
3745       command.application_info().composition_font(), &logfont));
3746   logfont.lfOrientation = 2700;
3747 
3748   std::vector<CompositionWindowLayout> layouts;
3749   CandidateWindowLayout candidate_layout;
3750   EXPECT_TRUE(layout_mgr.LayoutCompositionWindow(
3751       command, &layouts, &candidate_layout));
3752 
3753   ASSERT_EQ(1, layouts.size());
3754 
3755   // The first line
3756   {
3757     const CompositionWindowLayout &layout = layouts.at(0);
3758     EXPECT_COMPOSITION_WINDOW_LAYOUT(
3759         1932, 712, 1983, 1073, 0, 0, 51, 360, 51, 0,
3760         0, 360, 51, 361, logfont, layout);
3761     {
3762       const char kMsg[] = "��咤��咤��咤��咤";
3763       std::wstring msg;
3764       mozc::Util::UTF8ToWide(kMsg, &msg);
3765       EXPECT_EQ(msg, layout.text);
3766     }
3767     ASSERT_EQ(4, layout.marker_layouts.size());
3768 
3769     EXPECT_EQ(CPoint(50, 0), layout.marker_layouts[0].from);
3770     EXPECT_EQ(CPoint(50, 81), layout.marker_layouts[0].to);
3771     EXPECT_FALSE(layout.marker_layouts[0].highlighted);
3772     EXPECT_EQ(CPoint(50, 90), layout.marker_layouts[1].from);
3773     EXPECT_EQ(CPoint(50, 171), layout.marker_layouts[1].to);
3774     EXPECT_FALSE(layout.marker_layouts[1].highlighted);
3775     EXPECT_EQ(CPoint(50, 180), layout.marker_layouts[2].from);
3776     EXPECT_EQ(CPoint(50, 261), layout.marker_layouts[2].to);
3777     EXPECT_TRUE(layout.marker_layouts[2].highlighted);
3778     EXPECT_EQ(CPoint(50, 270), layout.marker_layouts[3].from);
3779     EXPECT_EQ(CPoint(50, 360), layout.marker_layouts[3].to);
3780     EXPECT_FALSE(layout.marker_layouts[3].highlighted);
3781   }
3782 
3783   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
3784       1932, 892, 1932, 892, 1983, 1072, candidate_layout);
3785 }
3786 
TEST_F(Win32RendererUtilTest,GetWritingDirectionTest)3787 TEST_F(Win32RendererUtilTest, GetWritingDirectionTest) {
3788   RendererCommand command;
3789 
3790   // Horizontal
3791   SetRenderereCommandForTest(
3792       false, true, false, 0, nullptr, &command);
3793   EXPECT_EQ(LayoutManager::HORIZONTAL_WRITING,
3794             LayoutManager::GetWritingDirection(command.application_info()));
3795 
3796   // Vertical
3797   SetRenderereCommandForTest(
3798       false, true, true, 0, nullptr, &command);
3799   EXPECT_EQ(LayoutManager::VERTICAL_WRITING,
3800             LayoutManager::GetWritingDirection(command.application_info()));
3801 
3802   // Unspecified
3803   command.mutable_application_info()->
3804       mutable_composition_font()->clear_escapement();
3805   EXPECT_EQ(LayoutManager::WRITING_DIRECTION_UNSPECIFIED,
3806             LayoutManager::GetWritingDirection(command.application_info()));
3807 
3808   // Unspecified
3809   command.mutable_application_info()->clear_composition_font();
3810   EXPECT_EQ(LayoutManager::WRITING_DIRECTION_UNSPECIFIED,
3811             LayoutManager::GetWritingDirection(command.application_info()));
3812 }
3813 
3814 // Hidemaru 8.01a True-Inline
TEST_F(Win32RendererUtilTest,Hidemaru_Horizontal_Suggest)3815 TEST_F(Win32RendererUtilTest, Hidemaru_Horizontal_Suggest) {
3816   const wchar_t kClassName[] = L"HM32CLIENT";
3817   const CRect kWindowRect(0, 20, 2016, 1050);
3818   const CPoint kClientOffset(8, 42);
3819   const CSize kClientSize(2000, 1000);
3820   const double kScaleFactor = 1.0;
3821 
3822   HWND hwnd = nullptr;
3823   LayoutManager layout_mgr(
3824       CreateDefaultGUIFontEmulator(),
3825       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
3826                            kScaleFactor, &hwnd));
3827 
3828   ApplicationInfo app_info;
3829   AppInfoUtil::SetBasicApplicationInfo(
3830       &app_info, hwnd, ApplicationInfo::ShowSuggestWindow);
3831 
3832   AppInfoUtil::SetCompositionFont(
3833       &app_info, -15, 0, 0, 0, FW_NORMAL, SHIFTJIS_CHARSET,
3834       OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
3835       DEFAULT_QUALITY, FF_MODERN | FIXED_PITCH,
3836       "MS ゴシック");
3837 
3838   AppInfoUtil::SetCompositionForm(
3839       &app_info, CompositionForm::RECT, 112, 25, 48, 0, 1408, 552);
3840 
3841   AppInfoUtil::SetCandidateForm(
3842       &app_info, CandidateForm::EXCLUDE, 112, 42, 112, 25, 752, 42);
3843 
3844   AppInfoUtil::SetCaretInfo(&app_info, true, 160, 25, 162, 40, hwnd);
3845 
3846   CandidateWindowLayout layout;
3847   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
3848   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
3849       168, 102, 168, 87, 170, 102, layout);
3850 }
3851 
3852 // Hidemaru 8.01a True-Inline
TEST_F(Win32RendererUtilTest,Hidemaru_Horizontal_Convert)3853 TEST_F(Win32RendererUtilTest, Hidemaru_Horizontal_Convert) {
3854   const wchar_t kClassName[] = L"HM32CLIENT";
3855   const CRect kWindowRect(0, 20, 2016, 1050);
3856   const CPoint kClientOffset(8, 42);
3857   const CSize kClientSize(2000, 1000);
3858   const double kScaleFactor = 1.0;
3859 
3860   HWND hwnd = nullptr;
3861   LayoutManager layout_mgr(
3862       CreateDefaultGUIFontEmulator(),
3863       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
3864                            kScaleFactor, &hwnd));
3865 
3866   ApplicationInfo app_info;
3867 
3868   AppInfoUtil::SetBasicApplicationInfo(
3869       &app_info, hwnd, ApplicationInfo::ShowCandidateWindow);
3870 
3871   AppInfoUtil::SetCompositionFont(
3872       &app_info, -15, 0, 0, 0, FW_NORMAL, SHIFTJIS_CHARSET,
3873       OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
3874       DEFAULT_QUALITY, FF_MODERN | FIXED_PITCH,
3875       "MS ゴシック");
3876 
3877   AppInfoUtil::SetCompositionForm(
3878       &app_info, CompositionForm::RECT, 112, 25, 48, 0, 1408, 552);
3879 
3880   AppInfoUtil::SetCandidateForm(
3881       &app_info, CandidateForm::EXCLUDE, 128, 25, 128, 25, 144, 42);
3882 
3883   AppInfoUtil::SetCaretInfo(&app_info, true, 160, 25, 162, 40, hwnd);
3884 
3885   CandidateWindowLayout layout;
3886   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
3887       app_info, &layout));
3888   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
3889       136, 87, 136, 87, 152, 104, layout);
3890 }
3891 
3892 // Hidemaru 8.01a True-Inline
TEST_F(Win32RendererUtilTest,Hidemaru_Vertical_Suggest)3893 TEST_F(Win32RendererUtilTest, Hidemaru_Vertical_Suggest) {
3894   const wchar_t kClassName[] = L"HM32CLIENT";
3895   const CRect kWindowRect(0, 20, 2016, 1050);
3896   const CPoint kClientOffset(8, 42);
3897   const CSize kClientSize(2000, 1000);
3898   const double kScaleFactor = 1.0;
3899 
3900   HWND hwnd = nullptr;
3901   LayoutManager layout_mgr(
3902       CreateDefaultGUIFontEmulator(),
3903       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
3904                            kScaleFactor, &hwnd));
3905 
3906   ApplicationInfo app_info;
3907 
3908   AppInfoUtil::SetBasicApplicationInfo(
3909       &app_info, hwnd, ApplicationInfo::ShowSuggestWindow);
3910 
3911   AppInfoUtil::SetCompositionFont(
3912       &app_info, -15, 0, 2700, 0, FW_NORMAL, SHIFTJIS_CHARSET,
3913       OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
3914       DEFAULT_QUALITY, FF_MODERN | FIXED_PITCH,
3915       "@MS ゴシック");
3916 
3917   AppInfoUtil::SetCompositionForm(
3918       &app_info, CompositionForm::RECT, 660, 48, 0, 48, 688, 397);
3919 
3920   AppInfoUtil::SetCandidateForm(
3921       &app_info, CandidateForm::EXCLUDE, 660, 67, 641, 48, 660, 400);
3922 
3923   AppInfoUtil::SetCaretInfo(&app_info, true, 644, 96, 661, 98, hwnd);
3924 
3925   CandidateWindowLayout layout;
3926   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
3927   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
3928       652, 158, 652, 158, 669, 160, layout);
3929 }
3930 
3931 // Hidemaru 8.01a True-Inline
TEST_F(Win32RendererUtilTest,Hidemaru_Vertical_Convert)3932 TEST_F(Win32RendererUtilTest, Hidemaru_Vertical_Convert) {
3933   const wchar_t kClassName[] = L"HM32CLIENT";
3934   const CRect kWindowRect(0, 20, 2016, 1050);
3935   const CPoint kClientOffset(8, 42);
3936   const CSize kClientSize(2000, 1000);
3937   const double kScaleFactor = 1.0;
3938 
3939   HWND hwnd = nullptr;
3940   LayoutManager layout_mgr(
3941       CreateDefaultGUIFontEmulator(),
3942       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
3943                            kScaleFactor, &hwnd));
3944 
3945   ApplicationInfo app_info;
3946 
3947   AppInfoUtil::SetBasicApplicationInfo(
3948       &app_info, hwnd,
3949       ApplicationInfo::ShowCandidateWindow |
3950       ApplicationInfo::ShowSuggestWindow);
3951 
3952   AppInfoUtil::SetCompositionFont(
3953       &app_info, -15, 0, 2700, 0, FW_NORMAL, SHIFTJIS_CHARSET,
3954       OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
3955       DEFAULT_QUALITY, FF_MODERN | FIXED_PITCH,
3956       "@MS ゴシック");
3957 
3958   AppInfoUtil::SetCompositionForm(
3959       &app_info, CompositionForm::RECT, 660, 48, 0, 48, 668, 397);
3960 
3961   AppInfoUtil::SetCandidateForm(
3962       &app_info, CandidateForm::EXCLUDE, 644, 63, 644, 63, 661, 80);
3963 
3964   AppInfoUtil::SetCaretInfo(&app_info, true, 644, 96, 661, 98, hwnd);
3965 
3966   CandidateWindowLayout layout;
3967   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
3968       app_info, &layout));
3969   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
3970       652, 125, 652, 125, 669, 142, layout);
3971 }
3972 
3973 // Open Office Writer 3.01
TEST_F(Win32RendererUtilTest,OOo_Suggest)3974 TEST_F(Win32RendererUtilTest, OOo_Suggest) {
3975   const wchar_t kClassName[] = L"SALFRAME";
3976   const CRect kWindowRect(0, 20, 2016, 1050);
3977   const CPoint kClientOffset(8, 42);
3978   const CSize kClientSize(2000, 1000);
3979   const double kScaleFactor = 1.0;
3980 
3981   HWND hwnd = nullptr;
3982   LayoutManager layout_mgr(
3983       CreateDefaultGUIFontEmulator(),
3984       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
3985                            kScaleFactor, &hwnd));
3986 
3987   ApplicationInfo app_info;
3988 
3989   AppInfoUtil::SetBasicApplicationInfo(
3990       &app_info, hwnd,
3991       ApplicationInfo::ShowSuggestWindow);
3992 
3993   AppInfoUtil::SetCompositionFont(
3994       &app_info, -16, 0, 0, 0, FW_DONTCARE, ANSI_CHARSET,
3995       OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,
3996       DEFAULT_QUALITY, 23,
3997       "Times New Roman");
3998 
3999   AppInfoUtil::SetCompositionForm(
4000       &app_info, CompositionForm::POINT, 292, 253, 0, 0, 0, 0);
4001 
4002   AppInfoUtil::SetCaretInfo(&app_info, true, 292, 253, 294, 273, hwnd);
4003 
4004   CandidateWindowLayout layout;
4005   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
4006   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
4007       300, 335, 300, 315, 302, 335, layout);
4008 }
4009 
4010 // Open Office Writer 3.01
TEST_F(Win32RendererUtilTest,OOo_Convert)4011 TEST_F(Win32RendererUtilTest, OOo_Convert) {
4012   const wchar_t kClassName[] = L"SALFRAME";
4013   const CRect kWindowRect(0, 20, 2016, 1050);
4014   const CPoint kClientOffset(8, 42);
4015   const CSize kClientSize(2000, 1000);
4016   const double kScaleFactor = 1.0;
4017 
4018   HWND hwnd = nullptr;
4019   LayoutManager layout_mgr(
4020       CreateDefaultGUIFontEmulator(),
4021       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4022                            kScaleFactor, &hwnd));
4023 
4024   ApplicationInfo app_info;
4025 
4026   AppInfoUtil::SetBasicApplicationInfo(
4027       &app_info, hwnd,
4028       ApplicationInfo::ShowCandidateWindow |
4029       ApplicationInfo::ShowSuggestWindow);
4030 
4031   AppInfoUtil::SetCompositionFont(
4032       &app_info, -16, 0, 0, 0, FW_DONTCARE, ANSI_CHARSET,
4033       OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,
4034       DEFAULT_QUALITY, 23,
4035       "Times New Roman");
4036 
4037   AppInfoUtil::SetCompositionForm(
4038       &app_info, CompositionForm::POINT, 264, 253, 0, 0, 0, 0);
4039 
4040   AppInfoUtil::SetCandidateForm(
4041       &app_info, CandidateForm::EXCLUDE, 250, 258, 250, 257, 253, 275);
4042 
4043   AppInfoUtil::SetCaretInfo(&app_info, true, 264, 253, 266, 273, hwnd);
4044 
4045   CandidateWindowLayout layout;
4046   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
4047       app_info, &layout));
4048   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
4049       258, 320, 258, 319, 261, 337, layout);
4050 }
4051 
4052 // Pidgin 2.6.1
TEST_F(Win32RendererUtilTest,Pidgin_Indicator)4053 TEST_F(Win32RendererUtilTest, Pidgin_Indicator) {
4054   const wchar_t kClassName[] = L"gdkWindowToplevel";
4055   const CRect kWindowRect(0, 20, 2016, 1050);
4056   const CPoint kClientOffset(8, 42);
4057   const CSize kClientSize(2000, 1000);
4058   const double kScaleFactor = 1.0;
4059 
4060   HWND hwnd = nullptr;
4061   LayoutManager layout_mgr(
4062     CreateDefaultGUIFontEmulator(),
4063     CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4064     kScaleFactor, &hwnd));
4065 
4066   ApplicationInfo app_info;
4067 
4068   AppInfoUtil::SetBasicApplicationInfo(
4069     &app_info, hwnd,
4070     ApplicationInfo::ShowCandidateWindow |
4071     ApplicationInfo::ShowSuggestWindow);
4072 
4073   AppInfoUtil::SetCompositionFont(
4074       &app_info, -16, 0, 0, 0, FW_NORMAL, SHIFTJIS_CHARSET,
4075       OUT_STROKE_PRECIS, CLIP_STROKE_PRECIS,
4076       DRAFT_QUALITY, 50,
4077       "メイリオ");
4078 
4079   AppInfoUtil::SetCompositionForm(
4080       &app_info, CompositionForm::POINT, 48, 589,
4081       96504880, 2617504, 97141432, 2617480);
4082 
4083   AppInfoUtil::SetCandidateForm(
4084       &app_info, CandidateForm::CANDIDATEPOS, 32, 636,
4085       40706080, 96552944, 2615824, 1815374140);
4086 
4087   AppInfoUtil::SetCaretInfo(&app_info, false, 0, 0, 0, 0, nullptr);
4088 
4089   IndicatorWindowLayout layout;
4090   EXPECT_TRUE(layout_mgr.LayoutIndicatorWindow(app_info, &layout));
4091   EXPECT_EQ(CRect(56, 651, 57, 667), layout.window_rect);
4092   EXPECT_FALSE(layout.is_vertical);
4093 }
4094 
4095 // Pidgin 2.6.1
TEST_F(Win32RendererUtilTest,Pidgin_Suggest)4096 TEST_F(Win32RendererUtilTest, Pidgin_Suggest) {
4097   const wchar_t kClassName[] = L"gdkWindowToplevel";
4098   const CRect kWindowRect(0, 20, 2016, 1050);
4099   const CPoint kClientOffset(8, 42);
4100   const CSize kClientSize(2000, 1000);
4101   const double kScaleFactor = 1.0;
4102 
4103   HWND hwnd = nullptr;
4104   LayoutManager layout_mgr(
4105       CreateDefaultGUIFontEmulator(),
4106       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4107                            kScaleFactor, &hwnd));
4108 
4109   ApplicationInfo app_info;
4110 
4111   AppInfoUtil::SetBasicApplicationInfo(
4112       &app_info, hwnd,
4113       ApplicationInfo::ShowSuggestWindow);
4114 
4115   AppInfoUtil::SetCompositionFont(
4116       &app_info, -16, 0, 0, 0, FW_NORMAL, SHIFTJIS_CHARSET,
4117       OUT_STROKE_PRECIS, CLIP_STROKE_PRECIS,
4118       DRAFT_QUALITY, 50,
4119       "メイリオ");
4120 
4121   AppInfoUtil::SetCompositionForm(
4122       &app_info, CompositionForm::POINT, 48, 589,
4123       96504880, 2617504, 97141432, 2617480);
4124 
4125   AppInfoUtil::SetCandidateForm(
4126       &app_info, CandidateForm::CANDIDATEPOS, 48, 636,
4127       40706080, 96552944, 2615824, 1815374140);
4128 
4129   AppInfoUtil::SetCaretInfo(&app_info, false, 0, 0, 0, 0, nullptr);
4130 
4131   CandidateWindowLayout layout;
4132   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
4133   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
4134       56, 667, 56, 651, 57, 667, layout);
4135 }
4136 
4137 // Pidgin 2.6.1
TEST_F(Win32RendererUtilTest,Pidgin_Convert)4138 TEST_F(Win32RendererUtilTest, Pidgin_Convert) {
4139   const wchar_t kClassName[] = L"gdkWindowToplevel";
4140   const CRect kWindowRect(0, 20, 2016, 1050);
4141   const CPoint kClientOffset(8, 42);
4142   const CSize kClientSize(2000, 1000);
4143   const double kScaleFactor = 1.0;
4144 
4145   HWND hwnd = nullptr;
4146   LayoutManager layout_mgr(
4147       CreateDefaultGUIFontEmulator(),
4148       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4149                            kScaleFactor, &hwnd));
4150 
4151   ApplicationInfo app_info;
4152 
4153   AppInfoUtil::SetBasicApplicationInfo(
4154       &app_info, hwnd,
4155       ApplicationInfo::ShowCandidateWindow |
4156       ApplicationInfo::ShowSuggestWindow);
4157 
4158   AppInfoUtil::SetCompositionFont(
4159       &app_info, -16, 0, 0, 0, FW_NORMAL, SHIFTJIS_CHARSET,
4160       OUT_STROKE_PRECIS, CLIP_STROKE_PRECIS,
4161       DRAFT_QUALITY, 50,
4162       "メイリオ");
4163 
4164   AppInfoUtil::SetCompositionForm(
4165       &app_info, CompositionForm::POINT, 48, 589,
4166       96504880, 2617504, 97141432, 2617480);
4167 
4168   AppInfoUtil::SetCandidateForm(
4169       &app_info, CandidateForm::CANDIDATEPOS, 32, 636,
4170       40706080, 96552944, 2615824, 1815374140);
4171 
4172   AppInfoUtil::SetCaretInfo(&app_info, false, 0, 0, 0, 0, nullptr);
4173 
4174   CandidateWindowLayout layout;
4175   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
4176       app_info, &layout));
4177   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
4178       32, 656, 32, 640, 33, 656, layout);
4179 }
4180 
4181 // V2C 2.1.6 on JRE 1.6.0.21 (32-bit)
TEST_F(Win32RendererUtilTest,V2C_Indicator)4182 TEST_F(Win32RendererUtilTest, V2C_Indicator) {
4183   const wchar_t kClassName[] = L"SunAwtFrame";
4184   const CRect kWindowRect(977, 446, 2042, 1052);
4185   const CPoint kClientOffset(8, 8);
4186   const CSize kClientSize(1049, 569);
4187   const double kScaleFactor = 1.0;
4188 
4189   HWND hwnd = nullptr;
4190   LayoutManager layout_mgr(
4191       CreateDefaultGUIFontEmulator(),
4192       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4193                            kScaleFactor, &hwnd));
4194 
4195   ApplicationInfo app_info;
4196 
4197   AppInfoUtil::SetBasicApplicationInfo(
4198       &app_info, hwnd,
4199       ApplicationInfo::ShowSuggestWindow);
4200 
4201   // V2C occasionally creates zero-initialized CANDIDATEFORM and maintains
4202   // it regardless of the actual position of the composition.
4203   AppInfoUtil::SetCompositionForm(
4204       &app_info, CompositionForm::DEFAULT, 0, 0, 0, 0, 0, 0);
4205 
4206   AppInfoUtil::SetCaretInfo(&app_info, false, 0, 0, 0, 0, nullptr);
4207 
4208   IndicatorWindowLayout layout;
4209   EXPECT_FALSE(layout_mgr.LayoutIndicatorWindow(app_info, &layout));
4210 }
4211 
4212 // V2C 2.1.6 on JRE 1.6.0.21 (32-bit)
TEST_F(Win32RendererUtilTest,V2C_Suggest)4213 TEST_F(Win32RendererUtilTest, V2C_Suggest) {
4214   const wchar_t kClassName[] = L"SunAwtFrame";
4215   const CRect kWindowRect(977, 446, 2042, 1052);
4216   const CPoint kClientOffset(8, 8);
4217   const CSize kClientSize(1049, 569);
4218   const double kScaleFactor = 1.0;
4219 
4220   HWND hwnd = nullptr;
4221   LayoutManager layout_mgr(
4222       CreateDefaultGUIFontEmulator(),
4223       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4224                            kScaleFactor, &hwnd));
4225 
4226   ApplicationInfo app_info;
4227 
4228   AppInfoUtil::SetBasicApplicationInfo(
4229       &app_info, hwnd,
4230       ApplicationInfo::ShowSuggestWindow);
4231 
4232   // V2C occasionally creates zero-initialized CANDIDATEFORM and maintains
4233   // it regardless of the actual position of the composition.
4234   AppInfoUtil::SetCompositionForm(
4235       &app_info, CompositionForm::DEFAULT, 0, 0, 0, 0, 0, 0);
4236 
4237   AppInfoUtil::SetCaretInfo(&app_info, false, 0, 0, 0, 0, nullptr);
4238 
4239   CandidateWindowLayout layout;
4240   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
4241   EXPECT_NON_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(985, 1023, layout);
4242 }
4243 
4244 // V2C 2.1.6 on JRE 1.6.0.21 (32-bit)
TEST_F(Win32RendererUtilTest,V2C_Convert)4245 TEST_F(Win32RendererUtilTest, V2C_Convert) {
4246   const wchar_t kClassName[] = L"SunAwtFrame";
4247   const CRect kWindowRect(977, 446, 2042, 1052);
4248   const CPoint kClientOffset(8, 8);
4249   const CSize kClientSize(1049, 569);
4250   const double kScaleFactor = 1.0;
4251 
4252   HWND hwnd = nullptr;
4253   LayoutManager layout_mgr(
4254       CreateDefaultGUIFontEmulator(),
4255       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4256                            kScaleFactor, &hwnd));
4257 
4258   ApplicationInfo app_info;
4259 
4260   AppInfoUtil::SetBasicApplicationInfo(
4261       &app_info, hwnd,
4262       ApplicationInfo::ShowCandidateWindow |
4263       ApplicationInfo::ShowSuggestWindow);
4264 
4265   // V2C occasionally creates zero-initialized CANDIDATEFORM and maintains
4266   // it regardless of the actual position of the composition.
4267   AppInfoUtil::SetCompositionForm(
4268       &app_info, CompositionForm::DEFAULT, 0, 0, 0, 0, 0, 0);
4269 
4270   AppInfoUtil::SetCandidateForm(
4271       &app_info, CandidateForm::CANDIDATEPOS, 234, 523,
4272       1272967816, 1974044135, -348494668, -2);
4273 
4274   AppInfoUtil::SetCaretInfo(&app_info, false, 0, 0, 0, 0, nullptr);
4275 
4276   CandidateWindowLayout layout;
4277   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
4278       app_info, &layout));
4279   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
4280       1211, 969, 1211, 951, 1212, 969, layout);
4281 }
4282 
4283 
4284 // Qt 4.6.3
TEST_F(Win32RendererUtilTest,Qt_Suggest)4285 TEST_F(Win32RendererUtilTest, Qt_Suggest) {
4286   const wchar_t kClassName[] = L"QWidget";
4287   const CRect kWindowRect(0, 20, 2016, 1050);
4288   const CPoint kClientOffset(8, 42);
4289   const CSize kClientSize(2000, 1000);
4290   const double kScaleFactor = 1.0;
4291 
4292   HWND hwnd = nullptr;
4293   LayoutManager layout_mgr(
4294       CreateDefaultGUIFontEmulator(),
4295       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4296                            kScaleFactor, &hwnd));
4297 
4298   ApplicationInfo app_info;
4299 
4300   AppInfoUtil::SetBasicApplicationInfo(
4301       &app_info,
4302       hwnd,
4303       ApplicationInfo::ShowSuggestWindow);
4304 
4305   AppInfoUtil::SetCompositionFont(
4306       &app_info, -12, 0, 0, 0, FW_DONTCARE, DEFAULT_CHARSET,
4307       OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
4308       DEFAULT_QUALITY, 0,
4309       "メイリオ");
4310 
4311   AppInfoUtil::SetCompositionForm(
4312       &app_info, CompositionForm::FORCE_POSITION, 211, 68,
4313       18901544, 103737984, 4247412, 19851904);
4314 
4315   AppInfoUtil::SetCandidateForm(
4316       &app_info, CandidateForm::EXCLUDE, 211, 87,
4317       211, 68, 221, 87);
4318 
4319   AppInfoUtil::SetCaretInfo(&app_info, false, 211, 68, 212, 69, hwnd);
4320 
4321   CandidateWindowLayout layout;
4322   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
4323   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
4324       219, 149, 219, 130, 229, 149, layout);
4325 }
4326 
4327 // Qt 4.6.3
TEST_F(Win32RendererUtilTest,Qt_Convert)4328 TEST_F(Win32RendererUtilTest, Qt_Convert) {
4329   const wchar_t kClassName[] = L"QWidget";
4330   const CRect kWindowRect(0, 20, 2016, 1050);
4331   const CPoint kClientOffset(8, 42);
4332   const CSize kClientSize(2000, 1000);
4333   const double kScaleFactor = 1.0;
4334 
4335   HWND hwnd = nullptr;
4336   LayoutManager layout_mgr(
4337       CreateDefaultGUIFontEmulator(),
4338       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4339                            kScaleFactor, &hwnd));
4340 
4341   ApplicationInfo app_info;
4342 
4343   AppInfoUtil::SetBasicApplicationInfo(
4344       &app_info,
4345       hwnd,
4346       ApplicationInfo::ShowCandidateWindow |
4347       ApplicationInfo::ShowSuggestWindow);
4348 
4349   AppInfoUtil::SetCompositionFont(
4350       &app_info, -12, 0, 0, 0, FW_DONTCARE, DEFAULT_CHARSET,
4351       OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
4352       DEFAULT_QUALITY, 0,
4353       "メイリオ");
4354 
4355   AppInfoUtil::SetCompositionForm(
4356       &app_info, CompositionForm::FORCE_POSITION, 187, 68,
4357       18901544, 103737984, 4247412, 19851904);
4358 
4359   AppInfoUtil::SetCandidateForm(
4360       &app_info, CandidateForm::EXCLUDE, 187, 87,
4361       187, 68, 197, 87);
4362 
4363   AppInfoUtil::SetCaretInfo(&app_info, false, 187, 68, 188, 69, hwnd);
4364 
4365   CandidateWindowLayout layout;
4366   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
4367       app_info, &layout));
4368   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
4369       195, 149, 195, 130, 205, 149, layout);
4370 }
4371 
4372 // Wordpad x86 on Vista SP1
TEST_F(Win32RendererUtilTest,Wordpad_Vista_Indicator)4373 TEST_F(Win32RendererUtilTest, Wordpad_Vista_Indicator) {
4374   const wchar_t kClassName[] = L"RICHEDIT50W";
4375   const CRect kWindowRect(617, 573, 1319, 881);
4376   const CPoint kClientOffset(2, 22);
4377   const CSize kClientSize(698, 304);
4378   const double kScaleFactor = 1.0;
4379 
4380   HWND hwnd = nullptr;
4381   LayoutManager layout_mgr(
4382       CreateDefaultGUIFontEmulator(),
4383       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4384       kScaleFactor, &hwnd));
4385 
4386   ApplicationInfo app_info;
4387 
4388   AppInfoUtil::SetBasicApplicationInfo(
4389       &app_info, hwnd,
4390       ApplicationInfo::ShowCandidateWindow |
4391       ApplicationInfo::ShowSuggestWindow);
4392 
4393   AppInfoUtil::SetCompositionFont(
4394       &app_info, 10, 0, 0, 0, FW_DONTCARE, SHIFTJIS_CHARSET,
4395       OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
4396       DEFAULT_QUALITY, 17,
4397       "MS Pゴシック");
4398 
4399   AppInfoUtil::SetCandidateForm(
4400       &app_info, CandidateForm::EXCLUDE, 62, 42, 62, 21, 64, 42);
4401 
4402   AppInfoUtil::SetCompositionTarget(
4403       &app_info, 1, 693, 596, 17, 625, 579, 1317, 879);
4404 
4405   AppInfoUtil::SetCaretInfo(&app_info, false, 74, 21, 75, 38, hwnd);
4406 
4407   IndicatorWindowLayout layout;
4408   EXPECT_TRUE(layout_mgr.LayoutIndicatorWindow(app_info, &layout));
4409   EXPECT_EQ(CRect(693, 596, 694, 613), layout.window_rect);
4410   EXPECT_FALSE(layout.is_vertical);
4411 }
4412 
4413 // Wordpad x86 on Vista SP1
TEST_F(Win32RendererUtilTest,Wordpad_Vista_Suggest)4414 TEST_F(Win32RendererUtilTest, Wordpad_Vista_Suggest) {
4415   const wchar_t kClassName[] = L"RICHEDIT50W";
4416   const CRect kWindowRect(617, 573, 1319, 881);
4417   const CPoint kClientOffset(2, 22);
4418   const CSize kClientSize(698, 304);
4419   const double kScaleFactor = 1.0;
4420 
4421   HWND hwnd = nullptr;
4422   LayoutManager layout_mgr(
4423       CreateDefaultGUIFontEmulator(),
4424       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4425                            kScaleFactor, &hwnd));
4426 
4427   ApplicationInfo app_info;
4428 
4429   AppInfoUtil::SetBasicApplicationInfo(
4430       &app_info, hwnd,
4431       ApplicationInfo::ShowSuggestWindow);
4432 
4433   AppInfoUtil::SetCompositionFont(
4434       &app_info, 10, 0, 0, 0, FW_DONTCARE, SHIFTJIS_CHARSET,
4435       OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
4436       DEFAULT_QUALITY, 17,
4437       "MS Pゴシック");
4438 
4439   AppInfoUtil::SetCompositionTarget(
4440       &app_info, 0, 681, 596, 17, 625, 579, 1317, 879);
4441 
4442   AppInfoUtil::SetCaretInfo(&app_info, false, 98, 21, 99, 38, hwnd);
4443 
4444   CandidateWindowLayout layout;
4445   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
4446   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
4447       681, 613, 681, 596, 682, 613, layout);
4448 }
4449 
4450 // Wordpad x86 on Vista SP1
TEST_F(Win32RendererUtilTest,Wordpad_Vista_Convert)4451 TEST_F(Win32RendererUtilTest, Wordpad_Vista_Convert) {
4452   const wchar_t kClassName[] = L"RICHEDIT50W";
4453   const CRect kWindowRect(617, 573, 1319, 881);
4454   const CPoint kClientOffset(2, 22);
4455   const CSize kClientSize(698, 304);
4456   const double kScaleFactor = 1.0;
4457 
4458   HWND hwnd = nullptr;
4459   LayoutManager layout_mgr(
4460       CreateDefaultGUIFontEmulator(),
4461       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4462                            kScaleFactor, &hwnd));
4463 
4464   ApplicationInfo app_info;
4465 
4466   AppInfoUtil::SetBasicApplicationInfo(
4467       &app_info, hwnd,
4468       ApplicationInfo::ShowCandidateWindow |
4469       ApplicationInfo::ShowSuggestWindow);
4470 
4471   AppInfoUtil::SetCompositionFont(
4472       &app_info, 10, 0, 0, 0, FW_DONTCARE, SHIFTJIS_CHARSET,
4473       OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
4474       DEFAULT_QUALITY, 17,
4475       "MS Pゴシック");
4476 
4477   AppInfoUtil::SetCandidateForm(
4478       &app_info, CandidateForm::EXCLUDE, 62, 42, 62, 21, 64, 42);
4479 
4480   AppInfoUtil::SetCompositionTarget(
4481       &app_info, 1, 693, 596, 17, 625, 579, 1317, 879);
4482 
4483   AppInfoUtil::SetCaretInfo(&app_info, false, 74, 21, 75, 38, hwnd);
4484 
4485   CandidateWindowLayout layout;
4486   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
4487       app_info, &layout));
4488   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
4489       693, 613, 681, 616, 683, 637, layout);
4490 }
4491 
4492 // MS Word 2010 x64, True Inline, Horizontal
TEST_F(Win32RendererUtilTest,MSWord2010_Horizontal_Suggest)4493 TEST_F(Win32RendererUtilTest, MSWord2010_Horizontal_Suggest) {
4494   const wchar_t kClassName[] = L"_WwG";
4495   const CRect kWindowRect(434, 288, 1275, 841);
4496   const CPoint kClientOffset(0, 0);
4497   const CSize kClientSize(841, 553);
4498   const double kScaleFactor = 1.0;
4499 
4500   HWND hwnd = nullptr;
4501   LayoutManager layout_mgr(
4502       CreateDefaultGUIFontEmulator(),
4503       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4504                            kScaleFactor, &hwnd));
4505 
4506   ApplicationInfo app_info;
4507 
4508   AppInfoUtil::SetBasicApplicationInfo(
4509       &app_info, hwnd,
4510       ApplicationInfo::ShowSuggestWindow);
4511 
4512   AppInfoUtil::SetCompositionFont(
4513       &app_info, -14, 0, 0, 0, FW_NORMAL, SHIFTJIS_CHARSET,
4514       OUT_SCREEN_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS,
4515       DEFAULT_QUALITY, 17,
4516       "MS 明朝");
4517 
4518   AppInfoUtil::SetCandidateForm(
4519       &app_info, CandidateForm::EXCLUDE, 234, 176,
4520       136, 176, 703, 193);
4521 
4522   AppInfoUtil::SetCompositionTarget(
4523       &app_info, 0, 626, 464, 17, 570, 288, 1137, 841);
4524 
4525   AppInfoUtil::SetCaretInfo(&app_info, false, 220, 176, 221, 194, hwnd);
4526 
4527   CandidateWindowLayout layout;
4528   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
4529   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
4530       626, 481, 626, 464, 627, 481, layout);
4531 }
4532 
4533 // MS Word 2010 x64, True Inline, Horizontal
TEST_F(Win32RendererUtilTest,MSWord2010_Horizontal_Convert)4534 TEST_F(Win32RendererUtilTest, MSWord2010_Horizontal_Convert) {
4535   const wchar_t kClassName[] = L"_WwG";
4536   const CRect kWindowRect(434, 288, 1275, 841);
4537   const CPoint kClientOffset(0, 0);
4538   const CSize kClientSize(841, 553);
4539   const double kScaleFactor = 1.0;
4540 
4541   HWND hwnd = nullptr;
4542   LayoutManager layout_mgr(
4543       CreateDefaultGUIFontEmulator(),
4544       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4545                            kScaleFactor, &hwnd));
4546 
4547   ApplicationInfo app_info;
4548 
4549   AppInfoUtil::SetBasicApplicationInfo(
4550       &app_info, hwnd,
4551       ApplicationInfo::ShowCandidateWindow |
4552       ApplicationInfo::ShowSuggestWindow);
4553 
4554   AppInfoUtil::SetCompositionFont(
4555       &app_info, -14, 0, 0, 0, FW_NORMAL, SHIFTJIS_CHARSET,
4556       OUT_SCREEN_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS,
4557       DEFAULT_QUALITY, 17,
4558       "MS 明朝");
4559 
4560   AppInfoUtil::SetCandidateForm(
4561       &app_info, CandidateForm::EXCLUDE, 206, 178,
4562       136, 178, 703, 194);
4563 
4564   AppInfoUtil::SetCompositionTarget(
4565       &app_info, 1, 640, 466, 16, 570, 288, 1137, 841);
4566 
4567   AppInfoUtil::SetCaretInfo(&app_info, false, 192, 179, 193, 197, hwnd);
4568 
4569   CandidateWindowLayout layout;
4570   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
4571       app_info, &layout));
4572   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
4573       640, 482, 570, 466, 1137, 482, layout);
4574 }
4575 
4576 // MS Word 2010 x64, True Inline, Vertical
TEST_F(Win32RendererUtilTest,MSWord2010_Vertical_Suggest)4577 TEST_F(Win32RendererUtilTest, MSWord2010_Vertical_Suggest) {
4578   const wchar_t kClassName[] = L"_WwG";
4579   const CRect kWindowRect(434, 288, 1275, 824);
4580   const CPoint kClientOffset(0, 0);
4581   const CSize kClientSize(841, 536);
4582   const double kScaleFactor = 1.0;
4583 
4584   HWND hwnd = nullptr;
4585   LayoutManager layout_mgr(
4586       CreateDefaultGUIFontEmulator(),
4587       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4588                            kScaleFactor, &hwnd));
4589 
4590   ApplicationInfo app_info;
4591 
4592   AppInfoUtil::SetBasicApplicationInfo(
4593       &app_info, hwnd,
4594       ApplicationInfo::ShowSuggestWindow);
4595 
4596   AppInfoUtil::SetCompositionFont(
4597       &app_info, -14, 0, 2700, 2700, FW_NORMAL, SHIFTJIS_CHARSET,
4598       OUT_SCREEN_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS,
4599       DEFAULT_QUALITY, 17,
4600       "@MS 明朝");
4601 
4602   AppInfoUtil::SetCandidateForm(
4603       &app_info, CandidateForm::EXCLUDE, 662, 228,
4604       644, 130, 662, 697);
4605 
4606   AppInfoUtil::SetCompositionTarget(
4607       &app_info, 0, 1096, 474, 18, 434, 418, 1275, 985);
4608 
4609   AppInfoUtil::SetCaretInfo(&app_info, false, 644, 214, 645, 235, hwnd);
4610 
4611   CandidateWindowLayout layout;
4612   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
4613   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
4614       1078, 474, 1078, 474, 1096, 475, layout);
4615 }
4616 
4617 // MS Word 2010 x64, True Inline, Vertical
TEST_F(Win32RendererUtilTest,MSWord2010_Vertical_Convert)4618 TEST_F(Win32RendererUtilTest, MSWord2010_Vertical_Convert) {
4619   const wchar_t kClassName[] = L"_WwG";
4620   const CRect kWindowRect(434, 288, 1275, 824);
4621   const CPoint kClientOffset(0, 0);
4622   const CSize kClientSize(841, 536);
4623   const double kScaleFactor = 1.0;
4624 
4625   HWND hwnd = nullptr;
4626   LayoutManager layout_mgr(
4627       CreateDefaultGUIFontEmulator(),
4628       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4629                            kScaleFactor, &hwnd));
4630 
4631   ApplicationInfo app_info;
4632 
4633   AppInfoUtil::SetBasicApplicationInfo(
4634       &app_info, hwnd,
4635       ApplicationInfo::ShowCandidateWindow |
4636       ApplicationInfo::ShowSuggestWindow);
4637 
4638   AppInfoUtil::SetCompositionFont(
4639       &app_info, -14, 0, 2700, 2700, FW_NORMAL, SHIFTJIS_CHARSET,
4640       OUT_SCREEN_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS,
4641       DEFAULT_QUALITY, 17,
4642       "@MS 明朝");
4643 
4644   AppInfoUtil::SetCandidateForm(
4645       &app_info, CandidateForm::EXCLUDE, 661, 200,
4646       643, 130, 661, 697);
4647 
4648   AppInfoUtil::SetCompositionTarget(
4649       &app_info, 1, 1095, 488, 18, 434, 418, 1275, 985);
4650 
4651   AppInfoUtil::SetCaretInfo(&app_info, false, 643, 200, 644, 221, hwnd);
4652 
4653   CandidateWindowLayout layout;
4654   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
4655       app_info, &layout));
4656   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
4657       1077, 488, 1077, 418, 1095, 985, layout);
4658 }
4659 
4660 // Firefox 3.6.10 on Vista SP1 / textarea
TEST_F(Win32RendererUtilTest,Firefox_textarea_Suggest)4661 TEST_F(Win32RendererUtilTest, Firefox_textarea_Suggest) {
4662   const wchar_t kClassName[] = L"MozillaWindowClass";
4663   const CRect kWindowRect(198, 329, 1043, 1133);
4664   const CPoint kClientOffset(0, 0);
4665   const CSize kClientSize(845, 804);
4666   const double kScaleFactor = 1.0;
4667 
4668   HWND hwnd = nullptr;
4669   LayoutManager layout_mgr(
4670       CreateDefaultGUIFontEmulator(),
4671       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4672                            kScaleFactor, &hwnd));
4673 
4674   ApplicationInfo app_info;
4675 
4676   AppInfoUtil::SetBasicApplicationInfo(
4677       &app_info, hwnd,
4678       ApplicationInfo::ShowSuggestWindow);
4679 
4680   AppInfoUtil::SetCandidateForm(
4681       &app_info, CandidateForm::EXCLUDE, 44, 378, 44, 378, 44, 398);
4682 
4683   AppInfoUtil::SetCompositionTarget(
4684       &app_info, 0, 242, 707, 20, 198, 329, 1043, 1133);
4685 
4686   AppInfoUtil::SetCaretInfo(&app_info, false, 89, 378, 90, 398, hwnd);
4687 
4688   CandidateWindowLayout layout;
4689   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
4690   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
4691       242, 727, 242, 707, 242, 727, layout);
4692 }
4693 
4694 // Firefox 3.6.10 on Vista SP1 / textarea
TEST_F(Win32RendererUtilTest,Firefox_textarea_Convert)4695 TEST_F(Win32RendererUtilTest, Firefox_textarea_Convert) {
4696   const wchar_t kClassName[] = L"MozillaWindowClass";
4697   const CRect kWindowRect(198, 329, 1043, 1133);
4698   const CPoint kClientOffset(0, 0);
4699   const CSize kClientSize(845, 804);
4700   const double kScaleFactor = 1.0;
4701 
4702   HWND hwnd = nullptr;
4703   LayoutManager layout_mgr(
4704       CreateDefaultGUIFontEmulator(),
4705       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4706                            kScaleFactor, &hwnd));
4707 
4708   ApplicationInfo app_info;
4709 
4710   AppInfoUtil::SetBasicApplicationInfo(
4711       &app_info, hwnd,
4712       ApplicationInfo::ShowCandidateWindow |
4713       ApplicationInfo::ShowSuggestWindow);
4714 
4715   AppInfoUtil::SetCandidateForm(
4716       &app_info, CandidateForm::EXCLUDE, 59, 378, 59, 378, 59, 398);
4717 
4718   AppInfoUtil::SetCompositionTarget(
4719       &app_info, 1, 257, 707, 20, 198, 329, 1043, 1133);
4720 
4721   AppInfoUtil::SetCaretInfo(&app_info, false, 60, 378, 61, 398, hwnd);
4722 
4723   CandidateWindowLayout layout;
4724   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
4725       app_info, &layout));
4726   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
4727       257, 727, 257, 707, 257, 727, layout);
4728 }
4729 
4730 // Chrome 6.0.472.63 on Vista SP1 / textarea
TEST_F(Win32RendererUtilTest,Chrome_textarea_Suggest)4731 TEST_F(Win32RendererUtilTest, Chrome_textarea_Suggest) {
4732   const wchar_t kClassName[] = L"Chrome_RenderWidgetHostHWND";
4733   const CRect kWindowRect(153, 190, 891, 906);
4734   const CPoint kClientOffset(0, 0);
4735   const CSize kClientSize(738, 716);
4736   const double kScaleFactor = 1.0;
4737 
4738   HWND hwnd = nullptr;
4739   LayoutManager layout_mgr(
4740       CreateDefaultGUIFontEmulator(),
4741       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4742                            kScaleFactor, &hwnd));
4743 
4744   ApplicationInfo app_info;
4745 
4746   AppInfoUtil::SetBasicApplicationInfo(
4747       &app_info, hwnd,
4748       ApplicationInfo::ShowSuggestWindow);
4749 
4750   AppInfoUtil::SetCompositionFont(
4751       &app_info, 11, 0, 0, 0, FW_DONTCARE, SHIFTJIS_CHARSET,
4752       OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
4753       DEFAULT_QUALITY, 0,
4754       "メイリオ");
4755 
4756   AppInfoUtil::SetCandidateForm(
4757       &app_info, CandidateForm::EXCLUDE, 84, 424, 84, 424, 85, 444);
4758 
4759   AppInfoUtil::SetCaretInfo(&app_info, false, 84, 444, 85, 445, hwnd);
4760 
4761   CandidateWindowLayout layout;
4762   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
4763   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
4764       237, 614, 237, 614, 238, 634, layout);
4765 }
4766 
4767 // Chrome 6.0.472.63 on Vista SP1 / textarea
TEST_F(Win32RendererUtilTest,Chrome_textarea_Convert)4768 TEST_F(Win32RendererUtilTest, Chrome_textarea_Convert) {
4769   const wchar_t kClassName[] = L"Chrome_RenderWidgetHostHWND";
4770   const CRect kWindowRect(153, 190, 891, 906);
4771   const CPoint kClientOffset(0, 0);
4772   const CSize kClientSize(738, 716);
4773   const double kScaleFactor = 1.0;
4774 
4775   HWND hwnd = nullptr;
4776   LayoutManager layout_mgr(
4777       CreateDefaultGUIFontEmulator(),
4778       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4779                            kScaleFactor, &hwnd));
4780 
4781   ApplicationInfo app_info;
4782 
4783   AppInfoUtil::SetBasicApplicationInfo(
4784       &app_info, hwnd,
4785       ApplicationInfo::ShowCandidateWindow |
4786       ApplicationInfo::ShowSuggestWindow);
4787 
4788   AppInfoUtil::SetCompositionFont(
4789       &app_info, 11, 0, 0, 0, FW_DONTCARE, SHIFTJIS_CHARSET,
4790       OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
4791       DEFAULT_QUALITY, 0,
4792       "メイリオ");
4793 
4794   AppInfoUtil::SetCandidateForm(
4795       &app_info, CandidateForm::EXCLUDE, 58, 424, 58, 424, 59, 444);
4796 
4797   AppInfoUtil::SetCaretInfo(&app_info, false, 58, 444, 59, 445, hwnd);
4798 
4799   CandidateWindowLayout layout;
4800   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
4801       app_info, &layout));
4802   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
4803       211, 614, 211, 614, 212, 634, layout);
4804 }
4805 
4806 // Internet Explorer 8.0.6001.18943 on Vista SP1 / textarea
TEST_F(Win32RendererUtilTest,IE8_textarea_Suggest)4807 TEST_F(Win32RendererUtilTest, IE8_textarea_Suggest) {
4808   const wchar_t kClassName[] = L"Internet Explorer_Server";
4809   const CRect kWindowRect(304, 349, 1360, 1067);
4810   const CPoint kClientOffset(0, 0);
4811   const CSize kClientSize(1056, 718);
4812   const double kScaleFactor = 1.0;
4813 
4814   HWND hwnd = nullptr;
4815   LayoutManager layout_mgr(
4816       CreateDefaultGUIFontEmulator(),
4817       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4818                            kScaleFactor, &hwnd));
4819 
4820   ApplicationInfo app_info;
4821 
4822   AppInfoUtil::SetBasicApplicationInfo(
4823       &app_info, hwnd,
4824       ApplicationInfo::ShowSuggestWindow);
4825 
4826   AppInfoUtil::SetCandidateForm(
4827       &app_info, CandidateForm::EXCLUDE, 105, 376, 105, 356, 107, 376);
4828 
4829   AppInfoUtil::SetCaretInfo(&app_info, false, 105, 368, 106, 384, hwnd);
4830 
4831   CandidateWindowLayout layout;
4832   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
4833   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
4834       409, 735, 409, 717, 410, 735, layout);
4835 }
4836 
4837 // Internet Explorer 8.0.6001.18943 on Vista SP1 / textarea
TEST_F(Win32RendererUtilTest,IE8_textarea_Convert)4838 TEST_F(Win32RendererUtilTest, IE8_textarea_Convert) {
4839   const wchar_t kClassName[] = L"Internet Explorer_Server";
4840   const CRect kWindowRect(304, 349, 1360, 1067);
4841   const CPoint kClientOffset(0, 0);
4842   const CSize kClientSize(1056, 718);
4843   const double kScaleFactor = 1.0;
4844 
4845   HWND hwnd = nullptr;
4846   LayoutManager layout_mgr(
4847       CreateDefaultGUIFontEmulator(),
4848       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4849                            kScaleFactor, &hwnd));
4850 
4851   ApplicationInfo app_info;
4852 
4853   AppInfoUtil::SetBasicApplicationInfo(
4854       &app_info, hwnd,
4855       ApplicationInfo::ShowCandidateWindow |
4856       ApplicationInfo::ShowSuggestWindow);
4857 
4858   AppInfoUtil::SetCandidateForm(
4859       &app_info, CandidateForm::EXCLUDE, 91, 387, 91, 367, 93, 387);
4860 
4861   AppInfoUtil::SetCaretInfo(&app_info, false, 91, 379, 92, 380, hwnd);
4862 
4863   CandidateWindowLayout layout;
4864   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
4865       app_info, &layout));
4866   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
4867       395, 736, 395, 716, 397, 736, layout);
4868 }
4869 
4870 // Fudemame 21.  See b/3067011.
4871 // It provides no positional information for suggestion. See b/3067011.
TEST_F(Win32RendererUtilTest,Fudemame21_Suggest)4872 TEST_F(Win32RendererUtilTest, Fudemame21_Suggest) {
4873   const wchar_t kClassName[] = L"MrnDirectEdit4";
4874   const CRect kWindowRect(507, 588, 1024, 698);
4875   const CPoint kClientOffset(0, 0);
4876   const CSize kClientSize(517, 110);
4877   const double kScaleFactor = 1.0;
4878 
4879   HWND hwnd = nullptr;
4880   LayoutManager layout_mgr(
4881       CreateDefaultGUIFontEmulator(),
4882       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4883                            kScaleFactor, &hwnd));
4884 
4885   ApplicationInfo app_info;
4886 
4887   AppInfoUtil::SetBasicApplicationInfo(
4888       &app_info, hwnd,
4889       ApplicationInfo::ShowSuggestWindow);
4890 
4891   AppInfoUtil::SetCaretInfo(&app_info, false, 0, 0, 0, 0, nullptr);
4892 
4893   CandidateWindowLayout layout;
4894   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
4895   EXPECT_NON_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(507, 698, layout);
4896 }
4897 
4898 // Fudemame 21.  See b/3067011.
TEST_F(Win32RendererUtilTest,Fudemame19_Convert)4899 TEST_F(Win32RendererUtilTest, Fudemame19_Convert) {
4900   const wchar_t kClassName[] = L"MrnDirectEdit4";
4901   const CRect kWindowRect(507, 588, 1024, 698);
4902   const CPoint kClientOffset(0, 0);
4903   const CSize kClientSize(517, 110);
4904   const double kScaleFactor = 1.0;
4905 
4906   HWND hwnd = nullptr;
4907   LayoutManager layout_mgr(
4908       CreateDefaultGUIFontEmulator(),
4909       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4910                            kScaleFactor, &hwnd));
4911 
4912   ApplicationInfo app_info;
4913 
4914   AppInfoUtil::SetBasicApplicationInfo(
4915       &app_info, hwnd,
4916       ApplicationInfo::ShowCandidateWindow |
4917       ApplicationInfo::ShowSuggestWindow);
4918 
4919   AppInfoUtil::SetCandidateForm(
4920       &app_info, CandidateForm::CANDIDATEPOS, 87, 87, 0, 0, 0, 0);
4921 
4922   AppInfoUtil::SetCaretInfo(&app_info, false, 0, 0, 0, 0, nullptr);
4923 
4924   CandidateWindowLayout layout;
4925   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
4926       app_info, &layout));
4927   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
4928       594, 675, 594, 657, 595, 675, layout);
4929 }
4930 
4931 // Opera 10.63 (build 3516) / Textarea
TEST_F(Win32RendererUtilTest,Opera10_Suggest)4932 TEST_F(Win32RendererUtilTest, Opera10_Suggest) {
4933   const wchar_t kClassName[] = L"OperaWindowClass";
4934   const UINT kClassStyle = CS_DBLCLKS;
4935   const DWORD kWindowStyle =
4936       WS_CAPTION | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
4937       WS_SYSMENU | WS_THICKFRAME | WS_OVERLAPPED | WS_MINIMIZEBOX |
4938       WS_MAXIMIZEBOX;
4939   static_assert(kWindowStyle == 0x16cf0000, "Check actual value");
4940   const DWORD kWindowExStyle =
4941       WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR |
4942       WS_EX_ACCEPTFILES | WS_EX_WINDOWEDGE;
4943   static_assert(kWindowExStyle == 0x00000110, "Check actual value");
4944 
4945   const CRect kWindowRect(538, 229, 2114, 1271);
4946   const CPoint kClientOffset(8, 0);
4947   const CSize kClientSize(1560, 1034);
4948   const double kScaleFactor = 1.0;
4949 
4950   HWND hwnd = nullptr;
4951   LayoutManager layout_mgr(
4952       CreateDefaultGUIFontEmulator(),
4953       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4954                            kScaleFactor, &hwnd));
4955 
4956   ApplicationInfo app_info;
4957 
4958   AppInfoUtil::SetBasicApplicationInfo(
4959       &app_info, hwnd,
4960       ApplicationInfo::ShowSuggestWindow);
4961 
4962   AppInfoUtil::SetCandidateForm(
4963       &app_info, CandidateForm::EXCLUDE, 44, 444, 44, 444, 44, 459);
4964 
4965   AppInfoUtil::SetCaretInfo(&app_info, false, 44, 444, 667, 750, hwnd);
4966 
4967   CandidateWindowLayout layout;
4968   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
4969   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
4970       590, 673, 590, 673, 590, 688, layout);
4971 }
4972 
4973 // Opera 10.63 (build 3516) / Textarea
TEST_F(Win32RendererUtilTest,Opera10_Convert)4974 TEST_F(Win32RendererUtilTest, Opera10_Convert) {
4975   const wchar_t kClassName[] = L"OperaWindowClass";
4976   const UINT kClassStyle = CS_DBLCLKS;
4977   const DWORD kWindowStyle =
4978       WS_CAPTION | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
4979       WS_SYSMENU | WS_THICKFRAME | WS_OVERLAPPED | WS_MINIMIZEBOX |
4980       WS_MAXIMIZEBOX;
4981   static_assert(kWindowStyle == 0x16cf0000, "Check actual value");
4982   const DWORD kWindowExStyle =
4983       WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR |
4984       WS_EX_ACCEPTFILES | WS_EX_WINDOWEDGE;
4985   static_assert(kWindowExStyle == 0x00000110, "Check actual value");
4986 
4987   const CRect kWindowRect(538, 229, 2114, 1271);
4988   const CPoint kClientOffset(8, 0);
4989   const CSize kClientSize(1560, 1034);
4990   const double kScaleFactor = 1.0;
4991 
4992   HWND hwnd = nullptr;
4993   LayoutManager layout_mgr(
4994       CreateDefaultGUIFontEmulator(),
4995       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
4996                            kScaleFactor, &hwnd));
4997 
4998   ApplicationInfo app_info;
4999 
5000   AppInfoUtil::SetBasicApplicationInfo(
5001       &app_info, hwnd,
5002       ApplicationInfo::ShowCandidateWindow |
5003       ApplicationInfo::ShowSuggestWindow);
5004 
5005   AppInfoUtil::SetCandidateForm(
5006       &app_info, CandidateForm::EXCLUDE, 22, 444, 22, 444, 22, 459);
5007 
5008   AppInfoUtil::SetCaretInfo(&app_info, false, 22, 444, 645, 750, hwnd);
5009 
5010   CandidateWindowLayout layout;
5011   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
5012       app_info, &layout));
5013   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
5014       568, 673, 568, 673, 568, 688, layout);
5015 }
5016 
5017 // NTEmacs22 / GNU Emacs 22.2.1
5018 // Issue 5824433
TEST_F(Win32RendererUtilTest,Emacs22)5019 TEST_F(Win32RendererUtilTest, Emacs22) {
5020   const wchar_t kClassName[] = L"Emacs";
5021   const UINT kClassStyle = CS_VREDRAW | CS_HREDRAW;
5022   const DWORD kWindowStyle =
5023       WS_CAPTION | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
5024       WS_SYSMENU | WS_THICKFRAME | WS_OVERLAPPED | WS_MINIMIZEBOX |
5025       WS_MAXIMIZEBOX;
5026   static_assert(kWindowStyle == 0x16cf0000, "Check actual value");
5027   const DWORD kWindowExStyle =
5028       WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR |
5029       WS_EX_ACCEPTFILES | WS_EX_OVERLAPPEDWINDOW;
5030   static_assert(kWindowExStyle == 0x00000310, "Check actual value");
5031 
5032   const CRect kWindowRect(175, 175, 797, 924);
5033   const CPoint kClientOffset(10, 53);
5034   const CSize kClientSize(602, 686);
5035   const double kScaleFactor = 1.0;
5036 
5037   HWND hwnd = nullptr;
5038   LayoutManager layout_mgr(
5039       CreateDefaultGUIFontEmulator(),
5040       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
5041                            kScaleFactor, &hwnd));
5042 
5043   ApplicationInfo app_info;
5044 
5045   AppInfoUtil::SetBasicApplicationInfo(
5046       &app_info, hwnd,
5047       ApplicationInfo::ShowCompositionWindow |
5048       ApplicationInfo::ShowCandidateWindow |
5049       ApplicationInfo::ShowSuggestWindow);
5050 
5051   AppInfoUtil::SetCompositionFont(
5052       &app_info, -14, 0, 0, 0, FW_NORMAL, ANSI_CHARSET,
5053       OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
5054       DEFAULT_QUALITY, FIXED_PITCH,
5055       "Courier New");
5056 
5057   AppInfoUtil::SetCompositionForm(
5058       &app_info, CompositionForm::RECT, 66, 58,
5059       10, 42, 570, 658);
5060 
5061   AppInfoUtil::SetCaretInfo(&app_info, false, 66, 58, 67, 74, hwnd);
5062 
5063   CandidateWindowLayout layout;
5064   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
5065       app_info, &layout));
5066   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
5067       251, 302, 251, 286, 252, 302, layout);
5068 
5069   // This application automatically and frequently generates
5070   // WM_IME_CONTROL/IMC_SETCOMPOSITIONWINDOW even when a user is not
5071   // typing. So we need to show InfoList without delay.  b/5824433.
5072   const int mode = layout_mgr.GetCompatibilityMode(app_info);
5073   EXPECT_EQ(SHOW_INFOLIST_IMMEDIATELY, mode & SHOW_INFOLIST_IMMEDIATELY);
5074 }
5075 
5076 // Meadow 3.0 / GNU Emacs 22.3.1
5077 // Issue 5824433
TEST_F(Win32RendererUtilTest,Meadow3)5078 TEST_F(Win32RendererUtilTest, Meadow3) {
5079   const wchar_t kClassName[] = L"MEADOW";
5080   const UINT kClassStyle = CS_VREDRAW | CS_HREDRAW;
5081   const DWORD kWindowStyle =
5082       WS_CAPTION | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
5083       WS_SYSMENU | WS_THICKFRAME | WS_OVERLAPPED | WS_MINIMIZEBOX |
5084       WS_MAXIMIZEBOX;
5085   static_assert(kWindowStyle == 0x16cf0000, "Check actual value");
5086   const DWORD kWindowExStyle =
5087       WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR |
5088       WS_EX_ACCEPTFILES | WS_EX_OVERLAPPEDWINDOW;
5089   static_assert(kWindowExStyle == 0x00000310, "Check actual value");
5090 
5091   const CRect kWindowRect(175, 175, 797, 928);
5092   const CPoint kClientOffset(10, 53);
5093   const CSize kClientSize(602, 690);
5094   const double kScaleFactor = 1.0;
5095 
5096   HWND hwnd = nullptr;
5097   LayoutManager layout_mgr(
5098       CreateDefaultGUIFontEmulator(),
5099       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
5100                            kScaleFactor, &hwnd));
5101 
5102   ApplicationInfo app_info;
5103 
5104   AppInfoUtil::SetBasicApplicationInfo(
5105       &app_info, hwnd,
5106       ApplicationInfo::ShowCompositionWindow |
5107       ApplicationInfo::ShowCandidateWindow |
5108       ApplicationInfo::ShowSuggestWindow);
5109 
5110   AppInfoUtil::SetCompositionForm(
5111       &app_info, CompositionForm::RECT, 73, 65,
5112       9, 49, 577, 657);
5113 
5114   AppInfoUtil::SetCaretInfo(&app_info, false, 0, 0, 0, 0, hwnd);
5115 
5116   CandidateWindowLayout layout;
5117   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
5118       app_info, &layout));
5119   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
5120       258, 311, 258, 293, 259, 311, layout);
5121 
5122   // This application automatically and frequently generates
5123   // WM_IME_CONTROL/IMC_SETCOMPOSITIONWINDOW even when a user is not
5124   // typing. So we need to show InfoList without delay.  b/5824433.
5125   const int mode = layout_mgr.GetCompatibilityMode(app_info);
5126   EXPECT_EQ(SHOW_INFOLIST_IMMEDIATELY, mode & SHOW_INFOLIST_IMMEDIATELY);
5127 }
5128 
5129 // Firefox 47.0a1 (2016-02-28)
TEST_F(Win32RendererUtilTest,Firefox_ExcludeRect_Suggest)5130 TEST_F(Win32RendererUtilTest, Firefox_ExcludeRect_Suggest) {
5131   const wchar_t kClassName[] = L"MozillaWindowClass";
5132   const UINT kClassStyle = CS_DBLCLKS;
5133   const DWORD kWindowStyle =
5134     WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
5135   static_assert(kWindowStyle == 0x96000000, "Check actual value");
5136   const DWORD kWindowExStyle =
5137     WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
5138   static_assert(kWindowExStyle == 0x00000000, "Check actual value");
5139 
5140   const CRect kWindowRect(58, 22, 1210, 622);
5141   const CPoint kClientOffset(6, 0);
5142   const CSize kClientSize(1140, 594);
5143   const double kScaleFactor = 1.0;
5144 
5145   HWND hwnd = nullptr;
5146   LayoutManager layout_mgr(
5147       CreateDefaultGUIFontEmulator(),
5148       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
5149                            kScaleFactor, &hwnd));
5150 
5151   ApplicationInfo app_info;
5152 
5153   AppInfoUtil::SetBasicApplicationInfo(
5154       &app_info, hwnd,
5155       ApplicationInfo::ShowSuggestWindow);
5156 
5157   AppInfoUtil::SetCandidateForm(
5158       &app_info, CandidateForm::EXCLUDE, 22, 100, 22, 100, 37, 160);
5159 
5160   AppInfoUtil::SetCompositionTarget(
5161       &app_info, 0, 86, 122, 20, 83, 119, 109, 525);
5162 
5163   AppInfoUtil::SetCaretInfo(&app_info, false, 35, 140, 36, 160, hwnd);
5164 
5165   CandidateWindowLayout layout;
5166   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(
5167       app_info, &layout));
5168   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
5169       86, 142, 86, 122, 101, 182, layout);
5170 }
5171 
5172 // Firefox 47.0a1 (2016-02-28)
TEST_F(Win32RendererUtilTest,Firefox_ExcludeRect_Convert)5173 TEST_F(Win32RendererUtilTest, Firefox_ExcludeRect_Convert) {
5174   const wchar_t kClassName[] = L"MozillaWindowClass";
5175   const UINT kClassStyle = CS_DBLCLKS;
5176   const DWORD kWindowStyle =
5177       WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
5178   static_assert(kWindowStyle == 0x96000000, "Check actual value");
5179   const DWORD kWindowExStyle =
5180       WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
5181   static_assert(kWindowExStyle == 0x00000000, "Check actual value");
5182 
5183   const CRect kWindowRect(58, 22, 1210, 622);
5184   const CPoint kClientOffset(6, 0);
5185   const CSize kClientSize(1140, 594);
5186   const double kScaleFactor = 1.0;
5187 
5188   HWND hwnd = nullptr;
5189   LayoutManager layout_mgr(
5190       CreateDefaultGUIFontEmulator(),
5191       CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
5192                            kScaleFactor, &hwnd));
5193 
5194   ApplicationInfo app_info;
5195 
5196   AppInfoUtil::SetBasicApplicationInfo(
5197       &app_info, hwnd,
5198       ApplicationInfo::ShowCandidateWindow |
5199       ApplicationInfo::ShowSuggestWindow);
5200 
5201   AppInfoUtil::SetCandidateForm(
5202       &app_info, CandidateForm::EXCLUDE, 22, 100, 22, 100, 37, 160);
5203 
5204   AppInfoUtil::SetCompositionTarget(
5205       &app_info, 0, 86, 122, 20, 83, 119, 109, 525);
5206 
5207   AppInfoUtil::SetCaretInfo(&app_info, false, 35, 140, 36, 160, hwnd);
5208 
5209   CandidateWindowLayout layout;
5210   EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
5211       app_info, &layout));
5212   EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
5213       86, 142, 86, 122, 101, 182, layout);
5214 }
5215 
5216 }  // namespace win32
5217 }  // namespace renderer
5218 }  // namespace mozc
5219