| Index: webkit/plugins/ppapi/ppapi_plugin_instance.cc
 | 
| diff --git a/webkit/plugins/ppapi/ppapi_plugin_instance.cc b/webkit/plugins/ppapi/ppapi_plugin_instance.cc
 | 
| index b18df2c3d8f05c7a8d126a400978df8bc4d22047..f25a6524014bf54348a1dfcb9c0511f5c79ed89a 100644
 | 
| --- a/webkit/plugins/ppapi/ppapi_plugin_instance.cc
 | 
| +++ b/webkit/plugins/ppapi/ppapi_plugin_instance.cc
 | 
| @@ -8,6 +8,7 @@
 | 
|  #include "base/memory/scoped_ptr.h"
 | 
|  #include "base/message_loop.h"
 | 
|  #include "base/metrics/histogram.h"
 | 
| +#include "base/utf_offset_string_conversions.h"
 | 
|  #include "base/utf_string_conversions.h"
 | 
|  #include "ppapi/c/dev/ppb_find_dev.h"
 | 
|  #include "ppapi/c/dev/ppb_fullscreen_dev.h"
 | 
| @@ -32,6 +33,7 @@
 | 
|  #include "ppapi/c/private/ppp_instance_private.h"
 | 
|  #include "ppapi/shared_impl/input_event_impl.h"
 | 
|  #include "ppapi/shared_impl/resource.h"
 | 
| +#include "ppapi/shared_impl/time_conversion.h"
 | 
|  #include "ppapi/shared_impl/var.h"
 | 
|  #include "ppapi/thunk/enter.h"
 | 
|  #include "ppapi/thunk/ppb_buffer_api.h"
 | 
| @@ -242,7 +244,11 @@ PluginInstance::PluginInstance(
 | 
|        sad_plugin_(NULL),
 | 
|        input_event_mask_(0),
 | 
|        filtered_input_event_mask_(0),
 | 
| +      text_input_type_(WebKit::WebTextInputTypeText),
 | 
| +      text_input_caret_set_(false),
 | 
|        lock_mouse_callback_(PP_BlockUntilComplete()) {
 | 
| +  memset(&text_input_caret_, 0, sizeof(text_input_caret_));
 | 
| +  memset(&text_input_caret_bounds_, 0, sizeof(text_input_caret_bounds_));
 | 
|    pp_instance_ = ResourceTracker::Get()->AddInstance(this);
 | 
|  
 | 
|    memset(¤t_print_settings_, 0, sizeof(current_print_settings_));
 | 
| @@ -445,6 +451,142 @@ bool PluginInstance::HandleDocumentLoad(PPB_URLLoader_Impl* loader) {
 | 
|        pp_instance(), loader->pp_resource()));
 | 
|  }
 | 
|  
 | 
| +bool PluginInstance::SendCompositionEventToPlugin(PP_InputEvent_Type type,
 | 
| +                                                  const string16& text) {
 | 
| +  std::vector<WebKit::WebCompositionUnderline> empty;
 | 
| +  return SendCompositionEventWithUnderlineInformationToPlugin(
 | 
| +      type, text, empty, static_cast<int>(text.size()),
 | 
| +      static_cast<int>(text.size()));
 | 
| +}
 | 
| +
 | 
| +bool PluginInstance::SendCompositionEventWithUnderlineInformationToPlugin(
 | 
| +    PP_InputEvent_Type type,
 | 
| +    const string16& text,
 | 
| +    const std::vector<WebKit::WebCompositionUnderline>& underlines,
 | 
| +    int selection_start,
 | 
| +    int selection_end) {
 | 
| +  // Keep a reference on the stack. See NOTE above.
 | 
| +  scoped_refptr<PluginInstance> ref(this);
 | 
| +
 | 
| +  if (!LoadInputEventInterface())
 | 
| +    return false;
 | 
| +
 | 
| +  PP_InputEvent_Class event_class = PP_INPUTEVENT_CLASS_IME;
 | 
| +  if (!(filtered_input_event_mask_ & event_class) &&
 | 
| +      !(input_event_mask_ & event_class))
 | 
| +    return false;
 | 
| +
 | 
| +  ::ppapi::InputEventData event;
 | 
| +  event.event_type = type;
 | 
| +  event.event_time_stamp = ::ppapi::TimeTicksToPPTimeTicks(
 | 
| +      base::TimeTicks::Now());
 | 
| +
 | 
| +  // Convert UTF16 text to UTF8 with offset conversion.
 | 
| +  std::vector<size_t> offsets;
 | 
| +  for (size_t i=0; i<underlines.size(); ++i) {
 | 
| +    offsets.push_back(underlines[i].startOffset);
 | 
| +    offsets.push_back(underlines[i].endOffset);
 | 
| +  }
 | 
| +  offsets.push_back(selection_start);
 | 
| +  offsets.push_back(selection_end);
 | 
| +  event.character_text = UTF16ToUTF8AndAdjustOffsets(text, &offsets);
 | 
| +
 | 
| +  size_t len = event.character_text.size();
 | 
| +  for (size_t i=0; i<underlines.size(); ++i) {
 | 
| +    // UTF16ToUTF8AndAdjustOffsets does not convert end-of-string offsets.
 | 
| +    size_t left = underlines[i].startOffset==text.size() ? len : offsets[2*i];
 | 
| +    size_t right = underlines[i].endOffset==text.size() ? len : offsets[2*i+1];
 | 
| +    if (left != string16::npos && right != string16::npos) {
 | 
| +      if (underlines[i].thick)
 | 
| +        event.composition_target_segment = event.composition_segments.size()/2;
 | 
| +      event.composition_segments.push_back(left);
 | 
| +      event.composition_segments.push_back(right);
 | 
| +    }
 | 
| +  }
 | 
| +  size_t left = selection_start==static_cast<int>(text.size()) ? len :
 | 
| +      offsets[offsets.size()-2];
 | 
| +  size_t right = selection_end==static_cast<int>(text.size()) ? len :
 | 
| +      offsets[offsets.size()-1];
 | 
| +  if (left != string16::npos && right != string16::npos) {
 | 
| +    event.composition_selection_start = left;
 | 
| +    event.composition_selection_end = right;
 | 
| +  } else {
 | 
| +    event.composition_selection_start = len;
 | 
| +    event.composition_selection_end = len;
 | 
| +  }
 | 
| +
 | 
| +  if (filtered_input_event_mask_ & event_class)
 | 
| +    event.is_filtered = true;
 | 
| +  scoped_refptr<InputEventImpl> event_resource(
 | 
| +      new InputEventImpl(InputEventImpl::InitAsImpl(),
 | 
| +                         pp_instance(), event));
 | 
| +
 | 
| +  return PP_ToBool(plugin_input_event_interface_->HandleInputEvent(
 | 
| +      pp_instance(), event_resource->pp_resource()));
 | 
| +}
 | 
| +
 | 
| +bool PluginInstance::HandleCompositionStart(const string16& text) {
 | 
| +  return SendCompositionEventToPlugin(PP_INPUTEVENT_TYPE_COMPOSITION_START,
 | 
| +                                      text);
 | 
| +}
 | 
| +
 | 
| +bool PluginInstance::HandleCompositionUpdate(
 | 
| +    const string16& text,
 | 
| +    const std::vector<WebKit::WebCompositionUnderline>& underlines,
 | 
| +    int selection_start,
 | 
| +    int selection_end) {
 | 
| +  return SendCompositionEventWithUnderlineInformationToPlugin(
 | 
| +      PP_INPUTEVENT_TYPE_COMPOSITION_UPDATE,
 | 
| +      text, underlines, selection_start, selection_end);
 | 
| +}
 | 
| +
 | 
| +bool PluginInstance::HandleCompositionEnd(const string16& text) {
 | 
| +  return SendCompositionEventToPlugin(PP_INPUTEVENT_TYPE_COMPOSITION_END,
 | 
| +                                      text);
 | 
| +}
 | 
| +
 | 
| +bool PluginInstance::HandleTextInput(const string16& text) {
 | 
| +  return SendCompositionEventToPlugin(PP_INPUTEVENT_TYPE_IME_TEXT,
 | 
| +                                      text);
 | 
| +}
 | 
| +
 | 
| +void PluginInstance::UpdateCaretPosition(const PP_Rect& caret,
 | 
| +                                         const PP_Rect& boundingBox) {
 | 
| +  text_input_caret_ = caret;
 | 
| +  text_input_caret_bounds_ = boundingBox;
 | 
| +  text_input_caret_set_ = true;
 | 
| +}
 | 
| +
 | 
| +void PluginInstance::SetTextInputType(WebKit::WebTextInputType type) {
 | 
| +  text_input_type_ = type;
 | 
| +}
 | 
| +
 | 
| +bool PluginInstance::CanComposeInline() const {
 | 
| +  return (filtered_input_event_mask_ & PP_INPUTEVENT_CLASS_IME) ||
 | 
| +      (input_event_mask_ & PP_INPUTEVENT_CLASS_IME);
 | 
| +}
 | 
| +
 | 
| +WebKit::WebRect PluginInstance::GetCaretBounds() const {
 | 
| +  if (!text_input_caret_set_) {
 | 
| +    // If it is never set by the plugin, use the bottom left corner.
 | 
| +    WebKit::WebRect caret(position().x(),
 | 
| +                          position().y(),
 | 
| +                          0,
 | 
| +                          position().height());
 | 
| +    return caret;
 | 
| +  }
 | 
| +
 | 
| +  // TODO(kinaba) take bounds into account
 | 
| +  // TODO(kinaba) take CSS transformation into accont
 | 
| +  WebKit::WebRect caret(text_input_caret_.point.x,
 | 
| +                        text_input_caret_.point.y,
 | 
| +                        text_input_caret_.size.width,
 | 
| +                        text_input_caret_.size.height);
 | 
| +  caret.x += position().x();
 | 
| +  caret.y += position().y();
 | 
| +  return caret;
 | 
| +}
 | 
| +
 | 
|  bool PluginInstance::HandleInputEvent(const WebKit::WebInputEvent& event,
 | 
|                                        WebCursorInfo* cursor_info) {
 | 
|    // Keep a reference on the stack. See NOTE above.
 | 
| @@ -542,7 +684,7 @@ void PluginInstance::SetWebKitFocus(bool has_focus) {
 | 
|    bool old_plugin_focus = PluginHasFocus();
 | 
|    has_webkit_focus_ = has_focus;
 | 
|    if (PluginHasFocus() != old_plugin_focus) {
 | 
| -    delegate()->PluginFocusChanged(PluginHasFocus());
 | 
| +    delegate()->PluginFocusChanged(this, PluginHasFocus());
 | 
|      instance_interface_->DidChangeFocus(pp_instance(),
 | 
|                                          PP_FromBool(PluginHasFocus()));
 | 
|    }
 | 
| 
 |