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