1 // Copyright 2010-2018, Google Inc. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above 11 // copyright notice, this list of conditions and the following disclaimer 12 // in the documentation and/or other materials provided with the 13 // distribution. 14 // * Neither the name of Google Inc. nor the names of its 15 // contributors may be used to endorse or promote products derived from 16 // this software without specific prior written permission. 17 // 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30 // A class handling the converter on the session layer. 31 32 #ifndef MOZC_SESSION_SESSION_CONVERTER_H_ 33 #define MOZC_SESSION_SESSION_CONVERTER_H_ 34 35 #include <memory> 36 #include <string> 37 #include <vector> 38 39 #include "base/port.h" 40 #include "session/session_converter_interface.h" 41 42 namespace mozc { 43 namespace commands { 44 class CandidateList; 45 class Candidates; 46 class Context; 47 class Output; 48 class Preedit; 49 class Request; 50 class Result; 51 } // namespace commands 52 53 namespace config { 54 class Config; 55 } // namespace config 56 57 namespace session { 58 class CandidateList; 59 60 // Class handling ConverterInterface with a session state. This class 61 // support stateful operations related with the converter. 62 class SessionConverter : public SessionConverterInterface { 63 public: 64 SessionConverter(const ConverterInterface *converter, 65 const commands::Request *request, 66 const config::Config *config); 67 virtual ~SessionConverter(); 68 69 // Checks if the current state is in the state bitmap. 70 virtual bool CheckState(States) const; 71 72 // Indicates if the conversion session is active or not. In general, 73 // Convert functions make it active and Cancel, Reset and Commit 74 // functions make it deactive. 75 virtual bool IsActive() const; 76 77 // Returns the default conversion preferences to be used for custom 78 // conversion. 79 virtual const ConversionPreferences &conversion_preferences() const; 80 81 // Gets the selected candidate. If no candidate is selected, returns NULL. 82 virtual const Segment::Candidate * 83 GetSelectedCandidateOfFocusedSegment() const; 84 85 // Sends a conversion request to the converter. 86 virtual bool Convert(const composer::Composer &composer); 87 virtual bool ConvertWithPreferences(const composer::Composer &composer, 88 const ConversionPreferences &preferences); 89 90 // Gets reading text (e.g. from "猫" to "ねこ"). 91 virtual bool GetReadingText(const string &source_text, string *reading); 92 93 // Sends a transliteration request to the converter. 94 virtual bool ConvertToTransliteration( 95 const composer::Composer &composer, 96 transliteration::TransliterationType type); 97 98 // Converts the current composition to half-width characters. 99 // NOTE(komatsu): This function might be merged to ConvertToTransliteration. 100 virtual bool ConvertToHalfWidth(const composer::Composer &composer); 101 102 // Switches the composition to Hiragana, full-width Katakana or 103 // half-width Katakana by rotation. 104 virtual bool SwitchKanaType(const composer::Composer &composer); 105 106 // Sends a suggestion request to the converter. 107 virtual bool Suggest(const composer::Composer &composer); 108 virtual bool SuggestWithPreferences(const composer::Composer &composer, 109 const ConversionPreferences &preferences); 110 111 // Sends a prediction request to the converter. 112 virtual bool Predict(const composer::Composer &composer); 113 virtual bool PredictWithPreferences(const composer::Composer &composer, 114 const ConversionPreferences &preferences); 115 116 // Sends a prediction request to the converter. 117 // The result is added at the tail of existing candidate list as "suggestion" 118 // candidates. 119 virtual bool ExpandSuggestion(const composer::Composer &composer); 120 virtual bool ExpandSuggestionWithPreferences( 121 const composer::Composer &composer, 122 const ConversionPreferences &preferences); 123 124 // Clears conversion segments, but keep the context. 125 virtual void Cancel(); 126 127 // Clears conversion segments and the context. 128 virtual void Reset(); 129 130 // Fixes the conversion with the current status. 131 virtual void Commit(const composer::Composer &composer, 132 const commands::Context &context); 133 134 // Fixes the suggestion candidate. Stores the number of characters in the key 135 // of the committed candidate to committed_key_size. 136 // For example, assume that "日本語" was suggested as a candidate for "にほ". 137 // The key of the candidate is "にほんご". Therefore, when the candidate is 138 // committed by this function, consumed_key_size will be set to 4. 139 // |consumed_key_size| can be very large value 140 // (i.e. SessionConverter::kConsumedAllCharacters). 141 // In this case all the composition characters are consumed. 142 // Examples: 143 // - {composition: "にほんご|", value: "日本語", consumed_key_size: 4} 144 // This is usual case of suggestion/composition. 145 // - {composition: "にほんg|", value: "日本語", 146 // consumed_key_size: kConsumedAllCharacters} 147 // kConsumedAllCharacters can be very large value. 148 // - {composition: "わた|しのなまえ", value: "綿", 149 // consumed_key_size: 2} 150 // (Non-Auto) Partial suggestion. 151 // New composition is "しのなまえ". 152 // - {composition: "わたしのなまえ|", value: "私の", 153 // consumed_key_size: 4} 154 // Auto partial suggestion. 155 // Consumed the composition partially and "なまえ" becomes composition. 156 // - {composition: "じゅえり", value: "クエリ", 157 // consumed_key_size: 4} 158 // Typing correction. 159 // The value クエリ corresponds to raw composition "じゅえり". 160 // True is returned if the suggestion is successfully committed. 161 virtual bool CommitSuggestionByIndex(size_t index, 162 const composer::Composer &composer, 163 const commands::Context &context, 164 size_t *consumed_key_size); 165 166 // Selects a candidate and commit the selected candidate. True is 167 // returned if the suggestion is successfully committed. 168 // c.f. CommitSuggestionInternal 169 virtual bool CommitSuggestionById(int id, 170 const composer::Composer &composer, 171 const commands::Context &context, 172 size_t *consumed_key_size); 173 174 // Fixes only the conversion of the first segment, and keep the rest. 175 // The caller should delete characters from composer based on returned 176 // |committed_key_size|. 177 // If |consumed_key_size| is 0, this means that there is only a segment 178 // so Commit() method is called instead. In this case, the caller 179 // should not delete any characters. 180 // c.f. CommitSuggestionInternal 181 virtual void CommitFirstSegment(const composer::Composer &composer, 182 const commands::Context &context, 183 size_t *consumed_key_size); 184 185 // Does allmost the same thing as CommitFirstSegment. 186 // The only difference is to fix the segments from the head to the focused. 187 virtual void CommitHeadToFocusedSegments(const composer::Composer &composer, 188 const commands::Context &context, 189 size_t *consumed_key_size); 190 191 // Commits the preedit string represented by Composer. 192 virtual void CommitPreedit(const composer::Composer &composer, 193 const commands::Context &context); 194 195 // Commits the specified number of characters at the head of the preedit 196 // string represented by Composer. 197 // The caller should delete characters from composer based on returned 198 // |consumed_key_size|. 199 // c.f. CommitSuggestionInternal 200 // TODO(yamaguchi): Enhance to support the conversion mode. 201 virtual void CommitHead(size_t count, 202 const composer::Composer &composer, 203 size_t *consumed_key_size); 204 205 // Reverts the last "Commit" operation 206 virtual void Revert(); 207 208 // Moves the focus of segments. 209 virtual void SegmentFocusRight(); 210 virtual void SegmentFocusLast(); 211 virtual void SegmentFocusLeft(); 212 virtual void SegmentFocusLeftEdge(); 213 214 // Resizes the focused segment. 215 virtual void SegmentWidthExpand(const composer::Composer &composer); 216 virtual void SegmentWidthShrink(const composer::Composer &composer); 217 218 // Moves the focus of candidates. 219 virtual void CandidateNext(const composer::Composer &composer); 220 virtual void CandidateNextPage(); 221 virtual void CandidatePrev(); 222 virtual void CandidatePrevPage(); 223 // Moves the focus to the candidate represented by the id. 224 virtual void CandidateMoveToId(int id, const composer::Composer &composer); 225 // Moves the focus to the index from the beginning of the current page. 226 virtual void CandidateMoveToPageIndex(size_t index); 227 // Moves the focus to the candidate represented by the shortcut. If 228 // the shortcut is not bound with any candidate, false is returned. 229 virtual bool CandidateMoveToShortcut(char shortcut); 230 231 // Operation for the candidate list. 232 virtual void SetCandidateListVisible(bool visible); 233 234 // Fills protocol buffers and update the internal status. 235 virtual void PopOutput(const composer::Composer &composer, 236 commands::Output *output); 237 238 // Fills protocol buffers 239 virtual void FillOutput(const composer::Composer &composer, 240 commands::Output *output) const; 241 242 // Sets setting by the request; 243 virtual void SetRequest(const commands::Request *request); 244 245 // Sets setting by the config; 246 virtual void SetConfig(const config::Config *config); 247 248 // Set setting by the context. 249 virtual void OnStartComposition(const commands::Context &context); 250 251 // Fills segments with the conversion preferences. 252 static void SetConversionPreferences( 253 const ConversionPreferences &preferences, 254 Segments *segments); 255 256 // Copies SessionConverter 257 // TODO(hsumita): Copy all member variables. 258 // Currently, converter_ is not copied. 259 virtual SessionConverter *Clone() const; 260 261 // Fills protocol buffers with all flatten candidate words. 262 void FillAllCandidateWords(commands::CandidateList *candidates) const; 263 set_selection_shortcut(config::Config::SelectionShortcut selection_shortcut)264 virtual void set_selection_shortcut( 265 config::Config::SelectionShortcut selection_shortcut) { 266 selection_shortcut_ = selection_shortcut; 267 } 268 set_use_cascading_window(bool use_cascading_window)269 virtual void set_use_cascading_window(bool use_cascading_window) { 270 use_cascading_window_ = use_cascading_window; 271 } 272 273 // Meaning that all the composition characters are consumed. 274 // c.f. CommitSuggestionInternal 275 static const size_t kConsumedAllCharacters; 276 277 private: 278 friend class SessionConverterTest; 279 280 // Resets the result value stored at the previous command. 281 void ResetResult(); 282 283 // Resets the session state variables. 284 void ResetState(); 285 286 // Notifies the converter that the current segment is focused. 287 void SegmentFocus(); 288 289 // Notifies the converter that the current segment is fixed. 290 void SegmentFix(); 291 292 // Fixes the conversion of the [0, segments_to_commit -1 ] segments, 293 // and keep the rest. 294 // Internal implementation for CommitFirstSegment and 295 // CommitHeadToFocusedSegment. 296 void CommitSegmentsInternal(const composer::Composer &composer, 297 const commands::Context &context, 298 size_t segments_to_commit, 299 size_t *consumed_key_size); 300 301 // Gets preedit from segment(index) to segment(index + size). 302 void GetPreedit(size_t index, size_t size, string *preedit) const; 303 // Gets conversion from segment(index) to segment(index + size). 304 void GetConversion(size_t index, size_t size, string *conversion) const; 305 // Gets consumed size of the preedit characters. 306 // c.f. CommitSuggestionInternal 307 size_t GetConsumedPreeditSize(const size_t index, size_t size) const; 308 309 // Performs the command if the command candidate is selected. True 310 // is returned if a command is performed. 311 bool MaybePerformCommandCandidate(size_t index, size_t size); 312 313 // Updates internal states 314 bool UpdateResult(size_t index, size_t size, size_t *consumed_key_size); 315 316 // Fills the candidate list with the focused segment's candidates. 317 // This method does not clear the candidate list before processing. 318 // Only the candidates of which id is not existent in the candidate list 319 // are appended. Other candidates are ignored. 320 void AppendCandidateList(); 321 // Clears the candidate list and fill it with the focused segment's 322 // candidates. 323 void UpdateCandidateList(); 324 325 // Returns the candidate index to be used by the converter. 326 int GetCandidateIndexForConverter(const size_t segment_index) const; 327 328 // If focus_id is pointing to the last of suggestions, 329 // call StartPrediction(). 330 void MaybeExpandPrediction(const composer::Composer &composer); 331 332 // Returns the value of candidate to be used by the converter. 333 string GetSelectedCandidateValue(size_t segment_index) const; 334 335 // Returns the candidate to be used by the converter. 336 const Segment::Candidate &GetSelectedCandidate(size_t segment_index) const; 337 338 // Returns the length of committed candidate's key in characters. 339 // True is returned if the selected candidate is successfully committed. 340 bool CommitSuggestionInternal(const composer::Composer &composer, 341 const commands::Context &context, 342 size_t *committed_length); 343 344 void SegmentFocusInternal(size_t segment_index); 345 void ResizeSegmentWidth(const composer::Composer &composer, int delta); 346 347 void FillConversion(commands::Preedit *preedit) const; 348 void FillResult(commands::Result *result) const; 349 void FillCandidates(commands::Candidates *candidates) const; 350 351 bool IsEmptySegment(const Segment &segment) const; 352 353 // Handles selected_indices for usage stats. 354 void InitializeSelectedCandidateIndices(); 355 void UpdateSelectedCandidateIndex(); 356 void UpdateCandidateStats(const string &base_name, int32 index); 357 void CommitUsageStats( 358 SessionConverterInterface::State commit_state, 359 const commands::Context &context); 360 void CommitUsageStatsWithSegmentsSize( 361 SessionConverterInterface::State commit_state, 362 const commands::Context &context, 363 size_t submit_segment_size); 364 365 SessionConverterInterface::State state_; 366 367 const ConverterInterface *converter_; 368 std::unique_ptr<Segments> segments_; 369 size_t segment_index_; 370 371 // Previous suggestions to be merged with the current predictions. 372 Segment previous_suggestions_; 373 374 // Default conversion preferences. 375 ConversionPreferences conversion_preferences_; 376 377 std::unique_ptr<commands::Result> result_; 378 379 std::unique_ptr<CandidateList> candidate_list_; 380 bool candidate_list_visible_; 381 382 const commands::Request *request_; 383 const config::Config *config_; 384 385 // Mutable values of |config_|. These values may be changed temporaliry per 386 // session. 387 bool use_cascading_window_; 388 config::Config::SelectionShortcut selection_shortcut_; 389 390 // Indicates whether config_ will be updated by the command candidate. 391 Segment::Candidate::Command updated_command_; 392 393 // Selected index data of each segments for usage stats. 394 std::vector<int> selected_candidate_indices_; 395 396 // Revision number of client context with which the converter determines when 397 // the history segments should be invalidated. See the implemenation of 398 // OnStartComposition for details. 399 int32 client_revision_; 400 401 DISALLOW_COPY_AND_ASSIGN(SessionConverter); 402 }; 403 404 } // namespace session 405 } // namespace mozc 406 407 #endif // MOZC_SESSION_SESSION_CONVERTER_H_ 408