| OLD | NEW | 
| (Empty) |  | 
 |    1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 
 |    2 // Use of this source code is governed by a BSD-style license that can be | 
 |    3 // found in the LICENSE file. | 
 |    4  | 
 |    5 #include <string> | 
 |    6 #include <utility> | 
 |    7 #include <vector> | 
 |    8  | 
 |    9 #include "base/scoped_ptr.h" | 
 |   10 #include "ppapi/c/dev/ppb_console_dev.h" | 
 |   11 #include "ppapi/c/dev/ppb_cursor_control_dev.h" | 
 |   12 #include "ppapi/cpp/completion_callback.h" | 
 |   13 #include "ppapi/cpp/dev/font_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" | 
 |   22 #include "ui/base/keycodes/keyboard_codes.h" | 
 |   23  | 
 |   24 namespace { | 
 |   25  | 
 |   26 static const uint32_t TEXTFIELD_BG_COLOR = 0xffffffff; | 
 |   27 static const uint32_t TEXTFIELD_TEXT_COLOR = 0xff000000; | 
 |   28 static const uint32_t TEXTFIELD_CARET_COLOR = 0xff000000; | 
 |   29 static const uint32_t TEXTFIELD_PREEDIT_TEXT_COLOR = 0xffff0000; | 
 |   30 static const uint32_t TEXTFIELD_UNDERLINE_COLOR_MAIN = 0xffff0000; | 
 |   31 static const uint32_t TEXTFIELD_UNDERLINE_COLOR_SUB = 0xffddaaaa; | 
 |   32  | 
 |   33 void FillRect(pp::ImageData* image, | 
 |   34               int left, int top, int width, int height, | 
 |   35               uint32_t color) { | 
 |   36   for (int y = std::max(0, top); | 
 |   37        y < std::min(image->size().height() - 1, top + height); | 
 |   38        ++y) { | 
 |   39     for (int x = std::max(0, left); | 
 |   40          x < std::min(image->size().width() - 1, left + width); | 
 |   41          ++x) | 
 |   42       *image->GetAddr32(pp::Point(x, y)) = color; | 
 |   43   } | 
 |   44 } | 
 |   45  | 
 |   46 void FillRect(pp::ImageData* image, const pp::Rect& rect, uint32_t color) { | 
 |   47   FillRect(image, rect.x(), rect.y(), rect.width(), rect.height(), color); | 
 |   48 } | 
 |   49  | 
 |   50 size_t utf8_prev(const std::string& str, size_t i) { | 
 |   51   if (i > 0) { | 
 |   52     do | 
 |   53       --i; | 
 |   54     while ((str[i] & 0xC0) == 0x80 && i > 0); | 
 |   55   } | 
 |   56   return i; | 
 |   57 } | 
 |   58  | 
 |   59 size_t utf8_next(const std::string& str, size_t i, size_t n) { | 
 |   60   for (size_t step = 0; step < n; ++step) { | 
 |   61     if (i < str.size()) { | 
 |   62       do | 
 |   63         ++i; | 
 |   64       while ((str[i] & 0xC0) == 0x80 && i < str.size()); | 
 |   65     } | 
 |   66   } | 
 |   67   return i; | 
 |   68 } | 
 |   69  | 
 |   70 }  // namespace | 
 |   71  | 
 |   72 class TextFieldStatusHandler { | 
 |   73  public: | 
 |   74   virtual ~TextFieldStatusHandler() {} | 
 |   75   virtual void focusIn(const pp::Rect& caret, const pp::Rect& boundingBox) {} | 
 |   76   virtual void focusOut() {} | 
 |   77 }; | 
 |   78  | 
 |   79 class TextFieldStatusNotifyingHanlder : public TextFieldStatusHandler { | 
 |   80  public: | 
 |   81   explicit TextFieldStatusNotifyingHanlder(pp::Instance* instance) | 
 |   82     : instance_(instance), | 
 |   83       textinput_control_(instance) {} | 
 |   84  | 
 |   85  protected: | 
 |   86   virtual void focusIn(const pp::Rect& caret, const pp::Rect& boundingBox) { | 
 |   87     textinput_control_.SetTextInputType(PP_TEXTINPUT_TYPE_TEXT); | 
 |   88     textinput_control_.UpdateCaretPosition(caret, boundingBox); | 
 |   89   } | 
 |   90   virtual void focusOut() { | 
 |   91     textinput_control_.CancelCompositionText(); | 
 |   92     textinput_control_.SetTextInputType(PP_TEXTINPUT_TYPE_NONE); | 
 |   93   } | 
 |   94  | 
 |   95  private: | 
 |   96   pp::Instance* instance_; | 
 |   97   pp::TextInput_Dev textinput_control_; | 
 |   98 }; | 
 |   99  | 
 |  100 // Hand-made text field for demonstrating text input API. | 
 |  101 class MyTextField { | 
 |  102  public: | 
 |  103   MyTextField(pp::Instance* instance, TextFieldStatusHandler* handler, | 
 |  104               int x, int y, int width, int height) | 
 |  105     : instance_(instance), | 
 |  106       status_handler_(handler), | 
 |  107       area_(x, y, width, height), | 
 |  108       font_size_(height-2), | 
 |  109       caret_pos_(std::string::npos) { | 
 |  110     pp::FontDescription_Dev desc; | 
 |  111     desc.set_family(PP_FONTFAMILY_SANSSERIF); | 
 |  112     desc.set_size(font_size_); | 
 |  113     font_ = pp::Font_Dev(instance_, desc); | 
 |  114   } | 
 |  115  | 
 |  116   // Paint on the specified ImageData. | 
 |  117   void PaintOn(pp::ImageData* image, pp::Rect clip) { | 
 |  118     clip = clip.Intersect(area_); | 
 |  119     FillRect(image, clip, TEXTFIELD_BG_COLOR); | 
 |  120  | 
 |  121     if (caret_pos_ != std::string::npos) { | 
 |  122       int offset = area_.x(); | 
 |  123       // before caret | 
 |  124       { | 
 |  125         std::string str = utf8_text_.substr(0, caret_pos_); | 
 |  126         font_.DrawTextAt( | 
 |  127             image, | 
 |  128             pp::TextRun_Dev(str.c_str(), false, false), | 
 |  129             pp::Point(offset, area_.y()+font_size_), | 
 |  130             TEXTFIELD_TEXT_COLOR, | 
 |  131             clip, | 
 |  132             false); | 
 |  133         offset += font_.MeasureSimpleText(str); | 
 |  134       } | 
 |  135       // composition | 
 |  136       { | 
 |  137         const std::string& str = composition_; | 
 |  138         font_.DrawTextAt( | 
 |  139             image, | 
 |  140             pp::TextRun_Dev(str.c_str(), false, false), | 
 |  141             pp::Point(offset, area_.y()+font_size_), | 
 |  142             TEXTFIELD_PREEDIT_TEXT_COLOR, | 
 |  143             clip, | 
 |  144             false); | 
 |  145         for (size_t i = 0; i < segments_.size(); ++i) { | 
 |  146           size_t l = segments_[i].first; | 
 |  147           size_t r = segments_[i].second; | 
 |  148           if (l != r) { | 
 |  149             int lx = font_.MeasureSimpleText(str.substr(0, l)); | 
 |  150             int rx = font_.MeasureSimpleText(str.substr(0, r)); | 
 |  151             FillRect(image, | 
 |  152                      offset+lx+2, area_.y()+font_size_+1, (rx-lx)-4, 2, | 
 |  153                      i == static_cast<size_t>(targetSegment_) ? | 
 |  154                          TEXTFIELD_UNDERLINE_COLOR_MAIN : | 
 |  155                          TEXTFIELD_UNDERLINE_COLOR_SUB); | 
 |  156           } | 
 |  157         } | 
 |  158         // caret | 
 |  159         int caretx = font_.MeasureSimpleText(str.substr(0, selection_.first)); | 
 |  160         FillRect(image, | 
 |  161                  pp::Rect(offset+caretx, area_.y(), 2, area_.height()), | 
 |  162                  TEXTFIELD_CARET_COLOR); | 
 |  163         offset += font_.MeasureSimpleText(str); | 
 |  164       } | 
 |  165       // after caret | 
 |  166       { | 
 |  167         std::string str = utf8_text_.substr(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             TEXTFIELD_TEXT_COLOR, | 
 |  173             clip, | 
 |  174             false); | 
 |  175       } | 
 |  176     } else { | 
 |  177       font_.DrawTextAt( | 
 |  178           image, | 
 |  179           pp::TextRun_Dev(utf8_text_.c_str(), false, false), | 
 |  180           pp::Point(area_.x(), area_.y()+font_size_), | 
 |  181           TEXTFIELD_TEXT_COLOR, | 
 |  182           clip, | 
 |  183           false); | 
 |  184     } | 
 |  185   } | 
 |  186  | 
 |  187   // Update current composition text. | 
 |  188   void setComposition( | 
 |  189       const std::string& text, | 
 |  190       const std::vector< std::pair<uint32_t, uint32_t> >& segments, | 
 |  191       int32_t target_segment, | 
 |  192       const std::pair<uint32_t, uint32_t>& selection) { | 
 |  193     composition_ = text; | 
 |  194     segments_ = segments; | 
 |  195     targetSegment_ = target_segment; | 
 |  196     selection_ = selection; | 
 |  197     caretPosChanged(); | 
 |  198   } | 
 |  199  | 
 |  200   // Am I focused? | 
 |  201   bool focused() const { | 
 |  202     return caret_pos_ != std::string::npos; | 
 |  203   } | 
 |  204  | 
 |  205   // Does the coordinate (x,y) is contained inside the edit box? | 
 |  206   bool contains(int x, int y) const { | 
 |  207     return area_.Contains(x, y); | 
 |  208   } | 
 |  209  | 
 |  210   // reset the content text | 
 |  211   void set_text(const std::string& text) { | 
 |  212     utf8_text_ = text; | 
 |  213     if (focused()) { | 
 |  214       caret_pos_ = text.size(); | 
 |  215       caretPosChanged(); | 
 |  216     } | 
 |  217   } | 
 |  218  | 
 |  219   // insert the text at the caret position | 
 |  220   void insert_text(const std::string& text) { | 
 |  221     if (!focused()) | 
 |  222       return; | 
 |  223     utf8_text_.insert(caret_pos_, text); | 
 |  224     if (focused()) { | 
 |  225       caret_pos_ += text.size(); | 
 |  226       caretPosChanged(); | 
 |  227     } | 
 |  228   } | 
 |  229  | 
 |  230   // event handling | 
 |  231   bool refocusByMouseClick(int x, int y) { | 
 |  232     if (!contains(x, y)) { | 
 |  233       // unfocus | 
 |  234       caret_pos_ = std::string::npos; | 
 |  235       return false; | 
 |  236     } | 
 |  237  | 
 |  238     // focus | 
 |  239     size_t n = font_.CharacterOffsetForPixel( | 
 |  240         pp::TextRun_Dev(utf8_text_.c_str()), x-area_.x()); | 
 |  241     caret_pos_ = utf8_next(utf8_text_, 0, n); | 
 |  242     caretPosChanged(); | 
 |  243     return true; | 
 |  244   } | 
 |  245  | 
 |  246   void keyLeft() { | 
 |  247     if (!focused()) | 
 |  248       return; | 
 |  249     caret_pos_ = utf8_prev(utf8_text_, caret_pos_); | 
 |  250     caretPosChanged(); | 
 |  251   } | 
 |  252  | 
 |  253   void keyRight() { | 
 |  254     if (!focused()) | 
 |  255       return; | 
 |  256     caret_pos_ = utf8_next(utf8_text_, caret_pos_, 1); | 
 |  257     caretPosChanged(); | 
 |  258   } | 
 |  259  | 
 |  260   void keyDelete() { | 
 |  261     if (!focused()) | 
 |  262       return; | 
 |  263     size_t i = utf8_next(utf8_text_, caret_pos_, 1); | 
 |  264     utf8_text_.erase(caret_pos_, i-caret_pos_); | 
 |  265     caretPosChanged(); | 
 |  266   } | 
 |  267  | 
 |  268   void keyBackspace() { | 
 |  269     if (!focused() || caret_pos_ == 0) | 
 |  270       return; | 
 |  271     keyLeft(); | 
 |  272     keyDelete(); | 
 |  273   } | 
 |  274  | 
 |  275  private: | 
 |  276   // Notify the plugin instance that the caret position has changed. | 
 |  277   void caretPosChanged() { | 
 |  278     if (focused()) { | 
 |  279       std::string str = utf8_text_.substr(0, caret_pos_); | 
 |  280       if (!composition_.empty()) | 
 |  281         str += composition_.substr(0, selection_.first); | 
 |  282       int px = font_.MeasureSimpleText(str); | 
 |  283       pp::Rect textarea(area_.x()+px, area_.y(), 2, area_.height()+2); | 
 |  284       status_handler_->focusIn(textarea, area_); | 
 |  285     } | 
 |  286   } | 
 |  287  | 
 |  288   pp::Instance* instance_; | 
 |  289   TextFieldStatusHandler* status_handler_; | 
 |  290  | 
 |  291   pp::Rect area_; | 
 |  292   int font_size_; | 
 |  293   pp::Font_Dev font_; | 
 |  294   std::string utf8_text_; | 
 |  295   size_t caret_pos_; | 
 |  296   std::string composition_; | 
 |  297   std::vector< std::pair<uint32_t, uint32_t> > segments_; | 
 |  298   std::pair<uint32_t, uint32_t> selection_; | 
 |  299   int targetSegment_; | 
 |  300 }; | 
 |  301  | 
 |  302 class MyInstance : public pp::Instance { | 
 |  303  public: | 
 |  304   explicit MyInstance(PP_Instance instance) | 
 |  305       : pp::Instance(instance), | 
 |  306         status_handler_(new TextFieldStatusHandler) { | 
 |  307   } | 
 |  308  | 
 |  309   virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) { | 
 |  310     RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE); | 
 |  311     RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); | 
 |  312  | 
 |  313     for (uint32_t i = 0; i < argc; ++i) { | 
 |  314       if (argn[i] == std::string("ime")) { | 
 |  315         if (argv[i] == std::string("no")) { | 
 |  316           // Example of NO-IME plugins (e.g., games). | 
 |  317           // Explicitly turns off the text input feature, and | 
 |  318           // Never call any text input related APIs. | 
 |  319           pp::TextInput_Dev(this).SetTextInputType(PP_TEXTINPUT_TYPE_NONE); | 
 |  320         } else if (argv[i] == std::string("unaware")) { | 
 |  321           // Demonstrating the behavior of IME-unaware plugins. | 
 |  322           // Never call any text input related APIs. | 
 |  323         } else if (argv[i] == std::string("caretmove")) { | 
 |  324           // Demonstrating the behavior of plugins with limited IME support. | 
 |  325           // It notifies updates of caret positions to the browser, | 
 |  326           // but unable to handle inline compositions. | 
 |  327           status_handler_.reset(new TextFieldStatusNotifyingHanlder(this)); | 
 |  328         } else if (argv[i] == std::string("full")) { | 
 |  329           // Demonstrating the behavior of plugins fully supporting IME. | 
 |  330           // It notifies updates of caret positions to the browser, | 
 |  331           // but handles all text input events by itself. | 
 |  332           status_handler_.reset(new TextFieldStatusNotifyingHanlder(this)); | 
 |  333           RequestInputEvents(PP_INPUTEVENT_CLASS_IME); | 
 |  334         } | 
 |  335         break; | 
 |  336       } | 
 |  337     } | 
 |  338  | 
 |  339     textfield_.push_back(MyTextField(this, status_handler_.get(), | 
 |  340                                      10, 10, 300, 20)); | 
 |  341     textfield_.back().set_text("Hello"); | 
 |  342     textfield_.push_back(MyTextField(this, status_handler_.get(), | 
 |  343                                      30, 100, 300, 20)); | 
 |  344     textfield_.back().set_text("World"); | 
 |  345     return true; | 
 |  346   } | 
 |  347  | 
 |  348  protected: | 
 |  349   virtual bool HandleInputEvent(const pp::InputEvent& event) { | 
 |  350     bool ret = false; | 
 |  351     switch (event.GetType()) { | 
 |  352       case PP_INPUTEVENT_TYPE_MOUSEDOWN: { | 
 |  353         const pp::MouseInputEvent mouseEvent(event); | 
 |  354         ret = onMouseDown(mouseEvent); | 
 |  355         break; | 
 |  356       } | 
 |  357       case PP_INPUTEVENT_TYPE_MOUSEMOVE: { | 
 |  358         const pp::MouseInputEvent mouseEvent(event); | 
 |  359         ret = onMouseMove(mouseEvent); | 
 |  360         break; | 
 |  361       } | 
 |  362       case PP_INPUTEVENT_TYPE_KEYDOWN: { | 
 |  363         Log("Keydown"); | 
 |  364         const pp::KeyboardInputEvent keyEvent(event); | 
 |  365         ret = onKeyDown(keyEvent); | 
 |  366         break; | 
 |  367       } | 
 |  368       case PP_INPUTEVENT_TYPE_CHAR: { | 
 |  369         const pp::KeyboardInputEvent keyEvent(event); | 
 |  370         Log("Char ["+keyEvent.GetCharacterText().AsString()+"]"); | 
 |  371         ret = onChar(keyEvent); | 
 |  372         break; | 
 |  373       } | 
 |  374       case PP_INPUTEVENT_TYPE_COMPOSITION_START: { | 
 |  375         const pp::CompositionInputEvent compositionEvent(event); | 
 |  376         Log("CompositionStart ["+compositionEvent.GetText().AsString()+"]"); | 
 |  377         ret = true; | 
 |  378         break; | 
 |  379       } | 
 |  380       case PP_INPUTEVENT_TYPE_COMPOSITION_UPDATE: { | 
 |  381         const pp::CompositionInputEvent compositionEvent(event); | 
 |  382         Log("CompositionUpdate ["+compositionEvent.GetText().AsString()+"]"); | 
 |  383         ret = onCompositionUpdate(compositionEvent); | 
 |  384         break; | 
 |  385       } | 
 |  386       case PP_INPUTEVENT_TYPE_COMPOSITION_END: { | 
 |  387         const pp::CompositionInputEvent compositionEvent(event); | 
 |  388         Log("CompositionEnd ["+compositionEvent.GetText().AsString()+"]"); | 
 |  389         ret = onCompositionEnd(compositionEvent); | 
 |  390         break; | 
 |  391       } | 
 |  392       case PP_INPUTEVENT_TYPE_IME_TEXT: { | 
 |  393         const pp::CompositionInputEvent compositionEvent(event); | 
 |  394         Log("ImeText ["+compositionEvent.GetText().AsString()+"]"); | 
 |  395         ret = onImeText(compositionEvent); | 
 |  396         break; | 
 |  397       } | 
 |  398       default: | 
 |  399         break; | 
 |  400     } | 
 |  401     if (ret && event.GetType() != PP_INPUTEVENT_TYPE_MOUSEMOVE) | 
 |  402       Paint(); | 
 |  403     return ret; | 
 |  404   } | 
 |  405  | 
 |  406   virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) { | 
 |  407     if (position.size() == last_size_) | 
 |  408       return; | 
 |  409     last_size_ = position.size(); | 
 |  410     Paint(); | 
 |  411   } | 
 |  412  | 
 |  413  private: | 
 |  414   bool onCompositionUpdate(const pp::CompositionInputEvent& ev) { | 
 |  415     for (std::vector<MyTextField>::iterator it = textfield_.begin(); | 
 |  416          it != textfield_.end(); | 
 |  417          ++it) { | 
 |  418       if (it->focused()) { | 
 |  419         it->setComposition(ev.GetText().AsString(), | 
 |  420                            ev.GetSegments(), | 
 |  421                            ev.GetTargetSegment(), | 
 |  422                            ev.GetSelection()); | 
 |  423         return true; | 
 |  424       } | 
 |  425     } | 
 |  426     return false; | 
 |  427   } | 
 |  428  | 
 |  429   bool onCompositionEnd(const pp::CompositionInputEvent& ev) { | 
 |  430     for (std::vector<MyTextField>::iterator it = textfield_.begin(); | 
 |  431          it != textfield_.end(); | 
 |  432          ++it) { | 
 |  433       if (it->focused()) { | 
 |  434         it->setComposition("", std::vector< std::pair<uint32_t, uint32_t> >(), | 
 |  435                            0, std::make_pair(0, 0)); | 
 |  436         return true; | 
 |  437       } | 
 |  438     } | 
 |  439     return false; | 
 |  440   } | 
 |  441  | 
 |  442   bool onMouseDown(const pp::MouseInputEvent& ev) { | 
 |  443     bool anyoneFocused = false; | 
 |  444     for (std::vector<MyTextField>::iterator it = textfield_.begin(); | 
 |  445          it != textfield_.end(); | 
 |  446          ++it) { | 
 |  447       if (it->refocusByMouseClick(ev.GetPosition().x(), | 
 |  448                                   ev.GetPosition().y())) { | 
 |  449         anyoneFocused = true; | 
 |  450       } | 
 |  451     } | 
 |  452     if (!anyoneFocused) | 
 |  453       status_handler_->focusOut(); | 
 |  454     return true; | 
 |  455   } | 
 |  456  | 
 |  457   bool onMouseMove(const pp::MouseInputEvent& ev) { | 
 |  458     const PPB_CursorControl_Dev* cursor_control = | 
 |  459         reinterpret_cast<const PPB_CursorControl_Dev*>( | 
 |  460             pp::Module::Get()->GetBrowserInterface( | 
 |  461                 PPB_CURSOR_CONTROL_DEV_INTERFACE)); | 
 |  462     if (!cursor_control) | 
 |  463       return false; | 
 |  464  | 
 |  465     for (std::vector<MyTextField>::iterator it = textfield_.begin(); | 
 |  466          it != textfield_.end(); | 
 |  467          ++it) { | 
 |  468       if (it->contains(ev.GetPosition().x(), | 
 |  469                        ev.GetPosition().y())) { | 
 |  470         cursor_control->SetCursor(pp_instance(), PP_CURSORTYPE_IBEAM, | 
 |  471                                   0, NULL); | 
 |  472         return true; | 
 |  473       } | 
 |  474     } | 
 |  475     cursor_control->SetCursor(pp_instance(), PP_CURSORTYPE_POINTER, | 
 |  476                               0, NULL); | 
 |  477     return true; | 
 |  478   } | 
 |  479  | 
 |  480   bool onKeyDown(const pp::KeyboardInputEvent& ev) { | 
 |  481     for (std::vector<MyTextField>::iterator it = textfield_.begin(); | 
 |  482          it != textfield_.end(); | 
 |  483          ++it) { | 
 |  484       if (it->focused()) { | 
 |  485         switch (ev.GetKeyCode()) { | 
 |  486           case ui::VKEY_LEFT: | 
 |  487             it->keyLeft(); | 
 |  488             break; | 
 |  489           case ui::VKEY_RIGHT: | 
 |  490             it->keyRight(); | 
 |  491             break; | 
 |  492           case ui::VKEY_DELETE: | 
 |  493             it->keyDelete(); | 
 |  494             break; | 
 |  495           case ui::VKEY_BACK: | 
 |  496             it->keyBackspace(); | 
 |  497             break; | 
 |  498         } | 
 |  499         return true; | 
 |  500       } | 
 |  501     } | 
 |  502     return false; | 
 |  503   } | 
 |  504  | 
 |  505   bool onChar(const pp::KeyboardInputEvent& ev) { | 
 |  506     for (std::vector<MyTextField>::iterator it = textfield_.begin(); | 
 |  507          it != textfield_.end(); | 
 |  508          ++it) { | 
 |  509       if (it->focused()) { | 
 |  510         it->insert_text(ev.GetCharacterText().AsString()); | 
 |  511         return true; | 
 |  512       } | 
 |  513     } | 
 |  514     return false; | 
 |  515   } | 
 |  516  | 
 |  517   bool onImeText(const pp::CompositionInputEvent& ev) { | 
 |  518     for (std::vector<MyTextField>::iterator it = textfield_.begin(); | 
 |  519          it != textfield_.end(); | 
 |  520          ++it) { | 
 |  521       if (it->focused()) { | 
 |  522         it->insert_text(ev.GetText().AsString()); | 
 |  523         return true; | 
 |  524       } | 
 |  525     } | 
 |  526     return false; | 
 |  527   } | 
 |  528  | 
 |  529   void Paint() { | 
 |  530     pp::Rect clip(0, 0, last_size_.height(), last_size_.width()); | 
 |  531     PaintClip(clip); | 
 |  532   } | 
 |  533  | 
 |  534   void PaintClip(const pp::Rect& clip) { | 
 |  535     pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, last_size_, true); | 
 |  536     pp::Graphics2D device(this, last_size_, false); | 
 |  537     BindGraphics(device); | 
 |  538  | 
 |  539     for (std::vector<MyTextField>::iterator it = textfield_.begin(); | 
 |  540          it != textfield_.end(); | 
 |  541          ++it) { | 
 |  542       it->PaintOn(&image, clip); | 
 |  543     } | 
 |  544  | 
 |  545     device.PaintImageData(image, pp::Point(0, 0)); | 
 |  546     device.Flush(pp::CompletionCallback(&OnFlush, this)); | 
 |  547   } | 
 |  548  | 
 |  549   static void OnFlush(void* user_data, int32_t result) {} | 
 |  550  | 
 |  551   // For debugging purpose. | 
 |  552   void Log(const pp::Var& value) { | 
 |  553     const PPB_Console_Dev* console = reinterpret_cast<const PPB_Console_Dev*>( | 
 |  554         pp::Module::Get()->GetBrowserInterface(PPB_CONSOLE_DEV_INTERFACE)); | 
 |  555     if (!console) | 
 |  556       return; | 
 |  557     console->Log(pp_instance(), PP_LOGLEVEL_LOG, value.pp_var()); | 
 |  558   } | 
 |  559  | 
 |  560   // IME Control interface. | 
 |  561   scoped_ptr<TextFieldStatusHandler> status_handler_; | 
 |  562  | 
 |  563   // Remembers the size of this instance. | 
 |  564   pp::Size last_size_; | 
 |  565  | 
 |  566   // Holds instances of text fields. | 
 |  567   std::vector<MyTextField> textfield_; | 
 |  568 }; | 
 |  569  | 
 |  570 class MyModule : public pp::Module { | 
 |  571   virtual pp::Instance* CreateInstance(PP_Instance instance) { | 
 |  572     return new MyInstance(instance); | 
 |  573   } | 
 |  574 }; | 
 |  575  | 
 |  576 namespace pp { | 
 |  577  | 
 |  578 Module* CreateModule() { | 
 |  579   return new MyModule(); | 
 |  580 } | 
 |  581  | 
 |  582 }  // namespace pp | 
| OLD | NEW |