blob: be951c4a427e26f7c94b3f0675b4eca7be82de36 [file] [log] [blame]
// Copyright 2010-2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <Shlwapi.h>
#define _ATL_NO_AUTOMATIC_NAMESPACE
#define _WTL_NO_AUTOMATIC_NAMESPACE
#include <atlbase.h>
#include <atlapp.h>
#include <atlgdi.h>
#include <atlmisc.h>
#include "base/logging.h"
#include "base/mmap.h"
#include "base/util.h"
#include "base/win_font_test_helper.h"
#include "renderer/renderer_command.pb.h"
#include "renderer/win32/win32_font_util.h"
#include "renderer/win32/win32_renderer_util.h"
#include "testing/base/public/gunit.h"
// Following functions should be placed in global namespace for Koenig look-up
// trick used in GTest.
void PrintTo(const POINT &point, ::std::ostream* os) {
*os << "(" << point.x << ", " << point.y << ")";
}
void PrintTo(const RECT &rect, ::std::ostream* os) {
*os << "(" << rect.left << ", " << rect.top << ", " << rect.right << ", "
<< rect.bottom << ")";
}
namespace WTL {
// These functions should be placed in WTL namespace for Koenig look-up
// trick used in GTest.
void PrintTo(const CPoint &point, ::std::ostream* os) {
*os << "(" << point.x << ", " << point.y << ")";
}
void PrintTo(const CRect &rect, ::std::ostream* os) {
*os << "(" << rect.left << ", " << rect.top << ", " << rect.right << ", "
<< rect.bottom << ")";
}
} // namespace WTL
namespace mozc {
namespace renderer {
namespace win32 {
typedef mozc::commands::Annotation Annotation;
typedef mozc::commands::CandidateList CandidateList;
typedef mozc::commands::CandidateWord CandidateWord;
typedef mozc::commands::Candidates Candidates;
typedef mozc::commands::Candidates::Candidate Candidate;
typedef mozc::commands::Footer Footer;
typedef mozc::commands::Output Output;
typedef mozc::commands::Preedit Preedit;
typedef mozc::commands::Preedit_Segment Segment;
typedef mozc::commands::RendererCommand RendererCommand;
typedef mozc::commands::RendererCommand_ApplicationInfo ApplicationInfo;
typedef mozc::commands::RendererCommand_CandidateForm CandidateForm;
typedef mozc::commands::RendererCommand_CaretInfo CaretInfo;
typedef mozc::commands::RendererCommand_CharacterPosition CharacterPosition;
typedef mozc::commands::RendererCommand_CompositionForm CompositionForm;
typedef mozc::commands::RendererCommand_Point Point;
typedef mozc::commands::RendererCommand_Rectangle Rectangle;
typedef mozc::commands::RendererCommand_WinLogFont WinLogFont;
typedef mozc::commands::Status Status;
namespace {
using WTL::CDC;
using WTL::CFont;
using WTL::CFontHandle;
using WTL::CLogFont;
using WTL::CPoint;
using WTL::CRect;
using WTL::CSize;
using WTL::PrintTo;
const int kDefaultFontHeightInPixel = 18;
const wchar_t kWindowClassName[] = L"Mozc: Default Window Class Name";
#define EXPECT_COMPOSITION_WINDOW_LAYOUT( \
window_pos_left, window_pos_top, window_pos_right, window_pos_bottom, \
text_left, text_top, text_right, text_bottom, base_x, base_y, \
caret_left, caret_top, caret_right, caret_bottom, font, window_layout) \
do { \
EXPECT_EQ(CRect((window_pos_left), (window_pos_top), \
(window_pos_right), (window_pos_bottom)), \
(window_layout).window_position_in_screen_coordinate); \
EXPECT_EQ((font), layout.log_font); \
EXPECT_EQ(CRect((text_left), (text_top), \
(text_right), (text_bottom)), \
(window_layout).text_area); \
EXPECT_EQ(CPoint((base_x), (base_y)), (window_layout).base_position); \
EXPECT_EQ(CRect((caret_left), (caret_top), \
(caret_right), (caret_bottom)), \
(window_layout).caret_rect); \
} while (false)
#define EXPECT_NON_EXCLUDE_CANDIDATE_WINDOW_LAYOUT( \
target_x, target_y, layout) \
do { \
EXPECT_TRUE((layout).initialized()); \
EXPECT_FALSE((layout).has_exclude_region()); \
EXPECT_EQ(CPoint((target_x), (target_y)), (layout).position()); \
} while (false)
#define EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT( \
target_x, target_y, exclude_rect_left, exclude_rect_top, \
exclude_rect_right, exclude_rect_bottom, layout) \
do { \
EXPECT_TRUE((layout).initialized()); \
EXPECT_TRUE((layout).has_exclude_region()); \
EXPECT_EQ(CPoint((target_x), (target_y)), (layout).position()); \
EXPECT_EQ(CRect((exclude_rect_left), (exclude_rect_top), \
(exclude_rect_right), (exclude_rect_bottom)), \
(layout).exclude_region()); \
} while (false)
WindowPositionEmulator *CreateWindowEmulator(
const wstring &class_name, const RECT &window_rect,
const POINT &client_area_offset, const SIZE &client_area_size,
double scale_factor, HWND *hwnd) {
WindowPositionEmulator *emulator = WindowPositionEmulator::Create();
*hwnd = emulator->RegisterWindow(
class_name, window_rect, client_area_offset,
client_area_size, scale_factor);
return emulator;
}
WindowPositionEmulator *CreateWindowEmulatorWithDPIScaling(
double scale_factor, HWND *hwnd) {
const CPoint kClientOffset(8, 42);
const CSize kClientSize(2000, 1000);
const CRect kWindowRect(500, 500, 2516, 1550);
return CreateWindowEmulator(kWindowClassName, kWindowRect,
kClientOffset, kClientSize, scale_factor, hwnd);
}
WindowPositionEmulator *CreateWindowEmulatorWithClassName(
const wstring &class_name, HWND *hwnd) {
const CPoint kClientOffset(8, 42);
const CSize kClientSize(2000, 1000);
const CRect kWindowRect(500, 500, 2516, 1550);
const double kScaleFactor = 1.0;
return CreateWindowEmulator(class_name, kWindowRect,
kClientOffset, kClientSize, kScaleFactor, hwnd);
}
class AppInfoUtil {
public:
static void SetBasicApplicationInfo(
ApplicationInfo *app_info, HWND hwnd, int visibility) {
app_info->set_ui_visibilities(visibility);
app_info->set_process_id(1234);
app_info->set_thread_id(5678);
app_info->set_target_window_handle(
reinterpret_cast<uint32>(hwnd));
app_info->set_input_framework(ApplicationInfo::IMM32);
}
static void 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) {
WinLogFont *font = app_info->mutable_composition_font();
font->set_height(height);
font->set_width(width);
font->set_escapement(escapement);
font->set_orientation(orientation);
font->set_weight(weight);
font->set_italic(false);
font->set_underline(false);
font->set_strike_out(false);
font->set_char_set(char_set);
font->set_out_precision(out_precision);
font->set_clip_precision(clip_precision);
font->set_quality(quality);
font->set_pitch_and_family(pitch_and_family);
font->set_face_name(face_name);
}
static void SetCompositionForm(
ApplicationInfo *app_info, uint32 style_bits,
int x, int y, int left, int top, int right, int bottom) {
CompositionForm *form = app_info->mutable_composition_form();
form->set_style_bits(style_bits);
Point *current_position = form->mutable_current_position();
Rectangle *area = form->mutable_area();
current_position->set_x(x);
current_position->set_y(y);
area->set_left(left);
area->set_top(top);
area->set_right(right);
area->set_bottom(bottom);
}
static void SetCandidateForm(
ApplicationInfo *app_info, uint32 style_bits,
int x, int y, int left, int top, int right, int bottom) {
CandidateForm *form = app_info->mutable_candidate_form();
form->set_style_bits(style_bits);
Point *current_pos = form->mutable_current_position();
current_pos->set_x(x);
current_pos->set_y(y);
Rectangle *area = form->mutable_area();
area->set_left(left);
area->set_top(top);
area->set_right(right);
area->set_bottom(bottom);
}
static void SetCaretInfo(
ApplicationInfo *app_info, bool blinking, int left, int top,
int right, int bottom, HWND target_window_handle) {
CaretInfo *info = app_info->mutable_caret_info();
info->set_blinking(blinking);
info->set_target_window_handle(
reinterpret_cast<uint32>(target_window_handle));
Rectangle *rect = info->mutable_caret_rect();
rect->set_left(left);
rect->set_top(top);
rect->set_right(right);
rect->set_bottom(bottom);
}
static void SetCompositionTarget(
ApplicationInfo *app_info, int position, int x, int y,
uint32 line_height, int left, int top, int right, int bottom) {
CharacterPosition *char_pos = app_info->mutable_composition_target();
char_pos->set_position(position);
char_pos->mutable_top_left()->set_x(x);
char_pos->mutable_top_left()->set_y(y);
char_pos->set_line_height(line_height);
Rectangle *area = char_pos->mutable_document_area();
area->set_left(left);
area->set_top(top);
area->set_right(right);
area->set_bottom(bottom);
}
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(AppInfoUtil);
};
} // namespace
class Win32RendererUtilTest : public testing::Test {
public:
static string GetMonospacedFontFaceForTest() {
return WinFontTestHelper::GetIPAexGothicFontName();
}
static string GetPropotionalFontFaceForTest() {
return WinFontTestHelper::GetIPAexMinchoFontName();
}
static CLogFont GetFont(bool is_proportional, bool is_vertical) {
wstring font_face;
Util::UTF8ToWide((is_proportional ? GetPropotionalFontFaceForTest()
: GetMonospacedFontFaceForTest()),
&font_face);
if (is_vertical) {
font_face = L"@" + font_face;
}
CLogFont font;
font.lfWeight = FW_NORMAL;
font.lfCharSet = DEFAULT_CHARSET;
// We use negative value here to specify absolute font height in pixel,
// assuming the mapping mode is MM_TEXT.
// http://msdn.microsoft.com/en-us/library/ms901140.aspx
font.lfHeight = -kDefaultFontHeightInPixel;
const errno_t error = wcscpy_s(font.lfFaceName, font_face.c_str());
CHECK_EQ(0, error) << "wcscpy_s failed";
if (is_vertical) {
// 2700 means the text grows from top to bottom.
font.lfEscapement = 2700;
font.lfOrientation = 2700;
}
return font;
}
static SystemPreferenceInterface *CreateDefaultGUIFontEmulator() {
CLogFont font = GetFont(true, false);
font.lfHeight = 18;
font.lfWidth = 0;
return SystemPreferenceFactory::CreateMock(font);
}
static wstring GetTestMessageWithCompositeGlyph(int num_repeat) {
wstring message;
for (size_t i = 0; i < num_repeat; ++i) {
// "ぱ"
message += L'\u3071';
message += L'\u309a';
}
return message;
}
static wstring GetTestMessageForMonospaced() {
wstring w_path;
// "熊本県阿蘇郡南阿蘇村大字中松南阿蘇水の生まれる里白水高原駅"
const char kMessage[] =
"\xe7\x86\x8a\xe6\x9c\xac\xe7\x9c\x8c\xe9\x98\xbf\xe8\x98\x87\xe9\x83"
"\xa1\xe5\x8d\x97\xe9\x98\xbf\xe8\x98\x87\xe6\x9d\x91\xe5\xa4\xa7\xe5"
"\xad\x97\xe4\xb8\xad\xe6\x9d\xbe\xe5\x8d\x97\xe9\x98\xbf\xe8\x98\x87"
"\xe6\xb0\xb4\xe3\x81\xae\xe7\x94\x9f\xe3\x81\xbe\xe3\x82\x8c\xe3\x82"
"\x8b\xe9\x87\x8c\xe7\x99\xbd\xe6\xb0\xb4\xe9\xab\x98\xe5\x8e\x9f\xe9"
"\xa7\x85";
wstring w_message;
Util::UTF8ToWide(kMessage, &w_message);
return w_message;
}
static wstring GetTestMessageForProportional() {
wstring w_path;
// "This open-source project originates from Google 日本語入力."
const char kMessage[] =
"This open-source project originates from Google "
"\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e\xe5\x85\xa5\xe5\x8a\x9b.";
wstring w_message;
Util::UTF8ToWide(kMessage, &w_message);
return w_message;
}
// Initializes |command| for unit test. Parameters to be set are based on
// an actual application which supports both horizontal and vertical writing.
static void SetRenderereCommandForTest(
bool use_proportional_font, bool has_candidates,
bool is_vertical, int cursor_offset, HWND hwnd,
RendererCommand *command) {
command->Clear();
command->set_type(RendererCommand::UPDATE);
command->set_visible(true);
{
Output *output = command->mutable_output();
output->set_id(123456789);
output->set_mode(commands::HIRAGANA);
output->set_consumed(true);
Preedit *preedit = output->mutable_preedit();
preedit->set_cursor(22);
{
Segment *segment = preedit->add_segment();
segment->set_annotation(Segment::UNDERLINE);
// "これは"
segment->set_value("\343\201\223\343\202\214\343\201\257");
segment->set_value_length(3);
// "これは"
segment->set_key(
"\343\201\223\343\202\214\343\201\257");
}
{
Segment *segment = preedit->add_segment();
segment->set_annotation(Segment::UNDERLINE);
// "、"
segment->set_value("\343\200\201");
segment->set_value_length(1);
// "、"
segment->set_key("\343\200\201");
}
{
Segment *segment = preedit->add_segment();
segment->set_annotation(Segment::HIGHLIGHT);
// "Google"
segment->set_value("Google");
segment->set_value_length(6);
// "Google"
segment->set_key("Google");
}
{
Segment *segment = preedit->add_segment();
segment->set_annotation(Segment::UNDERLINE);
// "日本語入力の"
segment->set_value("\346\227\245\346\234\254\350\252\236"
"\345\205\245\345\212\233\343\201\256");
segment->set_value_length(6);
// "にほんごにゅうりょくの"
segment->set_key(
"\343\201\253\343\201\273\343\202\223\343\201\224\343\201\253\343"
"\202\205\343\201\206\343\202\212\343\202\207\343\201\217\343\201"
"\256");
}
{
Segment *segment = preedit->add_segment();
segment->set_annotation(Segment::UNDERLINE);
// "Testです"
segment->set_value("Test\343\201\247\343\201\231");
segment->set_value_length(6);
// "Testです"
segment->set_key("Test\343\201\247\343\201\231");
}
preedit->set_highlighted_position(3);
if (has_candidates) {
Candidates *candidates = output->mutable_candidates();
candidates->set_focused_index(0);
candidates->set_size(2);
{
Candidate *candidate = candidates->add_candidate();
candidate->set_index(0);
// "Google"
candidate->set_value(
"Google");
Annotation *annotation = candidate->mutable_annotation();
// "[半] アルファベット"
annotation->set_description(
"[\345\215\212] \343\202\242\343\203\253\343\203\225\343\202\241"
"\343\203\231\343\203\203\343\203\210\202\277\343\202\253\343"
"\203\212");
annotation->set_shortcut("1");
candidate->set_id(0);
}
{
Candidate *candidate = candidates->add_candidate();
candidate->set_index(1);
// "そのほかの文字種"
candidate->set_value(
"\343\201\235\343\201\256\343\201\273\343\201\213"
"\343\201\256\346\226\207\345\255\227\347\250\256");
Annotation *annotation = candidate->mutable_annotation();
annotation->set_shortcut("2");
candidate->set_id(-11);
}
candidates->set_position(4);
candidates->set_category(commands::CONVERSION);
candidates->set_display_type(commands::MAIN);
Footer *footer = candidates->mutable_footer();
footer->set_index_visible(true);
footer->set_logo_visible(true);
footer->set_sub_label("build 000");
}
}
SetApplicationInfoForTest(
use_proportional_font, is_vertical, cursor_offset, hwnd, command);
}
// Initializes |command| for unit test. Parameters to be set are based on
// an actual application which supports both horizontal and vertical writing.
static void SetRenderereCommandForSuggestTest(
bool use_proportional_font, bool is_vertical, int cursor_offset,
HWND hwnd, RendererCommand *command) {
command->Clear();
command->set_type(RendererCommand::UPDATE);
command->set_visible(true);
{
Output *output = command->mutable_output();
output->set_id(123456789);
output->set_mode(commands::HIRAGANA);
output->set_consumed(true);
{
Preedit *preedit = output->mutable_preedit();
preedit->set_cursor(7);
{
Segment *segment = preedit->add_segment();
segment->set_annotation(Segment::UNDERLINE);
// "ねこを"
// "かいたい"
segment->set_value(
"\343\201\255\343\201\223\343\202\222"
"\343\201\213\343\201\204\343\201\237\343\201\204");
segment->set_value_length(7);
// "ねこを"
// "かいたい"
segment->set_key(
"\343\201\255\343\201\223\343\202\222"
"\343\201\213\343\201\204\343\201\237\343\201\204");
}
}
{
Candidates *candidates = output->mutable_candidates();
candidates->set_size(1);
{
Candidate *candidate = candidates->add_candidate();
candidate->set_index(0);
// "猫を"
// "飼いたい"
candidate->set_value(
"\347\214\253\343\202\222"
"\351\243\274\343\201\204\343\201\237\343\201\204");
{
Annotation *annotation = candidate->mutable_annotation();
annotation->set_description("Real-time Conversion");
candidate->set_id(0);
}
}
candidates->set_position(0);
candidates->set_category(commands::SUGGESTION);
candidates->set_display_type(commands::MAIN);
{
Footer *footer = candidates->mutable_footer();
footer->set_sub_label("build 754");
}
}
}
SetApplicationInfoForTest(
use_proportional_font, is_vertical, cursor_offset, hwnd, command);
}
// Initializes |command| for unit tests of caret. Parameters to be set are
// based on an actual application which supports both horizontal and vertical
// writing.
static void SetRenderereCommandForCaretTest(
bool use_proportional_font, bool is_vertical, int num_characters,
int cursor_position_in_preedit, int cursor_offset, HWND hwnd,
RendererCommand *command) {
command->Clear();
command->set_type(RendererCommand::UPDATE);
command->set_visible(true);
{
Output *output = command->mutable_output();
output->set_id(123456789);
output->set_mode(commands::HIRAGANA);
output->set_consumed(true);
Preedit *preedit = output->mutable_preedit();
preedit->set_cursor(cursor_position_in_preedit);
{
Segment *segment = preedit->add_segment();
segment->set_annotation(Segment::UNDERLINE);
string value;
for (size_t i = 0; i < num_characters; ++i) {
// "あ"
value.append("\343\201\202");
}
segment->set_value(value);
segment->set_value_length(num_characters);
segment->set_key(value);
}
}
SetApplicationInfoForTest(
use_proportional_font, is_vertical, cursor_offset, hwnd, command);
}
// Initializes |command| for unit tests of caret. Parameters to be set are
// based on an actual application which supports both horizontal and vertical
// writing.
static void SetRenderereCommandForSurrogatePair(
bool use_proportional_font, bool is_vertical, int cursor_offset,
HWND hwnd, RendererCommand *command) {
command->Clear();
command->set_type(RendererCommand::UPDATE);
command->set_visible(true);
{
Output *output = command->mutable_output();
output->set_id(123456789);
output->set_mode(commands::HIRAGANA);
output->set_consumed(true);
{
Preedit *preedit = output->mutable_preedit();
preedit->set_cursor(8);
{
Segment *segment = preedit->add_segment();
segment->set_annotation(Segment::UNDERLINE);
// "𠮟咤"
segment->set_value("\360\240\256\237\345\222\244");
segment->set_value_length(2);
// "しった"
segment->set_key("\343\201\227\343\201\243\343\201\237");
}
{
Segment *segment = preedit->add_segment();
segment->set_annotation(Segment::UNDERLINE);
// "𠮟咤"
segment->set_value("\360\240\256\237\345\222\244");
segment->set_value_length(2);
// "しった"
segment->set_key("\343\201\227\343\201\243\343\201\237");
}
{
Segment *segment = preedit->add_segment();
segment->set_annotation(Segment::HIGHLIGHT);
// "𠮟咤"
segment->set_value("\360\240\256\237\345\222\244");
segment->set_value_length(2);
// "しった"
segment->set_key("\343\201\227\343\201\243\343\201\237");
}
{
Segment *segment = preedit->add_segment();
segment->set_annotation(Segment::UNDERLINE);
// "𠮟咤"
segment->set_value("\360\240\256\237\345\222\244");
segment->set_value_length(2);
// "しった"
segment->set_key("\343\201\227\343\201\243\343\201\237");
}
preedit->set_highlighted_position(4);
}
{
Candidates *candidates = output->mutable_candidates();
candidates->set_focused_index(0);
candidates->set_size(5);
{
Candidate *candidate = candidates->add_candidate();
candidate->set_index(0);
// "𠮟咤"
candidate->set_value("\360\240\256\237\345\222\244");
{
Annotation *annotation = candidate->mutable_annotation();
annotation->set_shortcut("1");
}
candidate->set_id(0);
}
{
Candidate *candidate = candidates->add_candidate();
candidate->set_index(1);
// "知った"
candidate->set_value("\347\237\245\343\201\243\343\201\237");
{
Annotation *annotation = candidate->mutable_annotation();
annotation->set_shortcut("2");
}
candidate->set_id(1);
}
{
Candidate *candidate = candidates->add_candidate();
candidate->set_index(2);
// "しった"
candidate->set_value("\347\237\245\343\201\243\343\201\237");
{
Annotation *annotation = candidate->mutable_annotation();
// "ひらがな"
annotation->set_description(
"\343\201\262\343\202\211\343\201\214\343\201\252");
annotation->set_shortcut("3");
}
candidate->set_id(2);
}
{
Candidate *candidate = candidates->add_candidate();
candidate->set_index(3);
// "しった"
candidate->set_value("\347\237\245\343\201\243\343\201\237");
{
Annotation *annotation = candidate->mutable_annotation();
// "[全] カタカナ"
annotation->set_description(
"[\345\205\250] "
"\343\202\253\343\202\277\343\202\253\343\203\212");
annotation->set_shortcut("4");
}
candidate->set_id(4);
}
{
Candidate *candidate = candidates->add_candidate();
candidate->set_index(4);
// "そのほかの文字種"
candidate->set_value(
"\343\201\235\343\201\256\343\201\273\343\201\213"
"\343\201\256\346\226\207\345\255\227\347\250\256");
{
Annotation *annotation = candidate->mutable_annotation();
annotation->set_shortcut("5");
}
candidate->set_id(-1);
}
candidates->set_position(4);
candidates->set_category(commands::CONVERSION);
candidates->set_display_type(commands::MAIN);
{
Footer *footer = candidates->mutable_footer();
footer->set_index_visible(true);
footer->set_logo_visible(true);
footer->set_sub_label("build 670");
}
}
{
Status *status = output->mutable_status();
status->set_activated(true);
status->set_mode(commands::HIRAGANA);
}
{
CandidateList *all_candidate_words =
output->mutable_all_candidate_words();
all_candidate_words->set_focused_index(0);
{
CandidateWord *candidate_word =
all_candidate_words->add_candidates();
candidate_word->set_id(0);
candidate_word->set_index(0);
// "𠮟咤"
candidate_word->set_value("\360\240\256\237\345\222\244");
}
{
CandidateWord *candidate_word =
all_candidate_words->add_candidates();
candidate_word->set_id(1);
candidate_word->set_index(1);
// "知った"
candidate_word->set_value("\347\237\245\343\201\243\343\201\237");
}
{
CandidateWord *candidate_word =
all_candidate_words->add_candidates();
candidate_word->set_id(2);
candidate_word->set_index(2);
// "しっ"
candidate_word->set_key("\343\201\227\343\201\243");
// "しった"
candidate_word->set_value("\343\201\227\343\201\243\343\201\237");
}
{
CandidateWord *candidate_word =
all_candidate_words->add_candidates();
candidate_word->set_id(4);
candidate_word->set_index(3);
// "シッタ"
candidate_word->set_value("\343\202\267\343\203\203\343\202\277");
}
{
CandidateWord *candidate_word =
all_candidate_words->add_candidates();
candidate_word->set_id(-1);
candidate_word->set_index(4);
// "しった"
candidate_word->set_value("\343\201\227\343\201\243\343\201\237");
}
{
CandidateWord *candidate_word =
all_candidate_words->add_candidates();
candidate_word->set_id(-2);
candidate_word->set_index(5);
// "シッタ"
candidate_word->set_value("\343\202\267\343\203\203\343\202\277");
}
{
CandidateWord *candidate_word =
all_candidate_words->add_candidates();
candidate_word->set_id(-3);
candidate_word->set_index(6);
candidate_word->set_value("shitta");
}
{
CandidateWord *candidate_word =
all_candidate_words->add_candidates();
candidate_word->set_id(-4);
candidate_word->set_index(7);
candidate_word->set_value("SHITTA");
}
{
CandidateWord *candidate_word =
all_candidate_words->add_candidates();
candidate_word->set_id(-6);
candidate_word->set_index(8);
candidate_word->set_value("Shitta");
}
{
CandidateWord *candidate_word =
all_candidate_words->add_candidates();
candidate_word->set_id(-7);
candidate_word->set_index(9);
// "shitta"
candidate_word->set_value("\357\275\223\357\275\210\357\275\211"
"\357\275\224\357\275\224\357\275\201");
}
{
CandidateWord *candidate_word =
all_candidate_words->add_candidates();
candidate_word->set_id(-8);
candidate_word->set_index(10);
// "SHITTA"
candidate_word->set_value("\357\274\263\357\274\250\357\274\251"
"\357\274\264\357\274\264\357\274\241");
}
{
CandidateWord *candidate_word =
all_candidate_words->add_candidates();
candidate_word->set_id(-10);
candidate_word->set_index(11);
// "Shitta"
candidate_word->set_value("\357\274\263\357\275\210\357\275\211"
"\357\275\224\357\275\224\357\275\201");
}
{
CandidateWord *candidate_word =
all_candidate_words->add_candidates();
candidate_word->set_id(-11);
candidate_word->set_index(12);
// "シッタ"
candidate_word->set_value("\357\275\274\357\275\257\357\276\200");
}
all_candidate_words->set_category(commands::CONVERSION);
}
}
SetApplicationInfoForTest(
use_proportional_font, is_vertical, cursor_offset, hwnd, command);
}
// Verification of changes for b/3200425.
static void VerifyCompositionStyleBitsCompatibilityForIssue3200425(
bool use_deprecated_style, CompositionForm::Style style,
bool use_new_style, uint32 style_bits) {
const int kCursorOffsetX = 0;
RendererCommand command;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
// w/ candidates, monospaced, horizontal
SetRenderereCommandForTest(
false, true, false, kCursorOffsetX, hwnd, &command);
if (use_deprecated_style) {
command.mutable_application_info()->mutable_composition_form()
->set_deprecated_style(style);
} else {
command.mutable_application_info()->mutable_composition_form()
->clear_deprecated_style();
}
if (use_new_style) {
command.mutable_application_info()->mutable_composition_form()
->set_style_bits(style_bits);
} else {
command.mutable_application_info()->mutable_composition_form()
->clear_style_bits();
}
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(2, layouts.size());
// The first line
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1868, 599, 2003, 648, 0, 0, 135, 49,
0, 0, 0, 0, 0, 0, logfont, layout);
{
// "これは"
const char kMsg[] = "\343\201\223\343\202\214\343\201\257";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(1, layout.marker_layouts.size());
EXPECT_EQ(CPoint(0, 48), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(126, 48), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
}
// The second line
{
const CompositionWindowLayout &layout = layouts.at(1);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1193, 648, 1840, 697, 0, 0, 646, 49,
0, 0, 646, 0, 647, 49, logfont, layout);
{
// "、Google日本語入力のTestです"
const char kMsg[] =
"\343\200\201Google\346\227\245\346\234\254\350\252\236\345\205\245"
"\345\212\233\343\201\256Test\343\201\247\343\201\231";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(4, layout.marker_layouts.size());
EXPECT_EQ(CPoint(0, 48), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(36, 48), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(45, 48), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(190, 48), layout.marker_layouts[1].to);
EXPECT_TRUE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(196, 48), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(457, 48), layout.marker_layouts[2].to);
EXPECT_FALSE(layout.marker_layouts[2].highlighted);
EXPECT_EQ(CPoint(466, 48), layout.marker_layouts[3].from);
EXPECT_EQ(CPoint(646, 48), layout.marker_layouts[3].to);
EXPECT_FALSE(layout.marker_layouts[3].highlighted);
}
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1238, 697, 1238, 648, 1839, 697, candidate_layout);
// Check other candidate positions.
command.mutable_output()->mutable_candidates()->set_position(0);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1868, 648, 1868, 599, 2003, 648, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(3);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1193, 697, 1193, 648, 1839, 697, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(10);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1389, 697, 1389, 648, 1839, 697, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(16);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1659, 697, 1659, 648, 1839, 697, candidate_layout);
// w/o candidates, monospaced, horizontal
SetRenderereCommandForTest(false, false, false, 0, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
EXPECT_FALSE(candidate_layout.initialized());
}
protected:
static void SetUpTestCase() {
// On Windows XP, the availability of typical Japanese fonts such are as
// MS Gothic depends on the language edition and language packs.
// So we will register a private font for unit test.
EXPECT_TRUE(WinFontTestHelper::Initialize());
}
static void TearDownTestCase() {
// Free private fonts although the system automatically frees them when
// this process is terminated.
WinFontTestHelper::Uninitialize();
}
private:
static void SetApplicationInfoForTest(
bool use_proportional_font, bool is_vertical, int cursor_offset,
HWND hwnd, RendererCommand *command) {
ApplicationInfo *app = command->mutable_application_info();
app->set_process_id(1234);
app->set_thread_id(5678);
app->set_target_window_handle(reinterpret_cast<uint32>(hwnd));
WinLogFont *font = app->mutable_composition_font();
font->set_height(-45);
font->set_width(0);
font->set_escapement(0);
font->set_orientation(0);
font->set_weight(FW_NORMAL);
font->set_italic(false);
font->set_underline(false);
font->set_strike_out(false);
font->set_char_set(SHIFTJIS_CHARSET);
font->set_out_precision(0);
font->set_clip_precision(0);
font->set_quality(0);
if (use_proportional_font) {
// Use proportional font
font->set_pitch_and_family(VARIABLE_PITCH | FF_ROMAN | FF_SWISS);
font->set_face_name(GetPropotionalFontFaceForTest());
} else {
// Use monospaced font
font->set_pitch_and_family(FIXED_PITCH | FF_ROMAN | FF_SWISS);
font->set_face_name(GetMonospacedFontFaceForTest());
}
if (is_vertical) {
font->set_escapement(2700);
font->set_face_name("@" + font->face_name());
}
app->set_input_framework(ApplicationInfo::IMM32);
{
CompositionForm *composition_form = app->mutable_composition_form();
composition_form->set_style_bits(CompositionForm::RECT);
Point *current_position = composition_form->mutable_current_position();
Rectangle *area = composition_form->mutable_area();
if (is_vertical) {
current_position->set_x(1526);
current_position->set_y(385 + cursor_offset);
area->set_left(567);
area->set_top(170);
area->set_right(1540);
area->set_bottom(563);
} else {
current_position->set_x(1360 + cursor_offset);
current_position->set_y(57);
area->set_left(685);
area->set_top(47);
area->set_right(1523);
area->set_bottom(580);
}
}
{
CandidateForm *candidate_layout = app->mutable_candidate_form();
candidate_layout->set_style_bits(CandidateForm::CANDIDATEPOS);
Rectangle *area = candidate_layout->mutable_area();
area->set_left(567);
area->set_top(67);
area->set_right(1983755732);
area->set_bottom(-781021488);
}
}
};
TEST_F(Win32RendererUtilTest, GetPointInPhysicalCoordsTest) {
const CPoint kClientOffset(8, 42);
const CSize kClientSize(100, 200);
const CRect kWindowRect(1000, 500, 1116, 750);
const CPoint kInnerPoint(1100, 600);
const CPoint kOuterPoint(10, 300);
// Check DPI scale: 100%
{
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kWindowClassName, kWindowRect,
kClientOffset, kClientSize, 1.0, &hwnd));
// Conversion from an outer point should be calculated by emulation.
CPoint dest;
layout_mgr.GetPointInPhysicalCoords(hwnd, kOuterPoint, &dest);
// Should be the same position because DPI scaling is 100%.
EXPECT_EQ(kOuterPoint, dest);
// Conversion from an inner point should be calculated by API.
layout_mgr.GetPointInPhysicalCoords(hwnd, kInnerPoint, &dest);
// Should be the same position because DPI scaling is 100%.
EXPECT_EQ(kInnerPoint, dest);
}
// Check DPI scale: 200%
{
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kWindowClassName, kWindowRect, kClientOffset,
kClientSize, 2.0, &hwnd));
// Conversion from an outer point should be calculated by emulation.
CPoint dest;
layout_mgr.GetPointInPhysicalCoords(hwnd, kOuterPoint, &dest);
// Should be doubled because DPI scaling is 200%.
EXPECT_EQ(CPoint(20, 600), dest);
// Conversion from an inner point should be calculated by API.
layout_mgr.GetPointInPhysicalCoords(hwnd, kInnerPoint, &dest);
// Should be doubled because DPI scaling is 200%.
EXPECT_EQ(CPoint(2200, 1200), dest);
}
}
TEST_F(Win32RendererUtilTest, GetRectInPhysicalCoordsTest) {
const CPoint kClientOffset(8, 42);
const CSize kClientSize(100, 200);
const CRect kWindowRect(1000, 500, 1116, 750);
const CRect kInnerRect(1100, 600, 1070, 630);
const CRect kOuterRect(10, 300, 1110, 630);
// Check DPI scale: 100%
{
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kWindowClassName, kWindowRect,
kClientOffset, kClientSize, 1.0, &hwnd));
// Conversion from an outer rectangle should be calculated by emulation.
CRect dest;
layout_mgr.GetRectInPhysicalCoords(hwnd, kOuterRect, &dest);
// Should be the same rectangle because DPI scaling is 100%.
EXPECT_EQ(kOuterRect, dest);
// Conversion from an inner rectangle should be calculated by API.
layout_mgr.GetRectInPhysicalCoords(hwnd, kInnerRect, &dest);
// Should be the same rectangle because DPI scaling is 100%.
EXPECT_EQ(kInnerRect, dest);
}
// Check DPI scale: 200%
{
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kWindowClassName, kWindowRect,
kClientOffset, kClientSize, 2.0, &hwnd));
// Conversion from an outer rectangle should be calculated by emulation.
CRect dest;
layout_mgr.GetRectInPhysicalCoords(hwnd, kOuterRect, &dest);
// Should be doubled because DPI scaling is 200%.
EXPECT_EQ(CRect(20, 600, 2220, 1260), dest);
// Conversion from an inner rectangle should be calculated by API.
layout_mgr.GetRectInPhysicalCoords(hwnd, kInnerRect, &dest);
// Should be doubled because DPI scaling is 200%.
EXPECT_EQ(CRect(2200, 1200, 2140, 1260), dest);
}
}
TEST_F(Win32RendererUtilTest, GetScalingFactorTest) {
const double kScalingFactor = 1.5;
{
const CPoint kClientOffset(0, 0);
const CSize kClientSize(100, 200);
const CRect kWindowRect(1000, 500, 1100, 700);
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kWindowClassName, kWindowRect,
kClientOffset, kClientSize,
kScalingFactor, &hwnd));
ASSERT_DOUBLE_EQ(kScalingFactor, layout_mgr.GetScalingFactor(hwnd));
}
// Zero Width
{
const CPoint kClientOffset(0, 0);
const CSize kClientSize(0, 200);
const CRect kWindowRect(1000, 500, 1000, 700);
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kWindowClassName, kWindowRect,
kClientOffset, kClientSize,
kScalingFactor, &hwnd));
ASSERT_DOUBLE_EQ(kScalingFactor, layout_mgr.GetScalingFactor(hwnd));
}
// Zero Height
{
const CPoint kClientOffset(0, 0);
const CSize kClientSize(100, 0);
const CRect kWindowRect(1000, 500, 1100, 500);
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kWindowClassName, kWindowRect,
kClientOffset, kClientSize,
kScalingFactor, &hwnd));
ASSERT_DOUBLE_EQ(kScalingFactor, layout_mgr.GetScalingFactor(hwnd));
}
// Zero Size
{
const CPoint kClientOffset(0, 0);
const CSize kClientSize(0, 0);
const CRect kWindowRect(1000, 500, 1000, 500);
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kWindowClassName, kWindowRect,
kClientOffset, kClientSize,
kScalingFactor, &hwnd));
// If the window size is zero, the result should be fallen back 1.0.
ASSERT_DOUBLE_EQ(1.0, layout_mgr.GetScalingFactor(hwnd));
}
}
TEST_F(Win32RendererUtilTest, WindowPositionEmulatorTest) {
const CPoint kClientOffset(8, 42);
const CSize kClientSize(100, 200);
const CRect kWindowRect(1000, 500, 1116, 750);
const CPoint kInnerPoint(1100, 600);
const CPoint kOuterPoint(10, 300);
const CRect kInnerRect(1100, 600, 1070, 630);
const CRect kOuterRect(10, 300, 1110, 630);
// Check DPI scale: 100%
{
scoped_ptr<WindowPositionEmulator> emulator(
WindowPositionEmulator::Create());
const HWND hwnd = emulator->RegisterWindow(
kWindowClassName, kWindowRect, kClientOffset, kClientSize, 1.0);
CRect rect;
CPoint point;
// You cannot pass nullptr to |window_handle|.
EXPECT_FALSE(emulator->IsWindow(nullptr));
EXPECT_FALSE(emulator->GetWindowRect(nullptr, &rect));
EXPECT_FALSE(emulator->GetClientRect(nullptr, &rect));
EXPECT_FALSE(emulator->ClientToScreen(nullptr, &point));
EXPECT_TRUE(emulator->GetWindowRect(hwnd, &rect));
EXPECT_EQ(kWindowRect, rect);
EXPECT_TRUE(emulator->GetClientRect(hwnd, &rect));
EXPECT_EQ(CRect(CPoint(0, 0), kClientSize), rect);
point = CPoint(0, 0);
EXPECT_TRUE(emulator->ClientToScreen(hwnd, &point));
EXPECT_EQ(kWindowRect.TopLeft() + kClientOffset, point);
wstring class_name;
EXPECT_TRUE(emulator->GetWindowClassName(hwnd, &class_name));
EXPECT_EQ(kWindowClassName, class_name);
}
// Interestingly, the following results are independent of DPI scaling.
{
scoped_ptr<WindowPositionEmulator> emulator(
WindowPositionEmulator::Create());
const HWND hwnd = emulator->RegisterWindow(
kWindowClassName, kWindowRect, kClientOffset, kClientSize, 10.0);
CRect rect;
CPoint point;
// You cannot pass nullptr to |window_handle|.
EXPECT_FALSE(emulator->IsWindow(nullptr));
EXPECT_FALSE(emulator->GetWindowRect(nullptr, &rect));
EXPECT_FALSE(emulator->GetClientRect(nullptr, &rect));
EXPECT_FALSE(emulator->ClientToScreen(nullptr, &point));
EXPECT_TRUE(emulator->GetWindowRect(hwnd, &rect));
EXPECT_EQ(kWindowRect, rect);
EXPECT_TRUE(emulator->GetClientRect(hwnd, &rect));
EXPECT_EQ(CRect(CPoint(0, 0), kClientSize), rect);
point = CPoint(0, 0);
EXPECT_TRUE(emulator->ClientToScreen(hwnd, &point));
EXPECT_EQ(kWindowRect.TopLeft() + kClientOffset, point);
wstring class_name;
EXPECT_TRUE(emulator->GetWindowClassName(hwnd, &class_name));
EXPECT_EQ(kWindowClassName, class_name);
}
}
TEST_F(Win32RendererUtilTest, HorizontalProportional) {
const CLogFont &logfont = GetFont(true, false);
vector<mozc::renderer::win32::LineLayout> line_layouts;
bool result = true;
const wstring &message = GetTestMessageForProportional();
// Check if the |initial_offset| works as expected.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 200, 100, &line_layouts);
EXPECT_TRUE(result);
EXPECT_EQ(4, line_layouts.size());
EXPECT_EQ(line_layouts[0].line_width, line_layouts[1].line_width);
EXPECT_EQ(line_layouts[1].line_width, line_layouts[2].line_width);
EXPECT_EQ(line_layouts[2].line_width, line_layouts[3].line_width);
// Check if the text wrapping occurs in the first line when
// |initial_offset| > 0. In this case, the line height of first line is
// expected to be the same to that of the second line.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 200, 199, &line_layouts);
EXPECT_TRUE(result);
EXPECT_EQ(4, line_layouts.size());
EXPECT_EQ(0, line_layouts[0].line_length);
EXPECT_EQ(0, line_layouts[0].text.size());
EXPECT_EQ(0, line_layouts[0].character_positions.size());
EXPECT_EQ(line_layouts[0].line_width, line_layouts[1].line_width);
EXPECT_EQ(line_layouts[1].line_width, line_layouts[2].line_width);
EXPECT_EQ(line_layouts[2].line_width, line_layouts[3].line_width);
// Check if this function fails when there is no enough space for text
// wrapping.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 2, 1, &line_layouts);
EXPECT_FALSE(result);
// Check if an invalid |initial_offset| is detected as expected.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 200, -100, &line_layouts);
EXPECT_FALSE(result);
// Check if an invalid |initial_offset| is detected as expected.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 200, 201, &line_layouts);
EXPECT_FALSE(result);
// Check if an invalid |maximum_line_length| is detected as expected.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, -1, 0, &line_layouts);
EXPECT_FALSE(result);
// Check if an invalid |maximum_line_length| is detected as expected.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 0, 0, &line_layouts);
EXPECT_FALSE(result);
}
TEST_F(Win32RendererUtilTest, VerticalProportional) {
const CLogFont &logfont = GetFont(true, true);
vector<mozc::renderer::win32::LineLayout> line_layouts;
bool result = true;
const wstring &message = GetTestMessageForProportional();
// Check if the |initial_offset| works as expected.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 200, 100, &line_layouts);
EXPECT_TRUE(result);
EXPECT_EQ(4, line_layouts.size());
EXPECT_EQ(line_layouts[0].line_width, line_layouts[1].line_width);
EXPECT_EQ(line_layouts[1].line_width, line_layouts[2].line_width);
EXPECT_EQ(line_layouts[2].line_width, line_layouts[3].line_width);
// Check if the text wrapping occurs in the first line when
// |initial_offset| > 0. In this case, the line height of first line is
// expected to be the same to that of the second line.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 200, 199, &line_layouts);
EXPECT_TRUE(result);
EXPECT_EQ(4, line_layouts.size());
EXPECT_EQ(0, line_layouts[0].line_length);
EXPECT_EQ(0, line_layouts[0].text.size());
EXPECT_EQ(0, line_layouts[0].character_positions.size());
EXPECT_EQ(line_layouts[0].line_width, line_layouts[1].line_width);
EXPECT_EQ(line_layouts[1].line_width, line_layouts[2].line_width);
EXPECT_EQ(line_layouts[2].line_width, line_layouts[3].line_width);
// Check if this function fails when there is no enough space for text
// wrapping.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 2, 1, &line_layouts);
EXPECT_FALSE(result);
// Check if an invalid |initial_offset| is detected as expected.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 200, -100, &line_layouts);
EXPECT_FALSE(result);
// Check if an invalid |initial_offset| is detected as expected.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 200, 201, &line_layouts);
EXPECT_FALSE(result);
// Check if an invalid |maximum_line_length| is detected as expected.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, -1, 0, &line_layouts);
EXPECT_FALSE(result);
// Check if an invalid |maximum_line_length| is detected as expected.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 0, 0, &line_layouts);
EXPECT_FALSE(result);
}
TEST_F(Win32RendererUtilTest, HorizontalMonospaced) {
const CLogFont &logfont = GetFont(false, false);
vector<mozc::renderer::win32::LineLayout> line_layouts;
bool result = true;
const wstring &message = GetTestMessageForMonospaced();
// Check if the |initial_offset| works as expected.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 200, 100, &line_layouts);
EXPECT_TRUE(result);
EXPECT_EQ(4, line_layouts.size());
EXPECT_EQ(line_layouts[0].line_width, line_layouts[1].line_width);
EXPECT_EQ(line_layouts[1].line_width, line_layouts[2].line_width);
EXPECT_EQ(line_layouts[2].line_width, line_layouts[3].line_width);
// Check if the text wrapping occurs in the first line when
// |initial_offset| > 0. In this case, the line height of first line is
// expected to be the same to that of the second line.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 200, 199, &line_layouts);
EXPECT_TRUE(result);
EXPECT_EQ(4, line_layouts.size());
EXPECT_EQ(0, line_layouts[0].line_length);
EXPECT_EQ(0, line_layouts[0].text.size());
EXPECT_EQ(0, line_layouts[0].character_positions.size());
EXPECT_EQ(line_layouts[0].line_width, line_layouts[1].line_width);
EXPECT_EQ(line_layouts[1].line_width, line_layouts[2].line_width);
EXPECT_EQ(line_layouts[2].line_width, line_layouts[3].line_width);
// Check if this function fails when there is no enough space for text
// wrapping.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 2, 1, &line_layouts);
EXPECT_FALSE(result);
// Check if an invalid |initial_offset| is detected as expected.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 200, -100, &line_layouts);
EXPECT_FALSE(result);
// Check if an invalid |initial_offset| is detected as expected.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 200, 201, &line_layouts);
EXPECT_FALSE(result);
// Check if an invalid |maximum_line_length| is detected as expected.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, -1, 0, &line_layouts);
EXPECT_FALSE(result);
// Check if an invalid |maximum_line_length| is detected as expected.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 0, 0, &line_layouts);
EXPECT_FALSE(result);
}
TEST_F(Win32RendererUtilTest, VerticalMonospaced) {
const CLogFont &logfont = GetFont(false, true);
vector<mozc::renderer::win32::LineLayout> line_layouts;
bool result = true;
const wstring &message = GetTestMessageForMonospaced();
// Check if the |initial_offset| works as expected.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 200, 100, &line_layouts);
EXPECT_TRUE(result);
EXPECT_EQ(4, line_layouts.size());
EXPECT_EQ(line_layouts[0].line_width, line_layouts[1].line_width);
EXPECT_EQ(line_layouts[1].line_width, line_layouts[2].line_width);
EXPECT_EQ(line_layouts[2].line_width, line_layouts[3].line_width);
// Check if the text wrapping occurs in the first line when
// |initial_offset| > 0. In this case, the line height of first line is
// expected to be the same to that of the second line.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 200, 199, &line_layouts);
EXPECT_TRUE(result);
EXPECT_EQ(4, line_layouts.size());
EXPECT_EQ(0, line_layouts[0].line_length);
EXPECT_EQ(0, line_layouts[0].text.size());
EXPECT_EQ(0, line_layouts[0].character_positions.size());
EXPECT_EQ(line_layouts[0].line_width, line_layouts[1].line_width);
EXPECT_EQ(line_layouts[1].line_width, line_layouts[2].line_width);
EXPECT_EQ(line_layouts[2].line_width, line_layouts[3].line_width);
// Check if this function fails when there is no enough space for text
// wrapping.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 2, 1, &line_layouts);
EXPECT_FALSE(result);
// Check if an invalid |initial_offset| is detected as expected.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 200, -100, &line_layouts);
EXPECT_FALSE(result);
// Check if an invalid |initial_offset| is detected as expected.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 200, 201, &line_layouts);
EXPECT_FALSE(result);
// Check if an invalid |maximum_line_length| is detected as expected.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, -1, 0, &line_layouts);
EXPECT_FALSE(result);
// Check if an invalid |maximum_line_length| is detected as expected.
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 0, 0, &line_layouts);
EXPECT_FALSE(result);
}
TEST_F(Win32RendererUtilTest, HorizontalProportionalCompositeGlyph) {
const CLogFont &logfont = GetFont(true, false);
vector<mozc::renderer::win32::LineLayout> line_layouts;
bool result = true;
const wstring &message = GetTestMessageWithCompositeGlyph(1);
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 200, 100, &line_layouts);
EXPECT_TRUE(result);
EXPECT_EQ(1, line_layouts.size());
// CalcLayoutWithTextWrapping does not support composition glyph.
EXPECT_GT(line_layouts[0].character_positions[0].length, 0);
EXPECT_EQ(line_layouts[0].character_positions[1].begin +
line_layouts[0].character_positions[1].length,
line_layouts[0].line_length);
}
TEST_F(Win32RendererUtilTest, VerticalProportionalCompositeGlyph) {
const CLogFont &logfont = GetFont(true, true);
vector<mozc::renderer::win32::LineLayout> line_layouts;
bool result = true;
const wstring &message = GetTestMessageWithCompositeGlyph(1);
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 200, 100, &line_layouts);
EXPECT_TRUE(result);
EXPECT_EQ(1, line_layouts.size());
// CalcLayoutWithTextWrapping does not support composition glyph.
EXPECT_GT(line_layouts[0].character_positions[0].length, 0);
EXPECT_EQ(line_layouts[0].character_positions[1].begin +
line_layouts[0].character_positions[1].length,
line_layouts[0].line_length);
}
TEST_F(Win32RendererUtilTest, HorizontalMonospacedCompositeGlyph) {
const CLogFont &logfont = GetFont(false, false);
vector<mozc::renderer::win32::LineLayout> line_layouts;
bool result = true;
const wstring &message = GetTestMessageWithCompositeGlyph(1);
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 200, 100, &line_layouts);
EXPECT_TRUE(result);
EXPECT_EQ(1, line_layouts.size());
// CalcLayoutWithTextWrapping does not support composition glyph.
EXPECT_GT(line_layouts[0].character_positions[0].length, 0);
EXPECT_EQ(line_layouts[0].character_positions[1].begin +
line_layouts[0].character_positions[1].length,
line_layouts[0].line_length);
}
TEST_F(Win32RendererUtilTest, VerticalMonospacedCompositeGlyph) {
const CLogFont &logfont = GetFont(false, true);
vector<mozc::renderer::win32::LineLayout> line_layouts;
bool result = true;
const wstring &message = GetTestMessageWithCompositeGlyph(1);
result = LayoutManager::CalcLayoutWithTextWrapping(
logfont, message, 200, 100, &line_layouts);
EXPECT_TRUE(result);
EXPECT_EQ(1, line_layouts.size());
// CalcLayoutWithTextWrapping does not support composition glyph.
EXPECT_GT(line_layouts[0].character_positions[0].length, 0);
EXPECT_EQ(line_layouts[0].character_positions[1].begin +
line_layouts[0].character_positions[1].length,
line_layouts[0].line_length);
}
TEST_F(Win32RendererUtilTest,
CompositionHorizontalNoAdditionalSegmentationWithMonospacedFont) {
const int kCursorOffsetX = 0;
RendererCommand command;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
// w/ candidates, monospaced, horizontal
SetRenderereCommandForTest(
false, true, false, kCursorOffsetX, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(2, layouts.size());
// The first line
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1868, 599, 2003, 648, 0, 0, 135, 49,
0, 0, 0, 0, 0, 0, logfont, layout);
{
// "これは"
const char kMsg[] = "\343\201\223\343\202\214\343\201\257";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(1, layout.marker_layouts.size());
EXPECT_EQ(CPoint(0, 48), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(126, 48), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
}
// The second line
{
const CompositionWindowLayout &layout = layouts.at(1);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1193, 648, 1840, 697, 0, 0, 646, 49,
0, 0, 646, 0, 647, 49, logfont, layout);
{
// "、Google日本語入力のTestです"
const char kMsg[] =
"\343\200\201Google\346\227\245\346\234\254\350\252\236\345\205\245"
"\345\212\233\343\201\256Test\343\201\247\343\201\231";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(4, layout.marker_layouts.size());
EXPECT_EQ(CPoint(0, 48), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(36, 48), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(45, 48), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(190, 48), layout.marker_layouts[1].to);
EXPECT_TRUE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(196, 48), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(457, 48), layout.marker_layouts[2].to);
EXPECT_FALSE(layout.marker_layouts[2].highlighted);
EXPECT_EQ(CPoint(466, 48), layout.marker_layouts[3].from);
EXPECT_EQ(CPoint(646, 48), layout.marker_layouts[3].to);
EXPECT_FALSE(layout.marker_layouts[3].highlighted);
}
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1238, 697, 1238, 648, 1839, 697, candidate_layout);
// Check other candidate positions.
command.mutable_output()->mutable_candidates()->set_position(0);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1868, 648, 1868, 599, 2003, 648, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(3);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1193, 697, 1193, 648, 1839, 697, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(10);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1389, 697, 1389, 648, 1839, 697, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(16);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1659, 697, 1659, 648, 1839, 697, candidate_layout);
// w/o candidates, monospaced, horizontal
SetRenderereCommandForTest(false, false, false, 0, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
EXPECT_FALSE(candidate_layout.initialized());
}
TEST_F(Win32RendererUtilTest,
CompositionHorizontalAdditionalSegmentationWithMonospacedFont) {
const int kCursorOffsetX = -90;
RendererCommand command;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
// w/ candidates, monospaced, horizontal
SetRenderereCommandForTest(
false, true, false, kCursorOffsetX, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(2, layouts.size());
// The first line
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1778, 599, 2019, 648, 0, 0, 241, 49,
0, 0, 0, 0, 0, 0, logfont, layout);
{
// "これは、Go"
const char kMsg[] =
"\343\201\223\343\202\214\343\201\257\343\200\201Go";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(3, layout.marker_layouts.size());
EXPECT_EQ(CPoint(0, 48), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(126, 48), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(135, 48), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(171, 48), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(180, 48), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(241, 48), layout.marker_layouts[2].to);
EXPECT_TRUE(layout.marker_layouts[2].highlighted);
}
// The second line
{
const CompositionWindowLayout &layout = layouts.at(1);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1193, 648, 1734, 697, 0, 0, 540, 49,
0, 0, 540, 0, 541, 49, logfont, layout);
{
// "ogle日本語入力のTestです"
const char kMsg[] =
"ogle\346\227\245\346\234\254\350\252\236\345\205\245"
"\345\212\233\343\201\256Test\343\201\247\343\201\231";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(3, layout.marker_layouts.size());
EXPECT_EQ(CPoint(0, 48), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(84, 48), layout.marker_layouts[0].to);
EXPECT_TRUE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(90, 48), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(351, 48), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(360, 48), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(540, 48), layout.marker_layouts[2].to);
EXPECT_FALSE(layout.marker_layouts[2].highlighted);
}
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1958, 648, 1958, 599, 2019, 648, candidate_layout);
// Check other candidate positions.
command.mutable_output()->mutable_candidates()->set_position(0);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1778, 648, 1778, 599, 2019, 648, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(3);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1913, 648, 1913, 599, 2019, 648, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(10);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1283, 697, 1283, 648, 1733, 697, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(16);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1553, 697, 1553, 648, 1733, 697, candidate_layout);
// w/o candidates, monospaced, horizontal
SetRenderereCommandForTest(false, false, false, 0, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
EXPECT_FALSE(candidate_layout.initialized());
}
TEST_F(Win32RendererUtilTest,
CompositionVerticalNoAdditionalSegmentationWithMonospacedFont) {
const int kCursorOffsetY = 0;
RendererCommand command;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
// w/ candidates, monospaced, vertical
SetRenderereCommandForTest(
false, true, true, kCursorOffsetY, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
logfont.lfOrientation = 2700;
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(3, layouts.size());
// The first line
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1983, 927, 2034, 1062, 0, 0, 51, 135,
51, 0, 0, 0, 0, 0, logfont, layout);
{
// "これは"
const char kMsg[] = "\343\201\223\343\202\214\343\201\257";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(1, layout.marker_layouts.size());
EXPECT_EQ(CPoint(50, 0), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(50, 126), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
}
// The second line
{
const CompositionWindowLayout &layout = layouts.at(1);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1932, 712, 1983, 1088, 0, 0, 51, 376,
51, 0, 0, 0, 0, 0, logfont, layout);
{
// "、Google日本語入"
const char kMsg[] = "\343\200\201Google\346\227\245\346"
"\234\254\350\252\236\345\205\245";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(3, layout.marker_layouts.size());
EXPECT_EQ(CPoint(50, 0), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(50, 36), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(50, 45), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(50, 190), layout.marker_layouts[1].to);
EXPECT_TRUE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(50, 196), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(50, 376), layout.marker_layouts[2].to);
EXPECT_FALSE(layout.marker_layouts[2].highlighted);
}
// The third line
{
const CompositionWindowLayout &layout = layouts.at(2);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1881, 712, 1932, 983, 0, 0, 51, 270,
51, 0, 0, 270, 51, 271, logfont, layout);
{
// "力のTestです"
const char kMsg[] =
"\345\212\233\343\201\256Test\343\201\247\343\201\231";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(2, layout.marker_layouts.size());
EXPECT_EQ(CPoint(50, 0), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(50, 81), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(50, 90), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(50, 270), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
}
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1932, 757, 1932, 757, 1983, 1088, candidate_layout);
// Check other candidate positions.
command.mutable_output()->mutable_candidates()->set_position(0);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1983, 927, 1983, 927, 2034, 1062, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(3);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1932, 712, 1932, 712, 1983, 1088, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(10);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1932, 908, 1932, 908, 1983, 1088, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(16);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1881, 802, 1881, 802, 1932, 982, candidate_layout);
// w/o candidates, monospaced, vertical
SetRenderereCommandForTest(false, false, true, 0, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
EXPECT_FALSE(candidate_layout.initialized());
}
TEST_F(Win32RendererUtilTest,
CompositionVerticalAdditionalSegmentationWithMonospacedFont) {
const int kCursorOffsetY = -90;
RendererCommand command;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
// w/ candidates, monospaced, vertical
SetRenderereCommandForTest(
false, true, true, kCursorOffsetY, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
logfont.lfOrientation = 2700;
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(3, layouts.size());
// The first line
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1983, 837, 2034, 1105, 0, 0, 51, 268,
51, 0, 0, 0, 0, 0, logfont, layout);
{
// "これは、Goo"
const char kMsg[] =
"\343\201\223\343\202\214\343\201\257\343\200\201Goo";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(3, layout.marker_layouts.size());
EXPECT_EQ(CPoint(50, 0), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(50, 126), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(50, 135), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(50, 171), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(50, 180), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(50, 268), layout.marker_layouts[2].to);
EXPECT_TRUE(layout.marker_layouts[2].highlighted);
}
// The second line
{
const CompositionWindowLayout &layout = layouts.at(1);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1932, 712, 1983, 1098, 0, 0, 51, 386,
51, 0, 0, 0, 0, 0, logfont, layout);
{
// "gle日本語入力のTe"
const char kMsg[] = "gle\346\227\245\346\234\254\350\252\236"
"\345\205\245\345\212\233\343\201\256Te";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(3, layout.marker_layouts.size());
EXPECT_EQ(CPoint(50, 0), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(50, 57), layout.marker_layouts[0].to);
EXPECT_TRUE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(50, 63), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(50, 324), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(50, 333), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(50, 386), layout.marker_layouts[2].to);
EXPECT_FALSE(layout.marker_layouts[2].highlighted);
}
// The third line
{
const CompositionWindowLayout &layout = layouts.at(2);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1881, 712, 1932, 840, 0, 0, 51, 127,
51, 0, 0, 127, 51, 128, logfont, layout);
{
// "stです"
const char kMsg[] = "st\343\201\247\343\201\231";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(1, layout.marker_layouts.size());
EXPECT_EQ(CPoint(50, 0), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(50, 127), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
}
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1983, 1017, 1983, 1017, 2034, 1105, candidate_layout);
// Check other candidate positions.
command.mutable_output()->mutable_candidates()->set_position(0);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1983, 837, 1983, 837, 2034, 1105, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(3);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1983, 972, 1983, 972, 2034, 1105, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(10);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1932, 775, 1932, 775, 1983, 1098, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(16);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1932, 1045, 1932, 1045, 1983, 1098, candidate_layout);
// w/o candidates, monospaced, vertical
SetRenderereCommandForTest(false, false, true, 0, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
EXPECT_FALSE(candidate_layout.initialized());
}
TEST_F(Win32RendererUtilTest,
CompositionHorizontalNoAdditionalSegmentationWithProportionalFont) {
const int kCursorOffsetX = 0;
RendererCommand command;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
// w/ candidates, proportional, horizontal
SetRenderereCommandForTest(
true, true, false, kCursorOffsetX, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(2, layouts.size());
// The first line
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1868, 599, 2003, 653, 0, 0, 135, 54,
0, 0, 0, 0, 0, 0, logfont, layout);
{
// "これは"
const char kMsg[] = "\343\201\223\343\202\214\343\201\257";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(1, layout.marker_layouts.size());
EXPECT_EQ(CPoint(0, 53), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(126, 53), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
}
// The second line
{
const CompositionWindowLayout &layout = layouts.at(1);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1193, 653, 1840, 707, 0, 0, 646, 54,
0, 0, 646, 0, 647, 54, logfont, layout);
{
// "、Google日本語入力のTestです"
const char kMsg[] =
"\343\200\201Google\346\227\245\346\234\254\350\252\236\345\205\245"
"\345\212\233\343\201\256Test\343\201\247\343\201\231";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(4, layout.marker_layouts.size());
EXPECT_EQ(CPoint(0, 53), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(36, 53), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(45, 53), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(192, 53), layout.marker_layouts[1].to);
EXPECT_TRUE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(197, 53), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(458, 53), layout.marker_layouts[2].to);
EXPECT_FALSE(layout.marker_layouts[2].highlighted);
EXPECT_EQ(CPoint(467, 53), layout.marker_layouts[3].from);
EXPECT_EQ(CPoint(646, 53), layout.marker_layouts[3].to);
EXPECT_FALSE(layout.marker_layouts[3].highlighted);
}
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1238, 707, 1238, 653, 1839, 707, candidate_layout);
// Check other candidate positions.
command.mutable_output()->mutable_candidates()->set_position(0);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1868, 653, 1868, 599, 2003, 653, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(3);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1193, 707, 1193, 653, 1839, 707, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(10);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1390, 707, 1390, 653, 1839, 707, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(16);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1660, 707, 1660, 653, 1839, 707, candidate_layout);
// w/o candidates, proportional, horizontal
SetRenderereCommandForTest(true, false, false, 0, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
EXPECT_FALSE(candidate_layout.initialized());
}
TEST_F(Win32RendererUtilTest,
CompositionHorizontalAdditionalSegmentationWithProportionalFont) {
const int kCursorOffsetX = -90;
RendererCommand command;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
// w/ candidates, proportional, horizontal
SetRenderereCommandForTest(
true, true, false, kCursorOffsetX, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(2, layouts.size());
// The first line
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1778, 599, 2020, 653, 0, 0, 242, 54,
0, 0, 0, 0, 0, 0, logfont, layout);
{
// "これは、Go"
const char kMsg[] =
"\343\201\223\343\202\214\343\201\257\343\200\201Go";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(3, layout.marker_layouts.size());
EXPECT_EQ(CPoint(0, 53), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(126, 53), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(135, 53), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(171, 53), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(180, 53), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(242, 53), layout.marker_layouts[2].to);
EXPECT_TRUE(layout.marker_layouts[2].highlighted);
}
// The second line
{
const CompositionWindowLayout &layout = layouts.at(1);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1193, 653, 1733, 707, 0, 0, 539, 54,
0, 0, 539, 0, 540, 54, logfont, layout);
{
// "ogle日本語入力のTestです"
const char kMsg[] =
"ogle\346\227\245\346\234\254\350\252\236\345\205\245"
"\345\212\233\343\201\256Test\343\201\247\343\201\231";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(3, layout.marker_layouts.size());
EXPECT_EQ(CPoint(0, 53), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(85, 53), layout.marker_layouts[0].to);
EXPECT_TRUE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(90, 53), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(351, 53), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(360, 53), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(539, 53), layout.marker_layouts[2].to);
EXPECT_FALSE(layout.marker_layouts[2].highlighted);
}
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1958, 653, 1958, 599, 2020, 653, candidate_layout);
// Check other candidate positions.
command.mutable_output()->mutable_candidates()->set_position(0);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1778, 653, 1778, 599, 2020, 653, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(3);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1913, 653, 1913, 599, 2020, 653, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(10);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1283, 707, 1283, 653, 1732, 707, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(16);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1553, 707, 1553, 653, 1732, 707, candidate_layout);
// w/o candidates, proportional, horizontal
SetRenderereCommandForTest(true, false, false, 0, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
EXPECT_FALSE(candidate_layout.initialized());
}
TEST_F(Win32RendererUtilTest,
CompositionVerticalNoAdditionalSegmentationWithProportionalFont) {
const int kCursorOffsetY = 0;
RendererCommand command;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
// w/ candidates, proportional, vertical
SetRenderereCommandForTest(
true, true, true, kCursorOffsetY, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
logfont.lfOrientation = 2700;
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(3, layouts.size());
// The first line
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1978, 927, 2034, 1062, 0, 0, 56, 135,
56, 0, 0, 0, 0, 0, logfont, layout);
{
// "これは"
const char kMsg[] = "\343\201\223\343\202\214\343\201\257";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(1, layout.marker_layouts.size());
EXPECT_EQ(CPoint(55, 0), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(55, 126), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
}
// The second line
{
const CompositionWindowLayout &layout = layouts.at(1);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1922, 712, 1978, 1089, 0, 0, 56, 377,
56, 0, 0, 0, 0, 0, logfont, layout);
{
// "、Google日本語入"
const char kMsg[] = "\343\200\201Google\346\227\245\346"
"\234\254\350\252\236\345\205\245";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(3, layout.marker_layouts.size());
EXPECT_EQ(CPoint(55, 0), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(55, 36), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(55, 45), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(55, 192), layout.marker_layouts[1].to);
EXPECT_TRUE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(55, 197), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(55, 377), layout.marker_layouts[2].to);
EXPECT_FALSE(layout.marker_layouts[2].highlighted);
}
// The third line
{
const CompositionWindowLayout &layout = layouts.at(2);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1866, 712, 1922, 982, 0, 0, 56, 269,
56, 0, 0, 269, 56, 270, logfont, layout);
{
// "力のTestです"
const char kMsg[] =
"\345\212\233\343\201\256Test\343\201\247\343\201\231";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(2, layout.marker_layouts.size());
EXPECT_EQ(CPoint(55, 0), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(55, 81), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(55, 90), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(55, 269), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
}
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1922, 757, 1922, 757, 1978, 1089, candidate_layout);
// Check other candidate positions.
command.mutable_output()->mutable_candidates()->set_position(0);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1978, 927, 1978, 927, 2034, 1062, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(3);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1922, 712, 1922, 712, 1978, 1089, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(10);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1922, 909, 1922, 909, 1978, 1089, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(16);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1866, 802, 1866, 802, 1922, 981, candidate_layout);
// w/o candidates, proportional, vertical
SetRenderereCommandForTest(true, false, true, 0, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
EXPECT_FALSE(candidate_layout.initialized());
}
TEST_F(Win32RendererUtilTest,
CompositionVerticalAdditionalSegmentationWithProportionalFont) {
const int kCursorOffsetY = -90;
RendererCommand command;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
// w/ candidates, proportional, vertical
SetRenderereCommandForTest(
true, true, true, kCursorOffsetY, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
logfont.lfOrientation = 2700;
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(3, layouts.size());
// The first line
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1978, 837, 2034, 1079, 0, 0, 56, 242,
56, 0, 0, 0, 0, 0, logfont, layout);
{
// "これは、Go"
const char kMsg[] =
"\343\201\223\343\202\214\343\201\257\343\200\201Go";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(3, layout.marker_layouts.size());
EXPECT_EQ(CPoint(55, 0), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(55, 126), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(55, 135), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(55, 171), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(55, 180), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(55, 242), layout.marker_layouts[2].to);
EXPECT_TRUE(layout.marker_layouts[2].highlighted);
}
// The second line
{
const CompositionWindowLayout &layout = layouts.at(1);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1922, 712, 1978, 1100, 0, 0, 56, 388,
56, 0, 0, 0, 0, 0, logfont, layout);
{
// "ogle日本語入力のT"
const char kMsg[] = "ogle\346\227\245\346\234\254\350\252\236"
"\345\205\245\345\212\233\343\201\256T";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(3, layout.marker_layouts.size());
EXPECT_EQ(CPoint(55, 0), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(55, 85), layout.marker_layouts[0].to);
EXPECT_TRUE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(55, 90), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(55, 351), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(55, 360), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(55, 388), layout.marker_layouts[2].to);
EXPECT_FALSE(layout.marker_layouts[2].highlighted);
}
// The third line
{
const CompositionWindowLayout &layout = layouts.at(2);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1866, 712, 1922, 864, 0, 0, 56, 151,
56, 0, 0, 151, 56, 152, logfont, layout);
{
// "estです"
const char kMsg[] = "est\343\201\247\343\201\231";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(1, layout.marker_layouts.size());
EXPECT_EQ(CPoint(55, 0), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(55, 151), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
}
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1978, 1017, 1978, 1017, 2034, 1079, candidate_layout);
// Check other candidate positions.
command.mutable_output()->mutable_candidates()->set_position(0);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1978, 837, 1978, 837, 2034, 1079, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(3);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1978, 972, 1978, 972, 2034, 1079, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(10);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1922, 802, 1922, 802, 1978, 1100, candidate_layout);
command.mutable_output()->mutable_candidates()->set_position(16);
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1922, 1072, 1922, 1072, 1978, 1100, candidate_layout);
// w/o candidates, proportional, vertical
SetRenderereCommandForTest(false, false, true, 0, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
EXPECT_FALSE(candidate_layout.initialized());
}
TEST_F(Win32RendererUtilTest,
CompositionHorizontalFirstLineIsEmptyWithMonospacedFont) {
const int kCursorOffsetX = 120;
RendererCommand command;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
// w/ candidates, monospaced, horizontal
SetRenderereCommandForTest(
false, true, false, kCursorOffsetX, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(1, layouts.size());
// The first line
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1193, 648, 1975, 697, 0, 0, 781, 49,
0, 0, 781, 0, 782, 49, logfont, layout);
{
// "これは、Google日本語入力のTestです"
const char kMsg[] =
"\343\201\223\343\202\214\343\201\257\343\200\201Google\346\227\245"
"\346\234\254\350\252\236\345\205\245\345\212\233\343\201\256Test"
"\343\201\247\343\201\231";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(5, layout.marker_layouts.size());
EXPECT_EQ(CPoint(0, 48), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(126, 48), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(135, 48), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(171, 48), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(180, 48), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(325, 48), layout.marker_layouts[2].to);
EXPECT_TRUE(layout.marker_layouts[2].highlighted);
EXPECT_EQ(CPoint(331, 48), layout.marker_layouts[3].from);
EXPECT_EQ(CPoint(592, 48), layout.marker_layouts[3].to);
EXPECT_FALSE(layout.marker_layouts[3].highlighted);
EXPECT_EQ(CPoint(601, 48), layout.marker_layouts[4].from);
EXPECT_EQ(CPoint(781, 48), layout.marker_layouts[4].to);
EXPECT_FALSE(layout.marker_layouts[4].highlighted);
}
}
TEST_F(Win32RendererUtilTest,
CompositionHorizontalFirstLineIsEmptyWithProportionalFont) {
const int kCursorOffsetX = 120;
RendererCommand command;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
// w/ candidates, proportional, horizontal
SetRenderereCommandForTest(
true, true, false, kCursorOffsetX, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(1, layouts.size());
// The first line
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1193, 653, 1975, 707, 0, 0, 781, 54,
0, 0, 781, 0, 782, 54, logfont, layout);
{
// "これは、Google日本語入力のTestです"
const char kMsg[] =
"\343\201\223\343\202\214\343\201\257\343\200\201Google\346\227\245"
"\346\234\254\350\252\236\345\205\245\345\212\233\343\201\256Test"
"\343\201\247\343\201\231";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(5, layout.marker_layouts.size());
EXPECT_EQ(CPoint(0, 53), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(126, 53), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(135, 53), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(171, 53), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(180, 53), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(327, 53), layout.marker_layouts[2].to);
EXPECT_TRUE(layout.marker_layouts[2].highlighted);
EXPECT_EQ(CPoint(332, 53), layout.marker_layouts[3].from);
EXPECT_EQ(CPoint(593, 53), layout.marker_layouts[3].to);
EXPECT_FALSE(layout.marker_layouts[3].highlighted);
EXPECT_EQ(CPoint(602, 53), layout.marker_layouts[4].from);
EXPECT_EQ(CPoint(781, 53), layout.marker_layouts[4].to);
EXPECT_FALSE(layout.marker_layouts[4].highlighted);
}
}
TEST_F(Win32RendererUtilTest,
CompositionVerticalFirstLineIsEmptyWithMonospacedFont) {
const int kCursorOffsetY = 170;
RendererCommand command;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
// w/ candidates, monospaced, vertical
SetRenderereCommandForTest(
false, true, true, kCursorOffsetY, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
logfont.lfOrientation = 2700;
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(3, layouts.size());
// The first line
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1932, 712, 1983, 1088, 0, 0, 51, 376,
51, 0, 0, 0, 0, 0, logfont, layout);
{
// "これは、Google日"
const char kMsg[] =
"\343\201\223\343\202\214\343\201\257\343\200\201Google\346\227\245";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(4, layout.marker_layouts.size());
EXPECT_EQ(CPoint(50, 0), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(50, 126), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(50, 135), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(50, 171), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(50, 180), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(50, 325), layout.marker_layouts[2].to);
EXPECT_TRUE(layout.marker_layouts[2].highlighted);
EXPECT_EQ(CPoint(50, 331), layout.marker_layouts[3].from);
EXPECT_EQ(CPoint(50, 376), layout.marker_layouts[3].to);
EXPECT_FALSE(layout.marker_layouts[3].highlighted);
}
// The second line
{
const CompositionWindowLayout &layout = layouts.at(1);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1881, 712, 1932, 1072, 0, 0, 51, 360,
51, 0, 0, 0, 0, 0, logfont, layout);
{
// "本語入力のTestで"
const char kMsg[] =
"\346\234\254\350\252\236\345\205\245\345\212\233\343\201\256Test"
"\343\201\247";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(2, layout.marker_layouts.size());
EXPECT_EQ(CPoint(50, 0), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(50, 216), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(50, 225), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(50, 360), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
}
// The third line
{
const CompositionWindowLayout &layout = layouts.at(2);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1830, 712, 1881, 758, 0, 0, 51, 45,
51, 0, 0, 45, 51, 46, logfont, layout);
{
// "す"
const char kMsg[] = "\343\201\231";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(1, layout.marker_layouts.size());
EXPECT_EQ(CPoint(50, 0), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(50, 45), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
}
}
TEST_F(Win32RendererUtilTest,
CompositionVerticalFirstLineIsEmptyWithProportionalFont) {
const int kCursorOffsetY = 170;
RendererCommand command;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
// w/ candidates, proportional, vertical
SetRenderereCommandForTest(
true, true, true, kCursorOffsetY, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
logfont.lfOrientation = 2700;
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(3, layouts.size());
// The first line
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1922, 712, 1978, 1089, 0, 0, 56, 377,
56, 0, 0, 0, 0, 0, logfont, layout);
{
// "これは、Google日"
const char kMsg[] =
"\343\201\223\343\202\214\343\201\257\343\200\201Google\346\227\245";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(4, layout.marker_layouts.size());
EXPECT_EQ(CPoint(55, 0), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(55, 126), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(55, 135), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(55, 171), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(55, 180), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(55, 327), layout.marker_layouts[2].to);
EXPECT_TRUE(layout.marker_layouts[2].highlighted);
EXPECT_EQ(CPoint(55, 332), layout.marker_layouts[3].from);
EXPECT_EQ(CPoint(55, 377), layout.marker_layouts[3].to);
EXPECT_FALSE(layout.marker_layouts[3].highlighted);
}
// The second line
{
const CompositionWindowLayout &layout = layouts.at(1);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1866, 712, 1922, 1071, 0, 0, 56, 359,
56, 0, 0, 0, 0, 0, logfont, layout);
{
// "本語入力のTestで"
const char kMsg[] =
"\346\234\254\350\252\236\345\205\245\345\212\233\343\201\256Test"
"\343\201\247";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(2, layout.marker_layouts.size());
EXPECT_EQ(CPoint(55, 0), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(55, 216), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(55, 225), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(55, 359), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
}
// The third line
{
const CompositionWindowLayout &layout = layouts.at(2);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1810, 712, 1866, 758, 0, 0, 56, 45,
56, 0, 0, 45, 56, 46, logfont, layout);
{
// "す"
const char kMsg[] = "\343\201\231";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(1, layout.marker_layouts.size());
EXPECT_EQ(CPoint(55, 0), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(55, 45), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
}
}
TEST_F(Win32RendererUtilTest, CheckCaretPosInHorizontalComposition) {
// Check the caret points the first character.
{
const int kCursorOffsetX = -300;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
RendererCommand command;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
SetRenderereCommandForCaretTest(
false, false, 10, 0, kCursorOffsetX, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(1, layouts.size());
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1568, 599, 2018, 648, 0, 0, 450, 49,
0, 0, 0, 0, 1, 49, logfont, layout);
}
}
// Check the caret points the middle character.
{
const int kCursorOffsetX = -300;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
RendererCommand command;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
SetRenderereCommandForCaretTest(
false, false, 10, 5, kCursorOffsetX, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(1, layouts.size());
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1568, 599, 2018, 648, 0, 0, 450, 49,
0, 0, 225, 0, 226, 49, logfont, layout);
}
}
// Check the caret points the next to the last character.
// In this case, composition window should have an extra space to draw the
// caret except that there is no room to extend.
{
const int kCursorOffsetX = -300;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
RendererCommand command;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
SetRenderereCommandForCaretTest(
false, false, 10, 10, kCursorOffsetX, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(1, layouts.size());
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1568, 599, 2019, 648, 0, 0, 450, 49,
0, 0, 450, 0, 451, 49, logfont, layout);
}
}
// To emulate built-in edit control, we will adjust caret position to be
// inside of the line if it exceeds the end of line.
{
const int kCursorOffsetX = -287;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
RendererCommand command;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
SetRenderereCommandForCaretTest(
false, false, 10, 10, kCursorOffsetX, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(1, layouts.size());
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1581, 599, 2031, 648, 0, 0, 450, 49,
0, 0, 449, 0, 450, 49, logfont, layout);
}
}
// If there exists other characters in the next line, caret position should
// not be adjusted.
{
const int kCursorOffsetX = -287;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
RendererCommand command;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
SetRenderereCommandForCaretTest(
false, false, 11, 10, kCursorOffsetX, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(2, layouts.size());
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1581, 599, 2031, 648, 0, 0, 450, 49,
0, 0, 0, 0, 0, 0, logfont, layout);
}
{
const CompositionWindowLayout &layout = layouts.at(1);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1193, 648, 1238, 697, 0, 0, 45, 49,
0, 0, 0, 0, 1, 49, logfont, layout);
}
}
}
TEST_F(Win32RendererUtilTest, CheckCaretPosInVerticalComposition) {
// Check the caret points the first character.
{
const int kCursorOffsetY = -10;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
RendererCommand command;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
SetRenderereCommandForCaretTest(
false, true, 4, 0, kCursorOffsetY, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
logfont.lfOrientation = 2700;
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(1, layouts.size());
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1983, 917, 2034, 1097, 0, 0, 51, 180,
51, 0, 0, 0, 51, 1, logfont, layout);
}
}
// Check the caret points the middle character.
{
const int kCursorOffsetY = -10;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
RendererCommand command;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
SetRenderereCommandForCaretTest(
false, true, 4, 2, kCursorOffsetY, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
logfont.lfOrientation = 2700;
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(1, layouts.size());
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1983, 917, 2034, 1097, 0, 0, 51, 180,
51, 0, 0, 90, 51, 91, logfont, layout);
}
}
// Check the caret points the next to the last character.
// In this case, composition window should have an extra space to draw the
// caret except that there is no room to extend.
{
const int kCursorOffsetY = -10;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
RendererCommand command;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
SetRenderereCommandForCaretTest(
false, true, 4, 4, kCursorOffsetY, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
logfont.lfOrientation = 2700;
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(1, layouts.size());
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1983, 917, 2034, 1098, 0, 0, 51, 180,
51, 0, 0, 180, 51, 181, logfont, layout);
}
}
// To emulate built-in edit control, we will adjust caret position to be
// inside of the line if it exceeds the end of line.
{
const int kCursorOffsetY = -2;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
RendererCommand command;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
SetRenderereCommandForCaretTest(
false, true, 4, 4, kCursorOffsetY, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
logfont.lfOrientation = 2700;
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(1, layouts.size());
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1983, 925, 2034, 1105, 0, 0, 51, 180,
51, 0, 0, 179, 51, 180, logfont, layout);
}
}
// If there exists other characters in the next line, caret position should
// not be adjusted.
{
const int kCursorOffsetY = -2;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
RendererCommand command;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
SetRenderereCommandForCaretTest(
false, true, 5, 4, kCursorOffsetY, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
logfont.lfOrientation = 2700;
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
ASSERT_EQ(2, layouts.size());
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1983, 925, 2034, 1105, 0, 0, 51, 180,
51, 0, 0, 0, 0, 0, logfont, layout);
}
{
const CompositionWindowLayout &layout = layouts.at(1);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1932, 712, 1983, 757, 0, 0, 51, 45,
51, 0, 0, 0, 51, 1, logfont, layout);
}
}
}
// Check if suggest window does not hide preedit.
// See b/4317753 for details.
TEST_F(Win32RendererUtilTest, SuggestWindowNeverHidesHorizontalPreedit) {
const int kCursorOffsetX = 0;
RendererCommand command;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
// w/ candidates, proportional, horizontal
SetRenderereCommandForSuggestTest(true, false, kCursorOffsetX,
hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
// Suggest window should be aligned to the last composition window.
EXPECT_EQ(layouts.rbegin()->window_position_in_screen_coordinate.left,
candidate_layout.position().x);
EXPECT_EQ(layouts.rbegin()->window_position_in_screen_coordinate.bottom,
candidate_layout.position().y);
EXPECT_EQ(CRect(1193, 599, 2003, 707), candidate_layout.exclude_region());
}
// Check if suggest window does not hide preedit.
// See b/4317753 for details.
TEST_F(Win32RendererUtilTest, SuggestWindowNeverHidesVerticalPreedit) {
const int kCursorOffsetY = 0;
RendererCommand command;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
// w/ candidates, proportional, horizontal
SetRenderereCommandForSuggestTest(true, true, kCursorOffsetY,
hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
// Suggest window should be aligned to the first composition window.
// TODO(yukawa): Use the last composition window when vertical candidate
// window is implemented.
EXPECT_EQ(layouts.begin()->window_position_in_screen_coordinate.left,
candidate_layout.position().x);
EXPECT_EQ(layouts.begin()->window_position_in_screen_coordinate.top,
candidate_layout.position().y);
EXPECT_EQ(CRect(1978, 927, 2034, 1062), candidate_layout.exclude_region());
}
TEST_F(Win32RendererUtilTest, RemoveUnderlineFromFont_Issue2935480) {
const int kCursorOffsetY = 0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
vector<CompositionWindowLayout> layouts;
RendererCommand command;
CandidateWindowLayout candidate_layout;
CLogFont logfont;
bool result = false;
SetRenderereCommandForCaretTest(
false, true, 4, 0, kCursorOffsetY, hwnd, &command);
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
logfont.lfOrientation = 0;
// Assume underline is enabled in the application.
logfont.lfUnderline = 1;
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
// Underline should be stripped.
ASSERT_EQ(2, layouts.size());
EXPECT_EQ(0, layouts[0].log_font.lfUnderline);
EXPECT_EQ(0, layouts[1].log_font.lfUnderline);
}
// Some applications such as MIEFS use CompositionForm::RECT as a bit flag.
// We should consider the case where two or more style bits are specified
// at the same time.
TEST_F(Win32RendererUtilTest, CompositionFormRECTAsBitFlag_Issue3200425) {
// Check the backward compatibility.
VerifyCompositionStyleBitsCompatibilityForIssue3200425(
true, CompositionForm::RECT,
false, CompositionForm::DEFAULT);
// Set CompositionForm::RECT and CompositionForm::POINT at the same time.
VerifyCompositionStyleBitsCompatibilityForIssue3200425(
false, CompositionForm::DEFAULT,
true, CompositionForm::RECT | CompositionForm::POINT);
// If both of them are specified, the legacy one is used.
VerifyCompositionStyleBitsCompatibilityForIssue3200425(
true, CompositionForm::RECT,
true, CompositionForm::POINT);
}
// Evernote Windows Client 4.0.0.2880 (107102) / Editor component
TEST_F(Win32RendererUtilTest, EvernoteEditorComposition) {
const wchar_t kClassName[] = L"WebViewHost";
const UINT kClassStyle = CS_DBLCLKS;
const DWORD kWindowStyle =
WS_CHILDWINDOW | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
static_assert(kWindowStyle == 0x56000000, "Check actual value");
const DWORD kWindowExStyle =
WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
static_assert(kWindowExStyle == 0, "Check actual value");
const CRect kWindowRect(1548, 879, 1786, 1416);
const CPoint kClientOffset(0, 0);
const CSize kClientSize(238, 537);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
RendererCommand command;
SetRenderereCommandForTest(
false, true, false, 0, hwnd, &command);
// Clear the default ApplicationInfo and update it for Evernote.
command.clear_application_info();
AppInfoUtil::SetBasicApplicationInfo(
command.mutable_application_info(), hwnd,
(ApplicationInfo::ShowCandidateWindow |
ApplicationInfo::ShowSuggestWindow |
ApplicationInfo::ShowCompositionWindow));
AppInfoUtil::SetCaretInfo(
command.mutable_application_info(), false, 0, 0, 0, 0, hwnd);
CandidateWindowLayout candidate_layout;
vector<CompositionWindowLayout> layouts;
bool result = false;
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
// Default GUI font should be selected.
CLogFont default_font = GetFont(true, false);
default_font.lfHeight = 18;
default_font.lfWidth = 0;
ASSERT_EQ(2, layouts.size());
// The first line
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1548, 1416, 1777, 1434, 0, 0, 229, 18,
0, 0, 0, 0, 0, 0, default_font, layout);
{
// "これは、Google日本語入力のTest"
const char kMsg[] =
"\343\201\223\343\202\214\343\201\257\343\200\201Google\346\227\245"
"\346\234\254\350\252\236\345\205\245\345\212\233\343\201\256Test";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(5, layout.marker_layouts.size());
EXPECT_EQ(CPoint(0, 17), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(42, 17), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(45, 17), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(57, 17), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(60, 17), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(108, 17), layout.marker_layouts[2].to);
EXPECT_TRUE(layout.marker_layouts[2].highlighted);
EXPECT_EQ(CPoint(110, 17), layout.marker_layouts[3].from);
EXPECT_EQ(CPoint(197, 17), layout.marker_layouts[3].to);
EXPECT_FALSE(layout.marker_layouts[3].highlighted);
EXPECT_EQ(CPoint(200, 17), layout.marker_layouts[4].from);
EXPECT_EQ(CPoint(229, 17), layout.marker_layouts[4].to);
EXPECT_FALSE(layout.marker_layouts[4].highlighted);
}
// The second line
{
const CompositionWindowLayout &layout = layouts.at(1);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1548, 1434, 1579, 1452, 0, 0, 30, 18,
0, 0, 30, 0, 31, 18, default_font, layout);
{
// "です"
const char kMsg[] = "\343\201\247\343\201\231";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(1, layout.marker_layouts.size());
EXPECT_EQ(CPoint(0, 17), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(30, 17), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
}
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1608, 1434, 1608, 1416, 1777, 1434, candidate_layout);
}
// Crescent Eve 0.82a / Apr 24 2010.
// Crescent Eve sets larger composition form area than its client area.
// DPI virtualization API may fail in this case. See b/3239031.
TEST_F(Win32RendererUtilTest, CrescentEveComposition_Issue3239031) {
const wchar_t kClassName[] = L"CrescentEditer";
const UINT kClassStyle = CS_DBLCLKS | CS_BYTEALIGNCLIENT;
static_assert(kClassStyle == 0x00001008, "Check actual value");
const DWORD kWindowStyle = WS_CHILDWINDOW | WS_VISIBLE | WS_VSCROLL;
static_assert(kWindowStyle == 0x50200000, "Check actual value");
const DWORD kWindowExStyle =
WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR |
WS_EX_ACCEPTFILES | WS_EX_CLIENTEDGE;
static_assert(kWindowExStyle == 0x00000210, "Check actual value");
const CRect kWindowRect(184, 192, 1312, 1426);
const CPoint kClientOffset(2, 2);
const CSize kClientSize(1107, 1230);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
RendererCommand command;
SetRenderereCommandForTest(
false, true, false, 0, hwnd, &command);
// Replace the default values with those of Crescent Eve.
command.clear_application_info();
AppInfoUtil::SetBasicApplicationInfo(
command.mutable_application_info(), hwnd,
(ApplicationInfo::ShowCandidateWindow |
ApplicationInfo::ShowSuggestWindow |
ApplicationInfo::ShowCompositionWindow));
AppInfoUtil::SetCompositionForm(
command.mutable_application_info(),
CompositionForm::POINT | CompositionForm::RECT,
35, 0, 35, 0, 1106, 1624);
AppInfoUtil::SetCaretInfo(
command.mutable_application_info(),
false, 34, 0, 36, 14, hwnd);
CandidateWindowLayout candidate_layout;
vector<CompositionWindowLayout> layouts;
bool result = false;
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
// Default GUI font should be selected.
CLogFont default_font = GetFont(true, false);
default_font.lfHeight = 18;
default_font.lfWidth = 0;
ASSERT_EQ(1, layouts.size());
// The first line
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(221, 194, 481, 212, 0, 0, 259, 18, 0, 0,
259, 0, 260, 18, default_font, layout);
{
// "これは、Google日本語入力のTestです"
const char kMsg[] =
"\343\201\223\343\202\214\343\201\257\343\200\201Google\346\227\245"
"\346\234\254\350\252\236\345\205\245\345\212\233\343\201\256"
"Test\343\201\247\343\201\231";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(5, layout.marker_layouts.size());
EXPECT_EQ(CPoint(0, 17), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(42, 17), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(45, 17), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(57, 17), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(60, 17), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(108, 17), layout.marker_layouts[2].to);
EXPECT_TRUE(layout.marker_layouts[2].highlighted);
EXPECT_EQ(CPoint(110, 17), layout.marker_layouts[3].from);
EXPECT_EQ(CPoint(197, 17), layout.marker_layouts[3].to);
EXPECT_FALSE(layout.marker_layouts[3].highlighted);
EXPECT_EQ(CPoint(200, 17), layout.marker_layouts[4].from);
EXPECT_EQ(CPoint(259, 17), layout.marker_layouts[4].to);
EXPECT_FALSE(layout.marker_layouts[4].highlighted);
}
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
281, 212, 281, 194, 480, 212, candidate_layout);
}
// MSInfo32.exe 6.1.7600 on Windows 7. (b/3433099)
// The composition window and candidate window must be shown even when the
// client sets Composition/CandidateForm outside of the top-level window.
// Note that LogicalToPhysicalPoint API may return FALSE in this situation.
TEST_F(Win32RendererUtilTest, MSInfo32Composition_Issue3433099) {
const double kScaleFactor = 1.0;
WindowPositionEmulator *window_emulator = nullptr;
HWND root_window = nullptr;
HWND child_window = nullptr;
{
const wchar_t kRootClassName[] = L"#32770 (Dialog)";
const UINT kRootClassStyle = CS_DBLCLKS | CS_SAVEBITS;
const DWORD kRootWindowStyle = 0x96CF0044;
const DWORD kRootWindowExStyle = 0x00010100;
const CRect kRootWindowRect(838, 651, 1062, 1157);
const CPoint kRootClientOffset(8, 71);
const CSize kRootClientSize(208, 427);
window_emulator = CreateWindowEmulator(
kRootClassName, kRootWindowRect, kRootClientOffset, kRootClientSize,
kScaleFactor, &root_window);
}
{
const wchar_t kChildClassName[] = L"Edit";
const UINT kChildClassStyle = CS_DBLCLKS | CS_PARENTDC | CS_GLOBALCLASS;
const DWORD kChildWindowStyle = 0x50010080;
const DWORD kChildWindowExStyle = 0x00000204;
const CRect kChildWindowRect(951, 1071, 1072, 1098);
const CPoint kChildClientOffset(2, 2);
const CSize kChildClientSize(117, 23);
child_window = window_emulator->RegisterWindow(
kChildClassName, kChildWindowRect, kChildClientOffset,
kChildClientSize, kScaleFactor);
window_emulator->SetRoot(child_window, root_window);
}
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
window_emulator);
ApplicationInfo app_info;
RendererCommand command;
SetRenderereCommandForTest(
false, true, false, 0, child_window, &command);
// Replace the default values with those of MSInfo32.
command.clear_application_info();
AppInfoUtil::SetBasicApplicationInfo(
command.mutable_application_info(), child_window,
(ApplicationInfo::ShowCandidateWindow |
ApplicationInfo::ShowSuggestWindow |
ApplicationInfo::ShowCompositionWindow));
AppInfoUtil::SetCompositionForm(
command.mutable_application_info(),
CompositionForm::POINT, 2, 1, 0, 0, 0, 0);
AppInfoUtil::SetCaretInfo(
command.mutable_application_info(),
true, 2, 1, 3, 19, child_window);
CandidateWindowLayout candidate_layout;
vector<CompositionWindowLayout> layouts;
bool result = false;
layouts.clear();
candidate_layout.Clear();
result = layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout);
EXPECT_TRUE(result);
// Default GUI font should be selected.
CLogFont default_font = GetFont(true, false);
default_font.lfHeight = 18;
default_font.lfWidth = 0;
ASSERT_EQ(3, layouts.size());
// The first line
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(955, 1074, 1065, 1092, 0, 0, 110, 18, 0, 0,
0, 0, 0, 0, default_font, layout);
{
// "これは、Google"
const char kMsg[] =
"\343\201\223\343\202\214\343\201\257\343\200\201Google";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(3, layout.marker_layouts.size());
EXPECT_EQ(CPoint(0, 17), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(42, 17), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(45, 17), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(57, 17), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(60, 17), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(108, 17), layout.marker_layouts[2].to);
EXPECT_TRUE(layout.marker_layouts[2].highlighted);
}
// The second line
{
const CompositionWindowLayout &layout = layouts.at(1);
EXPECT_COMPOSITION_WINDOW_LAYOUT(953, 1092, 1067, 1110, 0, 0, 114, 18, 0, 0,
0, 0, 0, 0, default_font, layout);
{
// "日本語入力のTes"
const char kMsg[] =
"\346\227\245\346\234\254\350\252\236\345\205\245\345\212\233"
"\343\201\256Tes";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(2, layout.marker_layouts.size());
EXPECT_EQ(CPoint(0, 17), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(87, 17), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(90, 17), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(114, 17), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
}
// The third line
{
const CompositionWindowLayout &layout = layouts.at(2);
EXPECT_COMPOSITION_WINDOW_LAYOUT(953, 1110, 989, 1128, 0, 0, 35, 18, 0, 0,
35, 0, 36, 18, default_font, layout);
{
// "tです"
const char kMsg[] = "t\343\201\247\343\201\231";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(1, layout.marker_layouts.size());
EXPECT_EQ(CPoint(0, 17), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(35, 17), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
}
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1015, 1092, 1015, 1074, 1065, 1092, candidate_layout);
}
// Check if LayoutManager can handle preedits which contains surrogate pair.
// See b/4159275 for details.
// Temporarily disabled to support Windows XP En, where surrogate pair is
// disabled by default.
// TODO(yukawa): Enable this test.
TEST_F(Win32RendererUtilTest,
DISABLED_CheckSurrogatePairInHorizontalComposition_Issue4159275) {
const int kCursorOffsetX = 150;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
RendererCommand command;
SetRenderereCommandForSurrogatePair(
false, false, kCursorOffsetX, hwnd, &command);
CLogFont logfont;
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
vector<CompositionWindowLayout> layouts;
CandidateWindowLayout candidate_layout;
EXPECT_TRUE(layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout));
ASSERT_EQ(1, layouts.size());
// The first line
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(1193, 648, 1554, 697, 0, 0, 360, 49,
0, 0, 360, 0, 361, 49, logfont,
layout);
{
// "𠮟咤𠮟咤𠮟咤𠮟咤"
const char kMsg[] =
"\360\240\256\237\345\222\244\360\240\256\237\345\222\244"
"\360\240\256\237\345\222\244\360\240\256\237\345\222\244";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(4, layout.marker_layouts.size());
EXPECT_EQ(CPoint(0, 48), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(81, 48), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(90, 48), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(171, 48), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(180, 48), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(261, 48), layout.marker_layouts[2].to);
EXPECT_TRUE(layout.marker_layouts[2].highlighted);
EXPECT_EQ(CPoint(270, 48), layout.marker_layouts[3].from);
EXPECT_EQ(CPoint(360, 48), layout.marker_layouts[3].to);
EXPECT_FALSE(layout.marker_layouts[3].highlighted);
}
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1373, 697, 1373, 648, 1553, 697, candidate_layout);
}
// Check if LayoutManager can handle preedits which contains surrogate pair.
// See b/4159275 for details.
// Temporarily disabled to support Windows XP En, where surrogate pair is
// disabled by default.
// TODO(yukawa): Enable this test.
TEST_F(Win32RendererUtilTest,
DISABLED_CheckSurrogatePairInVerticalComposition_Issue4159275) {
const int kCursorOffsetY = 175;
HWND hwnd = nullptr;
LayoutManager layout_mgr(CreateDefaultGUIFontEmulator(),
CreateWindowEmulatorWithDPIScaling(1.0, &hwnd));
RendererCommand command;
SetRenderereCommandForSurrogatePair(
false, true, kCursorOffsetY, hwnd, &command);
CLogFont logfont;
EXPECT_TRUE(mozc::win32::FontUtil::ToLOGFONT(
command.application_info().composition_font(), &logfont));
logfont.lfOrientation = 2700;
vector<CompositionWindowLayout> layouts;
CandidateWindowLayout candidate_layout;
EXPECT_TRUE(layout_mgr.LayoutCompositionWindow(
command, &layouts, &candidate_layout));
ASSERT_EQ(1, layouts.size());
// The first line
{
const CompositionWindowLayout &layout = layouts.at(0);
EXPECT_COMPOSITION_WINDOW_LAYOUT(
1932, 712, 1983, 1073, 0, 0, 51, 360, 51, 0,
0, 360, 51, 361, logfont, layout);
{
// "𠮟咤𠮟咤𠮟咤𠮟咤"
const char kMsg[] =
"\360\240\256\237\345\222\244\360\240\256\237\345\222\244"
"\360\240\256\237\345\222\244\360\240\256\237\345\222\244";
wstring msg;
mozc::Util::UTF8ToWide(kMsg, &msg);
EXPECT_EQ(msg, layout.text);
}
ASSERT_EQ(4, layout.marker_layouts.size());
EXPECT_EQ(CPoint(50, 0), layout.marker_layouts[0].from);
EXPECT_EQ(CPoint(50, 81), layout.marker_layouts[0].to);
EXPECT_FALSE(layout.marker_layouts[0].highlighted);
EXPECT_EQ(CPoint(50, 90), layout.marker_layouts[1].from);
EXPECT_EQ(CPoint(50, 171), layout.marker_layouts[1].to);
EXPECT_FALSE(layout.marker_layouts[1].highlighted);
EXPECT_EQ(CPoint(50, 180), layout.marker_layouts[2].from);
EXPECT_EQ(CPoint(50, 261), layout.marker_layouts[2].to);
EXPECT_TRUE(layout.marker_layouts[2].highlighted);
EXPECT_EQ(CPoint(50, 270), layout.marker_layouts[3].from);
EXPECT_EQ(CPoint(50, 360), layout.marker_layouts[3].to);
EXPECT_FALSE(layout.marker_layouts[3].highlighted);
}
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1932, 892, 1932, 892, 1983, 1072, candidate_layout);
}
TEST_F(Win32RendererUtilTest, GetWritingDirectionTest) {
RendererCommand command;
// Horizontal
SetRenderereCommandForTest(
false, true, false, 0, nullptr, &command);
EXPECT_EQ(LayoutManager::HORIZONTAL_WRITING,
LayoutManager::GetWritingDirection(command.application_info()));
// Vertical
SetRenderereCommandForTest(
false, true, true, 0, nullptr, &command);
EXPECT_EQ(LayoutManager::VERTICAL_WRITING,
LayoutManager::GetWritingDirection(command.application_info()));
// Unspecified
command.mutable_application_info()->
mutable_composition_font()->clear_escapement();
EXPECT_EQ(LayoutManager::WRITING_DIRECTION_UNSPECIFIED,
LayoutManager::GetWritingDirection(command.application_info()));
// Unspecified
command.mutable_application_info()->clear_composition_font();
EXPECT_EQ(LayoutManager::WRITING_DIRECTION_UNSPECIFIED,
LayoutManager::GetWritingDirection(command.application_info()));
}
// Hidemaru 8.01a True-Inline
TEST_F(Win32RendererUtilTest, Hidemaru_Horizontal_Suggest) {
const wchar_t kClassName[] = L"HM32CLIENT";
const CRect kWindowRect(0, 20, 2016, 1050);
const CPoint kClientOffset(8, 42);
const CSize kClientSize(2000, 1000);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd, ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCompositionFont(
&app_info, -15, 0, 0, 0, FW_NORMAL, SHIFTJIS_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, FF_MODERN | FIXED_PITCH,
// "MSゴシック"
"\357\274\255\357\274\263 "
"\343\202\264\343\202\267\343\203\203\343\202\257");
AppInfoUtil::SetCompositionForm(
&app_info, CompositionForm::RECT, 112, 25, 48, 0, 1408, 552);
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::EXCLUDE, 112, 42, 112, 25, 752, 42);
AppInfoUtil::SetCaretInfo(&app_info, true, 160, 25, 162, 40, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
168, 102, 168, 87, 170, 102, layout);
}
// Hidemaru 8.01a True-Inline
TEST_F(Win32RendererUtilTest, Hidemaru_Horizontal_Convert) {
const wchar_t kClassName[] = L"HM32CLIENT";
const CRect kWindowRect(0, 20, 2016, 1050);
const CPoint kClientOffset(8, 42);
const CSize kClientSize(2000, 1000);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd, ApplicationInfo::ShowCandidateWindow);
AppInfoUtil::SetCompositionFont(
&app_info, -15, 0, 0, 0, FW_NORMAL, SHIFTJIS_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, FF_MODERN | FIXED_PITCH,
// "MSゴシック"
"\357\274\255\357\274\263 "
"\343\202\264\343\202\267\343\203\203\343\202\257");
AppInfoUtil::SetCompositionForm(
&app_info, CompositionForm::RECT, 112, 25, 48, 0, 1408, 552);
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::EXCLUDE, 128, 25, 128, 25, 144, 42);
AppInfoUtil::SetCaretInfo(&app_info, true, 160, 25, 162, 40, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
136, 87, 136, 87, 152, 104, layout);
}
// Hidemaru 8.01a True-Inline
TEST_F(Win32RendererUtilTest, Hidemaru_Vertical_Suggest) {
const wchar_t kClassName[] = L"HM32CLIENT";
const CRect kWindowRect(0, 20, 2016, 1050);
const CPoint kClientOffset(8, 42);
const CSize kClientSize(2000, 1000);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd, ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCompositionFont(
&app_info, -15, 0, 2700, 0, FW_NORMAL, SHIFTJIS_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, FF_MODERN | FIXED_PITCH,
// "@MSゴシック"
"@\357\274\255\357\274\263 "
"\343\202\264\343\202\267\343\203\203\343\202\257");
AppInfoUtil::SetCompositionForm(
&app_info, CompositionForm::RECT, 660, 48, 0, 48, 688, 397);
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::EXCLUDE, 660, 67, 641, 48, 660, 400);
AppInfoUtil::SetCaretInfo(&app_info, true, 644, 96, 661, 98, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
652, 158, 652, 158, 669, 160, layout);
}
// Hidemaru 8.01a True-Inline
TEST_F(Win32RendererUtilTest, Hidemaru_Vertical_Convert) {
const wchar_t kClassName[] = L"HM32CLIENT";
const CRect kWindowRect(0, 20, 2016, 1050);
const CPoint kClientOffset(8, 42);
const CSize kClientSize(2000, 1000);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowCandidateWindow |
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCompositionFont(
&app_info, -15, 0, 2700, 0, FW_NORMAL, SHIFTJIS_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, FF_MODERN | FIXED_PITCH,
// "@MSゴシック"
"@\357\274\255\357\274\263 "
"\343\202\264\343\202\267\343\203\203\343\202\257");
AppInfoUtil::SetCompositionForm(
&app_info, CompositionForm::RECT, 660, 48, 0, 48, 668, 397);
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::EXCLUDE, 644, 63, 644, 63, 661, 80);
AppInfoUtil::SetCaretInfo(&app_info, true, 644, 96, 661, 98, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
652, 125, 652, 125, 669, 142, layout);
}
// Open Office Writer 3.01
TEST_F(Win32RendererUtilTest, OOo_Suggest) {
const wchar_t kClassName[] = L"SALFRAME";
const CRect kWindowRect(0, 20, 2016, 1050);
const CPoint kClientOffset(8, 42);
const CSize kClientSize(2000, 1000);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCompositionFont(
&app_info, -16, 0, 0, 0, FW_DONTCARE, ANSI_CHARSET,
OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, 23,
"Times New Roman");
AppInfoUtil::SetCompositionForm(
&app_info, CompositionForm::POINT, 292, 253, 0, 0, 0, 0);
AppInfoUtil::SetCaretInfo(&app_info, true, 292, 253, 294, 273, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
300, 335, 300, 315, 302, 335, layout);
}
// Open Office Writer 3.01
TEST_F(Win32RendererUtilTest, OOo_Convert) {
const wchar_t kClassName[] = L"SALFRAME";
const CRect kWindowRect(0, 20, 2016, 1050);
const CPoint kClientOffset(8, 42);
const CSize kClientSize(2000, 1000);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowCandidateWindow |
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCompositionFont(
&app_info, -16, 0, 0, 0, FW_DONTCARE, ANSI_CHARSET,
OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, 23,
"Times New Roman");
AppInfoUtil::SetCompositionForm(
&app_info, CompositionForm::POINT, 264, 253, 0, 0, 0, 0);
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::EXCLUDE, 250, 258, 250, 257, 253, 275);
AppInfoUtil::SetCaretInfo(&app_info, true, 264, 253, 266, 273, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
258, 320, 258, 319, 261, 337, layout);
}
// Pidgin 2.6.1
TEST_F(Win32RendererUtilTest, Pidgin_Indicator) {
const wchar_t kClassName[] = L"gdkWindowToplevel";
const CRect kWindowRect(0, 20, 2016, 1050);
const CPoint kClientOffset(8, 42);
const CSize kClientSize(2000, 1000);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowCandidateWindow |
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCompositionFont(
&app_info, -16, 0, 0, 0, FW_NORMAL, SHIFTJIS_CHARSET,
OUT_STROKE_PRECIS, CLIP_STROKE_PRECIS,
DRAFT_QUALITY, 50,
// "メイリオ"
"\343\203\241\343\202\244\343\203\252\343\202\252");
AppInfoUtil::SetCompositionForm(
&app_info, CompositionForm::POINT, 48, 589,
96504880, 2617504, 97141432, 2617480);
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::CANDIDATEPOS, 32, 636,
40706080, 96552944, 2615824, 1815374140);
AppInfoUtil::SetCaretInfo(&app_info, false, 0, 0, 0, 0, nullptr);
IndicatorWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutIndicatorWindow(app_info, &layout));
EXPECT_EQ(CRect(56, 651, 57, 667), layout.window_rect);
EXPECT_FALSE(layout.is_vertical);
}
// Pidgin 2.6.1
TEST_F(Win32RendererUtilTest, Pidgin_Suggest) {
const wchar_t kClassName[] = L"gdkWindowToplevel";
const CRect kWindowRect(0, 20, 2016, 1050);
const CPoint kClientOffset(8, 42);
const CSize kClientSize(2000, 1000);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCompositionFont(
&app_info, -16, 0, 0, 0, FW_NORMAL, SHIFTJIS_CHARSET,
OUT_STROKE_PRECIS, CLIP_STROKE_PRECIS,
DRAFT_QUALITY, 50,
// "メイリオ"
"\343\203\241\343\202\244\343\203\252\343\202\252");
AppInfoUtil::SetCompositionForm(
&app_info, CompositionForm::POINT, 48, 589,
96504880, 2617504, 97141432, 2617480);
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::CANDIDATEPOS, 48, 636,
40706080, 96552944, 2615824, 1815374140);
AppInfoUtil::SetCaretInfo(&app_info, false, 0, 0, 0, 0, nullptr);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
56, 667, 56, 651, 57, 667, layout);
}
// Pidgin 2.6.1
TEST_F(Win32RendererUtilTest, Pidgin_Convert) {
const wchar_t kClassName[] = L"gdkWindowToplevel";
const CRect kWindowRect(0, 20, 2016, 1050);
const CPoint kClientOffset(8, 42);
const CSize kClientSize(2000, 1000);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowCandidateWindow |
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCompositionFont(
&app_info, -16, 0, 0, 0, FW_NORMAL, SHIFTJIS_CHARSET,
OUT_STROKE_PRECIS, CLIP_STROKE_PRECIS,
DRAFT_QUALITY, 50,
// "メイリオ"
"\343\203\241\343\202\244\343\203\252\343\202\252");
AppInfoUtil::SetCompositionForm(
&app_info, CompositionForm::POINT, 48, 589,
96504880, 2617504, 97141432, 2617480);
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::CANDIDATEPOS, 32, 636,
40706080, 96552944, 2615824, 1815374140);
AppInfoUtil::SetCaretInfo(&app_info, false, 0, 0, 0, 0, nullptr);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
32, 656, 32, 640, 33, 656, layout);
}
// V2C 2.1.6 on JRE 1.6.0.21 (32-bit)
TEST_F(Win32RendererUtilTest, V2C_Indicator) {
const wchar_t kClassName[] = L"SunAwtFrame";
const CRect kWindowRect(977, 446, 2042, 1052);
const CPoint kClientOffset(8, 8);
const CSize kClientSize(1049, 569);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowSuggestWindow);
// V2C occasionally creates zero-initialized CANDIDATEFORM and maintains
// it regardless of the actual position of the composition.
AppInfoUtil::SetCompositionForm(
&app_info, CompositionForm::DEFAULT, 0, 0, 0, 0, 0, 0);
AppInfoUtil::SetCaretInfo(&app_info, false, 0, 0, 0, 0, nullptr);
IndicatorWindowLayout layout;
EXPECT_FALSE(layout_mgr.LayoutIndicatorWindow(app_info, &layout));
}
// V2C 2.1.6 on JRE 1.6.0.21 (32-bit)
TEST_F(Win32RendererUtilTest, V2C_Suggest) {
const wchar_t kClassName[] = L"SunAwtFrame";
const CRect kWindowRect(977, 446, 2042, 1052);
const CPoint kClientOffset(8, 8);
const CSize kClientSize(1049, 569);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowSuggestWindow);
// V2C occasionally creates zero-initialized CANDIDATEFORM and maintains
// it regardless of the actual position of the composition.
AppInfoUtil::SetCompositionForm(
&app_info, CompositionForm::DEFAULT, 0, 0, 0, 0, 0, 0);
AppInfoUtil::SetCaretInfo(&app_info, false, 0, 0, 0, 0, nullptr);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
EXPECT_NON_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(985, 1023, layout);
}
// V2C 2.1.6 on JRE 1.6.0.21 (32-bit)
TEST_F(Win32RendererUtilTest, V2C_Convert) {
const wchar_t kClassName[] = L"SunAwtFrame";
const CRect kWindowRect(977, 446, 2042, 1052);
const CPoint kClientOffset(8, 8);
const CSize kClientSize(1049, 569);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowCandidateWindow |
ApplicationInfo::ShowSuggestWindow);
// V2C occasionally creates zero-initialized CANDIDATEFORM and maintains
// it regardless of the actual position of the composition.
AppInfoUtil::SetCompositionForm(
&app_info, CompositionForm::DEFAULT, 0, 0, 0, 0, 0, 0);
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::CANDIDATEPOS, 234, 523,
1272967816, 1974044135, -348494668, -2);
AppInfoUtil::SetCaretInfo(&app_info, false, 0, 0, 0, 0, nullptr);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1211, 969, 1211, 951, 1212, 969, layout);
}
// Qt 4.6.3
TEST_F(Win32RendererUtilTest, Qt_Suggest) {
const wchar_t kClassName[] = L"QWidget";
const CRect kWindowRect(0, 20, 2016, 1050);
const CPoint kClientOffset(8, 42);
const CSize kClientSize(2000, 1000);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info,
hwnd,
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCompositionFont(
&app_info, -12, 0, 0, 0, FW_DONTCARE, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, 0,
// "メイリオ"
"\343\203\241\343\202\244\343\203\252\343\202\252");
AppInfoUtil::SetCompositionForm(
&app_info, CompositionForm::FORCE_POSITION, 211, 68,
18901544, 103737984, 4247412, 19851904);
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::EXCLUDE, 211, 87,
211, 68, 221, 87);
AppInfoUtil::SetCaretInfo(&app_info, false, 211, 68, 212, 69, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
219, 149, 219, 130, 229, 149, layout);
}
// Qt 4.6.3
TEST_F(Win32RendererUtilTest, Qt_Convert) {
const wchar_t kClassName[] = L"QWidget";
const CRect kWindowRect(0, 20, 2016, 1050);
const CPoint kClientOffset(8, 42);
const CSize kClientSize(2000, 1000);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info,
hwnd,
ApplicationInfo::ShowCandidateWindow |
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCompositionFont(
&app_info, -12, 0, 0, 0, FW_DONTCARE, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, 0,
// "メイリオ"
"\343\203\241\343\202\244\343\203\252\343\202\252");
AppInfoUtil::SetCompositionForm(
&app_info, CompositionForm::FORCE_POSITION, 187, 68,
18901544, 103737984, 4247412, 19851904);
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::EXCLUDE, 187, 87,
187, 68, 197, 87);
AppInfoUtil::SetCaretInfo(&app_info, false, 187, 68, 188, 69, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
195, 149, 195, 130, 205, 149, layout);
}
// Wordpad x86 on Vista SP1
TEST_F(Win32RendererUtilTest, Wordpad_Vista_Indicator) {
const wchar_t kClassName[] = L"RICHEDIT50W";
const CRect kWindowRect(617, 573, 1319, 881);
const CPoint kClientOffset(2, 22);
const CSize kClientSize(698, 304);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowCandidateWindow |
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCompositionFont(
&app_info, 10, 0, 0, 0, FW_DONTCARE, SHIFTJIS_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, 17,
// "MSPゴシック"
"\357\274\255\357\274\263 "
"\357\274\260\343\202\264\343\202\267\343\203\203\343\202\257");
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::EXCLUDE, 62, 42, 62, 21, 64, 42);
AppInfoUtil::SetCompositionTarget(
&app_info, 1, 693, 596, 17, 625, 579, 1317, 879);
AppInfoUtil::SetCaretInfo(&app_info, false, 74, 21, 75, 38, hwnd);
IndicatorWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutIndicatorWindow(app_info, &layout));
EXPECT_EQ(CRect(693, 596, 694, 613), layout.window_rect);
EXPECT_FALSE(layout.is_vertical);
}
// Wordpad x86 on Vista SP1
TEST_F(Win32RendererUtilTest, Wordpad_Vista_Suggest) {
const wchar_t kClassName[] = L"RICHEDIT50W";
const CRect kWindowRect(617, 573, 1319, 881);
const CPoint kClientOffset(2, 22);
const CSize kClientSize(698, 304);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCompositionFont(
&app_info, 10, 0, 0, 0, FW_DONTCARE, SHIFTJIS_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, 17,
// "MSPゴシック"
"\357\274\255\357\274\263 "
"\357\274\260\343\202\264\343\202\267\343\203\203\343\202\257");
AppInfoUtil::SetCompositionTarget(
&app_info, 0, 681, 596, 17, 625, 579, 1317, 879);
AppInfoUtil::SetCaretInfo(&app_info, false, 98, 21, 99, 38, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
681, 613, 681, 596, 682, 613, layout);
}
// Wordpad x86 on Vista SP1
TEST_F(Win32RendererUtilTest, Wordpad_Vista_Convert) {
const wchar_t kClassName[] = L"RICHEDIT50W";
const CRect kWindowRect(617, 573, 1319, 881);
const CPoint kClientOffset(2, 22);
const CSize kClientSize(698, 304);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowCandidateWindow |
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCompositionFont(
&app_info, 10, 0, 0, 0, FW_DONTCARE, SHIFTJIS_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, 17,
// "MSPゴシック"
"\357\274\255\357\274\263 "
"\357\274\260\343\202\264\343\202\267\343\203\203\343\202\257");
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::EXCLUDE, 62, 42, 62, 21, 64, 42);
AppInfoUtil::SetCompositionTarget(
&app_info, 1, 693, 596, 17, 625, 579, 1317, 879);
AppInfoUtil::SetCaretInfo(&app_info, false, 74, 21, 75, 38, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
693, 613, 693, 596, 694, 613, layout);
}
// MS Word 2010 x64, True Inline, Horizontal
TEST_F(Win32RendererUtilTest, MSWord2010_Horizontal_Suggest) {
const wchar_t kClassName[] = L"_WwG";
const CRect kWindowRect(434, 288, 1275, 841);
const CPoint kClientOffset(0, 0);
const CSize kClientSize(841, 553);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCompositionFont(
&app_info, -14, 0, 0, 0, FW_NORMAL, SHIFTJIS_CHARSET,
OUT_SCREEN_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, 17,
// "MS 明朝"
"\357\274\255\357\274\263 \346\230\216\346\234\235");
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::EXCLUDE, 234, 176,
136, 176, 703, 193);
AppInfoUtil::SetCompositionTarget(
&app_info, 0, 626, 464, 17, 570, 288, 1137, 841);
AppInfoUtil::SetCaretInfo(&app_info, false, 220, 176, 221, 194, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
626, 481, 626, 464, 627, 481, layout);
}
// MS Word 2010 x64, True Inline, Horizontal
TEST_F(Win32RendererUtilTest, MSWord2010_Horizontal_Convert) {
const wchar_t kClassName[] = L"_WwG";
const CRect kWindowRect(434, 288, 1275, 841);
const CPoint kClientOffset(0, 0);
const CSize kClientSize(841, 553);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowCandidateWindow |
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCompositionFont(
&app_info, -14, 0, 0, 0, FW_NORMAL, SHIFTJIS_CHARSET,
OUT_SCREEN_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, 17,
// "MS 明朝"
"\357\274\255\357\274\263 \346\230\216\346\234\235");
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::EXCLUDE, 206, 178,
136, 178, 703, 194);
AppInfoUtil::SetCompositionTarget(
&app_info, 1, 640, 466, 16, 570, 288, 1137, 841);
AppInfoUtil::SetCaretInfo(&app_info, false, 192, 179, 193, 197, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
640, 482, 640, 466, 641, 482, layout);
}
// MS Word 2010 x64, True Inline, Vertical
TEST_F(Win32RendererUtilTest, MSWord2010_Vertical_Suggest) {
const wchar_t kClassName[] = L"_WwG";
const CRect kWindowRect(434, 288, 1275, 824);
const CPoint kClientOffset(0, 0);
const CSize kClientSize(841, 536);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCompositionFont(
&app_info, -14, 0, 2700, 2700, FW_NORMAL, SHIFTJIS_CHARSET,
OUT_SCREEN_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, 17,
// "@MS 明朝"
"@\357\274\255\357\274\263 \346\230\216\346\234\235");
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::EXCLUDE, 662, 228,
644, 130, 662, 697);
AppInfoUtil::SetCompositionTarget(
&app_info, 0, 1096, 474, 18, 434, 418, 1275, 985);
AppInfoUtil::SetCaretInfo(&app_info, false, 644, 214, 645, 235, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1078, 474, 1078, 474, 1096, 475, layout);
}
// MS Word 2010 x64, True Inline, Vertical
TEST_F(Win32RendererUtilTest, MSWord2010_Vertical_Convert) {
const wchar_t kClassName[] = L"_WwG";
const CRect kWindowRect(434, 288, 1275, 824);
const CPoint kClientOffset(0, 0);
const CSize kClientSize(841, 536);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowCandidateWindow |
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCompositionFont(
&app_info, -14, 0, 2700, 2700, FW_NORMAL, SHIFTJIS_CHARSET,
OUT_SCREEN_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, 17,
// "@MS 明朝"
"@\357\274\255\357\274\263 \346\230\216\346\234\235");
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::EXCLUDE, 661, 200,
643, 130, 661, 697);
AppInfoUtil::SetCompositionTarget(
&app_info, 1, 1095, 488, 18, 434, 418, 1275, 985);
AppInfoUtil::SetCaretInfo(&app_info, false, 643, 200, 644, 221, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
1077, 488, 1077, 488, 1095, 489, layout);
}
// Firefox 3.6.10 on Vista SP1 / textarea
TEST_F(Win32RendererUtilTest, Firefox_textarea_Suggest) {
const wchar_t kClassName[] = L"MozillaWindowClass";
const CRect kWindowRect(198, 329, 1043, 1133);
const CPoint kClientOffset(0, 0);
const CSize kClientSize(845, 804);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::EXCLUDE, 44, 378, 44, 378, 44, 398);
AppInfoUtil::SetCompositionTarget(
&app_info, 0, 242, 707, 20, 198, 329, 1043, 1133);
AppInfoUtil::SetCaretInfo(&app_info, false, 89, 378, 90, 398, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
242, 727, 242, 707, 243, 727, layout);
}
// Firefox 3.6.10 on Vista SP1 / textarea
TEST_F(Win32RendererUtilTest, Firefox_textarea_Convert) {
const wchar_t kClassName[] = L"MozillaWindowClass";
const CRect kWindowRect(198, 329, 1043, 1133);
const CPoint kClientOffset(0, 0);
const CSize kClientSize(845, 804);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowCandidateWindow |
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::EXCLUDE, 59, 378, 59, 378, 59, 398);
AppInfoUtil::SetCompositionTarget(
&app_info, 1, 257, 707, 20, 198, 329, 1043, 1133);
AppInfoUtil::SetCaretInfo(&app_info, false, 60, 378, 61, 398, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
257, 727, 257, 707, 258, 727, layout);
}
// Chrome 6.0.472.63 on Vista SP1 / textarea
TEST_F(Win32RendererUtilTest, Chrome_textarea_Suggest) {
const wchar_t kClassName[] = L"Chrome_RenderWidgetHostHWND";
const CRect kWindowRect(153, 190, 891, 906);
const CPoint kClientOffset(0, 0);
const CSize kClientSize(738, 716);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCompositionFont(
&app_info, 11, 0, 0, 0, FW_DONTCARE, SHIFTJIS_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, 0,
// "メイリオ"
"\343\203\241\343\202\244\343\203\252\343\202\252");
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::EXCLUDE, 84, 424, 84, 424, 85, 444);
AppInfoUtil::SetCaretInfo(&app_info, false, 84, 444, 85, 445, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
237, 614, 237, 614, 238, 634, layout);
}
// Chrome 6.0.472.63 on Vista SP1 / textarea
TEST_F(Win32RendererUtilTest, Chrome_textarea_Convert) {
const wchar_t kClassName[] = L"Chrome_RenderWidgetHostHWND";
const CRect kWindowRect(153, 190, 891, 906);
const CPoint kClientOffset(0, 0);
const CSize kClientSize(738, 716);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowCandidateWindow |
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCompositionFont(
&app_info, 11, 0, 0, 0, FW_DONTCARE, SHIFTJIS_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, 0,
// "メイリオ"
"\343\203\241\343\202\244\343\203\252\343\202\252");
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::EXCLUDE, 58, 424, 58, 424, 59, 444);
AppInfoUtil::SetCaretInfo(&app_info, false, 58, 444, 59, 445, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
211, 614, 211, 614, 212, 634, layout);
}
// Internet Explorer 8.0.6001.18943 on Vista SP1 / textarea
TEST_F(Win32RendererUtilTest, IE8_textarea_Suggest) {
const wchar_t kClassName[] = L"Internet Explorer_Server";
const CRect kWindowRect(304, 349, 1360, 1067);
const CPoint kClientOffset(0, 0);
const CSize kClientSize(1056, 718);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::EXCLUDE, 105, 376, 105, 356, 107, 376);
AppInfoUtil::SetCaretInfo(&app_info, false, 105, 368, 106, 384, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
409, 735, 409, 717, 410, 735, layout);
}
// Internet Explorer 8.0.6001.18943 on Vista SP1 / textarea
TEST_F(Win32RendererUtilTest, IE8_textarea_Convert) {
const wchar_t kClassName[] = L"Internet Explorer_Server";
const CRect kWindowRect(304, 349, 1360, 1067);
const CPoint kClientOffset(0, 0);
const CSize kClientSize(1056, 718);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowCandidateWindow |
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::EXCLUDE, 91, 387, 91, 367, 93, 387);
AppInfoUtil::SetCaretInfo(&app_info, false, 91, 379, 92, 380, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
395, 736, 395, 716, 397, 736, layout);
}
// Fudemame 21. See b/3067011.
// It provides no positional information for suggestion. See b/3067011.
TEST_F(Win32RendererUtilTest, Fudemame21_Suggest) {
const wchar_t kClassName[] = L"MrnDirectEdit4";
const CRect kWindowRect(507, 588, 1024, 698);
const CPoint kClientOffset(0, 0);
const CSize kClientSize(517, 110);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCaretInfo(&app_info, false, 0, 0, 0, 0, nullptr);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
EXPECT_NON_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(507, 698, layout);
}
// Fudemame 21. See b/3067011.
TEST_F(Win32RendererUtilTest, Fudemame19_Convert) {
const wchar_t kClassName[] = L"MrnDirectEdit4";
const CRect kWindowRect(507, 588, 1024, 698);
const CPoint kClientOffset(0, 0);
const CSize kClientSize(517, 110);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowCandidateWindow |
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::CANDIDATEPOS, 87, 87, 0, 0, 0, 0);
AppInfoUtil::SetCaretInfo(&app_info, false, 0, 0, 0, 0, nullptr);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
594, 675, 594, 657, 595, 675, layout);
}
// Opera 10.63 (build 3516) / Textarea
TEST_F(Win32RendererUtilTest, Opera10_Suggest) {
const wchar_t kClassName[] = L"OperaWindowClass";
const UINT kClassStyle = CS_DBLCLKS;
const DWORD kWindowStyle =
WS_CAPTION | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
WS_SYSMENU | WS_THICKFRAME | WS_OVERLAPPED | WS_MINIMIZEBOX |
WS_MAXIMIZEBOX;
static_assert(kWindowStyle == 0x16cf0000, "Check actual value");
const DWORD kWindowExStyle =
WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR |
WS_EX_ACCEPTFILES | WS_EX_WINDOWEDGE;
static_assert(kWindowExStyle == 0x00000110, "Check actual value");
const CRect kWindowRect(538, 229, 2114, 1271);
const CPoint kClientOffset(8, 0);
const CSize kClientSize(1560, 1034);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::EXCLUDE, 44, 444, 44, 444, 44, 459);
AppInfoUtil::SetCaretInfo(&app_info, false, 44, 444, 667, 750, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForSuggestion(app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
590, 673, 590, 673, 590, 688, layout);
}
// Opera 10.63 (build 3516) / Textarea
TEST_F(Win32RendererUtilTest, Opera10_Convert) {
const wchar_t kClassName[] = L"OperaWindowClass";
const UINT kClassStyle = CS_DBLCLKS;
const DWORD kWindowStyle =
WS_CAPTION | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
WS_SYSMENU | WS_THICKFRAME | WS_OVERLAPPED | WS_MINIMIZEBOX |
WS_MAXIMIZEBOX;
static_assert(kWindowStyle == 0x16cf0000, "Check actual value");
const DWORD kWindowExStyle =
WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR |
WS_EX_ACCEPTFILES | WS_EX_WINDOWEDGE;
static_assert(kWindowExStyle == 0x00000110, "Check actual value");
const CRect kWindowRect(538, 229, 2114, 1271);
const CPoint kClientOffset(8, 0);
const CSize kClientSize(1560, 1034);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowCandidateWindow |
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCandidateForm(
&app_info, CandidateForm::EXCLUDE, 22, 444, 22, 444, 22, 459);
AppInfoUtil::SetCaretInfo(&app_info, false, 22, 444, 645, 750, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
568, 673, 568, 673, 568, 688, layout);
}
// NTEmacs22 / GNU Emacs 22.2.1
// Issue 5824433
TEST_F(Win32RendererUtilTest, Emacs22) {
const wchar_t kClassName[] = L"Emacs";
const UINT kClassStyle = CS_VREDRAW | CS_HREDRAW;
const DWORD kWindowStyle =
WS_CAPTION | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
WS_SYSMENU | WS_THICKFRAME | WS_OVERLAPPED | WS_MINIMIZEBOX |
WS_MAXIMIZEBOX;
static_assert(kWindowStyle == 0x16cf0000, "Check actual value");
const DWORD kWindowExStyle =
WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR |
WS_EX_ACCEPTFILES | WS_EX_OVERLAPPEDWINDOW;
static_assert(kWindowExStyle == 0x00000310, "Check actual value");
const CRect kWindowRect(175, 175, 797, 924);
const CPoint kClientOffset(10, 53);
const CSize kClientSize(602, 686);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowCompositionWindow |
ApplicationInfo::ShowCandidateWindow |
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCompositionFont(
&app_info, -14, 0, 0, 0, FW_NORMAL, ANSI_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, FIXED_PITCH,
"Courier New");
AppInfoUtil::SetCompositionForm(
&app_info, CompositionForm::RECT, 66, 58,
10, 42, 570, 658);
AppInfoUtil::SetCaretInfo(&app_info, false, 66, 58, 67, 74, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
251, 302, 251, 286, 252, 302, layout);
// This application automatically and frequently generates
// WM_IME_CONTROL/IMC_SETCOMPOSITIONWINDOW even when a user is not
// typing. So we need to show InfoList without delay. b/5824433.
const int mode = layout_mgr.GetCompatibilityMode(app_info);
EXPECT_EQ(SHOW_INFOLIST_IMMEDIATELY, mode & SHOW_INFOLIST_IMMEDIATELY);
}
// Meadow 3.0 / GNU Emacs 22.3.1
// Issue 5824433
TEST_F(Win32RendererUtilTest, Meadow3) {
const wchar_t kClassName[] = L"MEADOW";
const UINT kClassStyle = CS_VREDRAW | CS_HREDRAW;
const DWORD kWindowStyle =
WS_CAPTION | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
WS_SYSMENU | WS_THICKFRAME | WS_OVERLAPPED | WS_MINIMIZEBOX |
WS_MAXIMIZEBOX;
static_assert(kWindowStyle == 0x16cf0000, "Check actual value");
const DWORD kWindowExStyle =
WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR |
WS_EX_ACCEPTFILES | WS_EX_OVERLAPPEDWINDOW;
static_assert(kWindowExStyle == 0x00000310, "Check actual value");
const CRect kWindowRect(175, 175, 797, 928);
const CPoint kClientOffset(10, 53);
const CSize kClientSize(602, 690);
const double kScaleFactor = 1.0;
HWND hwnd = nullptr;
LayoutManager layout_mgr(
CreateDefaultGUIFontEmulator(),
CreateWindowEmulator(kClassName, kWindowRect, kClientOffset, kClientSize,
kScaleFactor, &hwnd));
ApplicationInfo app_info;
AppInfoUtil::SetBasicApplicationInfo(
&app_info, hwnd,
ApplicationInfo::ShowCompositionWindow |
ApplicationInfo::ShowCandidateWindow |
ApplicationInfo::ShowSuggestWindow);
AppInfoUtil::SetCompositionForm(
&app_info, CompositionForm::RECT, 73, 65,
9, 49, 577, 657);
AppInfoUtil::SetCaretInfo(&app_info, false, 0, 0, 0, 0, hwnd);
CandidateWindowLayout layout;
EXPECT_TRUE(layout_mgr.LayoutCandidateWindowForConversion(
app_info, &layout));
EXPECT_EXCLUDE_CANDIDATE_WINDOW_LAYOUT(
258, 311, 258, 293, 259, 311, layout);
// This application automatically and frequently generates
// WM_IME_CONTROL/IMC_SETCOMPOSITIONWINDOW even when a user is not
// typing. So we need to show InfoList without delay. b/5824433.
const int mode = layout_mgr.GetCompatibilityMode(app_info);
EXPECT_EQ(SHOW_INFOLIST_IMMEDIATELY, mode & SHOW_INFOLIST_IMMEDIATELY);
}
} // namespace win32
} // namespace renderer
} // namespace mozc