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/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"
33 #define MAX_SURFACE_WIDTH_EGL 4096 // max supported Framebuffer width
34 #define MAX_SURFACE_HEIGHT_EGL 4096 // max supported Framebuffer height
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)
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;
48 class ScreenshotCapturedCallback {
50 ScreenshotCapturedCallback(Screenshot_Captured_Callback func, void* user_data)
51 : func_(func), user_data_(user_data) {}
52 void Run(Evas_Object* image) {
54 (func_)(image, user_data_);
58 Screenshot_Captured_Callback func_;
62 class RenderWidgetHostHelperAura : public RenderWidgetHostHelper {
64 explicit RenderWidgetHostHelperAura(RWHVAuraOffscreenHelperEfl* rwhv_helper)
65 : rwhv_helper_(rwhv_helper) {}
66 ~RenderWidgetHostHelperAura() override = default;
68 bool HasRenderWidgetHost() const override {
69 return !!rwhv_helper_->GetRenderWidgetHostImpl();
72 void ExtendSelectionAndDelete(int32_t before, int32_t after) override {
73 auto* handler = GetFrameWidgetInputHandler();
77 handler->ExtendSelectionAndDelete(before, after);
80 void SetCompositionFromExistingText(
83 const std::vector<ui::ImeTextSpan>& ime_text_spans) override {
84 auto* handler = GetFrameWidgetInputHandler();
88 handler->SetCompositionFromExistingText(start, end, ime_text_spans);
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();
99 rwhi->ImeCommitText(text, ime_text_spans, replacement_range,
100 relative_cursor_pos);
103 void ImeFinishComposingText(bool keep_selection) override {
104 auto* rwhi = rwhv_helper_->GetRenderWidgetHostImpl();
108 rwhi->ImeFinishComposingText(keep_selection);
111 void ImeSetComposition(const std::u16string& text,
112 const std::vector<ui::ImeTextSpan>& ime_text_spans,
113 const gfx::Range& replacement_range,
115 int selection_end) override {
116 auto* rwhi = rwhv_helper_->GetRenderWidgetHostImpl();
120 rwhi->ImeSetComposition(text, ime_text_spans, replacement_range,
121 selection_start, selection_end);
124 bool ExistsSelectedText() override { return false; }
126 bool ImeHandleKeyEventEnabled() override { return true; }
128 gfx::Size GetPhysicalBackingSize() const override {
129 return rwhv_helper_->GetPhysicalBackingSize();
132 Evas_Object* EwkView() const override { return rwhv_helper_->ewk_view(); }
135 blink::mojom::FrameWidgetInputHandler* GetFrameWidgetInputHandler() const {
136 auto* rwhi = rwhv_helper_->GetRenderWidgetHostImpl();
140 return rwhi->GetFrameWidgetInputHandler();
143 RWHVAuraOffscreenHelperEfl* rwhv_helper_;
146 RWHVAuraOffscreenHelperEfl::RWHVAuraOffscreenHelperEfl(
147 RenderWidgetHostViewAura* rwhva,
148 WebContents* web_contents)
150 web_contents_(web_contents),
151 rwh_helper_(std::make_unique<RenderWidgetHostHelperAura>(this)) {
155 RWHVAuraOffscreenHelperEfl::~RWHVAuraOffscreenHelperEfl() {
156 if (evas_gl_surface_) {
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_);
164 LOG(WARNING) << "Failed to unbind gl context";
166 if (evas_gl_context_)
167 evas_gl_context_destroy(evas_gl_, evas_gl_context_);
169 evas_gl_config_free(evas_gl_config_);
171 evas_gl_free(evas_gl_);
173 elm_object_part_content_unset(content_image_elm_host_, "overlay");
174 evas_object_event_callback_del(content_image_, EVAS_CALLBACK_FOCUS_IN,
176 evas_object_event_callback_del(content_image_, EVAS_CALLBACK_FOCUS_OUT,
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_);
183 content_image_elm_host_ = nullptr;
184 content_image_ = nullptr;
185 parent_view_ = nullptr;
188 void RWHVAuraOffscreenHelperEfl::Initialize() {
190 static_cast<WebContentsImpl*>(web_contents_)->GetEflNativeView();
191 evas_ = evas_object_evas_get(parent_view_);
195 evas_object_event_callback_add(parent_view_, EVAS_CALLBACK_RESIZE,
196 OnParentViewResize, this);
197 evas_object_show(content_image_);
199 device_scale_factor_ =
200 display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor();
202 snapshot_timer_.reset(new base::OneShotTimer);
205 void RWHVAuraOffscreenHelperEfl::SetAuraParentWindow(
206 gfx::NativeView parent_window) {
207 aura_parent_window_ = parent_window;
210 void RWHVAuraOffscreenHelperEfl::AuraChildWindowAdded() {
211 aura::WindowTreeHost* window_host = rwhv_aura_->window()->GetHost();
215 static_cast<aura::WindowTreeHostPlatform*>(window_host)
217 ->SetNativeViewOffscreen(content_image_);
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,
222 evas_object_event_callback_add(content_image_, EVAS_CALLBACK_FOCUS_OUT,
227 void RWHVAuraOffscreenHelperEfl::OnParentViewResize(void* data,
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();
236 window_host->SetBoundsInPixels(new_bounds);
238 aura::Window* parent_window = thiz->aura_parent_window_;
240 parent_window->SetBounds(new_bounds);
243 bool RWHVAuraOffscreenHelperEfl::ClearCurrent() {
244 return evas_gl_make_current(evas_gl_, 0, 0);
247 bool RWHVAuraOffscreenHelperEfl::MakeCurrent() {
248 return evas_gl_make_current(evas_gl_, evas_gl_surface_, evas_gl_context_);
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);
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"
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"
267 " v_texCoord = a_texCoord; \n"
270 static const char kFragmentShaderSourceSimple[] =
271 "precision mediump float; \n"
272 "varying vec2 v_texCoord; \n"
273 "uniform sampler2D s_texture; \n"
275 " gl_FragColor = texture2D( s_texture, v_texCoord );\n"
278 static void GLCheckProgramHelper(Evas_GL_API* api,
283 api->glGetProgramiv(program, GL_LINK_STATUS, &status);
287 const GLsizei buf_length = 2048;
288 std::unique_ptr<GLchar[]> log(new GLchar[buf_length]);
290 api->glGetProgramInfoLog(program, buf_length, &length, log.get());
291 LOG(ERROR) << "GL program link failed in: " << file << ":" << line << ":"
293 api->glDeleteProgram(program);
296 #define GLCheckProgram(api, program) \
297 GLCheckProgramHelper(api, program, __FILE__, __LINE__)
299 static void GLCheckShaderHelper(Evas_GL_API* api,
304 api->glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
308 const GLsizei buf_length = 2048;
309 std::unique_ptr<GLchar[]> log(new GLchar[buf_length]);
311 api->glGetShaderInfoLog(shader, buf_length, &length, log.get());
312 LOG(ERROR) << "GL shader compile failed in " << file << ":" << line << ":"
314 api->glDeleteShader(shader);
317 #define GLCheckShader(api, shader) \
318 GLCheckShaderHelper((api), (shader), __FILE__, __LINE__)
320 void RWHVAuraOffscreenHelperEfl::InitializeProgram() {
321 evas_gl_make_current(evas_gl_, evas_gl_surface_, evas_gl_context_);
323 // GL_CHECK_STATUS("GL Error before program initialization");
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");
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};
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);
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);
347 evas_gl_api_->glShaderSource(vertexShader, 1, &vertexShaderSourceProgram, 0);
348 evas_gl_api_->glShaderSource(fragmentShader, 1, &fragmentShaderSourceProgram,
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);
365 evas_gl_api_->glGetAttribLocation(program_id_, "a_position");
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);
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);
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_);
385 evas_gl_api_->glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_obj_);
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,
397 (void*)(3 * sizeof(GLfloat)));
398 evas_gl_api_->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_obj_);
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);
412 evas_gl_api_->glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL);
414 evas_gl_api_->glBindTexture(GL_TEXTURE_2D, 0);
415 evas_gl_make_current(evas_gl_, 0, 0);
418 frame_rendered_ = true;
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;
432 evas_gl_ = evas_gl_new(evas_);
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;
438 evas_gl_context_ = evas_gl_context_version_create(
439 evas_gl_, GLSharedContextEfl::GetEvasGLContext(), context_version);
441 if (!evas_gl_context_)
442 LOG(FATAL) << "Failed to create evas gl context";
444 evas_gl_api_ = evas_gl_context_api_get(evas_gl_, evas_gl_context_);
446 CreateNativeSurface();
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)
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;
461 if (!content_image_) {
462 content_image_ = evas_object_image_filled_add(evas_);
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",
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_);
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);
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_);
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";
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);
500 LOG(FATAL) << "Failed to get native surface";
503 return gfx::Size(width, height);
507 void RWHVAuraOffscreenHelperEfl::EvasObjectImagePixelsGetCallback(
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_);
519 void RWHVAuraOffscreenHelperEfl::NotifySwap(const uint32_t texture_id) {
520 if (texture_id <= 0) {
521 LOG(ERROR) << __FUNCTION__ << " invalid texture id ";
524 texture_id_ = texture_id;
525 evas_object_image_pixels_dirty_set(content_image_, true);
528 void RWHVAuraOffscreenHelperEfl::Focus(bool focus) {
529 elm_object_focus_set(content_image_elm_host_, focus);
530 evas_object_focus_set(content_image_, focus);
533 bool RWHVAuraOffscreenHelperEfl::HasFocus() {
534 return evas_object_focus_get(content_image_);
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;
544 void RWHVAuraOffscreenHelperEfl::OnFocusIn(void* data,
548 RWHVAuraOffscreenHelperEfl* thiz =
549 static_cast<RWHVAuraOffscreenHelperEfl*>(data);
552 if (IsMobileProfile() && thiz->GetSelectionController()) {
553 thiz->GetSelectionController()->ShowHandleAndContextMenuIfRequired();
556 if (!thiz->on_focus_in_callback_.is_null())
557 thiz->on_focus_in_callback_.Run();
560 void RWHVAuraOffscreenHelperEfl::OnFocusOut(void* data,
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())
570 aura::Window* focused_window =
571 aura::client::GetFocusClient(window_host->window())->GetFocusedWindow();
573 focused_window->LostFocus();
575 if (IsMobileProfile() && thiz->GetSelectionController()) {
576 thiz->GetSelectionController()->HideHandleAndContextMenu();
579 if (!thiz->on_focus_out_callback_.is_null())
580 thiz->on_focus_out_callback_.Run();
583 void RWHVAuraOffscreenHelperEfl::OnHostFocusIn(void* data,
586 RWHVAuraOffscreenHelperEfl* thiz =
587 static_cast<RWHVAuraOffscreenHelperEfl*>(data);
591 void RWHVAuraOffscreenHelperEfl::OnHostFocusOut(void* data,
594 RWHVAuraOffscreenHelperEfl* thiz =
595 static_cast<RWHVAuraOffscreenHelperEfl*>(data);
596 thiz->GetRenderWidgetHostImpl()->Blur();
599 void RWHVAuraOffscreenHelperEfl::OnMouseOrTouchEvent(ui::Event* event) {
600 if (event->type() == ui::ET_MOUSE_PRESSED ||
601 event->type() == ui::ET_TOUCH_PRESSED) {
606 void RWHVAuraOffscreenHelperEfl::DidHandleKeyEvent(
607 blink::WebInputEvent::Type input_event_type,
609 if (!GetIMContextEfl())
612 bool is_keydown = false;
613 switch (input_event_type) {
614 case blink::WebInputEvent::Type::kRawKeyDown:
615 case blink::WebInputEvent::Type::kKeyDown:
617 case blink::WebInputEvent::Type::kKeyUp:
618 GetIMContextEfl()->HandleKeyEvent(is_keydown, processed);
622 void RWHVAuraOffscreenHelperEfl::SelectionChanged(const std::u16string& text,
624 const gfx::Range& range) {
625 if (range.start() == range.end() && GetIMContextEfl())
626 GetIMContextEfl()->SetCaretPosition(range.start());
628 if (!GetSelectionController())
631 std::u16string selectedText;
632 if (!text.empty() && !range.is_empty())
633 selectedText = rwhv_aura_->GetSelectedText();
634 GetSelectionController()->UpdateSelectionData(selectedText);
637 void RWHVAuraOffscreenHelperEfl::EvasToBlinkCords(int x,
641 gfx::Rect view_bounds = GetViewBoundsInPix();
643 *view_x = x - view_bounds.x();
644 *view_x /= device_scale_factor_;
647 *view_y = y - view_bounds.y();
648 *view_y /= device_scale_factor_;
652 void RWHVAuraOffscreenHelperEfl::OnEvasRenderFlushPre(void* data,
655 RWHVAuraOffscreenHelperEfl* rwhv_helper =
656 static_cast<RWHVAuraOffscreenHelperEfl*>(data);
657 if (rwhv_helper && rwhv_helper->snapshot_task_list_.size() > 0)
658 rwhv_helper->ProcessSnapshotRequest();
661 void RWHVAuraOffscreenHelperEfl::InvalidateForSnapshot() {
662 evas_object_image_pixels_dirty_set(content_image_, true);
665 void RWHVAuraOffscreenHelperEfl::ProcessSnapshotRequest() {
666 if (!frame_rendered_)
669 // Process all snapshot requests pending now.
670 for (auto& task : snapshot_task_list_) {
672 std::move(task).Run();
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);
684 void RWHVAuraOffscreenHelperEfl::RunGetSnapshotOnMainThread(
685 const gfx::Rect snapshot_area,
687 float scale_factor) {
688 #if defined(USE_TTRACE)
689 TTRACE(TTRACE_TAG_WEB,
690 "RWHVAuraOffscreenHelperEfl::RunGetSnapshotOnMainThread");
692 ScreenshotCapturedCallback* callback =
693 screen_capture_cb_map_.Lookup(request_id);
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);
703 Evas_Object* RWHVAuraOffscreenHelperEfl::GetSnapshot(
704 const gfx::Rect& snapshot_area,
707 #if defined(USE_TTRACE)
708 TTRACE(TTRACE_TAG_WEB, "RWHVAuraOffscreenHelperEfl::GetSnapshot");
710 if (scale_factor == 0.0)
714 display::Screen::GetScreen()->GetPrimaryDisplay().RotationAsDegree();
716 bool is_evasgl_direct_landscape = false;
717 // For EvasGL Direct Rendering in landscape mode
719 is_evasgl_direct_landscape = ((rotation == 90 || rotation == 270) &&
720 !evas_gl_rotation_get(evas_gl_));
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();
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) {
739 const gfx::Size surface_size =
740 (is_direct_rendering) ? window_rect.size() : view_rect.size();
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();
748 // Convert |snapshot_area| to absolute coordinate.
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;
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;
766 std::swap(width, height);
768 // (0,0) is bottom left corner in opengl coordinate system.
769 y = surface_size.height() - y - height;
772 int size = width * height * sizeof(GLuint);
773 GLuint* data = (GLuint*)malloc(size);
775 LOG(ERROR) << "Failed to allocate memory for snapshot";
780 #if defined(USE_TTRACE)
781 TTRACE(TTRACE_TAG_WEB,
782 "RWHVAuraOffscreenHelperEfl::GetSnapshot(ReadPixels)");
784 if (!MakeCurrent()) {
785 LOG(ERROR) << "MakeCurrent() failed.";
790 evas_gl_api_->glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
795 if (!is_evasgl_direct_landscape && (rotation == 90 || rotation == 270))
796 std::swap(width, height);
799 static int frame_number = 0;
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");
807 fwrite(data, width * height * 4, 1, fp);
811 LOG(ERROR) << "Unable to open file";
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) |
823 px2 = ((px2 & 0xff) << 16) | ((px2 >> 16) & 0xff) | (px2 & 0xff00ff00) |
830 if (scale_factor != 1.0 || rotation) {
831 bitmap.setInfo(SkImageInfo::MakeN32Premul(width, height));
832 bitmap.setPixels(data);
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);
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);
854 if (rotation == 90 || rotation == 270)
855 std::swap(width, height);
857 Evas_Object* image = evas_object_image_filled_add(evas_);
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);
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");
876 void RWHVAuraOffscreenHelperEfl::RequestSnapshotAsync(
877 const gfx::Rect& snapshot_area,
878 Screenshot_Captured_Callback callback,
880 float scale_factor) {
881 #if defined(USE_TTRACE)
882 TTRACE(TTRACE_TAG_WEB, "RWHVAuraOffscreenHelperEfl::RequestSnapshotAsync");
884 ScreenshotCapturedCallback* cb =
885 new ScreenshotCapturedCallback(callback, user_data);
887 int request_id = screen_capture_cb_map_.Add(base::WrapUnique(cb));
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));
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);
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)));
909 // Sends message to renderer to capture the content snapshot of the view.
910 rwhv_aura_->host()->RequestContentSnapshot(snapshot_area, scale_factor,
915 void RWHVAuraOffscreenHelperEfl::DidGetContentSnapshot(const SkBitmap& bitmap,
916 const int request_id) {
917 ScreenshotCapturedCallback* callback =
918 screen_capture_cb_map_.Lookup(request_id);
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());
928 callback->Run(image);
929 screen_capture_cb_map_.Remove(request_id);
932 Evas_Object* RWHVAuraOffscreenHelperEfl::ewk_view() const {
933 auto wci = static_cast<WebContentsImpl*>(web_contents_);
937 return static_cast<Evas_Object*>(wci->ewk_view());
940 void RWHVAuraOffscreenHelperEfl::FocusRWHVA() {
941 if (!rwhv_aura_->HasFocus())
945 void RWHVAuraOffscreenHelperEfl::Show() {
946 evas_object_show(content_image_elm_host_);
949 void RWHVAuraOffscreenHelperEfl::Hide() {
950 evas_object_hide(content_image_elm_host_);
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();
961 gfx::Size RWHVAuraOffscreenHelperEfl::GetVisibleViewportSize() {
962 if (!custom_viewport_size_.IsEmpty())
963 return custom_viewport_size_;
964 return GetViewBounds().size();
967 gfx::Rect RWHVAuraOffscreenHelperEfl::GetViewBounds() {
968 return gfx::ToEnclosingRect(
969 gfx::ConvertRectToDips(GetViewBoundsInPix(), device_scale_factor_));
972 void RWHVAuraOffscreenHelperEfl::SetPageVisibility(bool visible) {
973 LOG(INFO) << __FUNCTION__ << ", visible : " << visible;
975 // Triggers RWHVA::ShowWithVisibility followed by RWHVAHelperEfl::Show
976 web_contents_->WasShown();
978 // Triggers RWHVA::Hide followed by RWHVAHelperEfl::Hide
979 web_contents_->WasHidden();
983 RenderWidgetHostImpl* RWHVAuraOffscreenHelperEfl::GetRenderWidgetHostImpl() {
984 return rwhv_aura_->host();
987 ui::EflEventHandler* RWHVAuraOffscreenHelperEfl::GetEventHandler() {
988 aura::WindowTreeHost* window_host = rwhv_aura_->window()->GetHost();
992 return static_cast<aura::WindowTreeHostPlatform*>(window_host)
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_;
1006 LOG(ERROR) << "im_context_efl_ is not set";
1009 return im_context_efl_;
1012 gfx::NativeView RWHVAuraOffscreenHelperEfl::GetNativeView() {
1013 return rwhv_aura_->GetNativeView();
1016 gfx::Point RWHVAuraOffscreenHelperEfl::ConvertPointInViewPix(gfx::Point point) {
1017 return gfx::ToFlooredPoint(
1018 gfx::ScalePoint(gfx::PointF(point), device_scale_factor_));
1021 void RWHVAuraOffscreenHelperEfl::TextInputStateChanged(
1022 const ui::mojom::TextInputState& params) {
1023 auto im_context = GetIMContextEfl();
1025 LOG(ERROR) << "im_context is nullptr";
1029 #if BUILDFLAG(IS_TIZEN_TV)
1030 if (!rwhv_aura_->IsShowing() || !HasFocus())
1032 if (!rwhv_aura_->IsShowing())
1036 bool show_ime_if_needed = params.show_ime_if_needed;
1038 if (show_ime_if_needed && !params.is_user_action)
1039 show_ime_if_needed = false;
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;
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_);
1058 im_context->UpdateInputMethodState(params.type, params.can_compose_inline,
1059 show_ime_if_needed);
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_));
1071 void RWHVAuraOffscreenHelperEfl::SelectClosestWord(
1072 const gfx::Point& touch_point) {
1074 EvasToBlinkCords(touch_point.x(), touch_point.y(), &view_x, &view_y);
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
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
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;
1100 void RWHVAuraOffscreenHelperEfl::FocusedNodeChanged(
1102 #if BUILDFLAG(IS_TIZEN_TV)
1104 bool is_radio_or_checkbox,
1105 int password_input_minlength,
1109 bool is_content_editable) {
1110 is_content_editable_ = is_content_editable;
1111 #if defined(USE_WAYLAND)
1112 ClipboardHelperEfl::GetInstance()->SetContentEditable(is_content_editable);
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;
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();
1129 // add ime focus out when focus out from an editable node.
1130 im_context->OnFocusOut();
1133 is_focused_node_editable_ = editable;
1136 gfx::Size RWHVAuraOffscreenHelperEfl::GetPhysicalBackingSize() const {
1138 evas_object_geometry_get(content_image_elm_host_, nullptr, nullptr, &w, &h);
1139 return gfx::Size(w, h);
1142 int RWHVAuraOffscreenHelperEfl::GetTopControlsHeight() {
1144 evas_object_geometry_get(content_image_, nullptr, &y, nullptr, nullptr);
1148 gfx::Rect RWHVAuraOffscreenHelperEfl::GetViewBoundsInPix() const {
1150 evas_object_geometry_get(content_image_, &x, &y, &w, &h);
1151 return gfx::Rect(x, y, w, h);
1154 const gfx::Size RWHVAuraOffscreenHelperEfl::GetScrollableSize() const {
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)
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)
1174 return gfx::Size(width, height);
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())
1185 evas_object_move(image, rect.x, rect.y);
1186 evas_object_show(image);
1188 voice_manager_labels_.push_back(image);
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]);
1196 voice_manager_labels_.clear();
1200 void RWHVAuraOffscreenHelperEfl::OnGetMainFrameScrollbarVisible(int callback_id,
1202 web_contents_->GetDelegate()->OnGetMainFrameScrollbarVisible(callback_id,
1206 void RWHVAuraOffscreenHelperEfl::OnGetFocusedNodeBounds(
1207 const gfx::RectF& rect) {
1208 web_contents_->GetDelegate()->OnDidChangeFocusedNodeBounds(rect);
1211 void RWHVAuraOffscreenHelperEfl::BackgroundColorReceived(int callback_id,
1213 web_contents_->GetDelegate()->BackgroundColorReceived(callback_id, bg_color);
1216 void RWHVAuraOffscreenHelperEfl::SetTouchEventsEnabled(bool enabled) {
1217 if (auto* event_handler = GetEventHandler())
1218 event_handler->SetTouchEventsEnabled(enabled);
1221 bool RWHVAuraOffscreenHelperEfl::TouchEventsEnabled() {
1222 if (auto* event_handler = GetEventHandler())
1223 return event_handler->TouchEventsEnabled();
1228 } // namespace content