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

Side by Side Diff: views/ime/character_composer.cc

Issue 7264015: CL for readability review (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Implemented SequenceIterator Created 9 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 | Annotate | Revision Log
« no previous file with comments | « views/ime/character_composer.h ('k') | views/ime/character_composer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
OLDNEW
« no previous file with comments | « views/ime/character_composer.h ('k') | views/ime/character_composer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698