1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <string>
6#include <utility>
7#include <vector>
8
9#include "ppapi/c/dev/ppb_cursor_control_dev.h"
10#include "ppapi/c/ppb_console.h"
11#include "ppapi/cpp/completion_callback.h"
12#include "ppapi/cpp/dev/font_dev.h"
13#include "ppapi/cpp/graphics_2d.h"
14#include "ppapi/cpp/image_data.h"
15#include "ppapi/cpp/input_event.h"
16#include "ppapi/cpp/instance.h"
17#include "ppapi/cpp/module.h"
18#include "ppapi/cpp/rect.h"
19#include "ppapi/cpp/size.h"
20#include "ppapi/cpp/text_input_controller.h"
21
22namespace {
23
24// Extracted from: ui/base/keycodes/keyboard_codes.h
25enum {
26  VKEY_BACK = 0x08,
27  VKEY_SHIFT = 0x10,
28  VKEY_DELETE = 0x2E,
29  VKEY_LEFT = 0x25,
30  VKEY_UP = 0x26,
31  VKEY_RIGHT = 0x27,
32  VKEY_DOWN = 0x28,
33};
34
35const uint32_t kTextfieldBgColor = 0xffffffff;
36const uint32_t kTextfieldTextColor = 0xff000000;
37const uint32_t kTextfieldCaretColor = 0xff000000;
38const uint32_t kTextfieldPreeditTextColor = 0xffff0000;
39const uint32_t kTextfieldSelectionBackgroundColor = 0xffeecccc;
40const uint32_t kTextfieldUnderlineColorMain = 0xffff0000;
41const uint32_t kTextfieldUnderlineColorSub = 0xffddaaaa;
42
43void FillRect(pp::ImageData* image,
44              int left, int top, int width, int height,
45              uint32_t color) {
46  for (int y = std::max(0, top);
47       y < std::min(image->size().height() - 1, top + height);
48       ++y) {
49    for (int x = std::max(0, left);
50         x < std::min(image->size().width() - 1, left + width);
51         ++x)
52      *image->GetAddr32(pp::Point(x, y)) = color;
53  }
54}
55
56void FillRect(pp::ImageData* image, const pp::Rect& rect, uint32_t color) {
57  FillRect(image, rect.x(), rect.y(), rect.width(), rect.height(), color);
58}
59
60size_t GetPrevCharOffsetUtf8(const std::string& str, size_t current_pos) {
61  size_t i = current_pos;
62  if (i > 0) {
63    do
64      --i;
65    while (i > 0 && (str[i] & 0xc0) == 0x80);
66  }
67  return i;
68}
69
70size_t GetNextCharOffsetUtf8(const std::string& str, size_t current_pos) {
71  size_t i = current_pos;
72  if (i < str.size()) {
73    do
74      ++i;
75    while (i < str.size() && (str[i] & 0xc0) == 0x80);
76  }
77  return i;
78}
79
80size_t GetNthCharOffsetUtf8(const std::string& str, size_t n) {
81  size_t i = 0;
82  for (size_t step = 0; step < n; ++step)
83    i = GetNextCharOffsetUtf8(str, i);
84  return i;
85}
86
87}  // namespace
88
89class TextFieldStatusHandler {
90 public:
91  virtual ~TextFieldStatusHandler() {}
92  virtual void FocusIn(const pp::Rect& caret) {}
93  virtual void FocusOut() {}
94  virtual void UpdateSelection(const std::string& text) {}
95};
96
97class TextFieldStatusNotifyingHandler : public TextFieldStatusHandler {
98 public:
99  explicit TextFieldStatusNotifyingHandler(pp::Instance* instance)
100      : textinput_control_(instance) {
101  }
102
103 protected:
104  // Implement TextFieldStatusHandler.
105  virtual void FocusIn(const pp::Rect& caret) {
106    textinput_control_.SetTextInputType(PP_TEXTINPUT_TYPE_TEXT);
107    textinput_control_.UpdateCaretPosition(caret);
108  }
109  virtual void FocusOut() {
110    textinput_control_.CancelCompositionText();
111    textinput_control_.SetTextInputType(PP_TEXTINPUT_TYPE_NONE);
112  }
113  virtual void UpdateSelection(const std::string& text) {
114    textinput_control_.UpdateSurroundingText(text, 0, text.size());
115  }
116
117 private:
118  pp::TextInputController textinput_control_;
119};
120
121// Hand-made text field for demonstrating text input API.
122class MyTextField {
123 public:
124  MyTextField(pp::Instance* instance, TextFieldStatusHandler* handler,
125              int x, int y, int width, int height)
126      : instance_(instance),
127        status_handler_(handler),
128        area_(x, y, width, height),
129        font_size_(height - 2),
130        caret_pos_(std::string::npos),
131        anchor_pos_(std::string::npos) {
132    pp::FontDescription_Dev desc;
133    desc.set_family(PP_FONTFAMILY_SANSSERIF);
134    desc.set_size(font_size_);
135    font_ = pp::Font_Dev(instance_, desc);
136  }
137
138  // Paint on the specified ImageData.
139  void PaintOn(pp::ImageData* image, pp::Rect clip) {
140    clip = clip.Intersect(area_);
141    FillRect(image, clip, kTextfieldBgColor);
142
143    if (caret_pos_ != std::string::npos) {
144      int offset = area_.x();
145      // selection (for the case without composition text)
146      if (composition_.empty() && HasSelection()) {
147        int left_x = font_.MeasureSimpleText(
148            utf8_text_.substr(0, SelectionLeft()));
149        int right_x = font_.MeasureSimpleText(
150            utf8_text_.substr(0, SelectionRight()));
151        FillRect(image, offset + left_x, area_.y(), right_x - left_x,
152                 area_.height(), kTextfieldSelectionBackgroundColor);
153      }
154      // before caret
155      {
156        std::string str = utf8_text_.substr(0, caret_pos_);
157        font_.DrawTextAt(
158            image,
159            pp::TextRun_Dev(str.c_str(), false, false),
160            pp::Point(offset, area_.y() + font_size_),
161            kTextfieldTextColor,
162            clip,
163            false);
164        offset += font_.MeasureSimpleText(str);
165      }
166      // composition
167      {
168        const std::string& str = composition_;
169        // selection
170        if (composition_selection_.first != composition_selection_.second) {
171          int left_x = font_.MeasureSimpleText(
172              str.substr(0, composition_selection_.first));
173          int right_x = font_.MeasureSimpleText(
174              str.substr(0, composition_selection_.second));
175          FillRect(image, offset + left_x, area_.y(), right_x - left_x,
176                   area_.height(), kTextfieldSelectionBackgroundColor);
177        }
178        // composition text
179        font_.DrawTextAt(
180            image,
181            pp::TextRun_Dev(str.c_str(), false, false),
182            pp::Point(offset, area_.y() + font_size_),
183            kTextfieldPreeditTextColor,
184            clip,
185            false);
186        for (size_t i = 0; i < segments_.size(); ++i) {
187          size_t l = segments_[i].first;
188          size_t r = segments_[i].second;
189          if (l != r) {
190            int lx = font_.MeasureSimpleText(str.substr(0, l));
191            int rx = font_.MeasureSimpleText(str.substr(0, r));
192            FillRect(image,
193                     offset + lx + 2, area_.y() + font_size_ + 1,
194                     rx - lx - 4, 2,
195                     i == static_cast<size_t>(target_segment_) ?
196                         kTextfieldUnderlineColorMain :
197                         kTextfieldUnderlineColorSub);
198          }
199        }
200        // caret
201        int caretx = font_.MeasureSimpleText(
202            str.substr(0, composition_selection_.first));
203        FillRect(image,
204                 pp::Rect(offset + caretx, area_.y(), 2, area_.height()),
205                 kTextfieldCaretColor);
206        offset += font_.MeasureSimpleText(str);
207      }
208      // after caret
209      {
210        std::string str = utf8_text_.substr(caret_pos_);
211        font_.DrawTextAt(
212            image,
213            pp::TextRun_Dev(str.c_str(), false, false),
214            pp::Point(offset, area_.y() + font_size_),
215            kTextfieldTextColor,
216            clip,
217            false);
218      }
219    } else {
220      font_.DrawTextAt(
221          image,
222          pp::TextRun_Dev(utf8_text_.c_str(), false, false),
223          pp::Point(area_.x(), area_.y() + font_size_),
224          kTextfieldTextColor,
225          clip,
226          false);
227    }
228  }
229
230  // Update current composition text.
231  void SetComposition(
232      const std::string& text,
233      const std::vector< std::pair<uint32_t, uint32_t> >& segments,
234      int32_t target_segment,
235      const std::pair<uint32_t, uint32_t>& selection) {
236    if (HasSelection() && !text.empty())
237      InsertText(std::string());
238    composition_ = text;
239    segments_ = segments;
240    target_segment_ = target_segment;
241    composition_selection_ = selection;
242    CaretPosChanged();
243  }
244
245  // Is the text field focused?
246  bool Focused() const {
247    return caret_pos_ != std::string::npos;
248  }
249
250  // Does the coordinate (x,y) is contained inside the edit box?
251  bool Contains(int x, int y) const {
252    return area_.Contains(x, y);
253  }
254
255  // Resets the content text.
256  void SetText(const std::string& text) {
257    utf8_text_ = text;
258    if (Focused()) {
259      caret_pos_ = anchor_pos_ = text.size();
260      CaretPosChanged();
261    }
262  }
263
264  // Inserts a text at the current caret position.
265  void InsertText(const std::string& text) {
266    if (!Focused())
267      return;
268    utf8_text_.replace(SelectionLeft(), SelectionRight() - SelectionLeft(),
269                       text);
270    caret_pos_ = anchor_pos_ = SelectionLeft() + text.size();
271    CaretPosChanged();
272  }
273
274  // Handles mouse click event and changes the focus state.
275  bool RefocusByMouseClick(int x, int y) {
276    if (!Contains(x, y)) {
277      // The text field is unfocused.
278      caret_pos_ = anchor_pos_ = std::string::npos;
279      return false;
280    }
281
282    // The text field is focused.
283    size_t n = font_.CharacterOffsetForPixel(
284        pp::TextRun_Dev(utf8_text_.c_str()), x - area_.x());
285    caret_pos_ = anchor_pos_ = GetNthCharOffsetUtf8(utf8_text_, n);
286    CaretPosChanged();
287    return true;
288  }
289
290  void MouseDrag(int x, int y) {
291    if (!Focused())
292      return;
293    size_t n = font_.CharacterOffsetForPixel(
294        pp::TextRun_Dev(utf8_text_.c_str()), x - area_.x());
295    caret_pos_ = GetNthCharOffsetUtf8(utf8_text_, n);
296  }
297
298  void MouseUp(int x, int y) {
299    if (!Focused())
300      return;
301    CaretPosChanged();
302  }
303
304  void KeyLeft(bool shift) {
305    if (!Focused())
306      return;
307    // Move caret to the head of the selection or to the previous character.
308    if (!shift && HasSelection())
309      caret_pos_ = SelectionLeft();
310    else
311      caret_pos_ = GetPrevCharOffsetUtf8(utf8_text_, caret_pos_);
312    // Move the anchor if the shift key is not pressed.
313    if (!shift)
314      anchor_pos_ = caret_pos_;
315    CaretPosChanged();
316  }
317
318  void KeyRight(bool shift) {
319    if (!Focused())
320      return;
321    // Move caret to the end of the selection or to the next character.
322    if (!shift && HasSelection())
323      caret_pos_ = SelectionRight();
324    else
325      caret_pos_ = GetNextCharOffsetUtf8(utf8_text_, caret_pos_);
326    // Move the anchor if the shift key is not pressed.
327    if (!shift)
328      anchor_pos_ = caret_pos_;
329    CaretPosChanged();
330  }
331
332  void KeyDelete() {
333    if (!Focused())
334      return;
335    if (HasSelection()) {
336      InsertText(std::string());
337    } else {
338      size_t i = GetNextCharOffsetUtf8(utf8_text_, caret_pos_);
339      utf8_text_.erase(caret_pos_, i - caret_pos_);
340      CaretPosChanged();
341    }
342  }
343
344  void KeyBackspace() {
345    if (!Focused())
346      return;
347    if (HasSelection()) {
348      InsertText(std::string());
349    } else if (caret_pos_ != 0) {
350      size_t i = GetPrevCharOffsetUtf8(utf8_text_, caret_pos_);
351      utf8_text_.erase(i, caret_pos_ - i);
352      caret_pos_ = anchor_pos_ = i;
353      CaretPosChanged();
354    }
355  }
356
357 private:
358  // Notify the plugin instance that the caret position has changed.
359  void CaretPosChanged() {
360    if (Focused()) {
361      std::string str = utf8_text_.substr(0, caret_pos_);
362      if (!composition_.empty())
363        str += composition_.substr(0, composition_selection_.first);
364      int px = font_.MeasureSimpleText(str);
365      pp::Rect caret(area_.x() + px, area_.y(), 0, area_.height() + 2);
366      status_handler_->FocusIn(caret);
367      status_handler_->UpdateSelection(
368          utf8_text_.substr(SelectionLeft(),
369                            SelectionRight() - SelectionLeft()));
370    }
371  }
372  size_t SelectionLeft() const {
373    return std::min(caret_pos_, anchor_pos_);
374  }
375  size_t SelectionRight() const {
376    return std::max(caret_pos_, anchor_pos_);
377  }
378  bool HasSelection() const {
379    return caret_pos_ != anchor_pos_;
380  }
381
382  pp::Instance* instance_;
383  TextFieldStatusHandler* status_handler_;
384
385  pp::Rect area_;
386  int font_size_;
387  pp::Font_Dev font_;
388  std::string utf8_text_;
389  size_t caret_pos_;
390  size_t anchor_pos_;
391  std::string composition_;
392  std::vector< std::pair<uint32_t, uint32_t> > segments_;
393  std::pair<uint32_t, uint32_t> composition_selection_;
394  int target_segment_;
395};
396
397class MyInstance : public pp::Instance {
398 public:
399  explicit MyInstance(PP_Instance instance)
400      : pp::Instance(instance),
401        status_handler_(new TextFieldStatusHandler),
402        dragging_(false) {
403  }
404
405  ~MyInstance() {
406    delete status_handler_;
407  }
408
409  virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
410    RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE);
411    RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD);
412
413    for (uint32_t i = 0; i < argc; ++i) {
414      if (argn[i] == std::string("ime")) {
415        if (argv[i] == std::string("no")) {
416          // Example of NO-IME plugins (e.g., games).
417          //
418          // When a plugin never wants to accept text input, at initialization
419          // explicitly turn off the text input feature by calling:
420          pp::TextInputController(this).SetTextInputType(
421              PP_TEXTINPUT_TYPE_NONE);
422        } else if (argv[i] == std::string("unaware")) {
423          // Demonstrating the behavior of IME-unaware plugins.
424          // Never call any text input related APIs.
425          //
426          // In such a case, the plugin is assumed to always accept text input.
427          // For example, when the plugin is focused in touch devices a virtual
428          // keyboard may pop up, or in environment IME is used, users can type
429          // text via IME on the plugin. The characters are delivered to the
430          // plugin via PP_INPUTEVENT_TYPE_CHAR events.
431        } else if (argv[i] == std::string("caretmove")) {
432          // Demonstrating the behavior of plugins with limited IME support.
433          //
434          // It uses SetTextInputType() and UpdateCaretPosition() API to notify
435          // text input status to the browser, but unable to handle inline
436          // compositions. By using the notified information. the browser can,
437          // say, show virtual keyboards or IMEs only at appropriate timing
438          // that the plugin does need to accept text input.
439          delete status_handler_;
440          status_handler_ = new TextFieldStatusNotifyingHandler(this);
441        } else if (argv[i] == std::string("full")) {
442          // Demonstrating the behavior of plugins fully supporting IME.
443          //
444          // It notifies updates of caret positions to the browser,
445          // and handles all text input events by itself.
446          delete status_handler_;
447          status_handler_ = new TextFieldStatusNotifyingHandler(this);
448          RequestInputEvents(PP_INPUTEVENT_CLASS_IME);
449        }
450        break;
451      }
452    }
453
454    textfield_.push_back(MyTextField(this, status_handler_,
455                                     10, 10, 300, 20));
456    textfield_.back().SetText("Hello");
457    textfield_.push_back(MyTextField(this, status_handler_,
458                                     30, 100, 300, 20));
459    textfield_.back().SetText("World");
460    return true;
461  }
462
463 protected:
464  virtual bool HandleInputEvent(const pp::InputEvent& event) {
465    bool ret = false;
466    switch (event.GetType()) {
467      case PP_INPUTEVENT_TYPE_MOUSEDOWN: {
468        const pp::MouseInputEvent mouseEvent(event);
469        ret = OnMouseDown(mouseEvent);
470        break;
471      }
472      case PP_INPUTEVENT_TYPE_MOUSEMOVE: {
473        const pp::MouseInputEvent mouseEvent(event);
474        ret = OnMouseMove(mouseEvent);
475        break;
476      }
477      case PP_INPUTEVENT_TYPE_MOUSEUP: {
478        const pp::MouseInputEvent mouseEvent(event);
479        ret = OnMouseUp(mouseEvent);
480        break;
481      }
482      case PP_INPUTEVENT_TYPE_KEYDOWN: {
483        Log("Keydown");
484        const pp::KeyboardInputEvent keyEvent(event);
485        ret = OnKeyDown(keyEvent);
486        break;
487      }
488      case PP_INPUTEVENT_TYPE_CHAR: {
489        const pp::KeyboardInputEvent keyEvent(event);
490        Log("Char [" + keyEvent.GetCharacterText().AsString() + "]");
491        ret = OnChar(keyEvent);
492        break;
493      }
494      case PP_INPUTEVENT_TYPE_IME_COMPOSITION_START: {
495        const pp::IMEInputEvent imeEvent(event);
496        Log("CompositionStart [" + imeEvent.GetText().AsString() + "]");
497        ret = true;
498        break;
499      }
500      case PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE: {
501        const pp::IMEInputEvent imeEvent(event);
502        Log("CompositionUpdate [" + imeEvent.GetText().AsString() + "]");
503        ret = OnCompositionUpdate(imeEvent);
504        break;
505      }
506      case PP_INPUTEVENT_TYPE_IME_COMPOSITION_END: {
507        const pp::IMEInputEvent imeEvent(event);
508        Log("CompositionEnd [" + imeEvent.GetText().AsString() + "]");
509        ret = OnCompositionEnd(imeEvent);
510        break;
511      }
512      case PP_INPUTEVENT_TYPE_IME_TEXT: {
513        const pp::IMEInputEvent imeEvent(event);
514        Log("ImeText [" + imeEvent.GetText().AsString() + "]");
515        ret = OnImeText(imeEvent);
516        break;
517      }
518      default:
519        break;
520    }
521    if (ret && (dragging_ || event.GetType() != PP_INPUTEVENT_TYPE_MOUSEMOVE))
522      Paint();
523    return ret;
524  }
525
526  virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
527    if (position.size() == last_size_)
528      return;
529    last_size_ = position.size();
530    Paint();
531  }
532
533 private:
534  bool OnCompositionUpdate(const pp::IMEInputEvent& ev) {
535    for (std::vector<MyTextField>::iterator it = textfield_.begin();
536         it != textfield_.end();
537         ++it) {
538      if (it->Focused()) {
539        std::vector< std::pair<uint32_t, uint32_t> > segs;
540        for (uint32_t i = 0; i < ev.GetSegmentNumber(); ++i)
541          segs.push_back(std::make_pair(ev.GetSegmentOffset(i),
542                                        ev.GetSegmentOffset(i + 1)));
543        uint32_t selection_start;
544        uint32_t selection_end;
545        ev.GetSelection(&selection_start, &selection_end);
546        it->SetComposition(ev.GetText().AsString(),
547                           segs,
548                           ev.GetTargetSegment(),
549                           std::make_pair(selection_start, selection_end));
550        return true;
551      }
552    }
553    return false;
554  }
555
556  bool OnCompositionEnd(const pp::IMEInputEvent& ev) {
557    for (std::vector<MyTextField>::iterator it = textfield_.begin();
558         it != textfield_.end();
559         ++it) {
560      if (it->Focused()) {
561        it->SetComposition(std::string(),
562                           std::vector<std::pair<uint32_t, uint32_t> >(),
563                           0,
564                           std::make_pair(0, 0));
565        return true;
566      }
567    }
568    return false;
569  }
570
571  bool OnMouseDown(const pp::MouseInputEvent& ev) {
572    dragging_ = true;
573
574    bool anyone_focused = false;
575    for (std::vector<MyTextField>::iterator it = textfield_.begin();
576         it != textfield_.end();
577         ++it) {
578      if (it->RefocusByMouseClick(ev.GetPosition().x(),
579                                  ev.GetPosition().y())) {
580        anyone_focused = true;
581      }
582    }
583    if (!anyone_focused)
584      status_handler_->FocusOut();
585    return true;
586  }
587
588  bool OnMouseMove(const pp::MouseInputEvent& ev) {
589    const PPB_CursorControl_Dev* cursor_control =
590        reinterpret_cast<const PPB_CursorControl_Dev*>(
591            pp::Module::Get()->GetBrowserInterface(
592                PPB_CURSOR_CONTROL_DEV_INTERFACE));
593    if (!cursor_control)
594      return false;
595
596    for (std::vector<MyTextField>::iterator it = textfield_.begin();
597         it != textfield_.end();
598         ++it) {
599      if (it->Contains(ev.GetPosition().x(),
600                       ev.GetPosition().y())) {
601        cursor_control->SetCursor(pp_instance(), PP_CURSORTYPE_IBEAM,
602                                  0, NULL);
603        if (it->Focused() && dragging_)
604          it->MouseDrag(ev.GetPosition().x(), ev.GetPosition().y());
605        return true;
606      }
607    }
608    cursor_control->SetCursor(pp_instance(), PP_CURSORTYPE_POINTER,
609                              0, NULL);
610    return true;
611  }
612
613  bool OnMouseUp(const pp::MouseInputEvent& ev) {
614    dragging_ = false;
615    for (std::vector<MyTextField>::iterator it = textfield_.begin();
616         it != textfield_.end();
617         ++it)
618      if (it->Focused())
619        it->MouseUp(ev.GetPosition().x(), ev.GetPosition().y());
620    return false;
621  }
622
623  bool OnKeyDown(const pp::KeyboardInputEvent& ev) {
624    for (std::vector<MyTextField>::iterator it = textfield_.begin();
625         it != textfield_.end();
626         ++it) {
627      if (it->Focused()) {
628        bool shift = ev.GetModifiers() & PP_INPUTEVENT_MODIFIER_SHIFTKEY;
629        switch (ev.GetKeyCode()) {
630          case VKEY_LEFT:
631            it->KeyLeft(shift);
632            break;
633          case VKEY_RIGHT:
634            it->KeyRight(shift);
635            break;
636          case VKEY_DELETE:
637            it->KeyDelete();
638            break;
639          case VKEY_BACK:
640            it->KeyBackspace();
641            break;
642        }
643        return true;
644      }
645    }
646    return false;
647  }
648
649  bool OnChar(const pp::KeyboardInputEvent& ev) {
650    for (std::vector<MyTextField>::iterator it = textfield_.begin();
651         it != textfield_.end();
652         ++it) {
653      if (it->Focused()) {
654        std::string str = ev.GetCharacterText().AsString();
655        if (str != "\r" && str != "\n")
656          it->InsertText(str);
657        return true;
658      }
659    }
660    return false;
661  }
662
663  bool OnImeText(const pp::IMEInputEvent ev) {
664    for (std::vector<MyTextField>::iterator it = textfield_.begin();
665         it != textfield_.end();
666         ++it) {
667      if (it->Focused()) {
668        it->InsertText(ev.GetText().AsString());
669        return true;
670      }
671    }
672    return false;
673  }
674
675  void Paint() {
676    pp::Rect clip(0, 0, last_size_.width(), last_size_.height());
677    PaintClip(clip);
678  }
679
680  void PaintClip(const pp::Rect& clip) {
681    pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, last_size_, true);
682    pp::Graphics2D device(this, last_size_, false);
683    BindGraphics(device);
684
685    for (std::vector<MyTextField>::iterator it = textfield_.begin();
686         it != textfield_.end();
687         ++it) {
688      it->PaintOn(&image, clip);
689    }
690
691    device.PaintImageData(image, pp::Point(0, 0));
692    device.Flush(pp::CompletionCallback(&OnFlush, this));
693  }
694
695  static void OnFlush(void* user_data, int32_t result) {}
696
697  // Prints a debug message.
698  void Log(const pp::Var& value) {
699    const PPB_Console* console = reinterpret_cast<const PPB_Console*>(
700        pp::Module::Get()->GetBrowserInterface(PPB_CONSOLE_INTERFACE));
701    if (!console)
702      return;
703    console->Log(pp_instance(), PP_LOGLEVEL_LOG, value.pp_var());
704  }
705
706  // IME Control interface.
707  TextFieldStatusHandler* status_handler_;
708
709  // Remembers the size of this instance.
710  pp::Size last_size_;
711
712  // Holds instances of text fields.
713  std::vector<MyTextField> textfield_;
714
715  // Whether or not during a drag operation.
716  bool dragging_;
717};
718
719class MyModule : public pp::Module {
720  virtual pp::Instance* CreateInstance(PP_Instance instance) {
721    return new MyInstance(instance);
722  }
723};
724
725namespace pp {
726
727Module* CreateModule() {
728  return new MyModule();
729}
730
731}  // namespace pp
732