blob: a7c40ef011ae2478faac27766d9de4f19a9e5c56 [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 "testing/base/public/googletest.h"
#include "testing/base/public/gunit.h"
#include "base/util.h"
#include "session/commands.pb.h"
#include "win32/ime/ime_candidate_info.h"
namespace mozc {
namespace win32 {
namespace {
#define EXPECT_CANDIDATEINFO( \
size, count, first_list_offset, private_size, private_offset, info) \
do { \
EXPECT_EQ((size), (info)->dwSize); \
EXPECT_EQ((count), (info)->dwCount); \
EXPECT_EQ((first_list_offset), (info)->dwOffset[0]); \
EXPECT_EQ(0, (info)->dwOffset[1]); \
EXPECT_EQ(0, (info)->dwOffset[2]); \
EXPECT_EQ(0, (info)->dwOffset[3]); \
EXPECT_EQ(0, (info)->dwOffset[4]); \
EXPECT_EQ(0, (info)->dwOffset[5]); \
EXPECT_EQ(0, (info)->dwOffset[6]); \
EXPECT_EQ(0, (info)->dwOffset[7]); \
EXPECT_EQ(0, (info)->dwOffset[8]); \
EXPECT_EQ(0, (info)->dwOffset[9]); \
EXPECT_EQ(0, (info)->dwOffset[10]); \
EXPECT_EQ(0, (info)->dwOffset[11]); \
EXPECT_EQ(0, (info)->dwOffset[12]); \
EXPECT_EQ(0, (info)->dwOffset[13]); \
EXPECT_EQ(0, (info)->dwOffset[14]); \
EXPECT_EQ(0, (info)->dwOffset[15]); \
EXPECT_EQ(0, (info)->dwOffset[16]); \
EXPECT_EQ(0, (info)->dwOffset[17]); \
EXPECT_EQ(0, (info)->dwOffset[18]); \
EXPECT_EQ(0, (info)->dwOffset[19]); \
EXPECT_EQ(0, (info)->dwOffset[20]); \
EXPECT_EQ(0, (info)->dwOffset[21]); \
EXPECT_EQ(0, (info)->dwOffset[22]); \
EXPECT_EQ(0, (info)->dwOffset[23]); \
EXPECT_EQ(0, (info)->dwOffset[24]); \
EXPECT_EQ(0, (info)->dwOffset[25]); \
EXPECT_EQ(0, (info)->dwOffset[26]); \
EXPECT_EQ(0, (info)->dwOffset[27]); \
EXPECT_EQ(0, (info)->dwOffset[28]); \
EXPECT_EQ(0, (info)->dwOffset[29]); \
EXPECT_EQ(0, (info)->dwOffset[30]); \
EXPECT_EQ(0, (info)->dwOffset[31]); \
EXPECT_EQ(0, (info)->dwOffset[32]); \
EXPECT_EQ((private_size), (info)->dwPrivateSize); \
EXPECT_EQ((private_offset), (info)->dwPrivateOffset); \
} while (false) \
#define EXPECT_CANDIDATELIST( \
size, style, count, selection, page_start, page_size, info) \
do { \
EXPECT_EQ((size), (info)->dwSize); \
EXPECT_EQ((style), (info)->dwStyle); \
EXPECT_EQ((count), (info)->dwCount); \
EXPECT_EQ((selection), (info)->dwSelection); \
EXPECT_EQ((page_start), (info)->dwPageStart); \
EXPECT_EQ((page_size), (info)->dwPageSize); \
EXPECT_EQ((page_start), (info)->dwPageStart); \
} while (false) \
const size_t kNumCandidates = 13;
const char* kValueList[kNumCandidates] = {
"Beta",
"\343\203\231\343\203\274\343\202\277", // "ベータ"
"BETA",
"beta",
"\316\262", // "β"
"\316\222", // "Β"
"\343\214\274", // "㌼"
"Beta",
"\343\201\271\343\203\274\343\201\237", // "べーた"
"\343\203\231\343\203\274\343\202\277", // "ベータ"
"be-ta",
// "be-ta"
"\357\275\202\357\275\205\357\274\215\357\275\224\357\275\201",
"\357\276\215\357\276\236\357\275\260\357\276\200", // "ベータ"
};
const int32 kValueLengths[kNumCandidates] = {
4, 3, 4, 4, 1, 1, 1, 4, 3, 3, 5, 5, 4,
};
const int32 kIDs[kNumCandidates] = {
0, 1, 2, 3, 4, 5, 6, 7, -1, -2, -3, -7, -11,
};
class ScopedCanidateInfoBuffer {
public:
explicit ScopedCanidateInfoBuffer(size_t size)
: header_(static_cast<CANDIDATEINFO *>(Allocate(size))) {}
~ScopedCanidateInfoBuffer() {
::HeapFree(::GetProcessHeap(), 0, header_);
}
const CANDIDATEINFO *header() const {
return header_;
}
CANDIDATEINFO *mutable_header() {
return header_;
}
const CANDIDATELIST *GetList(int candidate_list_no) const {
DCHECK_GE(candidate_list_no, 0);
DCHECK_LT(candidate_list_no, header_->dwCount);
return reinterpret_cast<const CANDIDATELIST *>(
reinterpret_cast<const BYTE *>(header_) +
header_->dwOffset[candidate_list_no]);
}
const wstring GetCandidateString(int candidate_list_no,
int candidate_index) const {
const CANDIDATELIST *list = GetList(candidate_list_no);
DCHECK_GE(candidate_index, 0);
DCHECK_LT(candidate_index, list->dwCount);
return reinterpret_cast<const wchar_t *>(
reinterpret_cast<const BYTE *>(list) +
list->dwOffset[candidate_index]);
}
private:
static void *Allocate(size_t size) {
return ::HeapAlloc(::GetProcessHeap(), 0, size);
}
CANDIDATEINFO *header_;
DISALLOW_COPY_AND_ASSIGN(ScopedCanidateInfoBuffer);
};
// TODO(yukawa): Make a common library for this function.
void FillOutputForSuggestion(commands::Output *output) {
DCHECK_NE(nullptr, output);
output->Clear();
output->set_mode(commands::HIRAGANA);
output->set_consumed(true);
{
commands::Preedit *preedit = output->mutable_preedit();
preedit->set_cursor(4);
{
commands::Preedit::Segment *segment = preedit->add_segment();
segment->set_annotation(commands::Preedit::Segment::UNDERLINE);
// "あるふぁ"
segment->set_value("\343\201\202\343\202\213\343\201\265\343\201\201");
segment->set_value_length(4);
// "あるふぁ"
segment->set_key("\343\201\202\343\202\213\343\201\265\343\201\201");
}
}
{
commands::Candidates *candidates = output->mutable_candidates();
candidates->set_size(2);
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(0);
candidate->set_value("AlphaBeta");
candidate->set_id(0);
}
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(1);
// "アルファ"
candidate->set_value("\343\202\242\343\203\253\343\203\225\343\202\241");
candidate->set_id(1);
}
candidates->set_position(0);
candidates->set_category(commands::SUGGESTION);
candidates->set_display_type(commands::MAIN);
{
commands::Footer *footer = candidates->mutable_footer();
footer->set_sub_label("build 436");
}
}
{
commands::Status *status = output->mutable_status();
status->set_activated(true);
status->set_mode(commands::HIRAGANA);
}
{
commands::CandidateList *candidate_list =
output->mutable_all_candidate_words();
candidate_list->set_focused_index(0);
{
commands::CandidateWord *candidate = candidate_list->add_candidates();
candidate->set_id(0);
candidate->set_index(0);
// "あるふぁべーた"
candidate->set_key("\343\201\202\343\202\213\343\201\265\343\201\201"
"\343\201\271\343\203\274\343\201\237");
candidate->set_value("AlphaBeta");
}
{
commands::CandidateWord *candidate = candidate_list->add_candidates();
candidate->set_id(1);
candidate->set_index(1);
// "アルファ"
candidate->set_value("\343\202\242\343\203\253\343\203\225\343\202\241");
}
candidate_list->set_category(commands::SUGGESTION);
}
}
// TODO(yukawa): Make a common library for this function.
void FillOutputForConversion(
commands::Output *output, int focused_index, bool has_candidates) {
DCHECK_LE(0, focused_index);
DCHECK_GT(kNumCandidates, focused_index);
DCHECK_NE(nullptr, output);
output->Clear();
const int32 focused_value_length = kValueLengths[focused_index];
const char *focused_value = kValueList[focused_index];
const int32 focused_id = kIDs[focused_index];
output->set_mode(commands::HIRAGANA);
output->set_consumed(true);
{
const int alpha_length = 5;
commands::Preedit *preedit = output->mutable_preedit();
preedit->set_cursor(alpha_length + focused_value_length);
{
commands::Preedit::Segment *segment = preedit->add_segment();
segment->set_annotation(commands::Preedit::Segment::UNDERLINE);
segment->set_value("Alpha");
segment->set_value_length(alpha_length);
// "あるふぁ"
segment->set_key("\343\201\202\343\202\213\343\201\265\343\201\201");
}
{
commands::Preedit::Segment *segment = preedit->add_segment();
segment->set_annotation(commands::Preedit::Segment::HIGHLIGHT);
segment->set_value(focused_value);
segment->set_value_length(focused_value_length);
// "べーた"
segment->set_key("\343\201\271\343\203\274\343\201\237");
}
preedit->set_highlighted_position(alpha_length);
}
if (has_candidates) {
commands::Candidates *candidates = output->mutable_candidates();
candidates->set_focused_index(focused_index);
candidates->set_size(9);
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(0);
candidate->set_value("BETA");
{
commands::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");
annotation->set_shortcut("1");
}
candidate->set_id(0);
}
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(1);
candidate->set_value("\343\203\231\343\203\274\343\202\277");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "[全] カタカナ"
annotation->set_description(
"[\345\215\212] \343\202\253\343\202\277\343\202\253\343\203\212");
annotation->set_shortcut("2");
}
candidate->set_id(1);
}
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(2);
candidate->set_value("beta");
{
commands::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");
annotation->set_shortcut("3");
}
candidate->set_id(2);
}
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(3);
// "β"
candidate->set_value("\316\262");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "ギリシャ文字(小文字)"
annotation->set_description(
"\343\202\256\343\203\252\343\202\267\343\203\243\346\226\207"
"\345\255\227(\345\260\217\346\226\207\345\255\227)");
annotation->set_shortcut("4");
}
candidate->set_id(3);
}
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(4);
// "Β"
candidate->set_value("\316\222");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "ギリシャ文字(大文字)"
annotation->set_description(
"\343\202\256\343\203\252\343\202\267\343\203\243\346\226\207"
"\345\255\227(\345\244\247\346\226\207\345\255\227)");
annotation->set_shortcut("5");
}
candidate->set_id(4);
}
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(5);
// "㌼"
candidate->set_value("\343\214\274");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "<機種依存文字>"
annotation->set_description("<\346\251\237\347\250\256\344\276\235"
"\345\255\230\346\226\207\345\255\227>");
annotation->set_shortcut("6");
}
candidate->set_id(5);
}
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(6);
candidate->set_value("Beta");
{
commands::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");
annotation->set_shortcut("7");
}
candidate->set_id(6);
}
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(7);
// "べーた"
candidate->set_value("\343\201\271\343\203\274\343\201\237");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "ひらがな"
annotation->set_description(
"\343\201\262\343\202\211\343\201\214\343\201\252");
annotation->set_shortcut("8");
}
candidate->set_id(7);
}
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(8);
// "そのほかの文字種"
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");
{
commands::Annotation *annotation = candidate->mutable_annotation();
annotation->set_shortcut("9");
}
candidate->set_id(-3);
}
candidates->set_position(5);
{
commands::Candidates *sub_candidates =
candidates->mutable_subcandidates();
sub_candidates->set_focused_index(2);
sub_candidates->set_size(5);
{
{
commands::Candidates::Candidate *candidate =
sub_candidates->add_candidate();
candidate->set_index(0);
// "べーた"
candidate->set_value("\343\201\271\343\203\274\343\201\237");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "ひらがな"
annotation->set_description(
"\343\201\262\343\202\211\343\201\214\343\201\252");
}
candidate->set_id(-1);
}
{
commands::Candidates::Candidate *candidate =
sub_candidates->add_candidate();
candidate->set_index(1);
// "ベータ"
candidate->set_value("\343\203\231\343\203\274\343\202\277");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "[全] カタカナ"
annotation->set_description(
"[\345\215\212] "
"\343\202\253\343\202\277\343\202\253\343\203\212");
}
candidate->set_id(-2);
}
{
commands::Candidates::Candidate *candidate =
sub_candidates->add_candidate();
candidate->set_index(2);
candidate->set_value("be-ta");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "[半]"
annotation->set_description("[\345\215\212]");
}
candidate->set_id(-3);
}
{
commands::Candidates::Candidate *candidate =
sub_candidates->add_candidate();
candidate->set_index(3);
// "be-ta"
candidate->set_value(
"\357\275\202\357\275\205\357\274\215\357\275\224\357\275\201");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "[全]"
annotation->set_description("[\345\205\250]");
}
candidate->set_id(-7);
}
{
commands::Candidates::Candidate *candidate =
sub_candidates->add_candidate();
candidate->set_index(4);
// "ベータ"
candidate->set_value(
"\357\276\215\357\276\236\357\275\260\357\276\200");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "[半] カタカナ"
annotation->set_description(
"[\345\215\212] "
"\343\202\253\343\202\277\343\202\253\343\203\212");
}
candidate->set_id(-11);
}
}
sub_candidates->set_position(8);
sub_candidates->set_category(commands::TRANSLITERATION);
sub_candidates->set_display_type(commands::CASCADE);
}
candidates->set_category(commands::CONVERSION);
candidates->set_display_type(commands::MAIN);
{
commands::Footer *footer = candidates->mutable_footer();
footer->set_index_visible(true);
footer->set_logo_visible(true);
footer->set_sub_label("build 436");
}
}
{
commands::Status *status = output->mutable_status();
status->set_activated(true);
status->set_mode(commands::HIRAGANA);
}
{
commands::CandidateList *candidate_list =
output->mutable_all_candidate_words();
candidate_list->set_focused_index(focused_index);
for (size_t i = 0; i < kNumCandidates; ++i) {
commands::CandidateWord *candidate = candidate_list->add_candidates();
candidate->set_id(kIDs[i]);
candidate->set_index(i);
candidate->set_value(kValueList[i]);
}
candidate_list->set_category(commands::CONVERSION);
}
}
string ToUTF8(const wstring &wstr) {
string result;
Util::WideToUTF8(wstr, &result);
return result;
}
} // anonymous namespace
// Some games such as EMIL CHRONICLE ONLINE assumes that
// CANDIDATELIST::dwPageSize never be zero nor grater than 10 despite that
// the WDK document for IMM32 declares this field can be 0. See b/3033499.
#define EXPECT_SAFE_PAGE_SIZE(pagesize) \
do { \
EXPECT_GT((pagesize), 0); \
EXPECT_LT((pagesize), 11); \
} while (false)
TEST(CandidateInfoUtilTest, ConversionTest) {
commands::Output output;
CandidateInfo info;
// First conversion.
// It is common for traditional IMEs not to display candidate window for the
// first conversion. These IMEs do not fill CANDIDATEINFO for the first
// conversion, too. See b/2978825 for details. Mozc server conforms
// to this behavior by keeping |output.candidates()| empty for the first
// conversion.
FillOutputForConversion(&output, 0, false);
info.Clear();
EXPECT_TRUE(CandidateInfoUtil::Convert(output, &info));
EXPECT_EQ(0, info.candidate_info_size);
EXPECT_EQ(0, info.candidate_list_size);
EXPECT_EQ(0, info.count);
EXPECT_EQ(0, info.selection);
EXPECT_FALSE(info.show_candidate);
EXPECT_TRUE(info.offsets.empty());
EXPECT_TRUE(info.text_buffer.empty());
// Second conversion.
FillOutputForConversion(&output, 1, true);
info.Clear();
EXPECT_TRUE(CandidateInfoUtil::Convert(output, &info));
EXPECT_EQ(330, info.candidate_info_size);
EXPECT_EQ(186, info.candidate_list_size);
EXPECT_EQ(kNumCandidates, info.count);
EXPECT_EQ(1, info.selection);
EXPECT_TRUE(info.show_candidate);
EXPECT_EQ(kNumCandidates, info.offsets.size());
EXPECT_EQ(55, info.text_buffer.size());
// End conversion.
output.clear_all_candidate_words();
output.clear_candidates();
info.Clear();
EXPECT_TRUE(CandidateInfoUtil::Convert(output, &info));
EXPECT_EQ(0, info.candidate_info_size);
EXPECT_EQ(0, info.candidate_list_size);
EXPECT_EQ(0, info.count);
EXPECT_EQ(0, info.selection);
EXPECT_FALSE(info.show_candidate);
EXPECT_TRUE(info.offsets.empty());
EXPECT_TRUE(info.text_buffer.empty());
}
TEST(CandidateInfoUtilTest, SuggestionTest) {
commands::Output output;
FillOutputForSuggestion(&output);
CandidateInfo info;
info.Clear();
EXPECT_TRUE(CandidateInfoUtil::Convert(output, &info));
EXPECT_EQ(0, info.candidate_info_size);
EXPECT_EQ(0, info.candidate_list_size);
EXPECT_EQ(0, info.count);
EXPECT_EQ(0, info.selection);
EXPECT_FALSE(info.show_candidate);
EXPECT_TRUE(info.offsets.empty());
EXPECT_TRUE(info.text_buffer.empty());
}
TEST(CandidateInfoUtilTest, WriteResultTest) {
commands::Output output;
FillOutputForConversion(&output, 1, true);
CandidateInfo info;
EXPECT_TRUE(CandidateInfoUtil::Convert(output, &info));
ScopedCanidateInfoBuffer buffer(info.candidate_info_size);
CandidateInfoUtil::Write(info, buffer.mutable_header());
EXPECT_CANDIDATEINFO(330, 1, sizeof(CANDIDATEINFO), 0, 0, buffer.header());
EXPECT_CANDIDATELIST(186, IME_CAND_READ, kNumCandidates, 1, 0, 9,
buffer.GetList(0));
EXPECT_EQ(kValueList[0], ToUTF8(buffer.GetCandidateString(0, 0)));
EXPECT_EQ(kValueList[1], ToUTF8(buffer.GetCandidateString(0, 1)));
EXPECT_EQ(kValueList[2], ToUTF8(buffer.GetCandidateString(0, 2)));
EXPECT_EQ(kValueList[3], ToUTF8(buffer.GetCandidateString(0, 3)));
EXPECT_EQ(kValueList[4], ToUTF8(buffer.GetCandidateString(0, 4)));
EXPECT_EQ(kValueList[5], ToUTF8(buffer.GetCandidateString(0, 5)));
EXPECT_EQ(kValueList[6], ToUTF8(buffer.GetCandidateString(0, 6)));
EXPECT_EQ(kValueList[7], ToUTF8(buffer.GetCandidateString(0, 7)));
EXPECT_EQ(kValueList[8], ToUTF8(buffer.GetCandidateString(0, 8)));
EXPECT_EQ(kValueList[9], ToUTF8(buffer.GetCandidateString(0, 9)));
EXPECT_EQ(kValueList[10], ToUTF8(buffer.GetCandidateString(0, 10)));
EXPECT_EQ(kValueList[11], ToUTF8(buffer.GetCandidateString(0, 11)));
EXPECT_EQ(kValueList[12], ToUTF8(buffer.GetCandidateString(0, 12)));
}
TEST(CandidateInfoUtilTest, PagingEmulation_Issue4077022) {
commands::Output output;
FillOutputForConversion(&output, 11, true);
CandidateInfo info;
EXPECT_TRUE(CandidateInfoUtil::Convert(output, &info));
ScopedCanidateInfoBuffer buffer(info.candidate_info_size);
CandidateInfoUtil::Write(info, buffer.mutable_header());
EXPECT_CANDIDATEINFO(330, 1, sizeof(CANDIDATEINFO), 0, 0, buffer.header());
EXPECT_CANDIDATELIST(186, IME_CAND_READ, kNumCandidates, 11, 9, 9,
buffer.GetList(0));
}
TEST(CandidateInfoUtilTest, WriteSafeDefaultTest) {
commands::Output output;
FillOutputForConversion(&output, 1, true);
CandidateInfo info;
CandidateInfoUtil::SetSafeDefault(&info);
ScopedCanidateInfoBuffer buffer(info.candidate_info_size);
CandidateInfoUtil::Write(info, buffer.mutable_header());
EXPECT_CANDIDATEINFO(
sizeof(CANDIDATEINFO) + sizeof(CANDIDATELIST), 1,
sizeof(CANDIDATEINFO), 0, 0, buffer.header());
}
} // namespace win32
} // namespace mozc