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