| Index: ui/base/ime/android/cursor_anchor_info_builder.cc | 
| diff --git a/ui/base/ime/android/cursor_anchor_info_builder.cc b/ui/base/ime/android/cursor_anchor_info_builder.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..6ece71e194787d838511cca704690c2b408365f7 | 
| --- /dev/null | 
| +++ b/ui/base/ime/android/cursor_anchor_info_builder.cc | 
| @@ -0,0 +1,157 @@ | 
| +// Copyright 2014 The Chromium Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +#include "ui/base/ime/android/cursor_anchor_info_builder.h" | 
| + | 
| +#include "base/android/jni_android.h" | 
| +#include "base/android/jni_string.h" | 
| +#include "base/android/jni_weak_ref.h" | 
| +#include "base/android/scoped_java_ref.h" | 
| +#include "base/containers/mru_cache.h" | 
| +#include "jni/CursorAnchorInfoBuilder_jni.h" | 
| + | 
| +namespace ui { | 
| +namespace { | 
| + | 
| +using base::android::AttachCurrentThread; | 
| + | 
| +const size_t kComposingTextCacheSize = 2; | 
| + | 
| +class CursorAnchorInfoBuilderImpl final | 
| +    : public CursorAnchorInfoBuilder { | 
| + public: | 
| +  CursorAnchorInfoBuilderImpl(); | 
| +  ~CursorAnchorInfoBuilderImpl() override; | 
| + | 
| +  void AddCharacterBounds(int index, | 
| +                          const gfx::RectF& rect, | 
| +                          uint32 flags) override; | 
| +  base::android::ScopedJavaLocalRef<jobject> Build() override; | 
| +  void Reset() override; | 
| +  void SetComposingText(int composingTextStart, | 
| +                        base::StringPiece16 composingText) override; | 
| +  void SetInsertionMarkerLocation(float horizontalPosition, | 
| +                                  float lineTop, | 
| +                                  float lineBaseline, | 
| +                                  float lineBottom, | 
| +                                  uint32 flags) override; | 
| +  void SetScaleAndTranslate(float scale, | 
| +                            const gfx::Vector2dF& translate) override; | 
| +  void SetSelectionRange(const gfx::Range& range) override; | 
| + | 
| +  static bool Register(JNIEnv* env); | 
| + | 
| + private: | 
| +  base::android::ScopedJavaGlobalRef<jobject> builder_; | 
| +  base::MRUCache<base::string16, base::android::ScopedJavaGlobalRef<jstring>> | 
| +      composing_text_cache_; | 
| + | 
| +  DISALLOW_COPY_AND_ASSIGN(CursorAnchorInfoBuilderImpl); | 
| +}; | 
| + | 
| +CursorAnchorInfoBuilderImpl::CursorAnchorInfoBuilderImpl() | 
| +    : builder_(Java_CursorAnchorInfoBuilder_create(AttachCurrentThread())), | 
| +      composing_text_cache_(kComposingTextCacheSize) { | 
| +} | 
| + | 
| +CursorAnchorInfoBuilderImpl::~CursorAnchorInfoBuilderImpl() { | 
| +} | 
| + | 
| +void CursorAnchorInfoBuilderImpl::AddCharacterBounds( | 
| +    int index, const gfx::RectF& rect, uint32 flags) { | 
| +  JNIEnv* env = AttachCurrentThread(); | 
| +  Java_CursorAnchorInfoBuilder_addCharacterBounds( | 
| +      env, | 
| +      builder_.obj(), | 
| +      index, | 
| +      rect.x(), | 
| +      rect.y(), | 
| +      rect.right(), | 
| +      rect.bottom(), | 
| +      flags); | 
| +} | 
| + | 
| +base::android::ScopedJavaLocalRef<jobject> | 
| +CursorAnchorInfoBuilderImpl::Build() { | 
| +  JNIEnv* env = AttachCurrentThread(); | 
| +  return Java_CursorAnchorInfoBuilder_build(env, builder_.obj()); | 
| +} | 
| + | 
| +void CursorAnchorInfoBuilderImpl::Reset() { | 
| +  JNIEnv* env = AttachCurrentThread(); | 
| +  Java_CursorAnchorInfoBuilder_reset(env, builder_.obj()); | 
| +} | 
| + | 
| +void CursorAnchorInfoBuilderImpl::SetComposingText( | 
| +    int composing_text_start, base::StringPiece16 composing_text) { | 
| +  JNIEnv* env = AttachCurrentThread(); | 
| +  const auto& key = composing_text.as_string(); | 
| +  auto it = composing_text_cache_.Get(key); | 
| +  if (it != composing_text_cache_.end()) { | 
| +    Java_CursorAnchorInfoBuilder_setComposingText( | 
| +        env, builder_.obj(), composing_text_start, it->second.obj()); | 
| +  } else { | 
| +    auto jstr = base::android::ConvertUTF16ToJavaString(env, composing_text); | 
| +    Java_CursorAnchorInfoBuilder_setComposingText( | 
| +        env, builder_.obj(), composing_text_start, jstr.obj()); | 
| +    composing_text_cache_.Put( | 
| +        key, base::android::ScopedJavaGlobalRef<jstring>(jstr)); | 
| +  } | 
| +} | 
| + | 
| +void CursorAnchorInfoBuilderImpl::SetInsertionMarkerLocation( | 
| +    float horizontalPosition, | 
| +    float lineTop, | 
| +    float lineBaseline, | 
| +    float lineBottom, | 
| +    uint32 flags) { | 
| +  JNIEnv* env = AttachCurrentThread(); | 
| +  Java_CursorAnchorInfoBuilder_setInsertionMarkerLocation( | 
| +      env, | 
| +      builder_.obj(), | 
| +      horizontalPosition, | 
| +      lineTop, | 
| +      lineBaseline, | 
| +      lineBottom, | 
| +      static_cast<jint>(flags)); | 
| +} | 
| + | 
| +void CursorAnchorInfoBuilderImpl::SetScaleAndTranslate( | 
| +    float scale, | 
| +    const gfx::Vector2dF& translate) { | 
| +  JNIEnv* env = AttachCurrentThread(); | 
| +  Java_CursorAnchorInfoBuilder_setScaleAndTranslate( | 
| +      env, | 
| +      builder_.obj(), | 
| +      scale, | 
| +      translate.x(), | 
| +      translate.y()); | 
| +} | 
| + | 
| +void CursorAnchorInfoBuilderImpl::SetSelectionRange(const gfx::Range& range) { | 
| +  JNIEnv* env = AttachCurrentThread(); | 
| +  Java_CursorAnchorInfoBuilder_setSelectionRange( | 
| +      env, builder_.obj(), range.start(), range.end()); | 
| +} | 
| + | 
| +}  // namespace | 
| + | 
| +CursorAnchorInfoBuilder::CursorAnchorInfoBuilder() { | 
| +} | 
| + | 
| +CursorAnchorInfoBuilder::~CursorAnchorInfoBuilder() { | 
| +} | 
| + | 
| +// static | 
| +scoped_ptr<CursorAnchorInfoBuilder> | 
| +CursorAnchorInfoBuilder::Create() { | 
| +  return scoped_ptr<CursorAnchorInfoBuilder>(new CursorAnchorInfoBuilderImpl); | 
| +} | 
| + | 
| +// static | 
| +bool CursorAnchorInfoBuilder::Register(JNIEnv* env) { | 
| +  return RegisterNativesImpl(env); | 
| +} | 
| + | 
| +}  // namespace ui | 
|  |