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 |