[M47_2526] Chromium upversion to m47_2526 branch
[platform/framework/web/chromium-efl.git] / tizen_src / ewk / efl_integration / renderer / render_view_observer_efl.cc
1 // Copyright 2014 Samsung Electronics. 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 "renderer/render_view_observer_efl.h"
6
7 #include <string>
8 #include <limits.h>
9
10 #include "base/files/file_path.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "content/public/renderer/content_renderer_client.h"
16 #include "content/public/renderer/render_view.h"
17 #include "common/render_messages_ewk.h"
18 #include "common/hit_test_params.h"
19 #include "third_party/WebKit/public/platform/WebCString.h"
20 #include "third_party/WebKit/public/platform/WebData.h"
21 #include "third_party/WebKit/public/platform/WebPoint.h"
22 #include "third_party/WebKit/public/platform/WebSize.h"
23 #include "third_party/WebKit/public/platform/WebString.h"
24 #include "third_party/WebKit/public/platform/WebURLError.h"
25 #include "third_party/WebKit/public/platform/WebURLRequest.h"
26 #include "third_party/WebKit/public/web/WebDocument.h"
27 #include "third_party/WebKit/public/web/WebDataSource.h"
28 #include "third_party/WebKit/public/web/WebFormElement.h"
29 #include "third_party/WebKit/public/web/WebFrame.h"
30 #include "third_party/WebKit/public/web/WebHitTestResult.h"
31 #include "third_party/WebKit/public/web/WebInputEvent.h"
32 #include "third_party/WebKit/public/web/WebLocalFrame.h"
33 #include "third_party/WebKit/public/web/WebPageSerializer.h"
34 #include "third_party/WebKit/public/web/WebView.h"
35 #include "third_party/WebKit/public/web/WebNodeList.h"
36
37 // XXX: config.h needs to be included before internal blink headers.
38 //      It'd be great if we did not include not internal blibk headers.
39 #include "third_party/WebKit/Source/config.h"
40 #include "third_party/WebKit/Source/platform/fonts/FontCache.h"
41
42 using blink::WebDataSource;
43 using blink::WebURLRequest;
44
45 namespace {
46
47 #if !defined(EWK_BRINGUP)
48 typedef blink::WebDocument::WebContentSecurityPolicyHeaderType SecurityPolicyHeaderType;
49
50 COMPILE_ASSERT(
51     int(SecurityPolicyHeaderType::WebContentSecurityPolicyHeaderTypeReport) ==
52     int(EWK_REPORT_ONLY), mismatching_enums);
53 COMPILE_ASSERT(
54     int(SecurityPolicyHeaderType::WebContentSecurityPolicyHeaderTypeEnforce) ==
55     int(EWK_ENFORCE_POLICY), mismatching_enums);
56
57 SecurityPolicyHeaderType ToSecurityPolicyHeaderType(Ewk_CSP_Header_Type type) {
58   return static_cast<SecurityPolicyHeaderType>(type);
59 }
60 #endif
61
62 bool GetGRBAValuesFromString(const std::string& input, int* r, int* g, int* b, int* a)
63 {
64   bool parsing_status = false;
65   // for example - rgba(255, 255, 255, 255)
66   // for example - rgb(255, 255, 255)
67   if (std::string::npos != input.find("rgb")) {
68     size_t startPos = input.find("(");
69     size_t endPos = input.find(")");
70
71     std::string value = input.substr(startPos + 1, endPos - startPos - 1);
72     std::vector<std::string> colorValues = base::SplitString(value,
73                                                              ",",
74                                                              base::TRIM_WHITESPACE,
75                                                              base::SPLIT_WANT_ALL);
76     if (colorValues.size() == 4 || colorValues.size() == 3) {
77       base::StringToInt(colorValues[0], r);
78       base::StringToInt(colorValues[1], g);
79       base::StringToInt(colorValues[2], b);
80       if (std::string::npos != input.find("rgba") && colorValues.size() == 4)
81         base::StringToInt(colorValues[3], a);
82       else
83         *a = 255;
84       parsing_status = true;
85     }
86   }
87   return parsing_status;
88 }
89
90 void PopulateEwkHitTestData(const blink::WebHitTestResult& web_hit_test, Hit_Test_Params* params)
91 {
92   DCHECK(params);
93   params->imageURI = web_hit_test.absoluteImageURL().string().utf8();
94   params->linkURI = web_hit_test.absoluteLinkURL().string().utf8();
95   params->mediaURI = web_hit_test.absoluteMediaURL().string().utf8();
96   params->linkLabel = web_hit_test.textContent().utf8();
97   params->linkTitle = web_hit_test.titleDisplayString().utf8();
98   params->isEditable = web_hit_test.isContentEditable();
99
100   int context = EWK_HIT_TEST_RESULT_CONTEXT_DOCUMENT;
101   if (!web_hit_test.absoluteLinkURL().isEmpty())
102     context |= EWK_HIT_TEST_RESULT_CONTEXT_LINK;
103   if (!web_hit_test.absoluteImageURL().isEmpty())
104     context |= EWK_HIT_TEST_RESULT_CONTEXT_IMAGE;
105   if (!web_hit_test.absoluteMediaURL().isEmpty())
106     context |= EWK_HIT_TEST_RESULT_CONTEXT_MEDIA;;
107   if (web_hit_test.isSelected())
108     context |= EWK_HIT_TEST_RESULT_CONTEXT_SELECTION;
109   if (web_hit_test.isContentEditable())
110     context |= EWK_HIT_TEST_RESULT_CONTEXT_EDITABLE;
111   if (web_hit_test.node().isTextNode())
112     context |= EWK_HIT_TEST_RESULT_CONTEXT_TEXT;
113
114   params->context = static_cast<Ewk_Hit_Test_Result_Context>(context);
115
116   if (params->mode & EWK_HIT_TEST_MODE_NODE_DATA) {
117     params->nodeData.nodeValue = web_hit_test.node().nodeValue().utf8();
118   }
119
120   if ((params->mode & EWK_HIT_TEST_MODE_IMAGE_DATA) &&
121       (params->context & EWK_HIT_TEST_RESULT_CONTEXT_IMAGE)) {
122     blink::WebElement hit_element = web_hit_test.node().toConst<blink::WebElement>();
123
124     params->imageData.imageBitmap = hit_element.imageContents().getSkBitmap();
125     params->imageData.fileNameExtension = hit_element.imageFilenameExtension().utf8();
126   }
127 }
128
129 void PopulateNodeAttributesMapFromHitTest(const blink::WebHitTestResult& web_hit_test,
130                                           Hit_Test_Params* params)
131 {
132   DCHECK(params);
133
134   if (!web_hit_test.node().isElementNode())
135     return;
136
137   blink::WebElement hit_element = web_hit_test.node().toConst<blink::WebElement>();
138   for (unsigned int i = 0; i < hit_element.attributeCount(); i++) {
139     params->nodeData.attributes.insert(std::pair<std::string, std::string>(
140         hit_element.attributeLocalName(i).utf8(), hit_element.attributeValue(i).utf8()));
141   }
142 }
143
144 }  //namespace
145
146 RenderViewObserverEfl::RenderViewObserverEfl(
147     content::RenderView* render_view,
148     ContentRendererClientEfl* render_client)
149   : content::RenderViewObserver(render_view),
150     cached_min_page_scale_factor_(-1.0),
151     cached_max_page_scale_factor_(-1.0),
152     link_effect_enabled_(true),
153     renderer_client_(render_client)
154 {
155 }
156
157 RenderViewObserverEfl::~RenderViewObserverEfl()
158 {
159 }
160
161 bool RenderViewObserverEfl::OnMessageReceived(const IPC::Message& message)
162 {
163   bool handled = true;
164   IPC_BEGIN_MESSAGE_MAP(RenderViewObserverEfl, message)
165     IPC_MESSAGE_HANDLER(EwkViewMsg_SetCSP, OnSetContentSecurityPolicy)
166     IPC_MESSAGE_HANDLER(EwkViewMsg_Scale, OnScale)
167     IPC_MESSAGE_HANDLER(EwkViewMsg_SetScroll, OnSetScroll)
168     IPC_MESSAGE_HANDLER(EwkViewMsg_UseSettingsFont, OnUseSettingsFont)
169     IPC_MESSAGE_HANDLER(EwkViewMsg_PlainTextGet, OnPlainTextGet)
170     IPC_MESSAGE_HANDLER(EwkViewMsg_GetSelectionStyle, OnGetSelectionStyle);
171     IPC_MESSAGE_HANDLER(EwkViewMsg_DoHitTest, OnDoHitTest)
172     IPC_MESSAGE_HANDLER(EwkViewMsg_DoHitTestAsync, OnDoHitTestAsync)
173     IPC_MESSAGE_HANDLER(EwkViewMsg_PrintToPdf, OnPrintToPdf)
174     IPC_MESSAGE_HANDLER(EwkViewMsg_GetMHTMLData, OnGetMHTMLData);
175     IPC_MESSAGE_HANDLER(EwkViewMsg_WebAppIconUrlGet, OnWebAppIconUrlGet);
176     IPC_MESSAGE_HANDLER(EwkViewMsg_WebAppIconUrlsGet, OnWebAppIconUrlsGet);
177     IPC_MESSAGE_HANDLER(EwkViewMsg_WebAppCapableGet, OnWebAppCapableGet);
178     IPC_MESSAGE_HANDLER(EwkViewMsg_SetDrawsTransparentBackground, OnSetDrawsTransparentBackground);
179     IPC_MESSAGE_HANDLER(EwkViewMsg_SetBrowserFont, OnSetBrowserFont);
180     IPC_MESSAGE_HANDLER(EwkViewMsg_SuspendScheduledTask, OnSuspendScheduledTasks);
181     IPC_MESSAGE_HANDLER(EwkViewMsg_ResumeScheduledTasks, OnResumeScheduledTasks);
182     IPC_MESSAGE_HANDLER(EflViewMsg_UpdateSettings, OnUpdateSettings);
183     IPC_MESSAGE_HANDLER(ViewMsg_SetViewMode, OnSetViewMode);
184
185     IPC_MESSAGE_UNHANDLED(handled = false)
186   IPC_END_MESSAGE_MAP()
187   return handled;
188 }
189
190 void RenderViewObserverEfl::DidCreateDocumentElement(blink::WebLocalFrame* frame)
191 {
192   std::string policy;
193   Ewk_CSP_Header_Type type = EWK_DEFAULT_POLICY;
194   Send(new EwkHostMsg_GetContentSecurityPolicy(render_view()->GetRoutingID(), &policy, &type));
195
196 #if !defined(EWK_BRINGUP)
197   // Since, Webkit supports some more types and we cast ewk type to Webkit type.
198   // We allow only ewk types.
199   if (type == EWK_REPORT_ONLY || type == EWK_ENFORCE_POLICY) {
200     frame->document().setContentSecurityPolicyUsingHeader(
201         blink::WebString::fromUTF8(policy), ToSecurityPolicyHeaderType(type));
202   }
203 #endif
204 }
205
206 void RenderViewObserverEfl::OnSetContentSecurityPolicy(const std::string& policy, Ewk_CSP_Header_Type header_type)
207 {
208   blink::WebView* view = render_view()->GetWebView();
209   DCHECK(view);
210   blink::WebDocument document = view->mainFrame()->document();
211 #if !defined(EWK_BRINGUP)
212   document.setContentSecurityPolicyUsingHeader(blink::WebString::fromUTF8(policy),
213       ToSecurityPolicyHeaderType(header_type));
214 #endif
215 }
216
217 void RenderViewObserverEfl::OnScale(double scale_factor, int x, int y)
218 {
219   blink::WebView* view = render_view()->GetWebView();
220   if (!view)
221     return;
222
223   view->setPageScaleFactor(scale_factor,
224                            blink::WebPoint(x, y));
225 }
226
227 void RenderViewObserverEfl::OnSetScroll(int x, int y)
228 {
229   blink::WebFrame* frame = render_view()->GetWebView()->mainFrame();
230   if (!frame)
231     return;
232   frame->setScrollOffset(blink::WebSize(x, y));
233 }
234
235 void RenderViewObserverEfl::OnUseSettingsFont()
236 {
237   blink::FontCache::fontCache()->invalidate();
238
239 #if !defined(EWK_BRINGUP)
240   blink::WebView* view = render_view()->GetWebView();
241   if (view)
242     view->sendResizeEventAndForceLayout();
243 #endif
244 }
245
246 void RenderViewObserverEfl::OnPlainTextGet(int plain_text_get_callback_id)
247 {
248   blink::WebFrame* frame = render_view()->GetWebView()->mainFrame();
249   if (!frame)
250     return;
251   blink::WebString content = frame->contentAsText(INT_MAX);
252   Send(new EwkHostMsg_PlainTextGetContents(render_view()->GetRoutingID(), content.utf8(), plain_text_get_callback_id));
253 }
254
255 void RenderViewObserverEfl::OnGetSelectionStyle()
256 {
257   blink::WebView* view = render_view()->GetWebView();
258   if (!view)
259     return;
260
261   blink::WebFrame* frame = view->focusedFrame();
262   if (!frame)
263     return;
264
265   SelectionStylePrams params;
266   params.underline_state = frame->commandState(blink::WebString::fromUTF8("underline"));
267   params.italic_state = frame->commandState(blink::WebString::fromUTF8("italic"));
268   params.bold_state = frame->commandState(blink::WebString::fromUTF8("bold"));
269   blink::WebString bg_color = frame->commandValue(blink::WebString::fromUTF8("BackColor"));
270   GetGRBAValuesFromString(std::string(bg_color.utf8()), &params.bg_color.r, &params.bg_color.g, &params.bg_color.b, &params.bg_color.a);
271   blink::WebString color = frame->commandValue(blink::WebString::fromUTF8("ForeColor"));
272   GetGRBAValuesFromString(std::string(color.utf8()), &params.color.r, &params.color.g, &params.color.b, &params.color.a);
273   blink::WebString  font_size = frame->commandValue(blink::WebString::fromUTF8("FontSize"));
274   params.font_size = font_size.utf8();
275   params.order_list_state = frame->commandState(blink::WebString::fromUTF8("InsertOrderedList"));
276   params.un_order_list_state = frame->commandState(blink::WebString::fromUTF8("InsertUnorderedList"));
277   params.text_align_center_state = frame->commandState(blink::WebString::fromUTF8("JustifyCenter"));
278   params.text_align_left_state = frame->commandState(blink::WebString::fromUTF8("JustifyLeft"));
279   params.text_align_right_state = frame->commandState(blink::WebString::fromUTF8("JustifyRight"));
280   params.text_align_full_state = frame->commandState(blink::WebString::fromUTF8("JustifyFull"));
281   params.has_composition = frame->hasMarkedText();
282   Send(new EwkViewMsg_SelectionTextStyleState(render_view()->GetRoutingID(), params));
283 }
284
285 void RenderViewObserverEfl::OnDoHitTest(int view_x, int view_y, Ewk_Hit_Test_Mode mode)
286 {
287   Hit_Test_Params params;
288
289   if (DoHitTest(view_x, view_y, mode, &params)) {
290     Send(new EwkViewHostMsg_HitTestReply(routing_id(), params));
291   }
292 }
293
294 void RenderViewObserverEfl::OnDoHitTestAsync(int view_x, int view_y, Ewk_Hit_Test_Mode mode, int64_t request_id)
295 {
296   Hit_Test_Params params;
297
298   if (DoHitTest(view_x, view_y, mode, &params)) {
299     Send(new EwkViewHostMsg_HitTestAsyncReply(routing_id(), params, request_id));
300   }
301 }
302
303 bool RenderViewObserverEfl::DoHitTest(int view_x, int view_y, Ewk_Hit_Test_Mode mode, Hit_Test_Params* params)
304 {
305   DCHECK(params);
306
307   if (!render_view() || !render_view()->GetWebView())
308     return false;
309
310   const blink::WebHitTestResult web_hit_test_result =
311       render_view()->GetWebView()->hitTestResultAt(
312           blink::WebPoint(view_x, view_y));
313
314   if (web_hit_test_result.node().isNull())
315     return false;
316
317   params->mode = mode;
318
319   PopulateEwkHitTestData(web_hit_test_result, params);
320   if (params->mode & EWK_HIT_TEST_MODE_NODE_DATA)
321     PopulateNodeAttributesMapFromHitTest(web_hit_test_result, params);
322
323   return true;
324 }
325
326 void RenderViewObserverEfl::OnPrintToPdf(int width, int height, const base::FilePath& filename)
327 {
328   blink::WebView* web_view = render_view()->GetWebView();
329   DCHECK(web_view);
330   PrintWebViewHelperEfl print_helper(render_view(), filename);
331   print_helper.PrintToPdf(width, height);
332 }
333
334 void RenderViewObserverEfl::OnGetMHTMLData(int callback_id)
335 {
336   blink::WebView* view = render_view()->GetWebView();
337   if (!view)
338     return;
339
340   std::string content_string;
341   blink::WebCString content =  blink::WebPageSerializer::serializeToMHTML(view);
342   if (!content.isEmpty())
343     content_string = content.data();
344
345   Send(new EwkHostMsg_ReadMHTMLData(render_view()->GetRoutingID(), content_string, callback_id));
346 }
347
348 #if !defined(EWK_BRINGUP)
349 void RenderViewObserverEfl::DidChangePageScaleFactor()
350 {
351   blink::WebView* view = render_view()->GetWebView();
352   if (!view)
353     return;
354
355   Send(new EwkHostMsg_DidChangePageScaleFactor(render_view()->GetRoutingID(), view->pageScaleFactor()));
356 }
357 #endif
358
359 void RenderViewObserverEfl::DidFailLoad(blink::WebLocalFrame* frame,
360                                         const blink::WebURLError& error) {
361   if (error.isCancellation)
362     return;
363
364   WebDataSource* ds = frame->dataSource();
365   DCHECK(ds);
366
367   const WebURLRequest& failed_request = ds->request();
368   base::string16 error_description;
369
370   renderer_client_->GetNavigationErrorStrings(
371       render_view(),
372       frame,
373       failed_request,
374       error,
375       NULL,
376       &error_description);
377
378   ErrorParams err;
379   err.url = error.unreachableURL;
380   err.is_main_frame = !frame->parent();
381   err.code = error.reason;
382   err.description = base::UTF16ToUTF8(error_description);
383   err.domain = error.domain.utf8();
384
385   Send(new EwkViewMsg_DidFailLoadWithError(routing_id(), err));
386 }
387
388 void RenderViewObserverEfl::DidUpdateLayout()
389 {
390   blink::WebView* view = render_view()->GetWebView();
391   if (!view)
392     return;
393
394 #if !defined(EWK_BRINGUP)
395   float min_scale = view->minimumPageScaleFactor();
396   float max_scale = view->maximumPageScaleFactor();
397 #else
398   // TODO: (m42_2311) WebView has no minimumPageScaleFactor, maximumPageScaleFactor
399   float min_scale = 1.0; //view->minimumPageScaleFactor();
400   float max_scale = 5.0; //view->maximumPageScaleFactor();
401 #endif
402
403   // Checking for change in minimum and maximum page scale factors
404   if (std::abs(cached_max_page_scale_factor_ - max_scale) < std::numeric_limits<float>::epsilon() &&
405         std::abs(cached_min_page_scale_factor_ - min_scale) < std::numeric_limits<float>::epsilon())
406     return;
407
408   cached_max_page_scale_factor_ = max_scale;
409   cached_min_page_scale_factor_ = min_scale;
410   Send(new EwkHostMsg_DidChangePageScaleRange(render_view()->GetRoutingID(), min_scale, max_scale));
411
412   // Check if the timer is already running
413   if (check_contents_size_timer_.IsRunning())
414     return;
415
416   check_contents_size_timer_.Start(FROM_HERE,
417                                    base::TimeDelta::FromMilliseconds(0), this,
418                                    &RenderViewObserverEfl::CheckContentsSize);
419 }
420
421 void RenderViewObserverEfl::CheckContentsSize()
422 {
423   blink::WebView* view = render_view()->GetWebView();
424   if (!view || !view->mainFrame())
425     return;
426
427   gfx::Size contents_size = view->mainFrame()->contentsSize();
428
429   // Fall back to contentsPreferredMinimumSize if the mainFrame is reporting a
430   // 0x0 size (this happens during initial load).
431   if (contents_size.IsEmpty()) {
432     contents_size = render_view()->GetWebView()->contentsPreferredMinimumSize();
433   }
434
435   if (contents_size == last_sent_contents_size_)
436     return;
437
438   last_sent_contents_size_ = contents_size;
439   const blink::WebSize size = static_cast<blink::WebSize>(contents_size);
440   Send(new EwkHostMsg_DidChangeContentsSize(render_view()->GetRoutingID(),
441                                             size.width,
442                                             size.height));
443 }
444
445 void RenderViewObserverEfl::OnSetDrawsTransparentBackground(bool draws_transparent_background)
446 {
447   blink::WebView* view = render_view()->GetWebView();
448   if (!view)
449     return;
450
451   blink::WebColor backgroundColor = draws_transparent_background ?
452       static_cast<blink::WebColor>(0x00000000) : static_cast<blink::WebColor>(0xFFFFFFFF);
453
454   view->setBaseBackgroundColor(backgroundColor);
455 }
456
457 void RenderViewObserverEfl::OnWebAppIconUrlGet(int callback_id)
458 {
459   blink::WebFrame *frame = render_view()->GetWebView()->mainFrame();
460   if (!frame) {
461     return;
462   }
463
464   blink::WebDocument document = frame->document();
465   blink::WebElement head = document.head();
466   if (head.isNull()) {
467     return;
468   }
469
470   std::string iconUrl;
471   std::string appleIconUrl;
472   blink::WebNodeList nodes = head.childNodes();
473   // We're looking for Apple style rel ("apple-touch-*")
474   // and Google style rel ("icon"), but we prefer the Apple one
475   // when both appear, as WebKit-efl was looking only for Apple style rels.
476   for (unsigned int i = 0; i < nodes.length(); ++i) {
477     blink::WebNode node = nodes.item(i);
478     if (!node.isElementNode()) {
479       continue;
480     }
481     blink::WebElement elem = node.to<blink::WebElement>();
482     if (!elem.hasHTMLTagName("link")) {
483       continue;
484     }
485     std::string rel = elem.getAttribute("rel").utf8();
486     if (base::LowerCaseEqualsASCII(rel, "apple-touch-icon") ||              // Apple's way
487         base::LowerCaseEqualsASCII(rel, "apple-touch-icon-precomposed")) {
488       appleIconUrl = document.completeURL(elem.getAttribute("href")).string().utf8();
489       break;
490     } else if (base::LowerCaseEqualsASCII(rel, "icon")) {                   // Google's way
491       iconUrl = document.completeURL(elem.getAttribute("href")).string().utf8();
492     }
493   }
494   Send(new EwkHostMsg_WebAppIconUrlGet(render_view()->GetRoutingID(), appleIconUrl.empty() ? iconUrl : appleIconUrl, callback_id));
495 }
496
497 void RenderViewObserverEfl::OnWebAppIconUrlsGet(int callback_id) {
498   blink::WebFrame *frame = render_view()->GetWebView()->mainFrame();
499   if (!frame) {
500     return;
501   }
502
503   blink::WebDocument document = frame->document();
504   blink::WebElement head = document.head();
505   if (head.isNull()) {
506     return;
507   }
508
509   std::map<std::string, std::string> iconUrls;
510   blink::WebNodeList nodes = head.childNodes();
511   for (unsigned int i = 0; i < nodes.length(); ++i) {
512     blink::WebNode node = nodes.item(i);
513     if (!node.isElementNode()) {
514       continue;
515     }
516     blink::WebElement elem = node.to<blink::WebElement>();
517     if (!elem.hasHTMLTagName("link")) {
518       continue;
519     }
520     std::string rel = elem.getAttribute("rel").utf8();
521     if (base::LowerCaseEqualsASCII(rel, "apple-touch-icon") ||              // Apple's way
522         base::LowerCaseEqualsASCII(rel, "apple-touch-icon-precomposed") ||  // same here
523         base::LowerCaseEqualsASCII(rel, "icon")) {                          // Google's way
524       std::string iconSize = elem.getAttribute("sizes").utf8();
525       std::string iconUrl = document.completeURL(elem.getAttribute("href")).string().utf8();
526
527       iconUrls[iconSize] = iconUrl;
528     }
529   }
530   Send(new EwkHostMsg_WebAppIconUrlsGet(render_view()->GetRoutingID(), iconUrls, callback_id));
531 }
532
533 void RenderViewObserverEfl::OnWebAppCapableGet(int callback_id) {
534   blink::WebFrame *frame = render_view()->GetWebView()->mainFrame();
535   if (!frame)
536     return;
537
538   blink::WebDocument document = frame->document();
539   blink::WebElement head = document.head();
540   if (head.isNull())
541     return;
542
543   bool capable = false;
544   blink::WebNodeList nodes = head.childNodes();
545   for (unsigned int i = 0; i < nodes.length(); ++i) {
546     blink::WebNode node = nodes.item(i);
547     if (!node.isElementNode())
548       continue;
549
550     blink::WebElement elem = node.to<blink::WebElement>();
551     if (!elem.hasHTMLTagName("meta"))
552       continue;
553
554     std::string name = elem.getAttribute("name").utf8();
555     if (base::LowerCaseEqualsASCII(name, "apple-mobile-web-app-capable") ||   // Apple's way
556         base::LowerCaseEqualsASCII(name, "mobile-web-app-capable")) {         // Google's way
557       std::string content = elem.getAttribute("content").utf8();
558       if (base::LowerCaseEqualsASCII(content, "yes")) {
559         capable = true;
560       }
561       break;
562     }
563   }
564   Send(new EwkHostMsg_WebAppCapableGet(render_view()->GetRoutingID(), capable, callback_id));
565 }
566
567 void RenderViewObserverEfl::DidHandleGestureEvent(const blink::WebGestureEvent& event)
568 {
569   if (event.type == blink::WebInputEvent::GestureTap)
570     HandleTap(event);
571 }
572
573 void RenderViewObserverEfl::OnSetBrowserFont()
574 {
575 #if !defined(EWK_BRINGUP)
576   blink::WebView* view = render_view()->GetWebView();
577   if (view) {
578     view->setBrowserFont();
579   }
580 #endif
581 }
582
583 void RenderViewObserverEfl::OnSuspendScheduledTasks()
584 {
585   blink::WebView* view = render_view()->GetWebView();
586   if (view)
587     view->suspendScheduledTasks();
588 }
589
590 void RenderViewObserverEfl::OnResumeScheduledTasks()
591 {
592   blink::WebView* view = render_view()->GetWebView();
593   if (view)
594     view->resumeScheduledTasks();
595 }
596
597 void RenderViewObserverEfl::OnSetViewMode(blink::WebViewMode view_mode) {
598   blink::WebView* view = render_view()->GetWebView();
599   if (view)
600     view->setViewMode(view_mode);
601 }
602
603 void RenderViewObserverEfl::OnUpdateSettings(const WebViewSettings& settings)
604 {
605   DCHECK(renderer_client_);
606   if (renderer_client_) {
607     static_cast<ContentRendererClientEfl*>(renderer_client_)->SetWebViewSettings(settings);
608   }
609   link_effect_enabled_ = settings.link_effect_enabled;
610 }
611
612 void RenderViewObserverEfl::HandleTap(const blink::WebGestureEvent& event)
613 {
614   // In order to closely match our touch adjustment logic, we
615   // perform a hit test "for tap" using the same "padding" as the
616   // original tap event. That way, touch adjustment picks up a link
617   // for clicking, we will emit a click sound.
618   blink::WebSize size(event.data.tap.width, event.data.tap.height);
619   const blink::WebHitTestResult web_hit_test_result =
620       render_view()->GetWebView()->hitTestResultForTap(
621           blink::WebPoint(event.x, event.y), size);
622
623   bool hit_link = !web_hit_test_result.absoluteLinkURL().isEmpty();
624   bool hit_content_editable = web_hit_test_result.isContentEditable();
625   Send(new EwkHostMsg_HandleTapGestureWithContext(render_view()->GetRoutingID(),
626       hit_link, hit_content_editable));
627 }