1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/base/ime/chromeos/character_composer.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <iterator>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/third_party/icu/icu_utf.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note for Gtk removal: gdkkeysyms.h only contains a set of
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// '#define GDK_KeyName 0xNNNN' macros and does not #include any Gtk headers.
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/gtk+/gdk/gdkkeysyms.h"
15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/glib/glib_integers.h"
17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/events/event.h"
18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/events/keycodes/keyboard_codes.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Note for Gtk removal: gtkimcontextsimpleseqs.h does not #include any Gtk
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// headers and only contains one big guint16 array |gtk_compose_seqs_compact|
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// which defines the main compose table. The table has internal linkage.
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The order of header inclusion is out of order because
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// gtkimcontextsimpleseqs.h depends on guint16, which is defined in
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// "ui/base/glib/glib_integers.h".
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "third_party/gtk+/gtk/gtkimcontextsimpleseqs.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// A black list for not composing dead keys. Once the key combination is listed
317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// below, the dead key won't work even when this is listed in
327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// gtkimcontextsimpleseqs.h. This only supports two keyevent sequenses.
337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// TODO(nona): Remove this hack.
347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochconst struct BlackListedDeadKey {
357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  uint32 first_key;  // target first key event.
367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  uint32 second_key;  // target second key event.
377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  uint32 output_char;  // the character to be inserted if the filter is matched.
387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  bool consume;  // true if the original key event will be consumed.
397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch} kBlackListedDeadKeys[] = {
40bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  { GDK_KEY_dead_acute, GDK_KEY_m, GDK_KEY_apostrophe, false },
417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  { GDK_KEY_dead_acute, GDK_KEY_s, GDK_KEY_apostrophe, false },
427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  { GDK_KEY_dead_acute, GDK_KEY_t, GDK_KEY_apostrophe, false },
43bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  { GDK_KEY_dead_acute, GDK_KEY_v, GDK_KEY_apostrophe, false },
447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  { GDK_KEY_dead_acute, GDK_KEY_dead_acute, GDK_KEY_apostrophe, true },
457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch};
467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef std::vector<unsigned int> ComposeBufferType;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// An iterator class to apply std::lower_bound for composition table.
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SequenceIterator
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public std::iterator<std::random_access_iterator_tag, const uint16*> {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SequenceIterator() : ptr_(NULL), stride_(0) {}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SequenceIterator(const uint16* ptr, int stride)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : ptr_(ptr), stride_(stride) {}
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const uint16* ptr() const {return ptr_;}
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int stride() const {return stride_;}
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SequenceIterator& operator++() {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ptr_ += stride_;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return *this;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SequenceIterator& operator+=(int n) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ptr_ += stride_*n;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return *this;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const uint16* operator*() const {return ptr_;}
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const uint16* ptr_;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int stride_;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline SequenceIterator operator+(const SequenceIterator& l, int r) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SequenceIterator(l) += r;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline int operator-(const SequenceIterator& l, const SequenceIterator& r) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int d = l.ptr() - r.ptr();
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(l.stride() == r.stride() && l.stride() > 0 && d%l.stride() == 0);
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return d/l.stride();
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline bool operator==(const SequenceIterator& l, const SequenceIterator& r) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(l.stride() == r.stride());
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return l.ptr() == r.ptr();
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline bool operator!=(const SequenceIterator& l, const SequenceIterator& r) {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !(l == r);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A function to compare key value.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline int CompareSequenceValue(unsigned int l, unsigned int r) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (l > r) ? 1 : ((l < r) ? -1 : 0);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A template to make |CompareFunc| work like operator<.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |CompareFunc| is required to implement a member function,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// int operator()(const ComposeBufferType& l, const uint16* r) const.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template<typename CompareFunc>
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct ComparatorAdoptor {
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool operator()(const ComposeBufferType& l, const uint16* r) const {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return CompareFunc()(l, r) == -1;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool operator()(const uint16* l, const ComposeBufferType& r) const {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return CompareFunc()(r, l) == 1;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ComposeChecker {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This class does not take the ownership of |data|, |data| should be alive
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for the lifetime of the object.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |data| is a pointer to the head of an array of
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // length (|max_sequence_length| + 2)*|n_sequences|.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Every (|max_sequence_length| + 2) elements of |data| represent an entry.
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First |max_sequence_length| elements of an entry is the sequecne which
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // composes the character represented by the last two elements of the entry.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ComposeChecker(const uint16* data, int max_sequence_length, int n_sequences);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool CheckSequence(const ComposeBufferType& sequence,
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     uint32* composed_character) const;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct CompareSequence {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int operator()(const ComposeBufferType& l, const uint16* r) const;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This class does not take the ownership of |data_|,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the dtor does not delete |data_|.
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const uint16* data_;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int max_sequence_length_;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int n_sequences_;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int row_stride_;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ComposeChecker);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ComposeChecker::ComposeChecker(const uint16* data,
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               int max_sequence_length,
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               int n_sequences)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : data_(data),
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      max_sequence_length_(max_sequence_length),
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      n_sequences_(n_sequences),
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      row_stride_(max_sequence_length + 2) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ComposeChecker::CheckSequence(const ComposeBufferType& sequence,
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   uint32* composed_character) const {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int sequence_length = sequence.size();
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sequence_length > max_sequence_length_)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find sequence in the table.
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const SequenceIterator begin(data_, row_stride_);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const SequenceIterator end = begin + n_sequences_;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const SequenceIterator found = std::lower_bound(
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      begin, end, sequence, ComparatorAdoptor<CompareSequence>());
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (found == end || CompareSequence()(sequence, *found) != 0)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sequence_length == max_sequence_length_ ||
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (*found)[sequence_length] == 0) {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // |found| is not partially matching. It's fully matching.
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (found + 1 == end ||
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CompareSequence()(sequence, *(found + 1)) != 0) {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // There is no composition longer than |found| which matches to
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // |sequence|.
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const uint32 value = ((*found)[max_sequence_length_] << 16) |
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (*found)[max_sequence_length_ + 1];
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *composed_character = value;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int ComposeChecker::CompareSequence::operator()(const ComposeBufferType& l,
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                const uint16* r) const {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(size_t i = 0; i < l.size(); ++i) {
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int compare_result = CompareSequenceValue(l[i], r[i]);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if(compare_result)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return compare_result;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ComposeCheckerWithCompactTable {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This class does not take the ownership of |data|, |data| should be alive
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for the lifetime of the object.
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First |index_size|*|index_stride| elements of |data| are an index table.
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Every |index_stride| elements of an index table are an index entry.
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If you are checking with a sequence of length N beginning with character C,
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // you have to find an index entry whose first element is C, then get the N-th
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // element of the index entry as the index.
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The index is pointing the element of |data| where the composition table for
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // sequences of length N beginning with C is placed.
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ComposeCheckerWithCompactTable(const uint16* data,
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 int max_sequence_length,
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 int index_size,
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 int index_stride);
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool CheckSequence(const ComposeBufferType& sequence,
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     uint32* composed_character) const;
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct CompareSequenceFront {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int operator()(const ComposeBufferType& l, const uint16* r) const;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct CompareSequenceSkipFront {
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int operator()(const ComposeBufferType& l, const uint16* r) const;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This class does not take the ownership of |data_|,
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the dtor does not delete |data_|.
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const uint16* data_;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int max_sequence_length_;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index_size_;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index_stride_;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ComposeCheckerWithCompactTable::ComposeCheckerWithCompactTable(
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const uint16* data,
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int max_sequence_length,
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int index_size,
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int index_stride)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : data_(data),
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      max_sequence_length_(max_sequence_length),
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      index_size_(index_size),
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      index_stride_(index_stride) {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ComposeCheckerWithCompactTable::CheckSequence(
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ComposeBufferType& sequence,
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32* composed_character) const {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int compose_length = sequence.size();
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (compose_length > max_sequence_length_)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find corresponding index for the first keypress.
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const SequenceIterator index_begin(data_, index_stride_);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const SequenceIterator index_end = index_begin + index_size_;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const SequenceIterator index =
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::lower_bound(index_begin, index_end, sequence,
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       ComparatorAdoptor<CompareSequenceFront>());
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (index == index_end || CompareSequenceFront()(sequence, *index) != 0)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (compose_length == 1)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check for composition sequences.
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int length = compose_length - 1; length < max_sequence_length_;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++length) {
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const uint16* table = data_ + (*index)[length];
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const uint16* table_next = data_ + (*index)[length + 1];
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (table_next > table) {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // There are composition sequences for this |length|.
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const int row_stride = length + 1;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const int n_sequences = (table_next - table)/row_stride;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const SequenceIterator table_begin(table, row_stride);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const SequenceIterator table_end = table_begin + n_sequences;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const SequenceIterator found =
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          std::lower_bound(table_begin, table_end, sequence,
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           ComparatorAdoptor<CompareSequenceSkipFront>());
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (found != table_end &&
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          CompareSequenceSkipFront()(sequence, *found) == 0) {
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (length == compose_length - 1)  // Exact match.
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          *composed_character = (*found)[length];
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int ComposeCheckerWithCompactTable::CompareSequenceFront::operator()(
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ComposeBufferType& l, const uint16* r) const {
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CompareSequenceValue(l[0], r[0]);
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int ComposeCheckerWithCompactTable::CompareSequenceSkipFront::operator()(
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ComposeBufferType& l, const uint16* r) const {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(size_t i = 1; i < l.size(); ++i) {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int compare_result = CompareSequenceValue(l[i], r[i - 1]);
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if(compare_result)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return compare_result;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Additional table.
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The difference between this and the default input method is the handling
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of C+acute - this method produces C WITH CEDILLA rather than C WITH ACUTE.
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For languages that use CCedilla and not acute, this is the preferred mapping,
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and is particularly important for pt_BR, where the us-intl keyboard is
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// used extensively.
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const uint16 cedilla_compose_seqs[] = {
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // LATIN_CAPITAL_LETTER_C_WITH_CEDILLA
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GDK_KEY_dead_acute, GDK_KEY_C, 0, 0, 0, 0x00C7,
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // LATIN_SMALL_LETTER_C_WITH_CEDILLA
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GDK_KEY_dead_acute, GDK_KEY_c, 0, 0, 0, 0x00E7,
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // LATIN_CAPITAL_LETTER_C_WITH_CEDILLA
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GDK_KEY_Multi_key, GDK_KEY_apostrophe, GDK_KEY_C, 0, 0, 0x00C7,
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // LATIN_SMALL_LETTER_C_WITH_CEDILLA
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GDK_KEY_Multi_key, GDK_KEY_apostrophe, GDK_KEY_c, 0, 0, 0x00E7,
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // LATIN_CAPITAL_LETTER_C_WITH_CEDILLA
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GDK_KEY_Multi_key, GDK_KEY_C, GDK_KEY_apostrophe, 0, 0, 0x00C7,
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // LATIN_SMALL_LETTER_C_WITH_CEDILLA
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GDK_KEY_Multi_key, GDK_KEY_c, GDK_KEY_apostrophe, 0, 0, 0x00E7,
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool KeypressShouldBeIgnored(unsigned int keyval) {
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch(keyval) {
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GDK_KEY_Shift_L:
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GDK_KEY_Shift_R:
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GDK_KEY_Control_L:
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GDK_KEY_Control_R:
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GDK_KEY_Caps_Lock:
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GDK_KEY_Shift_Lock:
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GDK_KEY_Meta_L:
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GDK_KEY_Meta_R:
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GDK_KEY_Alt_L:
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GDK_KEY_Alt_R:
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GDK_KEY_Super_L:
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GDK_KEY_Super_R:
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GDK_KEY_Hyper_L:
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GDK_KEY_Hyper_R:
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GDK_KEY_Mode_switch:
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GDK_KEY_ISO_Level3_Shift:
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CheckCharacterComposeTable(const ComposeBufferType& sequence,
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                uint32* composed_character) {
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check cedilla compose table.
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ComposeChecker kCedillaComposeChecker(
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cedilla_compose_seqs, 4, arraysize(cedilla_compose_seqs)/(4 + 2));
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kCedillaComposeChecker.CheckSequence(sequence, composed_character))
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check main compose table.
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ComposeCheckerWithCompactTable kMainComposeChecker(
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gtk_compose_seqs_compact, 5, 24, 6);
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kMainComposeChecker.CheckSequence(sequence, composed_character))
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Converts |character| to UTF16 string.
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns false when |character| is not a valid character.
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool UTF32CharacterToUTF16(uint32 character, base::string16* output) {
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output->clear();
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reject invalid character. (e.g. codepoint greater than 0x10ffff)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CBU_IS_UNICODE_CHAR(character))
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (character) {
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output->resize(CBU16_LENGTH(character));
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t i = 0;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CBU16_APPEND_UNSAFE(&(*output)[0], i, character);
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns an hexadecimal digit integer (0 to 15) corresponding to |keyval|.
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// -1 is returned when |keyval| cannot be a hexadecimal digit.
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int KeyvalToHexDigit(unsigned int keyval) {
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GDK_KEY_0 <= keyval && keyval <= GDK_KEY_9)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return keyval - GDK_KEY_0;
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GDK_KEY_a <= keyval && keyval <= GDK_KEY_f)
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return keyval - GDK_KEY_a + 10;
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GDK_KEY_A <= keyval && keyval <= GDK_KEY_F)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return keyval - GDK_KEY_A + 10;
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return -1;  // |keyval| cannot be a hexadecimal digit.
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
383f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Returns an hexadecimal digit integer (0 to 15) corresponding to |keycode|.
384f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// -1 is returned when |keycode| cannot be a hexadecimal digit.
385f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)int KeycodeToHexDigit(unsigned int keycode) {
386f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (ui::VKEY_0 <= keycode && keycode <= ui::VKEY_9)
387f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return keycode - ui::VKEY_0;
388f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (ui::VKEY_A <= keycode && keycode <= ui::VKEY_F)
389f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return keycode - ui::VKEY_A + 10;
390f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return -1;  // |keycode| cannot be a hexadecimal digit.
391f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
392f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ui {
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CharacterComposer::CharacterComposer() : composition_mode_(KEY_SEQUENCE_MODE) {}
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CharacterComposer::~CharacterComposer() {}
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CharacterComposer::Reset() {
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  compose_buffer_.clear();
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  composed_character_.clear();
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  preedit_string_.clear();
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  composition_mode_ = KEY_SEQUENCE_MODE;
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
408a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool CharacterComposer::FilterKeyPress(const ui::KeyEvent& event) {
409f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  uint32 keyval = event.platform_keycode();
410f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!keyval ||
411a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      (event.type() != ET_KEY_PRESSED && event.type() != ET_KEY_RELEASED))
412a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return false;
413a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
414f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return FilterKeyPressInternal(keyval, event.key_code(), event.flags());
415a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
416a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
417a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
418a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool CharacterComposer::FilterKeyPressInternal(unsigned int keyval,
419a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                               unsigned int keycode,
420a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                               int flags) {
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  composed_character_.clear();
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  preedit_string_.clear();
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't care about modifier key presses.
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if(KeypressShouldBeIgnored(keyval))
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // When the user presses Ctrl+Shift+U, maybe switch to HEX_MODE.
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't care about other modifiers like Alt.  When CapsLock is down, we
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // do nothing because what we receive is Ctrl+Shift+u (not U).
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (keyval == GDK_KEY_U && (flags & EF_SHIFT_DOWN) &&
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (flags & EF_CONTROL_DOWN)) {
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (composition_mode_ == KEY_SEQUENCE_MODE && compose_buffer_.empty()) {
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // There is no ongoing composition.  Let's switch to HEX_MODE.
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      composition_mode_ = HEX_MODE;
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UpdatePreeditStringHexMode();
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Filter key press in an appropriate manner.
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (composition_mode_) {
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case KEY_SEQUENCE_MODE:
444a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return FilterKeyPressSequenceMode(keyval, flags);
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case HEX_MODE:
44690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return FilterKeyPressHexMode(keyval, keycode, flags);
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CharacterComposer::FilterKeyPressSequenceMode(unsigned int keyval,
45490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                                   int flags) {
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(composition_mode_ == KEY_SEQUENCE_MODE);
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  compose_buffer_.push_back(keyval);
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (compose_buffer_.size() == 2U) {
4597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kBlackListedDeadKeys); ++i) {
4607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if (compose_buffer_[0] == kBlackListedDeadKeys[i].first_key &&
4617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          compose_buffer_[1] == kBlackListedDeadKeys[i].second_key ) {
4627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        Reset();
4637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        composed_character_.push_back(kBlackListedDeadKeys[i].output_char);
4647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        return kBlackListedDeadKeys[i].consume;
4657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      }
4667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
4677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
4687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check compose table.
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 composed_character_utf32 = 0;
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (CheckCharacterComposeTable(compose_buffer_, &composed_character_utf32)) {
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Key press is recognized as a part of composition.
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (composed_character_utf32 != 0) {
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We get a composed character.
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      compose_buffer_.clear();
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UTF32CharacterToUTF16(composed_character_utf32, &composed_character_);
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Key press is not a part of composition.
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  compose_buffer_.pop_back();  // Remove the keypress added this time.
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!compose_buffer_.empty()) {
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    compose_buffer_.clear();
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CharacterComposer::FilterKeyPressHexMode(unsigned int keyval,
49090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                              unsigned int keycode,
49190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                              int flags) {
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(composition_mode_ == HEX_MODE);
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const size_t kMaxHexSequenceLength = 8;
49490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int hex_digit = KeyvalToHexDigit(keyval);
49590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (hex_digit < 0) {
49690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // With 101 keyboard, control + shift + 3 produces '#', but a user may
49790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // have intended to type '3'.  So, if a hexadecimal character was not found,
49890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // suppose a user is holding shift key (and possibly control key, too) and
49990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // try a character with modifier keys removed.
500f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    hex_digit = KeycodeToHexDigit(keycode);
50190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (keyval == GDK_KEY_Escape) {
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Cancel composition when ESC is pressed.
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Reset();
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (keyval == GDK_KEY_Return || keyval == GDK_KEY_KP_Enter ||
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             keyval == GDK_KEY_ISO_Enter ||
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             keyval == GDK_KEY_space || keyval == GDK_KEY_KP_Space) {
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Commit the composed character when Enter or space is pressed.
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CommitHex();
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (keyval == GDK_KEY_BackSpace) {
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Pop back the buffer when Backspace is pressed.
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!compose_buffer_.empty()) {
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      compose_buffer_.pop_back();
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If there is no character in |compose_buffer_|, cancel composition.
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Reset();
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (hex_digit >= 0 &&
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             compose_buffer_.size() < kMaxHexSequenceLength) {
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Add the key to the buffer if it is a hex digit.
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    compose_buffer_.push_back(hex_digit);
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdatePreeditStringHexMode();
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CharacterComposer::CommitHex() {
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(composition_mode_ == HEX_MODE);
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 composed_character_utf32 = 0;
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i != compose_buffer_.size(); ++i) {
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const uint32 digit = compose_buffer_[i];
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(0 <= digit && digit < 16);
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    composed_character_utf32 <<= 4;
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    composed_character_utf32 |= digit;
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Reset();
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UTF32CharacterToUTF16(composed_character_utf32, &composed_character_);
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CharacterComposer::UpdatePreeditStringHexMode() {
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (composition_mode_ != HEX_MODE) {
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    preedit_string_.clear();
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string preedit_string_ascii("u");
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i != compose_buffer_.size(); ++i) {
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int digit = compose_buffer_[i];
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(0 <= digit && digit < 16);
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    preedit_string_ascii += digit <= 9 ? ('0' + digit) : ('a' + (digit - 10));
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  preedit_string_ = base::ASCIIToUTF16(preedit_string_ascii);
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace ui
558