Home | History | Annotate | Download | only in test_runner
      1 // Copyright 2014 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 "content/shell/renderer/test_runner/text_input_controller.h"
      6 
      7 #include "gin/arguments.h"
      8 #include "gin/handle.h"
      9 #include "gin/object_template_builder.h"
     10 #include "gin/wrappable.h"
     11 #include "third_party/WebKit/public/web/WebCompositionUnderline.h"
     12 #include "third_party/WebKit/public/web/WebFrame.h"
     13 #include "third_party/WebKit/public/web/WebInputEvent.h"
     14 #include "third_party/WebKit/public/web/WebKit.h"
     15 #include "third_party/WebKit/public/web/WebRange.h"
     16 #include "third_party/WebKit/public/web/WebView.h"
     17 #include "v8/include/v8.h"
     18 
     19 namespace content {
     20 
     21 class TextInputControllerBindings
     22     : public gin::Wrappable<TextInputControllerBindings> {
     23  public:
     24   static gin::WrapperInfo kWrapperInfo;
     25 
     26   static void Install(base::WeakPtr<TextInputController> controller,
     27                       blink::WebFrame* frame);
     28 
     29  private:
     30   explicit TextInputControllerBindings(
     31       base::WeakPtr<TextInputController> controller);
     32   virtual ~TextInputControllerBindings();
     33 
     34   // gin::Wrappable:
     35   virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
     36       v8::Isolate* isolate) OVERRIDE;
     37 
     38   void InsertText(const std::string& text);
     39   void UnmarkText();
     40   void DoCommand(const std::string& text);
     41   void SetMarkedText(const std::string& text, int start, int length);
     42   bool HasMarkedText();
     43   std::vector<int> MarkedRange();
     44   std::vector<int> SelectedRange();
     45   std::vector<int> FirstRectForCharacterRange(unsigned location,
     46                                               unsigned length);
     47   void SetComposition(const std::string& text);
     48 
     49   base::WeakPtr<TextInputController> controller_;
     50 
     51   DISALLOW_COPY_AND_ASSIGN(TextInputControllerBindings);
     52 };
     53 
     54 gin::WrapperInfo TextInputControllerBindings::kWrapperInfo = {
     55     gin::kEmbedderNativeGin};
     56 
     57 // static
     58 void TextInputControllerBindings::Install(
     59     base::WeakPtr<TextInputController> controller,
     60     blink::WebFrame* frame) {
     61   v8::Isolate* isolate = blink::mainThreadIsolate();
     62   v8::HandleScope handle_scope(isolate);
     63   v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
     64   if (context.IsEmpty())
     65     return;
     66 
     67   v8::Context::Scope context_scope(context);
     68 
     69   gin::Handle<TextInputControllerBindings> bindings =
     70       gin::CreateHandle(isolate, new TextInputControllerBindings(controller));
     71   if (bindings.IsEmpty())
     72     return;
     73   v8::Handle<v8::Object> global = context->Global();
     74   global->Set(gin::StringToV8(isolate, "textInputController"), bindings.ToV8());
     75 }
     76 
     77 TextInputControllerBindings::TextInputControllerBindings(
     78     base::WeakPtr<TextInputController> controller)
     79     : controller_(controller) {}
     80 
     81 TextInputControllerBindings::~TextInputControllerBindings() {}
     82 
     83 gin::ObjectTemplateBuilder
     84 TextInputControllerBindings::GetObjectTemplateBuilder(v8::Isolate* isolate) {
     85   return gin::Wrappable<TextInputControllerBindings>::GetObjectTemplateBuilder(
     86              isolate)
     87       .SetMethod("insertText", &TextInputControllerBindings::InsertText)
     88       .SetMethod("unmarkText", &TextInputControllerBindings::UnmarkText)
     89       .SetMethod("doCommand", &TextInputControllerBindings::DoCommand)
     90       .SetMethod("setMarkedText", &TextInputControllerBindings::SetMarkedText)
     91       .SetMethod("hasMarkedText", &TextInputControllerBindings::HasMarkedText)
     92       .SetMethod("markedRange", &TextInputControllerBindings::MarkedRange)
     93       .SetMethod("selectedRange", &TextInputControllerBindings::SelectedRange)
     94       .SetMethod("firstRectForCharacterRange",
     95                  &TextInputControllerBindings::FirstRectForCharacterRange)
     96       .SetMethod("setComposition",
     97                  &TextInputControllerBindings::SetComposition);
     98 }
     99 
    100 void TextInputControllerBindings::InsertText(const std::string& text) {
    101   if (controller_)
    102     controller_->InsertText(text);
    103 }
    104 
    105 void TextInputControllerBindings::UnmarkText() {
    106   if (controller_)
    107     controller_->UnmarkText();
    108 }
    109 
    110 void TextInputControllerBindings::DoCommand(const std::string& text) {
    111   if (controller_)
    112     controller_->DoCommand(text);
    113 }
    114 
    115 void TextInputControllerBindings::SetMarkedText(const std::string& text,
    116                                                 int start,
    117                                                 int length) {
    118   if (controller_)
    119     controller_->SetMarkedText(text, start, length);
    120 }
    121 
    122 bool TextInputControllerBindings::HasMarkedText() {
    123   return controller_ ? controller_->HasMarkedText() : false;
    124 }
    125 
    126 std::vector<int> TextInputControllerBindings::MarkedRange() {
    127   return controller_ ? controller_->MarkedRange() : std::vector<int>();
    128 }
    129 
    130 std::vector<int> TextInputControllerBindings::SelectedRange() {
    131   return controller_ ? controller_->SelectedRange() : std::vector<int>();
    132 }
    133 
    134 std::vector<int> TextInputControllerBindings::FirstRectForCharacterRange(
    135     unsigned location,
    136     unsigned length) {
    137   return controller_ ? controller_->FirstRectForCharacterRange(location, length)
    138                      : std::vector<int>();
    139 }
    140 
    141 void TextInputControllerBindings::SetComposition(const std::string& text) {
    142   if (controller_)
    143     controller_->SetComposition(text);
    144 }
    145 
    146 // TextInputController ---------------------------------------------------------
    147 
    148 TextInputController::TextInputController()
    149     : view_(NULL), weak_factory_(this) {}
    150 
    151 TextInputController::~TextInputController() {}
    152 
    153 void TextInputController::Install(blink::WebFrame* frame) {
    154   TextInputControllerBindings::Install(weak_factory_.GetWeakPtr(), frame);
    155 }
    156 
    157 void TextInputController::SetWebView(blink::WebView* view) {
    158   view_ = view;
    159 }
    160 
    161 void TextInputController::InsertText(const std::string& text) {
    162   view_->confirmComposition(blink::WebString::fromUTF8(text));
    163 }
    164 
    165 void TextInputController::UnmarkText() {
    166   view_->confirmComposition();
    167 }
    168 
    169 void TextInputController::DoCommand(const std::string& text) {
    170   if (view_->mainFrame())
    171     view_->mainFrame()->executeCommand(blink::WebString::fromUTF8(text));
    172 }
    173 
    174 void TextInputController::SetMarkedText(const std::string& text,
    175                                         int start,
    176                                         int length) {
    177   blink::WebString web_text(blink::WebString::fromUTF8(text));
    178 
    179   // Split underline into up to 3 elements (before, selection, and after).
    180   std::vector<blink::WebCompositionUnderline> underlines;
    181   blink::WebCompositionUnderline underline;
    182   if (!start) {
    183     underline.endOffset = length;
    184   } else {
    185     underline.endOffset = start;
    186     underlines.push_back(underline);
    187     underline.startOffset = start;
    188     underline.endOffset = start + length;
    189   }
    190   underline.thick = true;
    191   underlines.push_back(underline);
    192   if (start + length < static_cast<int>(web_text.length())) {
    193     underline.startOffset = underline.endOffset;
    194     underline.endOffset = web_text.length();
    195     underline.thick = false;
    196     underlines.push_back(underline);
    197   }
    198 
    199   view_->setComposition(web_text, underlines, start, start + length);
    200 }
    201 
    202 bool TextInputController::HasMarkedText() {
    203   return view_->mainFrame() && view_->mainFrame()->hasMarkedText();
    204 }
    205 
    206 std::vector<int> TextInputController::MarkedRange() {
    207   if (!view_->mainFrame())
    208     return std::vector<int>();
    209 
    210   blink::WebRange range = view_->mainFrame()->markedRange();
    211   std::vector<int> int_array(2);
    212   int_array[0] = range.startOffset();
    213   int_array[1] = range.endOffset();
    214 
    215   return int_array;
    216 }
    217 
    218 std::vector<int> TextInputController::SelectedRange() {
    219   if (!view_->mainFrame())
    220     return std::vector<int>();
    221 
    222   blink::WebRange range = view_->mainFrame()->selectionRange();
    223   std::vector<int> int_array(2);
    224   int_array[0] = range.startOffset();
    225   int_array[1] = range.endOffset();
    226 
    227   return int_array;
    228 }
    229 
    230 std::vector<int> TextInputController::FirstRectForCharacterRange(
    231     unsigned location,
    232     unsigned length) {
    233   blink::WebRect rect;
    234   if (!view_->focusedFrame() ||
    235       !view_->focusedFrame()->firstRectForCharacterRange(
    236           location, length, rect)) {
    237     return std::vector<int>();
    238   }
    239 
    240   std::vector<int> int_array(4);
    241   int_array[0] = rect.x;
    242   int_array[1] = rect.y;
    243   int_array[2] = rect.width;
    244   int_array[3] = rect.height;
    245 
    246   return int_array;
    247 }
    248 
    249 void TextInputController::SetComposition(const std::string& text) {
    250   // Sends a keydown event with key code = 0xE5 to emulate input method
    251   // behavior.
    252   blink::WebKeyboardEvent key_down;
    253   key_down.type = blink::WebInputEvent::RawKeyDown;
    254   key_down.modifiers = 0;
    255   key_down.windowsKeyCode = 0xE5;  // VKEY_PROCESSKEY
    256   key_down.setKeyIdentifierFromWindowsKeyCode();
    257   view_->handleInputEvent(key_down);
    258 
    259   blink::WebVector<blink::WebCompositionUnderline> underlines;
    260   blink::WebString web_text(blink::WebString::fromUTF8(text));
    261   view_->setComposition(web_text, underlines, 0, web_text.length());
    262 }
    263 
    264 }  // namespace content
    265