[M108 Migration][Text Selection] Selection handles & Caret Selection
[platform/framework/web/chromium-efl.git] / tizen_src / chromium_impl / content / browser / renderer_host / rwhv_aura_offscreen_helper_efl.cc
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.
4
5 #include "content/browser/renderer_host/rwhv_aura_offscreen_helper_efl.h"
6
7 #include <Ecore_Evas.h>
8 #include <Elementary.h>
9
10 #include "base/base_switches.h"
11 #include "content/browser/renderer_host/render_widget_host_view_aura.h"
12 #include "content/browser/web_contents/web_contents_impl.h"
13 #include "content/browser/web_contents/web_contents_view_aura.h"
14 #include "content/public/browser/render_widget_host_helper.h"
15 #include "content/public/browser/web_contents_delegate.h"
16 #include "gpu/command_buffer/service/texture_base.h"
17 #include "skia/ext/image_operations.h"
18 #include "tizen/system_info.h"
19 #include "ui/aura/client/focus_client.h"
20 #include "ui/aura/window.h"
21 #include "ui/aura/window_tree_host_platform.h"
22 #include "ui/base/clipboard/clipboard_helper_efl.h"
23 #include "ui/display/screen.h"
24 #include "ui/events/gestures/gesture_types.h"
25 #include "ui/gfx/geometry/dip_util.h"
26 #include "ui/gfx/skbitmap_operations.h"
27 #include "ui/gl/gl_share_group.h"
28 #include "ui/gl/gl_shared_context_efl.h"
29 #include "ui/ozone/platform/efl/efl_event_handler.h"
30 #include "ui/ozone/platform/efl/im_context_efl.h"
31 #include "ui/platform_window/platform_window.h"
32
33 #define MAX_SURFACE_WIDTH_EGL 4096   // max supported Framebuffer width
34 #define MAX_SURFACE_HEIGHT_EGL 4096  // max supported Framebuffer height
35
36 // These two constants are redefinitions of the original constants defined
37 // in evas_common.c. These are not supposed to be used directly by apps,
38 // but we do this because of chromium uses fbo for direct rendering.
39 #define EVAS_GL_OPTIONS_DIRECT_MEMORY_OPTIMIZE (1 << 12)
40 #define EVAS_GL_OPTIONS_DIRECT_OVERRIDE (1 << 13)
41
42 namespace content {
43
44 // If the first frame is not prepared after load is finished,
45 // delay getting the snapshot by 100ms.
46 static const int kSnapshotProcessDelay = 100;
47
48 class ScreenshotCapturedCallback {
49  public:
50   ScreenshotCapturedCallback(Screenshot_Captured_Callback func, void* user_data)
51       : func_(func), user_data_(user_data) {}
52   void Run(Evas_Object* image) {
53     if (func_ != NULL)
54       (func_)(image, user_data_);
55   }
56
57  private:
58   Screenshot_Captured_Callback func_;
59   void* user_data_;
60 };
61
62 class RenderWidgetHostHelperAura : public RenderWidgetHostHelper {
63  public:
64   explicit RenderWidgetHostHelperAura(RWHVAuraOffscreenHelperEfl* rwhv_helper)
65       : rwhv_helper_(rwhv_helper) {}
66   ~RenderWidgetHostHelperAura() override = default;
67
68   bool HasRenderWidgetHost() const override {
69     return !!rwhv_helper_->GetRenderWidgetHostImpl();
70   }
71
72   void ExtendSelectionAndDelete(int32_t before, int32_t after) override {
73     auto* handler = GetFrameWidgetInputHandler();
74     if (!handler)
75       return;
76
77     handler->ExtendSelectionAndDelete(before, after);
78   }
79
80   void SetCompositionFromExistingText(
81       int32_t start,
82       int32_t end,
83       const std::vector<ui::ImeTextSpan>& ime_text_spans) override {
84     auto* handler = GetFrameWidgetInputHandler();
85     if (!handler)
86       return;
87
88     handler->SetCompositionFromExistingText(start, end, ime_text_spans);
89   }
90
91   void ImeCommitText(const std::u16string& text,
92                      const std::vector<ui::ImeTextSpan>& ime_text_spans,
93                      const gfx::Range& replacement_range,
94                      int relative_cursor_pos) override {
95     auto* rwhi = rwhv_helper_->GetRenderWidgetHostImpl();
96     if (!rwhi)
97       return;
98
99     rwhi->ImeCommitText(text, ime_text_spans, replacement_range,
100                         relative_cursor_pos);
101   }
102
103   void ImeFinishComposingText(bool keep_selection) override {
104     auto* rwhi = rwhv_helper_->GetRenderWidgetHostImpl();
105     if (!rwhi)
106       return;
107
108     rwhi->ImeFinishComposingText(keep_selection);
109   }
110
111   void ImeSetComposition(const std::u16string& text,
112                          const std::vector<ui::ImeTextSpan>& ime_text_spans,
113                          const gfx::Range& replacement_range,
114                          int selection_start,
115                          int selection_end) override {
116     auto* rwhi = rwhv_helper_->GetRenderWidgetHostImpl();
117     if (!rwhi)
118       return;
119
120     rwhi->ImeSetComposition(text, ime_text_spans, replacement_range,
121                             selection_start, selection_end);
122   }
123
124   bool ExistsSelectedText() override { return false; }
125
126   bool ImeHandleKeyEventEnabled() override { return true; }
127
128   gfx::Size GetPhysicalBackingSize() const override {
129     return rwhv_helper_->GetPhysicalBackingSize();
130   }
131
132   Evas_Object* EwkView() const override { return rwhv_helper_->ewk_view(); }
133
134  private:
135   blink::mojom::FrameWidgetInputHandler* GetFrameWidgetInputHandler() const {
136     auto* rwhi = rwhv_helper_->GetRenderWidgetHostImpl();
137     if (!rwhi)
138       return nullptr;
139
140     return rwhi->GetFrameWidgetInputHandler();
141   }
142
143   RWHVAuraOffscreenHelperEfl* rwhv_helper_;
144 };
145
146 RWHVAuraOffscreenHelperEfl::RWHVAuraOffscreenHelperEfl(
147     RenderWidgetHostViewAura* rwhva,
148     WebContents* web_contents)
149     : rwhv_aura_(rwhva),
150       web_contents_(web_contents),
151       rwh_helper_(std::make_unique<RenderWidgetHostHelperAura>(this)) {
152   Initialize();
153 }
154
155 RWHVAuraOffscreenHelperEfl::~RWHVAuraOffscreenHelperEfl() {
156   if (evas_gl_surface_) {
157     if (!MakeCurrent())
158       LOG(WARNING) << "Failed to bind gl context";
159     evas_object_image_native_surface_set(content_image_, nullptr);
160     evas_gl_surface_destroy(evas_gl_, evas_gl_surface_);
161   }
162
163   if (!ClearCurrent())
164     LOG(WARNING) << "Failed to unbind gl context";
165
166   if (evas_gl_context_)
167     evas_gl_context_destroy(evas_gl_, evas_gl_context_);
168   if (evas_gl_config_)
169     evas_gl_config_free(evas_gl_config_);
170   if (evas_gl_)
171     evas_gl_free(evas_gl_);
172
173   elm_object_part_content_unset(content_image_elm_host_, "overlay");
174   evas_object_event_callback_del(content_image_, EVAS_CALLBACK_FOCUS_IN,
175                                  OnFocusIn);
176   evas_object_event_callback_del(content_image_, EVAS_CALLBACK_FOCUS_OUT,
177                                  OnFocusOut);
178   evas_event_callback_del_full(evas_, EVAS_CALLBACK_RENDER_FLUSH_PRE,
179                                OnEvasRenderFlushPre, this);
180   evas_object_del(content_image_elm_host_);
181   evas_object_del(content_image_);
182
183   content_image_elm_host_ = nullptr;
184   content_image_ = nullptr;
185   parent_view_ = nullptr;
186 }
187
188 void RWHVAuraOffscreenHelperEfl::Initialize() {
189   parent_view_ =
190       static_cast<WebContentsImpl*>(web_contents_)->GetEflNativeView();
191   evas_ = evas_object_evas_get(parent_view_);
192
193   InitEvasGL();
194   InitializeProgram();
195   evas_object_event_callback_add(parent_view_, EVAS_CALLBACK_RESIZE,
196                                  OnParentViewResize, this);
197   evas_object_show(content_image_);
198
199   device_scale_factor_ =
200       display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor();
201
202   snapshot_timer_.reset(new base::OneShotTimer);
203 }
204
205 void RWHVAuraOffscreenHelperEfl::SetAuraParentWindow(
206     gfx::NativeView parent_window) {
207   aura_parent_window_ = parent_window;
208 }
209
210 void RWHVAuraOffscreenHelperEfl::AuraChildWindowAdded() {
211   aura::WindowTreeHost* window_host = rwhv_aura_->window()->GetHost();
212   if (!window_host)
213     return;
214
215   static_cast<aura::WindowTreeHostPlatform*>(window_host)
216       ->platform_window()
217       ->SetNativeViewOffscreen(content_image_);
218
219   // Add FOCUS_{IN,OUT} callbacks only after child aura window is created.
220   evas_object_event_callback_add(content_image_, EVAS_CALLBACK_FOCUS_IN,
221                                  OnFocusIn, this);
222   evas_object_event_callback_add(content_image_, EVAS_CALLBACK_FOCUS_OUT,
223                                  OnFocusOut, this);
224 }
225
226 // static
227 void RWHVAuraOffscreenHelperEfl::OnParentViewResize(void* data,
228                                                     Evas*,
229                                                     Evas_Object* obj,
230                                                     void*) {
231   RWHVAuraOffscreenHelperEfl* thiz =
232       static_cast<RWHVAuraOffscreenHelperEfl*>(data);
233   gfx::Rect new_bounds(thiz->CreateNativeSurface());
234   aura::WindowTreeHost* window_host = thiz->rwhv_aura_->window()->GetHost();
235   if (window_host)
236     window_host->SetBoundsInPixels(new_bounds);
237
238   aura::Window* parent_window = thiz->aura_parent_window_;
239   if (parent_window)
240     parent_window->SetBounds(new_bounds);
241 }
242
243 bool RWHVAuraOffscreenHelperEfl::ClearCurrent() {
244   return evas_gl_make_current(evas_gl_, 0, 0);
245 }
246
247 bool RWHVAuraOffscreenHelperEfl::MakeCurrent() {
248   return evas_gl_make_current(evas_gl_, evas_gl_surface_, evas_gl_context_);
249 }
250
251 void RWHVAuraOffscreenHelperEfl::ClearBrowserFrame() {
252   DCHECK(evas_gl_api_);
253   evas_gl_api_->glClearColor(1.0, 1.0, 1.0, 1.0);
254   evas_gl_api_->glClear(GL_COLOR_BUFFER_BIT);
255 }
256
257 static const char kVertexShaderSourceSimple[] =
258     "attribute vec4 a_position;                                        \n"
259     "attribute vec2 a_texCoord;                                        \n"
260     "varying vec2 v_texCoord;                                          \n"
261     "uniform vec2 u_rotation;                                          \n"
262     "void main() {                                                     \n"
263     "  gl_Position = vec4(                                             \n"
264     "    (a_position.x * u_rotation.y + a_position.y * u_rotation.x),  \n"
265     "    (a_position.y * u_rotation.y - a_position.x * u_rotation.x),  \n"
266     "     0, 1);                                                       \n"
267     "  v_texCoord = a_texCoord;                                        \n"
268     "}                                                                 \n";
269
270 static const char kFragmentShaderSourceSimple[] =
271     "precision mediump float;                            \n"
272     "varying vec2 v_texCoord;                            \n"
273     "uniform sampler2D s_texture;                        \n"
274     "void main() {                                       \n"
275     "  gl_FragColor = texture2D( s_texture, v_texCoord );\n"
276     "}                                                   \n";
277
278 static void GLCheckProgramHelper(Evas_GL_API* api,
279                                  GLuint program,
280                                  const char* file,
281                                  int line) {
282   GLint status;
283   api->glGetProgramiv(program, GL_LINK_STATUS, &status);
284   if (status)
285     return;
286
287   const GLsizei buf_length = 2048;
288   std::unique_ptr<GLchar[]> log(new GLchar[buf_length]);
289   GLsizei length = 0;
290   api->glGetProgramInfoLog(program, buf_length, &length, log.get());
291   LOG(ERROR) << "GL program link failed in: " << file << ":" << line << ":"
292              << log.get();
293   api->glDeleteProgram(program);
294 }
295
296 #define GLCheckProgram(api, program) \
297   GLCheckProgramHelper(api, program, __FILE__, __LINE__)
298
299 static void GLCheckShaderHelper(Evas_GL_API* api,
300                                 GLuint shader,
301                                 const char* file,
302                                 int line) {
303   GLint status;
304   api->glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
305   if (status)
306     return;
307
308   const GLsizei buf_length = 2048;
309   std::unique_ptr<GLchar[]> log(new GLchar[buf_length]);
310   GLsizei length = 0;
311   api->glGetShaderInfoLog(shader, buf_length, &length, log.get());
312   LOG(ERROR) << "GL shader compile failed in " << file << ":" << line << ":"
313              << log.get();
314   api->glDeleteShader(shader);
315 }
316
317 #define GLCheckShader(api, shader) \
318   GLCheckShaderHelper((api), (shader), __FILE__, __LINE__)
319
320 void RWHVAuraOffscreenHelperEfl::InitializeProgram() {
321   evas_gl_make_current(evas_gl_, evas_gl_surface_, evas_gl_context_);
322
323   //  GL_CHECK_STATUS("GL Error before program initialization");
324
325   const char* vertexShaderSourceProgram = kVertexShaderSourceSimple;
326   const char* fragmentShaderSourceProgram = kFragmentShaderSourceSimple;
327   GLuint vertexShader = evas_gl_api_->glCreateShader(GL_VERTEX_SHADER);
328   // GL_CHECK_STATUS("vertex shader");
329   GLuint fragmentShader = evas_gl_api_->glCreateShader(GL_FRAGMENT_SHADER);
330   // GL_CHECK_STATUS("fragment shader");
331
332   const GLfloat vertex_attributes[] = {
333       -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f,  0.0f, 1.0f, 1.0f,
334       1.0f,  1.0f,  0.0f, 0.0f, 1.0f, 1.0f,  -1.0f, 0.0f, 0.0f, 0.0f};
335
336   evas_gl_api_->glGenBuffers(1, &vertex_buffer_obj_);
337   evas_gl_api_->glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_obj_);
338   evas_gl_api_->glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_attributes),
339                              vertex_attributes, GL_STATIC_DRAW);
340
341   const GLushort index_attributes[] = {0, 1, 2, 0, 2, 3};
342   evas_gl_api_->glGenBuffers(1, &index_buffer_obj_);
343   evas_gl_api_->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_obj_);
344   evas_gl_api_->glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(index_attributes),
345                              index_attributes, GL_STATIC_DRAW);
346
347   evas_gl_api_->glShaderSource(vertexShader, 1, &vertexShaderSourceProgram, 0);
348   evas_gl_api_->glShaderSource(fragmentShader, 1, &fragmentShaderSourceProgram,
349                                0);
350   program_id_ = evas_gl_api_->glCreateProgram();
351   evas_gl_api_->glCompileShader(vertexShader);
352   GLCheckShader(evas_gl_api_, vertexShader);
353   evas_gl_api_->glCompileShader(fragmentShader);
354   GLCheckShader(evas_gl_api_, fragmentShader);
355   evas_gl_api_->glAttachShader(program_id_, vertexShader);
356   evas_gl_api_->glAttachShader(program_id_, fragmentShader);
357   evas_gl_api_->glLinkProgram(program_id_);
358   GLCheckProgram(evas_gl_api_, program_id_);
359   evas_gl_api_->glDetachShader(program_id_, vertexShader);
360   evas_gl_api_->glDetachShader(program_id_, fragmentShader);
361   evas_gl_api_->glDeleteShader(vertexShader);
362   evas_gl_api_->glDeleteShader(fragmentShader);
363
364   position_attrib_ =
365       evas_gl_api_->glGetAttribLocation(program_id_, "a_position");
366   texcoord_attrib_ =
367       evas_gl_api_->glGetAttribLocation(program_id_, "a_texCoord");
368   source_texture_location_ =
369       evas_gl_api_->glGetUniformLocation(program_id_, "s_texture");
370   rotate_position_attrib_ =
371       evas_gl_api_->glGetUniformLocation(program_id_, "u_rotation");
372   evas_gl_make_current(evas_gl_, 0, 0);
373 }
374
375 void RWHVAuraOffscreenHelperEfl::PaintTextureToSurface(GLuint texture_id) {
376   int x, y, width = 0, height = 0;
377   evas_object_geometry_get(parent_view_, &x, &y, &width, &height);
378
379   evas_gl_make_current(evas_gl_, evas_gl_surface_, evas_gl_context_);
380   evas_gl_api_->glViewport(0, 0, width, height);
381   evas_gl_api_->glClearColor(1.0, 1.0, 1.0, 1.0);
382   evas_gl_api_->glClear(GL_COLOR_BUFFER_BIT);
383   evas_gl_api_->glUseProgram(program_id_);
384
385   evas_gl_api_->glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_obj_);
386
387   evas_gl_api_->glEnableVertexAttribArray(position_attrib_);
388   // Below 5 * sizeof(GLfloat) value specifies the size of a vertex
389   // attribute (x, y, z, u, v).
390   evas_gl_api_->glVertexAttribPointer(position_attrib_, 3, GL_FLOAT, GL_FALSE,
391                                       5 * sizeof(GLfloat), NULL);
392   evas_gl_api_->glEnableVertexAttribArray(texcoord_attrib_);
393   // Below 3 * sizeof(GLfloat) value specifies the location of texture
394   // coordinate in the vertex.
395   evas_gl_api_->glVertexAttribPointer(texcoord_attrib_, 2, GL_FLOAT, GL_FALSE,
396                                       5 * sizeof(GLfloat),
397                                       (void*)(3 * sizeof(GLfloat)));
398   evas_gl_api_->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_obj_);
399
400   evas_gl_api_->glActiveTexture(GL_TEXTURE0);
401   evas_gl_api_->glBindTexture(GL_TEXTURE_2D, texture_id);
402   evas_gl_api_->glUniform1i(source_texture_location_, 0);
403   if (rotation_ == 0) {
404     evas_gl_api_->glUniform2f(rotate_position_attrib_, 0, -1);
405   } else if (rotation_ == 90) {
406     evas_gl_api_->glUniform2f(rotate_position_attrib_, 1, 0);
407   } else if (rotation_ == 180) {
408     evas_gl_api_->glUniform2f(rotate_position_attrib_, 0, 1);
409   } else if (rotation_ == 270) {
410     evas_gl_api_->glUniform2f(rotate_position_attrib_, -1, 0);
411   }
412   evas_gl_api_->glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL);
413
414   evas_gl_api_->glBindTexture(GL_TEXTURE_2D, 0);
415   evas_gl_make_current(evas_gl_, 0, 0);
416
417   // for snapshot
418   frame_rendered_ = true;
419 }
420
421 void RWHVAuraOffscreenHelperEfl::InitEvasGL() {
422   evas_gl_config_ = evas_gl_config_new();
423   evas_gl_config_->options_bits =
424       (Evas_GL_Options_Bits)(EVAS_GL_OPTIONS_DIRECT |
425                              EVAS_GL_OPTIONS_DIRECT_MEMORY_OPTIMIZE |
426                              EVAS_GL_OPTIONS_DIRECT_OVERRIDE |
427                              EVAS_GL_OPTIONS_CLIENT_SIDE_ROTATION);
428   evas_gl_config_->color_format = EVAS_GL_RGBA_8888;
429   evas_gl_config_->depth_bits = EVAS_GL_DEPTH_BIT_24;
430   evas_gl_config_->stencil_bits = EVAS_GL_STENCIL_BIT_8;
431
432   evas_gl_ = evas_gl_new(evas_);
433
434   Evas_GL_Context_Version context_version = EVAS_GL_GLES_2_X;
435   if (GLSharedContextEfl::GetShareGroup()->GetUseGLES3())
436     context_version = EVAS_GL_GLES_3_X;
437
438   evas_gl_context_ = evas_gl_context_version_create(
439       evas_gl_, GLSharedContextEfl::GetEvasGLContext(), context_version);
440
441   if (!evas_gl_context_)
442     LOG(FATAL) << "Failed to create evas gl context";
443
444   evas_gl_api_ = evas_gl_context_api_get(evas_gl_, evas_gl_context_);
445
446   CreateNativeSurface();
447
448   MakeCurrent();
449 }
450
451 gfx::Size RWHVAuraOffscreenHelperEfl::CreateNativeSurface() {
452   int x, y, width = 0, height = 0;
453   evas_object_geometry_get(parent_view_, &x, &y, &width, &height);
454   if (width == 0 || height == 0)
455     width = height = 1;
456   if (width > MAX_SURFACE_WIDTH_EGL)
457     width = MAX_SURFACE_WIDTH_EGL;
458   if (height > MAX_SURFACE_HEIGHT_EGL)
459     height = MAX_SURFACE_HEIGHT_EGL;
460
461   if (!content_image_) {
462     content_image_ = evas_object_image_filled_add(evas_);
463
464     // elm host for focus handling
465     content_image_elm_host_ = elm_bg_add(parent_view_);
466     elm_object_part_content_set(parent_view_, "content",
467                                 content_image_elm_host_);
468     elm_object_part_content_set(content_image_elm_host_, "overlay",
469                                 content_image_);
470     elm_object_focus_allow_set(content_image_elm_host_, EINA_TRUE);
471     evas_object_smart_callback_add(content_image_elm_host_, "focused",
472                                    OnHostFocusIn, this);
473     evas_object_smart_callback_add(content_image_elm_host_, "unfocused",
474                                    OnHostFocusOut, this);
475     evas_object_show(content_image_elm_host_);
476   }
477
478   evas_object_image_size_set(content_image_, width, height);
479   evas_object_geometry_set(content_image_, x, y, width, height);
480   evas_object_geometry_set(content_image_elm_host_, x, y, width, height);
481
482   if (evas_gl_surface_) {
483     evas_object_image_native_surface_set(content_image_, NULL);
484     evas_gl_surface_destroy(evas_gl_, evas_gl_surface_);
485     ClearCurrent();
486   }
487
488   evas_gl_surface_ =
489       evas_gl_surface_create(evas_gl_, evas_gl_config_, width, height);
490   if (!evas_gl_surface_)
491     LOG(FATAL) << "Failed to create evas gl surface";
492
493   Evas_Native_Surface nativeSurface;
494   if (evas_gl_native_surface_get(evas_gl_, evas_gl_surface_, &nativeSurface)) {
495     evas_object_image_native_surface_set(content_image_, &nativeSurface);
496     evas_object_image_pixels_get_callback_set(
497         content_image_, EvasObjectImagePixelsGetCallback, this);
498     evas_object_image_pixels_dirty_set(content_image_, true);
499   } else {
500     LOG(FATAL) << "Failed to get native surface";
501   }
502
503   return gfx::Size(width, height);
504 }
505
506 // static
507 void RWHVAuraOffscreenHelperEfl::EvasObjectImagePixelsGetCallback(
508     void* data,
509     Evas_Object* obj) {
510   RWHVAuraOffscreenHelperEfl* rwhv_helper =
511       reinterpret_cast<RWHVAuraOffscreenHelperEfl*>(data);
512   rwhv_helper->MakeCurrent();
513   rwhv_helper->ClearBrowserFrame();
514   rwhv_helper->ClearCurrent();
515   if (rwhv_helper->texture_id_)
516     rwhv_helper->PaintTextureToSurface(rwhv_helper->texture_id_);
517 }
518
519 void RWHVAuraOffscreenHelperEfl::NotifySwap(const uint32_t texture_id) {
520   if (texture_id <= 0) {
521     LOG(ERROR) << __FUNCTION__ << " invalid texture id ";
522     return;
523   }
524   texture_id_ = texture_id;
525   evas_object_image_pixels_dirty_set(content_image_, true);
526 }
527
528 void RWHVAuraOffscreenHelperEfl::Focus(bool focus) {
529   elm_object_focus_set(content_image_elm_host_, focus);
530   evas_object_focus_set(content_image_, focus);
531 }
532
533 bool RWHVAuraOffscreenHelperEfl::HasFocus() {
534   return evas_object_focus_get(content_image_);
535 }
536
537 void RWHVAuraOffscreenHelperEfl::SetFocusInOutCallbacks(
538     const OnFocusCallback& on_focus_in,
539     const OnFocusCallback& on_focus_out) {
540   on_focus_in_callback_ = on_focus_in;
541   on_focus_out_callback_ = on_focus_out;
542 }
543
544 void RWHVAuraOffscreenHelperEfl::OnFocusIn(void* data,
545                                            Evas* evas,
546                                            Evas_Object* obj,
547                                            void* event_info) {
548   RWHVAuraOffscreenHelperEfl* thiz =
549       static_cast<RWHVAuraOffscreenHelperEfl*>(data);
550   thiz->FocusRWHVA();
551
552   if (IsMobileProfile() && thiz->GetSelectionController()) {
553     thiz->GetSelectionController()->ShowHandleAndContextMenuIfRequired();
554   }
555
556   if (!thiz->on_focus_in_callback_.is_null())
557     thiz->on_focus_in_callback_.Run();
558 }
559
560 void RWHVAuraOffscreenHelperEfl::OnFocusOut(void* data,
561                                             Evas* evas,
562                                             Evas_Object* obj,
563                                             void* event_info) {
564   RWHVAuraOffscreenHelperEfl* thiz =
565       static_cast<RWHVAuraOffscreenHelperEfl*>(data);
566   aura::WindowTreeHost* window_host = thiz->rwhv_aura_->window()->GetHost();
567   if (!window_host || !window_host->window())
568     return;
569
570   aura::Window* focused_window =
571       aura::client::GetFocusClient(window_host->window())->GetFocusedWindow();
572   if (focused_window)
573     focused_window->LostFocus();
574
575   if (IsMobileProfile() && thiz->GetSelectionController()) {
576     thiz->GetSelectionController()->HideHandleAndContextMenu();
577   }
578
579   if (!thiz->on_focus_out_callback_.is_null())
580     thiz->on_focus_out_callback_.Run();
581 }
582
583 void RWHVAuraOffscreenHelperEfl::OnHostFocusIn(void* data,
584                                                Evas_Object*,
585                                                void*) {
586   RWHVAuraOffscreenHelperEfl* thiz =
587       static_cast<RWHVAuraOffscreenHelperEfl*>(data);
588   thiz->Focus(true);
589 }
590
591 void RWHVAuraOffscreenHelperEfl::OnHostFocusOut(void* data,
592                                                 Evas_Object*,
593                                                 void*) {
594   RWHVAuraOffscreenHelperEfl* thiz =
595       static_cast<RWHVAuraOffscreenHelperEfl*>(data);
596   thiz->GetRenderWidgetHostImpl()->Blur();
597 }
598
599 void RWHVAuraOffscreenHelperEfl::OnMouseOrTouchEvent(ui::Event* event) {
600   if (event->type() == ui::ET_MOUSE_PRESSED ||
601       event->type() == ui::ET_TOUCH_PRESSED) {
602     FocusRWHVA();
603   }
604 }
605
606 void RWHVAuraOffscreenHelperEfl::DidHandleKeyEvent(
607     blink::WebInputEvent::Type input_event_type,
608     bool processed) {
609   if (!GetIMContextEfl())
610     return;
611
612   bool is_keydown = false;
613   switch (input_event_type) {
614     case blink::WebInputEvent::Type::kRawKeyDown:
615     case blink::WebInputEvent::Type::kKeyDown:
616       is_keydown = true;
617     case blink::WebInputEvent::Type::kKeyUp:
618       GetIMContextEfl()->HandleKeyEvent(is_keydown, processed);
619   }
620 }
621
622 void RWHVAuraOffscreenHelperEfl::SelectionChanged(const std::u16string& text,
623                                                   size_t offset,
624                                                   const gfx::Range& range) {
625   if (range.start() == range.end() && GetIMContextEfl())
626     GetIMContextEfl()->SetCaretPosition(range.start());
627
628   if (!GetSelectionController())
629     return;
630
631   std::u16string selectedText;
632   if (!text.empty() && !range.is_empty())
633     selectedText = rwhv_aura_->GetSelectedText();
634   GetSelectionController()->UpdateSelectionData(selectedText);
635 }
636
637 void RWHVAuraOffscreenHelperEfl::EvasToBlinkCords(int x,
638                                                   int y,
639                                                   int* view_x,
640                                                   int* view_y) {
641   gfx::Rect view_bounds = GetViewBoundsInPix();
642   if (view_x) {
643     *view_x = x - view_bounds.x();
644     *view_x /= device_scale_factor_;
645   }
646   if (view_y) {
647     *view_y = y - view_bounds.y();
648     *view_y /= device_scale_factor_;
649   }
650 }
651
652 void RWHVAuraOffscreenHelperEfl::OnEvasRenderFlushPre(void* data,
653                                                       Evas* evas,
654                                                       void* event_info) {
655   RWHVAuraOffscreenHelperEfl* rwhv_helper =
656       static_cast<RWHVAuraOffscreenHelperEfl*>(data);
657   if (rwhv_helper && rwhv_helper->snapshot_task_list_.size() > 0)
658     rwhv_helper->ProcessSnapshotRequest();
659 }
660
661 void RWHVAuraOffscreenHelperEfl::InvalidateForSnapshot() {
662   evas_object_image_pixels_dirty_set(content_image_, true);
663 }
664
665 void RWHVAuraOffscreenHelperEfl::ProcessSnapshotRequest() {
666   if (!frame_rendered_)
667     return;
668
669   // Process all snapshot requests pending now.
670   for (auto& task : snapshot_task_list_) {
671     if (!task.is_null())
672       std::move(task).Run();
673   }
674
675   if (snapshot_timer_->IsRunning())
676     snapshot_timer_->Stop();
677   // Stop now and clear task list
678   snapshot_task_list_.clear();
679   // Unregister render post event
680   evas_event_callback_del_full(evas_, EVAS_CALLBACK_RENDER_FLUSH_PRE,
681                                OnEvasRenderFlushPre, this);
682 }
683
684 void RWHVAuraOffscreenHelperEfl::RunGetSnapshotOnMainThread(
685     const gfx::Rect snapshot_area,
686     int request_id,
687     float scale_factor) {
688 #if defined(USE_TTRACE)
689   TTRACE(TTRACE_TAG_WEB,
690          "RWHVAuraOffscreenHelperEfl::RunGetSnapshotOnMainThread");
691 #endif
692   ScreenshotCapturedCallback* callback =
693       screen_capture_cb_map_.Lookup(request_id);
694
695   if (!callback)
696     return;
697
698   if (rwhv_aura_->IsShowing() && evas_focus_get(evas_))
699     callback->Run(GetSnapshot(snapshot_area, scale_factor));
700   screen_capture_cb_map_.Remove(request_id);
701 }
702
703 Evas_Object* RWHVAuraOffscreenHelperEfl::GetSnapshot(
704     const gfx::Rect& snapshot_area,
705     float scale_factor,
706     bool is_magnifier) {
707 #if defined(USE_TTRACE)
708   TTRACE(TTRACE_TAG_WEB, "RWHVAuraOffscreenHelperEfl::GetSnapshot");
709 #endif
710   if (scale_factor == 0.0)
711     return nullptr;
712
713   int rotation =
714       display::Screen::GetScreen()->GetPrimaryDisplay().RotationAsDegree();
715
716   bool is_evasgl_direct_landscape = false;
717   // For EvasGL Direct Rendering in landscape mode
718   if (!is_magnifier) {
719     is_evasgl_direct_landscape = ((rotation == 90 || rotation == 270) &&
720                                   !evas_gl_rotation_get(evas_gl_));
721   }
722
723   const gfx::Rect window_rect = gfx::ToEnclosingRect(gfx::ConvertRectToPixels(
724       rwhv_aura_->GetBoundsInRootWindow(), device_scale_factor_));
725   // |view_rect| is absolute coordinate of webview.
726   gfx::Rect view_rect = GetViewBoundsInPix();
727
728   // the gl coordinate system is based on screen rect for direct rendering.
729   // if direct rendering is disabled, the coordinate is based on webview.
730   // TODO(is46.kim) : Even though evas direct rendering flag is set, direct
731   // rendering may be disabled in the runtime depend on environment.
732   // There is no way to get current rendering mode. |is_direct_rendering|
733   // flag should be changed by current rendering mode.
734   bool is_direct_rendering = !is_magnifier;
735   if (!is_direct_rendering) {
736     view_rect.set_x(0);
737     view_rect.set_y(0);
738   }
739   const gfx::Size surface_size =
740       (is_direct_rendering) ? window_rect.size() : view_rect.size();
741
742   // |snapshot_area| is relative coordinate in webview.
743   int x = snapshot_area.x();
744   int y = snapshot_area.y();
745   int width = snapshot_area.width();
746   int height = snapshot_area.height();
747
748   // Convert |snapshot_area| to absolute coordinate.
749   x += view_rect.x();
750   y += view_rect.y();
751
752   // Limit snapshot rect by webview size
753   if (x + width > view_rect.right())
754     width = view_rect.right() - x;
755   if (y + height > view_rect.bottom())
756     height = view_rect.bottom() - y;
757
758   // Convert coordinate system for OpenGL.
759   // (0,0) is top left corner in webview coordinate system.
760   if (is_evasgl_direct_landscape) {
761     if (rotation == 270) {
762       x = surface_size.width() - x - width;
763       y = surface_size.height() - y - height;
764     }
765     std::swap(x, y);
766     std::swap(width, height);
767   } else {
768     // (0,0) is bottom left corner in opengl coordinate system.
769     y = surface_size.height() - y - height;
770   }
771
772   int size = width * height * sizeof(GLuint);
773   GLuint* data = (GLuint*)malloc(size);
774   if (!data) {
775     LOG(ERROR) << "Failed to allocate memory for snapshot";
776     return nullptr;
777   }
778
779   {
780 #if defined(USE_TTRACE)
781     TTRACE(TTRACE_TAG_WEB,
782            "RWHVAuraOffscreenHelperEfl::GetSnapshot(ReadPixels)");
783 #endif
784     if (!MakeCurrent()) {
785       LOG(ERROR) << "MakeCurrent() failed.";
786       free(data);
787       return nullptr;
788     }
789
790     evas_gl_api_->glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
791                                data);
792     ClearCurrent();
793   }
794
795   if (!is_evasgl_direct_landscape && (rotation == 90 || rotation == 270))
796     std::swap(width, height);
797
798 #if _DUMP_SNAPSHOT_
799   static int frame_number = 0;
800   frame_number++;
801   {
802     char filename[150];
803     sprintf(filename, "/opt/share/dump/snapshot%02d-%d_%dx%d_rgba8888.raw",
804             frame_number, rotation, width, height);
805     FILE* fp = fopen(filename, "w");
806     if (fp) {
807       fwrite(data, width * height * 4, 1, fp);
808       fflush(fp);
809       fclose(fp);
810     } else {
811       LOG(ERROR) << "Unable to open file";
812     }
813   }
814 #endif
815
816   // flip the Y axis and change color format from RGBA to BGRA
817   for (int j = 0; j < height / 2; j++) {
818     for (int i = 0; i < width; i++) {
819       GLuint& px1 = data[(j * width) + i];
820       GLuint& px2 = data[((height - 1) - j) * width + i];
821       px1 = ((px1 & 0xff) << 16) | ((px1 >> 16) & 0xff) | (px1 & 0xff00ff00) |
822             0xff000000;
823       px2 = ((px2 & 0xff) << 16) | ((px2 >> 16) & 0xff) | (px2 & 0xff00ff00) |
824             0xff000000;
825       std::swap(px1, px2);
826     }
827   }
828
829   SkBitmap bitmap;
830   if (scale_factor != 1.0 || rotation) {
831     bitmap.setInfo(SkImageInfo::MakeN32Premul(width, height));
832     bitmap.setPixels(data);
833
834     // scaling bitmap
835     if (scale_factor != 1.0) {
836       width = scale_factor * width;
837       height = scale_factor * height;
838       bitmap = skia::ImageOperations::Resize(
839           bitmap, skia::ImageOperations::RESIZE_GOOD, width, height);
840     }
841
842     if (rotation == 90) {
843       bitmap = SkBitmapOperations::Rotate(bitmap,
844                                           SkBitmapOperations::ROTATION_90_CW);
845     } else if (rotation == 180) {
846       bitmap = SkBitmapOperations::Rotate(bitmap,
847                                           SkBitmapOperations::ROTATION_180_CW);
848     } else if (rotation == 270) {
849       bitmap = SkBitmapOperations::Rotate(bitmap,
850                                           SkBitmapOperations::ROTATION_270_CW);
851     }
852   }
853
854   if (rotation == 90 || rotation == 270)
855     std::swap(width, height);
856
857   Evas_Object* image = evas_object_image_filled_add(evas_);
858   if (image) {
859     evas_object_image_size_set(image, width, height);
860     evas_object_image_alpha_set(image, EINA_TRUE);
861     evas_object_image_data_copy_set(image,
862                                     bitmap.empty() ? data : bitmap.getPixels());
863     evas_object_resize(image, width, height);
864 #if _DUMP_SNAPSHOT_
865     char filename[150];
866     sprintf(filename, "/opt/share/dump/snapshot%02d-%d_%dx%d.png", frame_number,
867             rotation, width, height);
868     evas_object_image_save(image, filename, NULL, "quality=100");
869 #endif
870   }
871   free(data);
872
873   return image;
874 }
875
876 void RWHVAuraOffscreenHelperEfl::RequestSnapshotAsync(
877     const gfx::Rect& snapshot_area,
878     Screenshot_Captured_Callback callback,
879     void* user_data,
880     float scale_factor) {
881 #if defined(USE_TTRACE)
882   TTRACE(TTRACE_TAG_WEB, "RWHVAuraOffscreenHelperEfl::RequestSnapshotAsync");
883 #endif
884   ScreenshotCapturedCallback* cb =
885       new ScreenshotCapturedCallback(callback, user_data);
886
887   int request_id = screen_capture_cb_map_.Add(base::WrapUnique(cb));
888
889   if (rwhv_aura_->IsShowing() && evas_focus_get(evas_)) {
890     // Create a snapshot task that will be executed after frame
891     // is generated and drawn to surface.
892     snapshot_task_list_.push_back(base::BindOnce(
893         &RWHVAuraOffscreenHelperEfl::RunGetSnapshotOnMainThread,
894         base::Unretained(this), snapshot_area, request_id, scale_factor));
895
896     // Delete OnEvasRenderPost callback to prevent registration twice.
897     evas_event_callback_del_full(evas_, EVAS_CALLBACK_RENDER_FLUSH_PRE,
898                                  OnEvasRenderFlushPre, this);
899     evas_event_callback_add(evas_, EVAS_CALLBACK_RENDER_FLUSH_PRE,
900                             OnEvasRenderFlushPre, this);
901
902     // If there is no EVAS_CALLBACK_RENDER_FLUSH_PRE event sent out in 400ms,
903     // we trigger one by ourself
904     snapshot_timer_->Start(
905         FROM_HERE, base::Milliseconds(4 * kSnapshotProcessDelay),
906         base::BindOnce(&RWHVAuraOffscreenHelperEfl::InvalidateForSnapshot,
907                        base::Unretained(this)));
908   } else {
909     // Sends message to renderer to capture the content snapshot of the view.
910     rwhv_aura_->host()->RequestContentSnapshot(snapshot_area, scale_factor,
911                                                request_id);
912   }
913 }
914
915 void RWHVAuraOffscreenHelperEfl::DidGetContentSnapshot(const SkBitmap& bitmap,
916                                                        const int request_id) {
917   ScreenshotCapturedCallback* callback =
918       screen_capture_cb_map_.Lookup(request_id);
919   if (!callback)
920     return;
921
922   Evas_Object* image = nullptr;
923   if (!bitmap.empty()) {
924     image = evas_object_image_filled_add(evas_);
925     evas_object_image_size_set(image, bitmap.width(), bitmap.height());
926     evas_object_image_data_copy_set(image, bitmap.getPixels());
927   }
928   callback->Run(image);
929   screen_capture_cb_map_.Remove(request_id);
930 }
931
932 Evas_Object* RWHVAuraOffscreenHelperEfl::ewk_view() const {
933   auto wci = static_cast<WebContentsImpl*>(web_contents_);
934   if (!wci)
935     return nullptr;
936
937   return static_cast<Evas_Object*>(wci->ewk_view());
938 }
939
940 void RWHVAuraOffscreenHelperEfl::FocusRWHVA() {
941   if (!rwhv_aura_->HasFocus())
942     rwhv_aura_->Focus();
943 }
944
945 void RWHVAuraOffscreenHelperEfl::Show() {
946   evas_object_show(content_image_elm_host_);
947 }
948
949 void RWHVAuraOffscreenHelperEfl::Hide() {
950   evas_object_hide(content_image_elm_host_);
951 }
952
953 void RWHVAuraOffscreenHelperEfl::SetCustomViewportSize(const gfx::Size& size) {
954   if (custom_viewport_size_ != size) {
955     custom_viewport_size_ = size;
956     // Take the view port change into account.
957     rwhv_aura_->host()->SynchronizeVisualProperties();
958   }
959 }
960
961 gfx::Size RWHVAuraOffscreenHelperEfl::GetVisibleViewportSize() {
962   if (!custom_viewport_size_.IsEmpty())
963     return custom_viewport_size_;
964   return GetViewBounds().size();
965 }
966
967 gfx::Rect RWHVAuraOffscreenHelperEfl::GetViewBounds() {
968   return gfx::ToEnclosingRect(
969       gfx::ConvertRectToDips(GetViewBoundsInPix(), device_scale_factor_));
970 }
971
972 void RWHVAuraOffscreenHelperEfl::SetPageVisibility(bool visible) {
973   LOG(INFO) << __FUNCTION__ << ", visible : " << visible;
974   if (visible) {
975     // Triggers RWHVA::ShowWithVisibility followed by RWHVAHelperEfl::Show
976     web_contents_->WasShown();
977   } else {
978     // Triggers RWHVA::Hide followed by RWHVAHelperEfl::Hide
979     web_contents_->WasHidden();
980   }
981 }
982
983 RenderWidgetHostImpl* RWHVAuraOffscreenHelperEfl::GetRenderWidgetHostImpl() {
984   return rwhv_aura_->host();
985 }
986
987 ui::EflEventHandler* RWHVAuraOffscreenHelperEfl::GetEventHandler() {
988   aura::WindowTreeHost* window_host = rwhv_aura_->window()->GetHost();
989   if (!window_host)
990     return nullptr;
991
992   return static_cast<aura::WindowTreeHostPlatform*>(window_host)
993       ->platform_window()
994       ->GetEventHandler();
995 }
996
997 ui::IMContextEfl* RWHVAuraOffscreenHelperEfl::GetIMContextEfl() {
998   // im_context_efl_ is always nullptr on desktop efl.
999 #if BUILDFLAG(IS_TIZEN)
1000   if (!im_context_efl_) {
1001     if (GetEventHandler() && GetEventHandler()->GetIMContextEfl()) {
1002       im_context_efl_ = GetEventHandler()->GetIMContextEfl();
1003       im_context_efl_->SetRWHHelper(rwh_helper_.get());
1004       return im_context_efl_;
1005     }
1006     LOG(ERROR) << "im_context_efl_ is not set";
1007   }
1008 #endif
1009   return im_context_efl_;
1010 }
1011
1012 gfx::NativeView RWHVAuraOffscreenHelperEfl::GetNativeView() {
1013   return rwhv_aura_->GetNativeView();
1014 }
1015
1016 gfx::Point RWHVAuraOffscreenHelperEfl::ConvertPointInViewPix(gfx::Point point) {
1017   return gfx::ToFlooredPoint(
1018       gfx::ScalePoint(gfx::PointF(point), device_scale_factor_));
1019 }
1020
1021 void RWHVAuraOffscreenHelperEfl::TextInputStateChanged(
1022     const ui::mojom::TextInputState& params) {
1023   auto im_context = GetIMContextEfl();
1024   if (!im_context) {
1025     LOG(ERROR) << "im_context is nullptr";
1026     return;
1027   }
1028
1029 #if BUILDFLAG(IS_TIZEN_TV)
1030   if (!rwhv_aura_->IsShowing() || !HasFocus())
1031 #else
1032   if (!rwhv_aura_->IsShowing())
1033 #endif
1034     return;
1035
1036   bool show_ime_if_needed = params.show_ime_if_needed;
1037
1038   if (show_ime_if_needed && !params.is_user_action)
1039     show_ime_if_needed = false;
1040
1041   // Prevent scroll and zoom for autofocus'ed elements.
1042   if (show_ime_if_needed && params.type != ui::TEXT_INPUT_TYPE_NONE) {
1043     // If webview isn't resized yet, return previous IME state.
1044     bool is_ime_show = im_context->WebViewWillBeResized()
1045                            ? !im_context->IsVisible()
1046                            : im_context->IsVisible();
1047     if (im_context && !is_ime_show)
1048       is_scrolling_needed_ = true;
1049   }
1050
1051   if (im_context) {
1052     im_context->SetIsInFormTag(params.is_in_form_tag);
1053 #if BUILDFLAG(IS_TIZEN_TV)
1054     im_context->UpdateInputMethodState(
1055         params.type, params.can_compose_inline, show_ime_if_needed,
1056         password_input_minlength_, input_maxlength_);
1057 #else
1058     im_context->UpdateInputMethodState(params.type, params.can_compose_inline,
1059                                        show_ime_if_needed);
1060 #endif
1061   }
1062 }
1063
1064 void RWHVAuraOffscreenHelperEfl::MoveCaret(const gfx::Point& point) {
1065   if (auto* delegate = rwhv_aura_->host()->delegate()) {
1066     delegate->MoveCaret(gfx::Point(point.x() / device_scale_factor_,
1067                                    point.y() / device_scale_factor_));
1068   }
1069 }
1070
1071 void RWHVAuraOffscreenHelperEfl::SelectClosestWord(
1072     const gfx::Point& touch_point) {
1073   int view_x, view_y;
1074   EvasToBlinkCords(touch_point.x(), touch_point.y(), &view_x, &view_y);
1075
1076 #if !defined(EWK_BRINGUP)  // FIXME: m67 bringup
1077   // FIXME: The SelectClosestWord function was removed by
1078   // commit 9720a4494c8bcd24d1f496feec5cfac7582103d2 in s-chromium
1079   // It will be fixed by webview team.
1080   // FIXME: http://suprem.sec.samsung.net/jira/browse/TWF-2122
1081   Send(new ViewMsg_SelectClosestWord(host_->GetRoutingID(), view_x, view_y));
1082 #endif  // EWK_BRINGUP
1083 }
1084
1085 bool RWHVAuraOffscreenHelperEfl::HasSelectableText() {
1086   // If the last character of textarea is '\n', We can assume an extra '\n'.
1087   // Actually when you insert line break by ENTER key, '\n\n' is stored in
1088   // textarea. And If you press delete key, only a '\n' character will be stored
1089   // although there is no visible and selectable character in textarea. That's
1090   // why we should check whether selection_text contains only one line break.
1091   // Bug: http://suprem.sec.samsung.net/jira/browse/TSAM-2230
1092   //
1093   // Please see below commit for more information.
1094   // https://codereview.chromium.org/1785603002
1095   std::u16string selection_text = rwhv_aura_->GetSelectedText();
1096   return !selection_text.empty() &&
1097          base::UTF16ToUTF8(selection_text).compare("\n") != 0;
1098 }
1099
1100 void RWHVAuraOffscreenHelperEfl::FocusedNodeChanged(
1101     bool editable
1102 #if BUILDFLAG(IS_TIZEN_TV)
1103     ,
1104     bool is_radio_or_checkbox,
1105     int password_input_minlength,
1106     int input_maxlength
1107 #endif
1108     ,
1109     bool is_content_editable) {
1110   is_content_editable_ = is_content_editable;
1111 #if defined(USE_WAYLAND)
1112   ClipboardHelperEfl::GetInstance()->SetContentEditable(is_content_editable);
1113 #endif
1114
1115 #if BUILDFLAG(IS_TIZEN_TV)
1116   radio_or_checkbox_focused_ = is_radio_or_checkbox;
1117   password_input_minlength_ = password_input_minlength;
1118   input_maxlength_ = input_maxlength;
1119 #endif
1120
1121   auto im_context = GetIMContextEfl();
1122   if (im_context && is_focused_node_editable_) {
1123     // focus out from an editable node,
1124     // need reset ime context.
1125     // or else will cause previous preedit text be copied.
1126     if (im_context->IsVisible()) {
1127       im_context->CancelComposition();
1128     } else {
1129       // add ime focus out when focus out from an editable node.
1130       im_context->OnFocusOut();
1131     }
1132   }
1133   is_focused_node_editable_ = editable;
1134 }
1135
1136 gfx::Size RWHVAuraOffscreenHelperEfl::GetPhysicalBackingSize() const {
1137   int w, h;
1138   evas_object_geometry_get(content_image_elm_host_, nullptr, nullptr, &w, &h);
1139   return gfx::Size(w, h);
1140 }
1141
1142 int RWHVAuraOffscreenHelperEfl::GetTopControlsHeight() {
1143   int y = 0;
1144   evas_object_geometry_get(content_image_, nullptr, &y, nullptr, nullptr);
1145   return y;
1146 }
1147
1148 gfx::Rect RWHVAuraOffscreenHelperEfl::GetViewBoundsInPix() const {
1149   int x, y, w, h;
1150   evas_object_geometry_get(content_image_, &x, &y, &w, &h);
1151   return gfx::Rect(x, y, w, h);
1152 }
1153
1154 const gfx::Size RWHVAuraOffscreenHelperEfl::GetScrollableSize() const {
1155   int width = 0;
1156   int height = 0;
1157   gfx::Rect viewport_size = GetViewBoundsInPix();
1158   if (scaled_contents_size_.width() > viewport_size.width()) {
1159     width = scaled_contents_size_.width() - viewport_size.width();
1160     // When device scale factor is larger than 1.0, content size is ceiled up
1161     // during converting pixel to dip in
1162     // RWHVAuraOffscreenHelperEfl::GetViewBounds. So we ignore when
1163     // scroll size is 1. It is also same for height. Please refer to
1164     // https://review.tizen.org/gerrit/#/c/74044/.
1165     if (device_scale_factor_ > 1.0f && width == 1)
1166       width = 0;
1167   }
1168   if (scaled_contents_size_.height() > viewport_size.height()) {
1169     height = scaled_contents_size_.height() - viewport_size.height();
1170     if (device_scale_factor_ > 1.0f && height == 1)
1171       height = 0;
1172   }
1173
1174   return gfx::Size(width, height);
1175 }
1176
1177 #if BUILDFLAG(IS_TIZEN_TV)
1178 void RWHVAuraOffscreenHelperEfl::DrawLabel(Evas_Object* image,
1179                                            Eina_Rectangle rect) {
1180   // check view boundary
1181   if (rect.x < 0 || rect.y < 0 || rect.x > GetViewBoundsInPix().width() ||
1182       rect.y > GetViewBoundsInPix().height())
1183     return;
1184
1185   evas_object_move(image, rect.x, rect.y);
1186   evas_object_show(image);
1187
1188   voice_manager_labels_.push_back(image);
1189 }
1190
1191 void RWHVAuraOffscreenHelperEfl::ClearLabels() {
1192   for (size_t i = 0; i < voice_manager_labels_.size(); i++) {
1193     evas_object_hide(voice_manager_labels_[i]);
1194     evas_object_del(voice_manager_labels_[i]);
1195   }
1196   voice_manager_labels_.clear();
1197 }
1198 #endif
1199
1200 void RWHVAuraOffscreenHelperEfl::OnGetMainFrameScrollbarVisible(int callback_id,
1201                                                                 bool visible) {
1202   web_contents_->GetDelegate()->OnGetMainFrameScrollbarVisible(callback_id,
1203                                                                visible);
1204 }
1205
1206 void RWHVAuraOffscreenHelperEfl::OnGetFocusedNodeBounds(
1207     const gfx::RectF& rect) {
1208   web_contents_->GetDelegate()->OnDidChangeFocusedNodeBounds(rect);
1209 }
1210
1211 void RWHVAuraOffscreenHelperEfl::BackgroundColorReceived(int callback_id,
1212                                                          SkColor bg_color) {
1213   web_contents_->GetDelegate()->BackgroundColorReceived(callback_id, bg_color);
1214 }
1215
1216 void RWHVAuraOffscreenHelperEfl::SetTouchEventsEnabled(bool enabled) {
1217   if (auto* event_handler = GetEventHandler())
1218     event_handler->SetTouchEventsEnabled(enabled);
1219 }
1220
1221 bool RWHVAuraOffscreenHelperEfl::TouchEventsEnabled() {
1222   if (auto* event_handler = GetEventHandler())
1223     return event_handler->TouchEventsEnabled();
1224
1225   return false;
1226 }
1227
1228 }  // namespace content