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

Side by Side Diff: services/prediction/dictionary_service.cc

Issue 1247903003: Add spellcheck and word suggestion to the prediction service (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <algorithm>
6 #include <deque>
7 #include <fstream>
8 #include <string>
9
10 #include "base/base_paths.h"
11 #include "base/files/file_path.h"
12 #include "base/path_service.h"
13 #include "mojo/services/prediction/public/interfaces/prediction.mojom.h"
14 #include "mojo/tools/embed/data.h"
15 #include "services/prediction/dictionary_service.h"
16 #include "services/prediction/input_info.h"
17 #include "services/prediction/kDictFile.h"
18 #include "services/prediction/key_set.h"
19 #include "third_party/prediction/suggest/core/dictionary/dictionary.h"
20 #include "third_party/prediction/suggest/core/result/suggestion_results.h"
21 #include "third_party/prediction/suggest/core/session/dic_traverse_session.h"
22 #include "third_party/prediction/suggest/core/session/prev_words_info.h"
23 #include "third_party/prediction/suggest/core/suggest_options.h"
24 #include "third_party/prediction/suggest/policyimpl/dictionary/structure/diction ary_structure_with_buffer_policy_factory.h"
25
26 namespace prediction {
27
28 DictionaryService::DictionaryService() {
29 max_suggestion_size = 50;
30 default_dictionary = NULL;
APW 2015/07/23 18:02:15 use nullptr everywhere instead of NULL.
riajiang 2015/07/31 02:13:05 Done.
31 default_session = NULL;
32 }
33
34 DictionaryService::~DictionaryService() {
35 delete default_dictionary;
qsr 2015/07/23 19:40:42 You want to use a std::unique_ptr instead of havin
riajiang 2015/07/31 02:13:04 I changed it to use base/memory/scoped_ptr, is it
36 }
37
38 void DictionaryService::LoadDictionary() {
APW 2015/07/23 19:51:38 This function name is misleading... I think you're
riajiang 2015/07/31 02:13:05 How's CopyDictionaryFromRes? And added checking if
39 base::FilePath dir_temp;
APW 2015/07/23 19:51:39 Since the path for writing the dictionary and read
riajiang 2015/07/31 02:13:04 I changed to only creating the path once in GetDic
40 PathService::Get(base::DIR_TEMP, &dir_temp);
41 std::string path = dir_temp.value() + "/main_en.dict";
42 std::ofstream dic_file(path.c_str(),
43 std::ofstream::out | std::ofstream::binary);
44 dic_file.write(prediction::kDictFile.data, prediction::kDictFile.size);
45 dic_file.close();
46 }
47
48 latinime::Dictionary* const DictionaryService::OpenDictionary(
49 const std::string path,
50 const int start_offset,
51 const int size,
52 const bool is_updatable) {
53 latinime::DictionaryStructureWithBufferPolicy::StructurePolicyPtr
54 dictionary_structure_with_buffer_policy(
55 latinime::DictionaryStructureWithBufferPolicyFactory::
56 newPolicyForExistingDictFile(path.c_str(), start_offset, size,
APW 2015/07/23 19:51:38 Function names must start upper case unless its a
riajiang 2015/07/31 02:13:05 This is a function in Android's native code. Since
57 is_updatable));
58 if (!dictionary_structure_with_buffer_policy) {
59 return 0;
60 }
61
62 latinime::Dictionary* const dictionary = new latinime::Dictionary(
63 std::move(dictionary_structure_with_buffer_policy));
64 return dictionary;
65 }
66
67 mojo::Array<mojo::String> DictionaryService::GetDictionarySuggestion(
68 PredictionInfoPtr prediction_info,
69 ProximityInfoService* proximity_info) {
70 mojo::Array<mojo::String> suggestion_words =
71 mojo::Array<mojo::String>::New(0);
72
73 // dictionary
74 base::FilePath dir_temp;
75 PathService::Get(base::DIR_TEMP, &dir_temp);
76 std::string path = dir_temp.value() + "/main_en.dict";
77 if (!default_dictionary) {
78 LoadDictionary();
79 default_dictionary =
APW 2015/07/23 19:51:39 default_dictionary should probably be a scoped_ptr
riajiang 2015/07/31 02:13:04 Done.
80 this->OpenDictionary(path, 0, prediction::kDictFile.size, false);
81 if (!default_dictionary) {
82 suggestion_words.push_back(prediction_info->current_word);
83 return suggestion_words.Clone().Pass();
84 }
85 }
86
87 // dic_traverse_session
88 if (!default_session) {
89 default_session = reinterpret_cast<latinime::DicTraverseSession*>(
APW 2015/07/23 19:51:39 should this be scoped_ptr too?
riajiang 2015/07/31 02:13:04 Done.
90 latinime::DicTraverseSession::getSessionInstance(
91 "en", prediction::kDictFile.size));
92 latinime::PrevWordsInfo empty_prev_words;
93 default_session->init(default_dictionary, &empty_prev_words, 0);
94 }
95
96 // current word
97 int input_size = prediction_info->current_word.size();
98 InputInfo input_info(input_size);
99 input_info.ProcessInput(prediction_info->current_word);
100
101 // previous words
102 latinime::PrevWordsInfo* prev_words_info =
APW 2015/07/23 19:51:38 since you allocate this here and delete it right a
riajiang 2015/07/31 02:13:05 Done.
103 ProcessPrevWord(prediction_info->previous_words,
104 prediction_info->are_beginning_of_sentence);
105
106 // suggestion options
107 // is_gesture, use_full_edit_distance,
108 // block_offensive_words, space_aware gesture_enabled
109 int options[4] = {0, 0, 0, 0};
110 latinime::SuggestOptions suggest_options(options, 4);
APW 2015/07/23 19:51:38 there's a macro for determining the array size of
riajiang 2015/07/31 02:13:05 Done.
111
112 latinime::SuggestionResults suggestion_results(max_suggestion_size);
113 if (input_size > 0) {
114 DictionaryService::default_dictionary->getSuggestions(
115 proximity_info->GetNativeProximityInfoService(),
116 DictionaryService::default_session, input_info.GetXCoordinates(),
117 input_info.GetYCoordinates(), input_info.GetTimes(),
118 input_info.GetPointerIds(), input_info.GetCodepoints(), input_size,
119 prev_words_info, &suggest_options, -1.0f, &suggestion_results);
120 } else {
121 DictionaryService::default_dictionary->getPredictions(prev_words_info,
122 &suggestion_results);
123 }
124 delete prev_words_info;
125
126 // process suggestion results
127 std::deque<std::string> suggestion_words_reverse;
128 char cur_beginning = prediction_info->current_word[0];
APW 2015/07/23 19:51:39 this assumes current_word is size > 0. You didn't
riajiang 2015/07/31 02:13:05 Done.
129 std::string cur_rest =
130 std::string(prediction_info->current_word.data())
131 .substr(1, prediction_info->current_word.size() - 1);
132 std::string lo_cur = std::string(1, (char)tolower(cur_beginning)) + cur_rest;
133 std::string up_cur = std::string(1, (char)toupper(cur_beginning)) + cur_rest;
134 while (!suggestion_results.mSuggestedWords.empty()) {
APW 2015/07/23 19:51:38 Please use an iterator instead of popping and chec
riajiang 2015/07/31 02:13:05 But mSuggestedWords is a std::priority_queue?
APW 2015/07/31 21:49:15 shoudl still be iterable I think
135 const latinime::SuggestedWord& suggested_word =
136 suggestion_results.mSuggestedWords.top();
137 int word_count =
138 std::min(suggested_word.getCodePointCount(), MAX_WORD_LENGTH);
139 char word[word_count + 1];
140 for (int i = 0; i < word_count; i++) {
141 word[i] = (char)suggested_word.getCodePoint()[i];
APW 2015/07/23 19:51:38 While this conversion from code point (int) to cha
APW 2015/07/23 19:51:39 use static_cast<char>(var)
riajiang 2015/07/31 02:13:04 Changed to use char16 as we discussed.
riajiang 2015/07/31 02:13:04 Changed to use char16 as we discussed.
142 }
143 word[word_count] = '\0';
144 std::string word_string(word);
145 // remove dups
146 if (word_string != lo_cur && word_string != up_cur) {
APW 2015/07/23 19:51:39 I don't think this does what you think. You'll ne
riajiang 2015/07/31 02:13:05 Changed to use compare and added removing dups wit
147 if (isupper(cur_beginning))
148 word_string[0] = toupper(word_string[0]);
149 suggestion_words_reverse.push_front(word_string);
150 }
151 suggestion_results.mSuggestedWords.pop();
152 }
153 for (std::deque<std::string>::iterator it = suggestion_words_reverse.begin();
APW 2015/07/23 19:51:39 Why do the reverse thing? You can push_back inste
riajiang 2015/07/31 02:13:05 mSuggestedWords is a priority queue but I don't kn
154 it != suggestion_words_reverse.end(); ++it) {
155 suggestion_words.push_back(mojo::String(*it));
156 }
157
158 if (suggestion_words.size() == 0)
159 suggestion_words.push_back(prediction_info->current_word);
APW 2015/07/23 19:51:38 Why return current word as the suggestion if empty
riajiang 2015/07/31 02:13:04 I was thinking if there's no suggestion based on u
160
161 return suggestion_words.Clone().Pass();
162 }
163
164 // modified from Android JniDataUtils::constructPrevWordsInfo
165 latinime::PrevWordsInfo* DictionaryService::ProcessPrevWord(
166 mojo::Array<mojo::String>& prev_words,
167 mojo::Array<bool>& beginnings) {
168 int prev_word_codepoints[MAX_PREV_WORD_COUNT_FOR_N_GRAM][MAX_WORD_LENGTH];
169 int prev_word_codepoint_count[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
170 bool is_beginning_of_sentence[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
171 int prevwords_count =
172 std::min((int)prev_words.size(), MAX_PREV_WORD_COUNT_FOR_N_GRAM);
APW 2015/07/23 19:51:38 instead of using int here can you use size_t?
riajiang 2015/07/31 02:13:04 I used (size_t) for MAX_PREV_WORD_COUNT_FOR_N_GRAM
173 for (int i = 0; i < prevwords_count; ++i) {
174 prev_word_codepoint_count[i] = 0;
175 is_beginning_of_sentence[i] = false;
176 int prev_word_size = prev_words[i].size();
177 if (prev_word_size > MAX_WORD_LENGTH) {
178 continue;
179 }
180 for (int j = 0; j < prev_word_size; j++) {
181 prev_word_codepoints[i][j] = (int)prev_words[i][j];
182 }
183 prev_word_codepoint_count[i] = prev_word_size;
184 is_beginning_of_sentence[i] = beginnings[i];
185 }
186 latinime::PrevWordsInfo* prev_words_info = new latinime::PrevWordsInfo(
187 prev_word_codepoints, prev_word_codepoint_count, is_beginning_of_sentence,
188 prevwords_count);
189 return prev_words_info;
190 }
191
192 } // namespace prediction
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698