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.
5 #include "content/browser/renderer_host/rwhv_aura_offscreen_helper_efl.h"
7 #include <Ecore_Evas.h>
8 #include <Elementary.h>
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"
36 #if BUILDFLAG(IS_TIZEN_TV)
37 #include "third_party/blink/public/platform/web_application_type.h"
40 #define MAX_SURFACE_WIDTH_EGL 4096 // max supported Framebuffer width
41 #define MAX_SURFACE_HEIGHT_EGL 4096 // max supported Framebuffer height
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)
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;
55 class RenderWidgetHostHelperAura : public RenderWidgetHostHelper {
57 explicit RenderWidgetHostHelperAura(RWHVAuraOffscreenHelperEfl* rwhv_helper)
58 : rwhv_helper_(rwhv_helper) {}
59 ~RenderWidgetHostHelperAura() override = default;
61 bool HasRenderWidgetHost() const override {
62 return !!rwhv_helper_->GetRenderWidgetHostImpl();
65 void ExtendSelectionAndDelete(int32_t before, int32_t after) override {
66 auto* handler = GetFrameWidgetInputHandler();
70 handler->ExtendSelectionAndDelete(before, after);
73 void SetCompositionFromExistingText(
76 const std::vector<ui::ImeTextSpan>& ime_text_spans) override {
77 auto* handler = GetFrameWidgetInputHandler();
81 handler->SetCompositionFromExistingText(start, end, ime_text_spans);
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();
92 rwhi->ImeCommitText(text, ime_text_spans, replacement_range,
96 void ImeFinishComposingText(bool keep_selection) override {
97 auto* rwhi = rwhv_helper_->GetRenderWidgetHostImpl();
101 rwhi->ImeFinishComposingText(keep_selection);
104 void ImeSetComposition(const std::u16string& text,
105 const std::vector<ui::ImeTextSpan>& ime_text_spans,
106 const gfx::Range& replacement_range,
108 int selection_end) override {
109 auto* rwhi = rwhv_helper_->GetRenderWidgetHostImpl();
113 rwhi->ImeSetComposition(text, ime_text_spans, replacement_range,
114 selection_start, selection_end);
117 bool ExistsSelectedText() override {
118 auto* controller = rwhv_helper_->GetSelectionController();
122 return controller->ExistsSelectedText();
125 bool ImeHandleKeyEventEnabled() override { return true; }
127 gfx::Size GetPhysicalBackingSize() const override {
128 return rwhv_helper_->GetPhysicalBackingSize();
131 Evas_Object* EwkView() const override { return rwhv_helper_->ewk_view(); }
134 blink::mojom::FrameWidgetInputHandler* GetFrameWidgetInputHandler() const {
135 auto* rwhi = rwhv_helper_->GetRenderWidgetHostImpl();
139 return rwhi->GetFrameWidgetInputHandler();
142 RWHVAuraOffscreenHelperEfl* rwhv_helper_;
145 RWHVAuraOffscreenHelperEfl::RWHVAuraOffscreenHelperEfl(
146 RenderWidgetHostViewAura* rwhva,
147 WebContents* web_contents)
148 : RWHVAuraCommonHelperEfl(rwhva, web_contents) {
153 RWHVAuraOffscreenHelperEfl::~RWHVAuraOffscreenHelperEfl() {
154 if (evas_gl_surface_) {
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;
164 LOG(WARNING) << "Failed to unbind gl context";
166 if (evas_gl_context_) {
167 evas_gl_context_destroy(evas_gl_, evas_gl_context_);
168 evas_gl_context_ = nullptr;
170 if (evas_gl_config_) {
171 evas_gl_config_free(evas_gl_config_);
172 evas_gl_config_ = nullptr;
175 evas_gl_free(evas_gl_);
179 elm_object_part_content_unset(content_image_elm_host_, "overlay");
180 evas_object_event_callback_del(content_image_, EVAS_CALLBACK_FOCUS_IN,
182 evas_object_event_callback_del(content_image_, EVAS_CALLBACK_FOCUS_OUT,
184 evas_object_smart_callback_del(content_image_elm_host_, "focused",
186 evas_object_smart_callback_del(content_image_elm_host_, "unfocused",
188 evas_event_callback_del_full(evas_, EVAS_CALLBACK_RENDER_FLUSH_PRE,
189 OnEvasRenderFlushPre, this);
190 evas_object_del(content_image_);
192 content_image_elm_host_ = nullptr;
193 content_image_ = nullptr;
194 efl_main_layout_ = nullptr;
197 void RWHVAuraOffscreenHelperEfl::Initialize() {
199 static_cast<WebContentsImpl*>(GetWebContents())->GetEflMainLayout();
200 evas_ = evas_object_evas_get(efl_main_layout_);
204 evas_object_event_callback_add(efl_main_layout_, EVAS_CALLBACK_RESIZE,
205 OnParentViewResize, this);
206 evas_object_show(content_image_);
208 device_scale_factor_ =
209 display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor();
211 snapshot_timer_.reset(new base::OneShotTimer);
214 void RWHVAuraOffscreenHelperEfl::AuraChildWindowAdded() {
215 aura::WindowTreeHost* window_host = rwhva()->window()->GetHost();
219 static_cast<aura::WindowTreeHostPlatform*>(window_host)
221 ->SetEventsOverlayForOffscreen(content_image_);
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,
226 evas_object_event_callback_add(content_image_, EVAS_CALLBACK_FOCUS_OUT,
231 void RWHVAuraOffscreenHelperEfl::OnParentViewResize(void* data,
235 RWHVAuraOffscreenHelperEfl* thiz =
236 static_cast<RWHVAuraOffscreenHelperEfl*>(data);
237 gfx::Rect new_bounds(thiz->CreateNativeSurface());
238 aura::WindowTreeHost* window_host = thiz->rwhva()->window()->GetHost();
240 window_host->SetBoundsInPixels(new_bounds);
242 aura::Window* parent_window = thiz->aura_parent_window_;
244 parent_window->SetBounds(new_bounds);
247 bool RWHVAuraOffscreenHelperEfl::ClearCurrent() {
248 return evas_gl_make_current(evas_gl_, 0, 0);
251 bool RWHVAuraOffscreenHelperEfl::MakeCurrent() {
252 return evas_gl_make_current(evas_gl_, evas_gl_surface_, evas_gl_context_);
255 void RWHVAuraOffscreenHelperEfl::ClearBrowserFrame() {
256 DCHECK(evas_gl_api_);
257 absl::optional<SkColor> bg_color = rwhva()->GetBackgroundColor();
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);
265 evas_gl_api_->glClearColor(1.0, 1.0, 1.0, 1.0);
267 evas_gl_api_->glClear(GL_COLOR_BUFFER_BIT);
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"
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"
280 " v_texCoord = a_texCoord; \n"
283 static const char kFragmentShaderSourceSimple[] =
284 "precision mediump float; \n"
285 "varying vec2 v_texCoord; \n"
286 "uniform sampler2D s_texture; \n"
288 " gl_FragColor = texture2D( s_texture, v_texCoord );\n"
291 static void GLCheckProgramHelper(Evas_GL_API* api,
296 api->glGetProgramiv(program, GL_LINK_STATUS, &status);
300 const GLsizei buf_length = 2048;
301 std::unique_ptr<GLchar[]> log(new GLchar[buf_length]);
303 api->glGetProgramInfoLog(program, buf_length, &length, log.get());
304 LOG(ERROR) << "GL program link failed in: " << file << ":" << line << ":"
306 api->glDeleteProgram(program);
309 #define GLCheckProgram(api, program) \
310 GLCheckProgramHelper(api, program, __FILE__, __LINE__)
312 static void GLCheckShaderHelper(Evas_GL_API* api,
317 api->glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
321 const GLsizei buf_length = 2048;
322 std::unique_ptr<GLchar[]> log(new GLchar[buf_length]);
324 api->glGetShaderInfoLog(shader, buf_length, &length, log.get());
325 LOG(ERROR) << "GL shader compile failed in " << file << ":" << line << ":"
327 api->glDeleteShader(shader);
330 #define GLCheckShader(api, shader) \
331 GLCheckShaderHelper((api), (shader), __FILE__, __LINE__)
333 void RWHVAuraOffscreenHelperEfl::InitializeProgram() {
334 evas_gl_make_current(evas_gl_, evas_gl_surface_, evas_gl_context_);
336 // GL_CHECK_STATUS("GL Error before program initialization");
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");
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};
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);
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);
360 evas_gl_api_->glShaderSource(vertexShader, 1, &vertexShaderSourceProgram, 0);
361 evas_gl_api_->glShaderSource(fragmentShader, 1, &fragmentShaderSourceProgram,
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);
378 evas_gl_api_->glGetAttribLocation(program_id_, "a_position");
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);
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);
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);
401 evas_gl_api_->glClearColor(1.0, 1.0, 1.0, 1.0);
403 evas_gl_api_->glClear(GL_COLOR_BUFFER_BIT);
404 evas_gl_api_->glUseProgram(program_id_);
406 evas_gl_api_->glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_obj_);
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,
418 (void*)(3 * sizeof(GLfloat)));
419 evas_gl_api_->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_obj_);
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);
433 evas_gl_api_->glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL);
435 evas_gl_api_->glBindTexture(GL_TEXTURE_2D, 0);
436 if (bg_color && *bg_color == SK_ColorTRANSPARENT) {
437 evas_gl_api_->glDisable(GL_BLEND);
439 evas_gl_make_current(evas_gl_, 0, 0);
442 frame_rendered_ = true;
444 // Get snapshot for magnifier.
445 if (!magnifier_snapshot_request_.is_null()) {
446 std::move(magnifier_snapshot_request_).Run();
447 magnifier_snapshot_request_.Reset();
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;
462 #if BUILDFLAG(IS_TIZEN_TV)
463 if (!blink::IsSupportRGBA())
464 evas_gl_config_->color_format = EVAS_GL_RGB_888;
467 evas_gl_ = evas_gl_new(evas_);
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;
473 evas_gl_context_ = evas_gl_context_version_create(
474 evas_gl_, GLSharedContextEfl::GetEvasGLContext(), context_version);
476 if (!evas_gl_context_)
477 LOG(FATAL) << "Failed to create evas gl context";
479 evas_gl_api_ = evas_gl_context_api_get(evas_gl_, evas_gl_context_);
481 CreateNativeSurface();
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)
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;
496 if (!content_image_) {
497 content_image_ = evas_object_image_filled_add(evas_);
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",
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_);
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);
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_);
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";
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);
535 LOG(FATAL) << "Failed to get native surface";
538 return gfx::Size(width, height);
542 void RWHVAuraOffscreenHelperEfl::EvasObjectImagePixelsGetCallback(
545 RWHVAuraOffscreenHelperEfl* rwhv_helper =
546 reinterpret_cast<RWHVAuraOffscreenHelperEfl*>(data);
547 if (!rwhv_helper->texture_id_)
550 rwhv_helper->MakeCurrent();
551 rwhv_helper->ClearBrowserFrame();
552 rwhv_helper->ClearCurrent();
553 rwhv_helper->PaintTextureToSurface(rwhv_helper->texture_id_);
556 void RWHVAuraOffscreenHelperEfl::NotifySwap(const size_t texture_id) {
557 if (texture_id <= 0) {
558 LOG(ERROR) << __FUNCTION__ << " invalid texture id ";
561 texture_id_ = texture_id;
562 evas_object_image_pixels_dirty_set(content_image_, true);
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);
570 #if BUILDFLAG(IS_TIZEN_TV)
571 // sync focus on efl window
572 aura::WindowTreeHost* window_host = rwhva()->window()->GetHost();
574 static_cast<aura::WindowTreeHostPlatform*>(window_host)
576 ->UpdateFocus(focus);
581 bool RWHVAuraOffscreenHelperEfl::HasFocus() {
582 return evas_object_focus_get(content_image_);
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;
592 void RWHVAuraOffscreenHelperEfl::OnFocusIn(void* data,
596 LOG(INFO) << "OnFocusIn";
597 RWHVAuraOffscreenHelperEfl* thiz =
598 static_cast<RWHVAuraOffscreenHelperEfl*>(data);
601 if (IsMobileProfile() && thiz->GetSelectionController()) {
602 thiz->GetSelectionController()->ShowHandleAndContextMenuIfRequired();
605 if (!thiz->on_focus_in_callback_.is_null())
606 thiz->on_focus_in_callback_.Run();
609 void RWHVAuraOffscreenHelperEfl::OnFocusOut(void* data,
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())
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) {
627 aura::Window* focused_window = focus_client->GetFocusedWindow();
630 focused_window->LostFocus();
633 if (IsMobileProfile() && thiz->GetSelectionController()) {
634 thiz->GetSelectionController()->HideHandleAndContextMenu();
637 if (!thiz->on_focus_out_callback_.is_null())
638 thiz->on_focus_out_callback_.Run();
641 void RWHVAuraOffscreenHelperEfl::OnHostFocusIn(void* data,
644 LOG(INFO) << "OnHostFocusIn";
645 RWHVAuraOffscreenHelperEfl* thiz =
646 static_cast<RWHVAuraOffscreenHelperEfl*>(data);
650 void RWHVAuraOffscreenHelperEfl::OnHostFocusOut(void* data,
653 LOG(INFO) << "OnHostFocusOut";
654 RWHVAuraOffscreenHelperEfl* thiz =
655 static_cast<RWHVAuraOffscreenHelperEfl*>(data);
656 if (thiz && thiz->GetRenderWidgetHostImpl())
657 thiz->GetRenderWidgetHostImpl()->Blur();
660 void RWHVAuraOffscreenHelperEfl::EvasToBlinkCords(int x,
664 gfx::Rect view_bounds = GetViewBoundsInPix();
666 *view_x = x - view_bounds.x();
667 *view_x /= device_scale_factor_;
670 *view_y = y - view_bounds.y();
671 *view_y /= device_scale_factor_;
675 void RWHVAuraOffscreenHelperEfl::OnEvasRenderFlushPre(void* data,
678 RWHVAuraOffscreenHelperEfl* rwhv_helper =
679 static_cast<RWHVAuraOffscreenHelperEfl*>(data);
680 if (rwhv_helper && rwhv_helper->snapshot_task_list_.size() > 0)
681 rwhv_helper->ProcessSnapshotRequest();
684 void RWHVAuraOffscreenHelperEfl::InvalidateForSnapshot() {
685 evas_object_image_pixels_dirty_set(content_image_, true);
688 void RWHVAuraOffscreenHelperEfl::ProcessSnapshotRequest() {
689 if (!frame_rendered_)
692 // Process all snapshot requests pending now.
693 for (auto& task : snapshot_task_list_) {
695 std::move(task).Run();
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);
707 void RWHVAuraOffscreenHelperEfl::RunGetSnapshotOnMainThread(
708 const gfx::Rect snapshot_area,
710 float scale_factor) {
711 #if defined(USE_TTRACE)
712 TTRACE(TTRACE_TAG_WEB,
713 "RWHVAuraOffscreenHelperEfl::RunGetSnapshotOnMainThread");
715 ScreenshotCapturedCallback* callback =
716 screen_capture_cb_map_.Lookup(request_id);
721 if (rwhva()->IsShowing() && evas_focus_get(evas_))
722 callback->Run(GetSnapshot(snapshot_area, scale_factor));
723 screen_capture_cb_map_.Remove(request_id);
726 Evas_Object* RWHVAuraOffscreenHelperEfl::GetSnapshot(
727 const gfx::Rect& snapshot_area,
730 #if defined(USE_TTRACE)
731 TTRACE(TTRACE_TAG_WEB, "RWHVAuraOffscreenHelperEfl::GetSnapshot");
733 if (scale_factor == 0.0)
737 display::Screen::GetScreen()->GetPrimaryDisplay().RotationAsDegree();
739 bool is_evasgl_direct_landscape = false;
740 // For EvasGL Direct Rendering in landscape mode
742 is_evasgl_direct_landscape = ((rotation == 90 || rotation == 270) &&
743 !evas_gl_rotation_get(evas_gl_));
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();
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) {
762 const gfx::Size surface_size =
763 (is_direct_rendering) ? window_rect.size() : view_rect.size();
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();
771 // Convert |snapshot_area| to absolute coordinate.
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;
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;
789 std::swap(width, height);
791 // (0,0) is bottom left corner in opengl coordinate system.
792 y = surface_size.height() - y - height;
795 int size = width * height * sizeof(GLuint);
796 GLuint* data = (GLuint*)malloc(size);
798 LOG(ERROR) << "Failed to allocate memory for snapshot";
803 #if defined(USE_TTRACE)
804 TTRACE(TTRACE_TAG_WEB,
805 "RWHVAuraOffscreenHelperEfl::GetSnapshot(ReadPixels)");
807 if (!MakeCurrent()) {
808 LOG(ERROR) << "MakeCurrent() failed.";
813 evas_gl_api_->glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
818 if (!is_evasgl_direct_landscape && (rotation == 90 || rotation == 270))
819 std::swap(width, height);
822 static int frame_number = 0;
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");
830 fwrite(data, width * height * 4, 1, fp);
834 LOG(ERROR) << "Unable to open file";
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) |
846 px2 = ((px2 & 0xff) << 16) | ((px2 >> 16) & 0xff) | (px2 & 0xff00ff00) |
853 if (scale_factor != 1.0 || rotation) {
854 bitmap.setInfo(SkImageInfo::MakeN32Premul(width, height));
855 bitmap.setPixels(data);
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);
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);
877 if (rotation == 90 || rotation == 270)
878 std::swap(width, height);
880 Evas_Object* image = evas_object_image_filled_add(evas_);
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);
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");
899 void RWHVAuraOffscreenHelperEfl::RequestSnapshotAsync(
900 const gfx::Rect& snapshot_area,
901 Screenshot_Captured_Callback callback,
903 float scale_factor) {
904 #if defined(USE_TTRACE)
905 TTRACE(TTRACE_TAG_WEB, "RWHVAuraOffscreenHelperEfl::RequestSnapshotAsync");
907 ScreenshotCapturedCallback* cb =
908 new ScreenshotCapturedCallback(callback, user_data);
910 int request_id = screen_capture_cb_map_.Add(base::WrapUnique(cb));
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));
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);
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)));
932 // Sends message to renderer to capture the content snapshot of the view.
933 rwhva()->host()->RequestContentSnapshot(snapshot_area, scale_factor,
938 void RWHVAuraOffscreenHelperEfl::Show() {
939 evas_object_show(content_image_elm_host_);
942 void RWHVAuraOffscreenHelperEfl::Hide() {
943 evas_object_hide(content_image_elm_host_);
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();
954 gfx::Size RWHVAuraOffscreenHelperEfl::GetVisibleViewportSize() {
955 if (!custom_viewport_size_.IsEmpty())
956 return custom_viewport_size_;
957 return GetViewBounds().size();
960 gfx::Rect RWHVAuraOffscreenHelperEfl::GetViewBounds() {
961 return gfx::ToEnclosingRect(
962 gfx::ConvertRectToDips(GetViewBoundsInPix(), device_scale_factor_));
965 gfx::Point RWHVAuraOffscreenHelperEfl::ConvertPointInViewPix(gfx::Point point) {
966 return gfx::ToFlooredPoint(
967 gfx::ScalePoint(gfx::PointF(point), device_scale_factor_));
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_));
977 void RWHVAuraOffscreenHelperEfl::SelectClosestWord(
978 const gfx::Point& touch_point) {
980 EvasToBlinkCords(touch_point.x(), touch_point.y(), &view_x, &view_y);
982 rwhva()->host()->SelectClosestWord(view_x, view_y);
985 gfx::Size RWHVAuraOffscreenHelperEfl::GetPhysicalBackingSize() const {
987 evas_object_geometry_get(content_image_elm_host_, nullptr, nullptr, &w, &h);
988 return gfx::Size(w, h);
991 int RWHVAuraOffscreenHelperEfl::GetTopControlsHeight() {
993 evas_object_geometry_get(content_image_, nullptr, &y, nullptr, nullptr);
997 gfx::Rect RWHVAuraOffscreenHelperEfl::GetViewBoundsInPix() const {
999 evas_object_geometry_get(content_image_, &x, &y, &w, &h);
1000 return gfx::Rect(x, y, w, h);
1003 const gfx::Size RWHVAuraOffscreenHelperEfl::GetScrollableSize() const {
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)
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)
1023 return gfx::Size(width, height);
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())
1034 evas_object_move(image, rect.x, rect.y);
1035 evas_object_show(image);
1037 voice_manager_labels_.push_back(image);
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]);
1045 voice_manager_labels_.clear();
1049 EdgeEffect& RWHVAuraOffscreenHelperEfl::EnsureEdgeEffect() {
1050 if (!edge_effect_) {
1051 edge_effect_ = base::WrapUnique(new EdgeEffect(content_image_));
1052 edge_effect_->UpdateRect();
1055 return *edge_effect_.get();
1058 void RWHVAuraOffscreenHelperEfl::HandleGestureBegin() {
1059 EnsureEdgeEffect().Enable();
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();
1068 void RWHVAuraOffscreenHelperEfl::GetMagnifierSnapshot(
1069 gfx::Rect snapshot_area,
1071 std::unique_ptr<ScreenshotCapturedCallback> cb) {
1072 #if defined(USE_TTRACE)
1073 TTRACE(TTRACE_TAG_WEB,
1074 "RenderWidgetHostViewAuraHelperEfl::GetMagnifierSnapshot");
1076 // GetSnapshot might be replaced with something designed for magnifier.
1077 Evas_Object* image = GetSnapshot(snapshot_area, scale_factor, true);
1079 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1080 FROM_HERE, base::BindOnce(&ScreenshotCapturedCallback::Run,
1081 base::Owned(cb.release()),
1082 base::Unretained((void*)image)));
1085 void RWHVAuraOffscreenHelperEfl::RequestMagnifierSnapshotAsync(
1086 const Eina_Rectangle rect,
1087 Screenshot_Captured_Callback callback,
1089 float scale_factor) {
1090 gfx::Rect snapshot_area(rect.x, rect.y, rect.w, rect.h);
1091 gfx::Rect view_rect = GetViewBoundsInPix();
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);
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)));
1112 void RWHVAuraOffscreenHelperEfl::HandleGesture(blink::WebGestureEvent& event) {
1113 RWHVAuraCommonHelperEfl::HandleGesture(event);
1115 blink::WebInputEvent::Type event_type = event.GetType();
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);
1140 #if BUILDFLAG(IS_TIZEN)
1141 void RWHVAuraOffscreenHelperEfl::OnEdgeEffectForUIF(bool top,
1145 EnsureEdgeEffect().Enable();
1148 EnsureEdgeEffect().ShowOrHide(EdgeEffect::Direction::TOP, true);
1150 EnsureEdgeEffect().ShowOrHide(EdgeEffect::Direction::BOTTOM, true);
1152 EnsureEdgeEffect().ShowOrHide(EdgeEffect::Direction::LEFT, true);
1154 EnsureEdgeEffect().ShowOrHide(EdgeEffect::Direction::RIGHT, true);
1156 EnsureEdgeEffect().Hide();
1157 EnsureEdgeEffect().Disable();
1161 void RWHVAuraOffscreenHelperEfl::DidOverscroll(
1162 const ui::DidOverscrollParams& params) {
1163 RWHVAuraCommonHelperEfl::DidOverscroll(params);
1165 const gfx::Vector2dF& accumulated_overscroll = params.accumulated_overscroll;
1166 const gfx::Vector2dF& latest_overscroll_delta =
1167 params.latest_overscroll_delta;
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);
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);
1181 if (latest_overscroll_delta.y() > 0 && (int)accumulated_overscroll.y() > 0)
1182 EnsureEdgeEffect().ShowOrHide(EdgeEffect::Direction::BOTTOM, true);
1186 void RWHVAuraOffscreenHelperEfl::UpdateEdgeEffect() {
1187 EnsureEdgeEffect().UpdateRect();
1190 } // namespace content