Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "character_composer.h" | 5 #include "character_composer.h" |
| 6 | 6 |
| 7 #include <cstdlib> | 7 #include <algorithm> |
| 8 #include <iterator> | |
| 8 | 9 |
| 9 #include "third_party/gtk+/gdk/gdkkeysyms.h" | 10 #include "third_party/gtk+/gdk/gdkkeysyms.h" |
| 11 #include "ui/base/gtk/gtk_integers.h" | |
| 10 | 12 |
| 11 namespace { | 13 namespace { |
| 12 | 14 |
| 13 inline int CompareSequenceValue(unsigned int key, uint16 value) { | 15 typedef std::vector<unsigned int> ComposeBufferType; |
| 14 return (key > value) ? 1 : ((key < value) ? -1 : 0); | 16 |
| 17 // An iterator class to apply std::lower_bound for composition table | |
|
brettw
2011/07/07 15:36:46
Be sure to get a period at the end of this new com
hashimoto
2011/07/08 03:22:44
Fixed
| |
| 18 class SequenceIterator : | |
|
brettw
2011/07/07 15:36:46
I'd put the colon on this line indented 4 spaces (
hashimoto
2011/07/08 03:22:44
Fixed
| |
| 19 public std::iterator<std::random_access_iterator_tag, const uint16*> { | |
| 20 public: | |
| 21 SequenceIterator() : ptr_(NULL), stride_(0) {} | |
| 22 SequenceIterator(const uint16* ptr, int stride) | |
| 23 : ptr_(ptr), stride_(stride) {} | |
| 24 | |
| 25 const uint16* ptr() const {return ptr_;} | |
| 26 int stride() const {return stride_;} | |
| 27 | |
| 28 SequenceIterator& operator++() { | |
| 29 ptr_ += stride_; | |
| 30 return *this; | |
| 31 } | |
| 32 SequenceIterator& operator+=(int n) { | |
| 33 ptr_ += stride_*n; | |
| 34 return *this; | |
| 35 } | |
| 36 | |
| 37 const uint16* operator*() const {return ptr_;} | |
| 38 | |
| 39 private: | |
| 40 const uint16* ptr_; | |
| 41 int stride_; | |
| 42 }; | |
| 43 | |
| 44 inline SequenceIterator operator+(const SequenceIterator& l, int r) { | |
| 45 return SequenceIterator(l) += r; | |
| 15 } | 46 } |
| 16 | 47 |
| 48 inline int operator-(const SequenceIterator& l, const SequenceIterator& r) { | |
| 49 const int d = l.ptr() - r.ptr(); | |
| 50 DCHECK(l.stride() == r.stride() && l.stride() > 0 && d%l.stride() == 0); | |
| 51 return d/l.stride(); | |
| 52 } | |
| 53 | |
| 54 inline bool operator==(const SequenceIterator& l, const SequenceIterator& r) { | |
| 55 DCHECK(l.stride() == r.stride()); | |
| 56 return l.ptr() == r.ptr(); | |
| 57 } | |
| 58 | |
| 59 inline bool operator!=(const SequenceIterator& l, const SequenceIterator& r) { | |
| 60 return !(l == r); | |
| 61 } | |
| 62 | |
| 63 // A function to compare keycode value | |
| 64 inline int CompareSequenceValue(unsigned int l, unsigned int r) { | |
| 65 return (l > r) ? 1 : ((l < r) ? -1 : 0); | |
| 66 } | |
| 67 | |
| 68 // A template to make |CompareFunc| work like operator<. | |
| 69 // |CompareFunc| is required to implement a member function, | |
| 70 // int operator()(const ComposeBufferType& l, const uint16* r) const. | |
| 71 template<typename CompareFunc> | |
| 72 struct ComparatorAdoptor { | |
| 73 bool operator()(const ComposeBufferType& l, const uint16* r) const { | |
| 74 return CompareFunc()(l, r) == -1; | |
| 75 } | |
| 76 bool operator()(const uint16* l, const ComposeBufferType& r) const { | |
| 77 return CompareFunc()(r, l) == 1; | |
| 78 } | |
| 79 }; | |
| 80 | |
| 17 class ComposeChecker { | 81 class ComposeChecker { |
| 18 public: | 82 public: |
| 83 // This class does not take the ownership of |data|, |data| should be alive | |
| 84 // for the lifetime of the object. | |
| 85 // |data| is a pointer to the head of an array of | |
| 86 // length (|max_sequence_length| + 2)*|n_sequences|. | |
| 87 // Every (|max_sequence_length| + 2) elements of |data| represent an entry. | |
| 88 // First |max_sequence_length| elements of an entry is the sequecne which | |
| 89 // composes the character represented by the last two elements of the entry. | |
| 19 ComposeChecker(const uint16* data, int max_sequence_length, int n_sequences); | 90 ComposeChecker(const uint16* data, int max_sequence_length, int n_sequences); |
| 20 bool CheckSequence(const std::vector<unsigned int>& sequence, | 91 bool CheckSequence(const ComposeBufferType& sequence, |
| 21 uint32* composed_character) const; | 92 uint32* composed_character) const; |
| 22 | 93 |
| 23 private: | 94 private: |
| 24 static int CompareSequence(const void* key_void, const void* value_void); | 95 struct CompareSequence { |
| 96 int operator()(const ComposeBufferType& l, const uint16* r) const; | |
| 97 }; | |
| 25 | 98 |
| 99 // This class does not take the ownership of |data_|, | |
| 100 // the dtor does not delete |data_|. | |
| 26 const uint16* data_; | 101 const uint16* data_; |
| 27 int max_sequence_length_; | 102 int max_sequence_length_; |
| 28 int n_sequences_; | 103 int n_sequences_; |
| 29 int row_stride_; | 104 int row_stride_; |
| 30 | 105 |
| 31 DISALLOW_COPY_AND_ASSIGN(ComposeChecker); | 106 DISALLOW_COPY_AND_ASSIGN(ComposeChecker); |
| 32 }; | 107 }; |
| 33 | 108 |
| 34 ComposeChecker::ComposeChecker(const uint16* data, | 109 ComposeChecker::ComposeChecker(const uint16* data, |
| 35 int max_sequence_length, | 110 int max_sequence_length, |
| 36 int n_sequences) | 111 int n_sequences) |
| 37 : data_(data), | 112 : data_(data), |
| 38 max_sequence_length_(max_sequence_length), | 113 max_sequence_length_(max_sequence_length), |
| 39 n_sequences_(n_sequences), | 114 n_sequences_(n_sequences), |
| 40 row_stride_(max_sequence_length + 2) { | 115 row_stride_(max_sequence_length + 2) { |
| 41 } | 116 } |
| 42 | 117 |
| 43 bool ComposeChecker::CheckSequence( | 118 bool ComposeChecker::CheckSequence(const ComposeBufferType& sequence, |
| 44 const std::vector<unsigned int>& sequence, | 119 uint32* composed_character) const { |
| 45 uint32* composed_character) const { | |
| 46 const int sequence_length = sequence.size(); | 120 const int sequence_length = sequence.size(); |
| 47 if (sequence_length > max_sequence_length_) | 121 if (sequence_length > max_sequence_length_) |
| 48 return false; | 122 return false; |
| 49 // Find sequence in the table | 123 // Find sequence in the table. |
| 50 const uint16* found = static_cast<const uint16*>( | 124 const SequenceIterator begin(data_, row_stride_); |
| 51 bsearch(&sequence, data_, n_sequences_, | 125 const SequenceIterator end = begin + n_sequences_; |
| 52 sizeof(uint16)*row_stride_, CompareSequence)); | 126 const SequenceIterator found = std::lower_bound( |
| 53 if (!found) | 127 begin, end, sequence, ComparatorAdoptor<CompareSequence>()); |
| 128 if (found == end || CompareSequence()(sequence, *found) != 0) | |
| 54 return false; | 129 return false; |
| 55 // Ensure |found| is pointing the first matching element | |
| 56 while (found > data_ && | |
| 57 CompareSequence(&sequence, found - row_stride_) == 0) | |
| 58 found -= row_stride_; | |
| 59 | 130 |
| 60 if (sequence_length == max_sequence_length_ || found[sequence_length] == 0) { | 131 if (sequence_length == max_sequence_length_ || |
| 61 // |found| is not partially matching. It's fully matching | 132 (*found)[sequence_length] == 0) { |
| 62 const uint16* data_end = data_ + row_stride_*n_sequences_; | 133 // |found| is not partially matching. It's fully matching. |
| 63 if (found + row_stride_ >= data_end || | 134 if (found + 1 == end || |
| 64 CompareSequence(&sequence, found + row_stride_) != 0) { | 135 CompareSequence()(sequence, *(found + 1)) != 0) { |
| 65 // There is no composition longer than |found| which matches to |sequence| | 136 // There is no composition longer than |found| which matches to |
| 66 const uint32 value = (found[max_sequence_length_] << 16) | | 137 // |sequence|. |
| 67 found[max_sequence_length_ + 1]; | 138 const uint32 value = ((*found)[max_sequence_length_] << 16) | |
| 139 (*found)[max_sequence_length_ + 1]; | |
| 68 *composed_character = value; | 140 *composed_character = value; |
| 69 } | 141 } |
| 70 } | 142 } |
| 71 return true; | 143 return true; |
| 72 } | 144 } |
| 73 | 145 |
| 74 // static | 146 int ComposeChecker::CompareSequence::operator()(const ComposeBufferType& l, |
| 75 int ComposeChecker::CompareSequence(const void* key_void, | 147 const uint16* r) const { |
| 76 const void* value_void) { | 148 for(size_t i = 0; i < l.size(); ++i) { |
| 77 typedef std::vector<unsigned int> KeyType; | 149 const int compare_result = CompareSequenceValue(l[i], r[i]); |
| 78 const KeyType& key = *static_cast<const KeyType*>(key_void); | |
| 79 const uint16* value = static_cast<const uint16*>(value_void); | |
| 80 | |
| 81 for(size_t i = 0; i < key.size(); ++i) { | |
| 82 const int compare_result = CompareSequenceValue(key[i], value[i]); | |
| 83 if(compare_result) | 150 if(compare_result) |
| 84 return compare_result; | 151 return compare_result; |
| 85 } | 152 } |
| 86 return 0; | 153 return 0; |
| 87 } | 154 } |
| 88 | 155 |
| 89 | 156 |
| 90 class ComposeCheckerWithCompactTable { | 157 class ComposeCheckerWithCompactTable { |
| 91 public: | 158 public: |
| 159 // This class does not take the ownership of |data|, |data| should be alive | |
| 160 // for the lifetime of the object. | |
| 161 // First |index_size|*|index_stride| elements of |data| are an index table. | |
| 162 // Every |index_stride| elements of an index table are an index entry. | |
| 163 // If you are checking with a sequence of length N beginning with character C, | |
| 164 // you have to find an index entry whose first element is C, then get the N-th | |
| 165 // element of the index entry as the index. | |
| 166 // The index is pointing the element of |data| where the composition table for | |
| 167 // sequences of length N beginning with C is placed. | |
| 168 | |
| 92 ComposeCheckerWithCompactTable(const uint16* data, | 169 ComposeCheckerWithCompactTable(const uint16* data, |
| 93 int max_sequence_length, | 170 int max_sequence_length, |
| 94 int index_size, | 171 int index_size, |
| 95 int index_stride); | 172 int index_stride); |
| 96 bool CheckSequence(const std::vector<unsigned int>& sequence, | 173 bool CheckSequence(const ComposeBufferType& sequence, |
| 97 uint32* composed_character) const; | 174 uint32* composed_character) const; |
| 98 | 175 |
| 99 private: | 176 private: |
| 100 static int CompareSequenceFront(const void* key_void, const void* value_void); | 177 struct CompareSequenceFront { |
| 101 static int CompareSequenceSkipFront(const void* key_void, | 178 int operator()(const ComposeBufferType& l, const uint16* r) const; |
| 102 const void* value_void); | 179 }; |
| 180 struct CompareSequenceSkipFront { | |
| 181 int operator()(const ComposeBufferType& l, const uint16* r) const; | |
| 182 }; | |
| 103 | 183 |
| 184 // This class does not take the ownership of |data_|, | |
| 185 // the dtor does not delete |data_|. | |
| 104 const uint16* data_; | 186 const uint16* data_; |
| 105 int max_sequence_length_; | 187 int max_sequence_length_; |
| 106 int index_size_; | 188 int index_size_; |
| 107 int index_stride_; | 189 int index_stride_; |
| 108 }; | 190 }; |
| 109 | 191 |
| 110 ComposeCheckerWithCompactTable::ComposeCheckerWithCompactTable( | 192 ComposeCheckerWithCompactTable::ComposeCheckerWithCompactTable( |
| 111 const uint16* data, | 193 const uint16* data, |
| 112 int max_sequence_length, | 194 int max_sequence_length, |
| 113 int index_size, | 195 int index_size, |
| 114 int index_stride) | 196 int index_stride) |
| 115 : data_(data), | 197 : data_(data), |
| 116 max_sequence_length_(max_sequence_length), | 198 max_sequence_length_(max_sequence_length), |
| 117 index_size_(index_size), | 199 index_size_(index_size), |
| 118 index_stride_(index_stride) { | 200 index_stride_(index_stride) { |
| 119 } | 201 } |
| 120 | 202 |
| 121 bool ComposeCheckerWithCompactTable::CheckSequence( | 203 bool ComposeCheckerWithCompactTable::CheckSequence( |
| 122 const std::vector<unsigned int>& sequence, | 204 const ComposeBufferType& sequence, |
| 123 uint32* composed_character) const { | 205 uint32* composed_character) const { |
| 124 const int compose_length = sequence.size(); | 206 const int compose_length = sequence.size(); |
| 125 if (compose_length > max_sequence_length_) | 207 if (compose_length > max_sequence_length_) |
| 126 return false; | 208 return false; |
| 127 // Find corresponding index for the first keypress | 209 // Find corresponding index for the first keypress. |
| 128 const uint16* index = static_cast<const uint16*>( | 210 const SequenceIterator index_begin(data_, index_stride_); |
| 129 bsearch(&sequence, data_, index_size_, | 211 const SequenceIterator index_end = index_begin + index_size_; |
| 130 sizeof(uint16)*index_stride_, CompareSequenceFront)); | 212 const SequenceIterator index = |
| 131 if (!index) | 213 std::lower_bound(index_begin, index_end, sequence, |
| 214 ComparatorAdoptor<CompareSequenceFront>()); | |
| 215 if (index == index_end || CompareSequenceFront()(sequence, *index) != 0) | |
| 132 return false; | 216 return false; |
| 133 if (compose_length == 1) | 217 if (compose_length == 1) |
| 134 return true; | 218 return true; |
| 135 // Check for composition sequences | 219 // Check for composition sequences. |
| 136 for (int length = compose_length - 1; length < max_sequence_length_; | 220 for (int length = compose_length - 1; length < max_sequence_length_; |
| 137 ++length) { | 221 ++length) { |
| 138 const uint16* table = data_ + index[length]; | 222 const uint16* table = data_ + (*index)[length]; |
| 139 const uint16* table_next = data_ + index[length + 1]; | 223 const uint16* table_next = data_ + (*index)[length + 1]; |
| 140 if (table_next > table) { | 224 if (table_next > table) { |
| 141 // There are composition sequences for this |length| | 225 // There are composition sequences for this |length|. |
| 142 const int row_stride = length + 1; | 226 const int row_stride = length + 1; |
| 143 const int n_sequences = (table_next - table)/row_stride; | 227 const int n_sequences = (table_next - table)/row_stride; |
| 144 const uint16* seq = static_cast<const uint16*>( | 228 const SequenceIterator table_begin(table, row_stride); |
| 145 bsearch(&sequence, table, n_sequences, | 229 const SequenceIterator table_end = table_begin + n_sequences; |
| 146 sizeof(uint16)*row_stride, CompareSequenceSkipFront)); | 230 const SequenceIterator found = |
| 147 if (seq) { | 231 std::lower_bound(table_begin, table_end, sequence, |
| 148 if (length == compose_length - 1) // exact match | 232 ComparatorAdoptor<CompareSequenceSkipFront>()); |
| 149 *composed_character = seq[length]; | 233 if (found != table_end && |
| 234 CompareSequenceSkipFront()(sequence, *found) == 0) { | |
| 235 if (length == compose_length - 1) // Exact match. | |
| 236 *composed_character = (*found)[length]; | |
| 150 return true; | 237 return true; |
| 151 } | 238 } |
| 152 } | 239 } |
| 153 } | 240 } |
| 154 return false; | 241 return false; |
| 155 } | 242 } |
| 156 | 243 |
| 157 // static | 244 int ComposeCheckerWithCompactTable::CompareSequenceFront::operator()( |
| 158 int ComposeCheckerWithCompactTable::CompareSequenceFront( | 245 const ComposeBufferType& l, const uint16* r) const { |
| 159 const void* key_void, | 246 return CompareSequenceValue(l[0], r[0]); |
| 160 const void* value_void) { | |
| 161 typedef std::vector<unsigned int> KeyType; | |
| 162 const KeyType& key = *static_cast<const KeyType*>(key_void); | |
| 163 const uint16* value = static_cast<const uint16*>(value_void); | |
| 164 | |
| 165 return CompareSequenceValue(key[0], value[0]); | |
| 166 } | 247 } |
| 167 | 248 |
| 168 // static | 249 int ComposeCheckerWithCompactTable::CompareSequenceSkipFront::operator()( |
| 169 int ComposeCheckerWithCompactTable::CompareSequenceSkipFront( | 250 const ComposeBufferType& l, const uint16* r) const { |
| 170 const void* key_void, | 251 for(size_t i = 1; i < l.size(); ++i) { |
| 171 const void* value_void) { | 252 const int compare_result = CompareSequenceValue(l[i], r[i - 1]); |
| 172 typedef std::vector<unsigned int> KeyType; | |
| 173 const KeyType& key = *static_cast<const KeyType*>(key_void); | |
| 174 const uint16* value = static_cast<const uint16*>(value_void); | |
| 175 | |
| 176 for(size_t i = 1; i < key.size(); ++i) { | |
| 177 const int compare_result = CompareSequenceValue(key[i], value[i - 1]); | |
| 178 if(compare_result) | 253 if(compare_result) |
| 179 return compare_result; | 254 return compare_result; |
| 180 } | 255 } |
| 181 return 0; | 256 return 0; |
| 182 } | 257 } |
| 183 | 258 |
| 184 // Main table | 259 |
| 185 typedef uint16 guint16; | 260 // Main table. |
| 261 | |
| 262 // This file is included here intentionally, instead of the top of the file, | |
| 263 // because including this file outside the anonymous namespace will define a | |
| 264 // global constant and contaminate the global namespace. | |
| 186 #include "third_party/gtk+/gtk/gtkimcontextsimpleseqs.h" | 265 #include "third_party/gtk+/gtk/gtkimcontextsimpleseqs.h" |
| 187 | 266 |
| 188 // Additional table | 267 |
| 268 // Additional table. | |
| 189 | 269 |
| 190 // The difference between this and the default input method is the handling | 270 // The difference between this and the default input method is the handling |
| 191 // of C+acute - this method produces C WITH CEDILLA rather than C WITH ACUTE. | 271 // of C+acute - this method produces C WITH CEDILLA rather than C WITH ACUTE. |
| 192 // For languages that use CCedilla and not acute, this is the preferred mapping, | 272 // For languages that use CCedilla and not acute, this is the preferred mapping, |
| 193 // and is particularly important for pt_BR, where the us-intl keyboard is | 273 // and is particularly important for pt_BR, where the us-intl keyboard is |
| 194 // used extensively. | 274 // used extensively. |
| 195 | 275 |
| 196 const uint16 cedilla_compose_seqs[] = { | 276 const uint16 cedilla_compose_seqs[] = { |
| 197 // LATIN_CAPITAL_LETTER_C_WITH_CEDILLA | 277 // LATIN_CAPITAL_LETTER_C_WITH_CEDILLA |
| 198 GDK_KEY_dead_acute, GDK_KEY_C, 0, 0, 0, 0x00C7, | 278 GDK_KEY_dead_acute, GDK_KEY_C, 0, 0, 0, 0x00C7, |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 225 case GDK_KEY_Hyper_L: | 305 case GDK_KEY_Hyper_L: |
| 226 case GDK_KEY_Hyper_R: | 306 case GDK_KEY_Hyper_R: |
| 227 case GDK_KEY_Mode_switch: | 307 case GDK_KEY_Mode_switch: |
| 228 case GDK_KEY_ISO_Level3_Shift: | 308 case GDK_KEY_ISO_Level3_Shift: |
| 229 return true; | 309 return true; |
| 230 default: | 310 default: |
| 231 return false; | 311 return false; |
| 232 } | 312 } |
| 233 } | 313 } |
| 234 | 314 |
| 235 bool CheckCharacterComposeTable(const std::vector<unsigned int>& sequence, | 315 bool CheckCharacterComposeTable(const ComposeBufferType& sequence, |
| 236 uint32* composed_character) { | 316 uint32* composed_character) { |
| 237 // Check cedilla compose table | 317 // Check cedilla compose table. |
| 238 const ComposeChecker kCedillaComposeChecker( | 318 const ComposeChecker kCedillaComposeChecker( |
| 239 cedilla_compose_seqs, 4, arraysize(cedilla_compose_seqs)/(4 + 2)); | 319 cedilla_compose_seqs, 4, arraysize(cedilla_compose_seqs)/(4 + 2)); |
| 240 if (kCedillaComposeChecker.CheckSequence(sequence, composed_character)) | 320 if (kCedillaComposeChecker.CheckSequence(sequence, composed_character)) |
| 241 return true; | 321 return true; |
| 242 | 322 |
| 243 // Check main compose table | 323 // Check main compose table. |
| 244 const ComposeCheckerWithCompactTable kMainComposeChecker( | 324 const ComposeCheckerWithCompactTable kMainComposeChecker( |
| 245 gtk_compose_seqs_compact, 5, 24, 6); | 325 gtk_compose_seqs_compact, 5, 24, 6); |
| 246 if (kMainComposeChecker.CheckSequence(sequence, composed_character)) | 326 if (kMainComposeChecker.CheckSequence(sequence, composed_character)) |
| 247 return true; | 327 return true; |
| 248 | 328 |
| 249 return false; | 329 return false; |
| 250 } | 330 } |
| 251 | 331 |
| 252 } // anonymous namespace | 332 } // namespace |
| 253 | 333 |
| 254 namespace views { | 334 namespace views { |
| 255 | 335 |
| 256 CharacterComposer::CharacterComposer() {} | 336 CharacterComposer::CharacterComposer() {} |
| 257 | 337 |
| 258 CharacterComposer::~CharacterComposer() {} | 338 CharacterComposer::~CharacterComposer() {} |
| 259 | 339 |
| 260 void CharacterComposer::Reset() { | 340 void CharacterComposer::Reset() { |
| 261 compose_buffer_.clear(); | 341 compose_buffer_.clear(); |
| 262 composed_character_.clear(); | 342 composed_character_.clear(); |
| 263 } | 343 } |
| 264 | 344 |
| 265 bool CharacterComposer::FilterKeyPress(unsigned int keycode) { | 345 bool CharacterComposer::FilterKeyPress(unsigned int keycode) { |
| 266 if(KeypressShouldBeIgnored(keycode)) | 346 if(KeypressShouldBeIgnored(keycode)) |
| 267 return false; | 347 return false; |
| 268 | 348 |
| 269 compose_buffer_.push_back(keycode); | 349 compose_buffer_.push_back(keycode); |
| 270 | 350 |
| 271 // Check compose table | 351 // Check compose table. |
| 272 composed_character_.clear(); | 352 composed_character_.clear(); |
| 273 uint32 composed_character_utf32 = 0; | 353 uint32 composed_character_utf32 = 0; |
| 274 if (CheckCharacterComposeTable(compose_buffer_, &composed_character_utf32)) { | 354 if (CheckCharacterComposeTable(compose_buffer_, &composed_character_utf32)) { |
| 275 // Key press is recognized as a part of composition | 355 // Key press is recognized as a part of composition. |
| 276 if (composed_character_utf32 !=0) { | 356 if (composed_character_utf32 !=0) { |
| 277 // We get a composed character | 357 // We get a composed character. |
| 278 compose_buffer_.clear(); | 358 compose_buffer_.clear(); |
| 279 // We assume that composed character is in BMP | 359 // We assume that composed character is in BMP. |
| 280 if (composed_character_utf32 <= 0xffff) | 360 if (composed_character_utf32 <= 0xffff) |
| 281 composed_character_ += static_cast<char16>(composed_character_utf32); | 361 composed_character_ += static_cast<char16>(composed_character_utf32); |
| 282 } | 362 } |
| 283 return true; | 363 return true; |
| 284 } | 364 } |
| 285 // Key press is not a part of composition | 365 // Key press is not a part of composition. |
| 286 compose_buffer_.pop_back(); // remove the keypress added this time | 366 compose_buffer_.pop_back(); // Remove the keypress added this time. |
| 287 if (!compose_buffer_.empty()) { | 367 if (!compose_buffer_.empty()) { |
| 288 compose_buffer_.clear(); | 368 compose_buffer_.clear(); |
| 289 return true; | 369 return true; |
| 290 } | 370 } |
| 291 return false; | 371 return false; |
| 292 } | 372 } |
| 293 | 373 |
| 294 } // namespace views | 374 } // namespace views |
| OLD | NEW |