Index: views/ime/character_composer.cc |
diff --git a/views/ime/character_composer.cc b/views/ime/character_composer.cc |
index 685e0ba5d94540fba26451b4a4783b0127df844a..fb162f1063b0ea8d74dc9726040de72e832f2e6d 100644 |
--- a/views/ime/character_composer.cc |
+++ b/views/ime/character_composer.cc |
@@ -4,25 +4,100 @@ |
#include "character_composer.h" |
-#include <cstdlib> |
+#include <algorithm> |
+#include <iterator> |
#include "third_party/gtk+/gdk/gdkkeysyms.h" |
+#include "ui/base/gtk/gtk_integers.h" |
namespace { |
-inline int CompareSequenceValue(unsigned int key, uint16 value) { |
- return (key > value) ? 1 : ((key < value) ? -1 : 0); |
+typedef std::vector<unsigned int> ComposeBufferType; |
+ |
+// An iterator class to apply std::lower_bound for composition table. |
+class SequenceIterator |
+ : public std::iterator<std::random_access_iterator_tag, const uint16*> { |
+ public: |
+ SequenceIterator() : ptr_(NULL), stride_(0) {} |
+ SequenceIterator(const uint16* ptr, int stride) |
+ : ptr_(ptr), stride_(stride) {} |
+ |
+ const uint16* ptr() const {return ptr_;} |
+ int stride() const {return stride_;} |
+ |
+ SequenceIterator& operator++() { |
+ ptr_ += stride_; |
+ return *this; |
+ } |
+ SequenceIterator& operator+=(int n) { |
+ ptr_ += stride_*n; |
+ return *this; |
+ } |
+ |
+ const uint16* operator*() const {return ptr_;} |
+ |
+ private: |
+ const uint16* ptr_; |
+ int stride_; |
+}; |
+ |
+inline SequenceIterator operator+(const SequenceIterator& l, int r) { |
+ return SequenceIterator(l) += r; |
+} |
+ |
+inline int operator-(const SequenceIterator& l, const SequenceIterator& r) { |
+ const int d = l.ptr() - r.ptr(); |
+ DCHECK(l.stride() == r.stride() && l.stride() > 0 && d%l.stride() == 0); |
+ return d/l.stride(); |
+} |
+ |
+inline bool operator==(const SequenceIterator& l, const SequenceIterator& r) { |
+ DCHECK(l.stride() == r.stride()); |
+ return l.ptr() == r.ptr(); |
+} |
+ |
+inline bool operator!=(const SequenceIterator& l, const SequenceIterator& r) { |
+ return !(l == r); |
} |
+// A function to compare keycode value. |
+inline int CompareSequenceValue(unsigned int l, unsigned int r) { |
+ return (l > r) ? 1 : ((l < r) ? -1 : 0); |
+} |
+ |
+// A template to make |CompareFunc| work like operator<. |
+// |CompareFunc| is required to implement a member function, |
+// int operator()(const ComposeBufferType& l, const uint16* r) const. |
+template<typename CompareFunc> |
+struct ComparatorAdoptor { |
+ bool operator()(const ComposeBufferType& l, const uint16* r) const { |
+ return CompareFunc()(l, r) == -1; |
+ } |
+ bool operator()(const uint16* l, const ComposeBufferType& r) const { |
+ return CompareFunc()(r, l) == 1; |
+ } |
+}; |
+ |
class ComposeChecker { |
public: |
+ // This class does not take the ownership of |data|, |data| should be alive |
+ // for the lifetime of the object. |
+ // |data| is a pointer to the head of an array of |
+ // length (|max_sequence_length| + 2)*|n_sequences|. |
+ // Every (|max_sequence_length| + 2) elements of |data| represent an entry. |
+ // First |max_sequence_length| elements of an entry is the sequecne which |
+ // composes the character represented by the last two elements of the entry. |
ComposeChecker(const uint16* data, int max_sequence_length, int n_sequences); |
- bool CheckSequence(const std::vector<unsigned int>& sequence, |
+ bool CheckSequence(const ComposeBufferType& sequence, |
uint32* composed_character) const; |
private: |
- static int CompareSequence(const void* key_void, const void* value_void); |
+ struct CompareSequence { |
+ int operator()(const ComposeBufferType& l, const uint16* r) const; |
+ }; |
+ // This class does not take the ownership of |data_|, |
+ // the dtor does not delete |data_|. |
const uint16* data_; |
int max_sequence_length_; |
int n_sequences_; |
@@ -40,46 +115,38 @@ ComposeChecker::ComposeChecker(const uint16* data, |
row_stride_(max_sequence_length + 2) { |
} |
-bool ComposeChecker::CheckSequence( |
- const std::vector<unsigned int>& sequence, |
- uint32* composed_character) const { |
+bool ComposeChecker::CheckSequence(const ComposeBufferType& sequence, |
+ uint32* composed_character) const { |
const int sequence_length = sequence.size(); |
if (sequence_length > max_sequence_length_) |
return false; |
- // Find sequence in the table |
- const uint16* found = static_cast<const uint16*>( |
- bsearch(&sequence, data_, n_sequences_, |
- sizeof(uint16)*row_stride_, CompareSequence)); |
- if (!found) |
+ // Find sequence in the table. |
+ const SequenceIterator begin(data_, row_stride_); |
+ const SequenceIterator end = begin + n_sequences_; |
+ const SequenceIterator found = std::lower_bound( |
+ begin, end, sequence, ComparatorAdoptor<CompareSequence>()); |
+ if (found == end || CompareSequence()(sequence, *found) != 0) |
return false; |
- // Ensure |found| is pointing the first matching element |
- while (found > data_ && |
- CompareSequence(&sequence, found - row_stride_) == 0) |
- found -= row_stride_; |
- |
- if (sequence_length == max_sequence_length_ || found[sequence_length] == 0) { |
- // |found| is not partially matching. It's fully matching |
- const uint16* data_end = data_ + row_stride_*n_sequences_; |
- if (found + row_stride_ >= data_end || |
- CompareSequence(&sequence, found + row_stride_) != 0) { |
- // There is no composition longer than |found| which matches to |sequence| |
- const uint32 value = (found[max_sequence_length_] << 16) | |
- found[max_sequence_length_ + 1]; |
+ |
+ if (sequence_length == max_sequence_length_ || |
+ (*found)[sequence_length] == 0) { |
+ // |found| is not partially matching. It's fully matching. |
+ if (found + 1 == end || |
+ CompareSequence()(sequence, *(found + 1)) != 0) { |
+ // There is no composition longer than |found| which matches to |
+ // |sequence|. |
+ const uint32 value = ((*found)[max_sequence_length_] << 16) | |
+ (*found)[max_sequence_length_ + 1]; |
*composed_character = value; |
} |
} |
return true; |
} |
-// static |
-int ComposeChecker::CompareSequence(const void* key_void, |
- const void* value_void) { |
- typedef std::vector<unsigned int> KeyType; |
- const KeyType& key = *static_cast<const KeyType*>(key_void); |
- const uint16* value = static_cast<const uint16*>(value_void); |
- |
- for(size_t i = 0; i < key.size(); ++i) { |
- const int compare_result = CompareSequenceValue(key[i], value[i]); |
+int ComposeChecker::CompareSequence::operator()(const ComposeBufferType& l, |
+ const uint16* r) const { |
+ for(size_t i = 0; i < l.size(); ++i) { |
+ const int compare_result = CompareSequenceValue(l[i], r[i]); |
if(compare_result) |
return compare_result; |
} |
@@ -89,18 +156,33 @@ int ComposeChecker::CompareSequence(const void* key_void, |
class ComposeCheckerWithCompactTable { |
public: |
+ // This class does not take the ownership of |data|, |data| should be alive |
+ // for the lifetime of the object. |
+ // First |index_size|*|index_stride| elements of |data| are an index table. |
+ // Every |index_stride| elements of an index table are an index entry. |
+ // If you are checking with a sequence of length N beginning with character C, |
+ // you have to find an index entry whose first element is C, then get the N-th |
+ // element of the index entry as the index. |
+ // The index is pointing the element of |data| where the composition table for |
+ // sequences of length N beginning with C is placed. |
+ |
ComposeCheckerWithCompactTable(const uint16* data, |
int max_sequence_length, |
int index_size, |
int index_stride); |
- bool CheckSequence(const std::vector<unsigned int>& sequence, |
+ bool CheckSequence(const ComposeBufferType& sequence, |
uint32* composed_character) const; |
private: |
- static int CompareSequenceFront(const void* key_void, const void* value_void); |
- static int CompareSequenceSkipFront(const void* key_void, |
- const void* value_void); |
- |
+ struct CompareSequenceFront { |
+ int operator()(const ComposeBufferType& l, const uint16* r) const; |
+ }; |
+ struct CompareSequenceSkipFront { |
+ int operator()(const ComposeBufferType& l, const uint16* r) const; |
+ }; |
+ |
+ // This class does not take the ownership of |data_|, |
+ // the dtor does not delete |data_|. |
const uint16* data_; |
int max_sequence_length_; |
int index_size_; |
@@ -119,34 +201,39 @@ ComposeCheckerWithCompactTable::ComposeCheckerWithCompactTable( |
} |
bool ComposeCheckerWithCompactTable::CheckSequence( |
- const std::vector<unsigned int>& sequence, |
+ const ComposeBufferType& sequence, |
uint32* composed_character) const { |
const int compose_length = sequence.size(); |
if (compose_length > max_sequence_length_) |
return false; |
- // Find corresponding index for the first keypress |
- const uint16* index = static_cast<const uint16*>( |
- bsearch(&sequence, data_, index_size_, |
- sizeof(uint16)*index_stride_, CompareSequenceFront)); |
- if (!index) |
+ // Find corresponding index for the first keypress. |
+ const SequenceIterator index_begin(data_, index_stride_); |
+ const SequenceIterator index_end = index_begin + index_size_; |
+ const SequenceIterator index = |
+ std::lower_bound(index_begin, index_end, sequence, |
+ ComparatorAdoptor<CompareSequenceFront>()); |
+ if (index == index_end || CompareSequenceFront()(sequence, *index) != 0) |
return false; |
if (compose_length == 1) |
return true; |
- // Check for composition sequences |
+ // Check for composition sequences. |
for (int length = compose_length - 1; length < max_sequence_length_; |
++length) { |
- const uint16* table = data_ + index[length]; |
- const uint16* table_next = data_ + index[length + 1]; |
+ const uint16* table = data_ + (*index)[length]; |
+ const uint16* table_next = data_ + (*index)[length + 1]; |
if (table_next > table) { |
- // There are composition sequences for this |length| |
+ // There are composition sequences for this |length|. |
const int row_stride = length + 1; |
const int n_sequences = (table_next - table)/row_stride; |
- const uint16* seq = static_cast<const uint16*>( |
- bsearch(&sequence, table, n_sequences, |
- sizeof(uint16)*row_stride, CompareSequenceSkipFront)); |
- if (seq) { |
- if (length == compose_length - 1) // exact match |
- *composed_character = seq[length]; |
+ const SequenceIterator table_begin(table, row_stride); |
+ const SequenceIterator table_end = table_begin + n_sequences; |
+ const SequenceIterator found = |
+ std::lower_bound(table_begin, table_end, sequence, |
+ ComparatorAdoptor<CompareSequenceSkipFront>()); |
+ if (found != table_end && |
+ CompareSequenceSkipFront()(sequence, *found) == 0) { |
+ if (length == compose_length - 1) // Exact match. |
+ *composed_character = (*found)[length]; |
return true; |
} |
} |
@@ -154,38 +241,31 @@ bool ComposeCheckerWithCompactTable::CheckSequence( |
return false; |
} |
-// static |
-int ComposeCheckerWithCompactTable::CompareSequenceFront( |
- const void* key_void, |
- const void* value_void) { |
- typedef std::vector<unsigned int> KeyType; |
- const KeyType& key = *static_cast<const KeyType*>(key_void); |
- const uint16* value = static_cast<const uint16*>(value_void); |
- |
- return CompareSequenceValue(key[0], value[0]); |
+int ComposeCheckerWithCompactTable::CompareSequenceFront::operator()( |
+ const ComposeBufferType& l, const uint16* r) const { |
+ return CompareSequenceValue(l[0], r[0]); |
} |
-// static |
-int ComposeCheckerWithCompactTable::CompareSequenceSkipFront( |
- const void* key_void, |
- const void* value_void) { |
- typedef std::vector<unsigned int> KeyType; |
- const KeyType& key = *static_cast<const KeyType*>(key_void); |
- const uint16* value = static_cast<const uint16*>(value_void); |
- |
- for(size_t i = 1; i < key.size(); ++i) { |
- const int compare_result = CompareSequenceValue(key[i], value[i - 1]); |
+int ComposeCheckerWithCompactTable::CompareSequenceSkipFront::operator()( |
+ const ComposeBufferType& l, const uint16* r) const { |
+ for(size_t i = 1; i < l.size(); ++i) { |
+ const int compare_result = CompareSequenceValue(l[i], r[i - 1]); |
if(compare_result) |
return compare_result; |
} |
return 0; |
} |
-// Main table |
-typedef uint16 guint16; |
+ |
+// Main table. |
+ |
+// This file is included here intentionally, instead of the top of the file, |
+// because including this file outside the anonymous namespace will define a |
+// global constant and contaminate the global namespace. |
#include "third_party/gtk+/gtk/gtkimcontextsimpleseqs.h" |
-// Additional table |
+ |
+// Additional table. |
// The difference between this and the default input method is the handling |
// of C+acute - this method produces C WITH CEDILLA rather than C WITH ACUTE. |
@@ -232,15 +312,15 @@ bool KeypressShouldBeIgnored(unsigned int keycode) { |
} |
} |
-bool CheckCharacterComposeTable(const std::vector<unsigned int>& sequence, |
+bool CheckCharacterComposeTable(const ComposeBufferType& sequence, |
uint32* composed_character) { |
- // Check cedilla compose table |
+ // Check cedilla compose table. |
const ComposeChecker kCedillaComposeChecker( |
- cedilla_compose_seqs, 4, arraysize(cedilla_compose_seqs)/(4 + 2)); |
+ cedilla_compose_seqs, 4, arraysize(cedilla_compose_seqs)/(4 + 2)); |
if (kCedillaComposeChecker.CheckSequence(sequence, composed_character)) |
return true; |
- // Check main compose table |
+ // Check main compose table. |
const ComposeCheckerWithCompactTable kMainComposeChecker( |
gtk_compose_seqs_compact, 5, 24, 6); |
if (kMainComposeChecker.CheckSequence(sequence, composed_character)) |
@@ -249,7 +329,7 @@ bool CheckCharacterComposeTable(const std::vector<unsigned int>& sequence, |
return false; |
} |
-} // anonymous namespace |
+} // namespace |
namespace views { |
@@ -268,22 +348,22 @@ bool CharacterComposer::FilterKeyPress(unsigned int keycode) { |
compose_buffer_.push_back(keycode); |
- // Check compose table |
+ // Check compose table. |
composed_character_.clear(); |
uint32 composed_character_utf32 = 0; |
if (CheckCharacterComposeTable(compose_buffer_, &composed_character_utf32)) { |
- // Key press is recognized as a part of composition |
+ // Key press is recognized as a part of composition. |
if (composed_character_utf32 !=0) { |
- // We get a composed character |
+ // We get a composed character. |
compose_buffer_.clear(); |
- // We assume that composed character is in BMP |
+ // We assume that composed character is in BMP. |
if (composed_character_utf32 <= 0xffff) |
composed_character_ += static_cast<char16>(composed_character_utf32); |
} |
return true; |
} |
- // Key press is not a part of composition |
- compose_buffer_.pop_back(); // remove the keypress added this time |
+ // Key press is not a part of composition. |
+ compose_buffer_.pop_back(); // Remove the keypress added this time. |
if (!compose_buffer_.empty()) { |
compose_buffer_.clear(); |
return true; |