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