Switch to new internal chromium branch dev/m38_2114 .
[platform/framework/web/chromium-efl.git] / tizen_src / impl / renderer / render_view_observer_efl.cc
1 #include "renderer/render_view_observer_efl.h"
2
3 #include <string>
4 #include <limits.h>
5
6 #include "base/files/file_path.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "base/strings/string_split.h"
9 #include "base/strings/string_util.h"
10 #include "content/public/renderer/render_view.h"
11 #include "common/render_messages_efl.h"
12 #include "third_party/WebKit/public/platform/WebCString.h"
13 #include "third_party/WebKit/public/platform/WebData.h"
14 #include "third_party/WebKit/public/platform/WebPoint.h"
15 #include "third_party/WebKit/public/platform/WebSize.h"
16 #include "third_party/WebKit/public/platform/WebString.h"
17 #include "third_party/WebKit/public/web/WebDocument.h"
18 #include "third_party/WebKit/public/web/WebFormElement.h"
19 #include "third_party/WebKit/public/web/WebFrame.h"
20 #include "third_party/WebKit/public/web/WebHitTestResult.h"
21 #include "third_party/WebKit/public/web/WebLocalFrame.h"
22 #include "third_party/WebKit/public/web/WebPageSerializer.h"
23 #include "third_party/WebKit/public/web/WebView.h"
24 #include "third_party/WebKit/public/web/WebNodeList.h"
25
26 // XXX: config.h needs to be included before internal blink headers.
27 //      It'd be great if we did not include not internal blibk headers.
28 #include "third_party/WebKit/Source/config.h"
29 #include "third_party/WebKit/Source/platform/fonts/FontCache.h"
30
31 using namespace tizen_webview;
32
33 namespace {
34
35 bool GetGRBAValuesFromString(const std::string& input, int* r, int* g, int* b, int* a)
36 {
37   bool parsing_status = false;
38   // for example - rgba(255, 255, 255, 255)
39   // for example - rgb(255, 255, 255)
40   if (std::string::npos != input.find("rgb")) {
41     size_t startPos = input.find("(");
42     size_t endPos = input.find(")");
43
44     std::string value = input.substr(startPos + 1, endPos - startPos - 1);
45     std::vector<std::string> colorValues;
46     base::SplitString(value, ',', &colorValues);
47     if (colorValues.size() == 4 || colorValues.size() == 3) {
48       base::StringToInt(colorValues[0], r);
49       base::StringToInt(colorValues[1], g);
50       base::StringToInt(colorValues[2], b);
51       if (std::string::npos != input.find("rgba") && colorValues.size() == 4)
52         base::StringToInt(colorValues[3], a);
53       else
54         *a = 255;
55       parsing_status = true;
56     }
57   }
58   return parsing_status;
59 }
60
61 void PopulateEwkHitTestData(const blink::WebHitTestResult& web_hit_test, _Ewk_Hit_Test* ewk_hit_test)
62 {
63   DCHECK(ewk_hit_test);
64 #if !defined(EWK_BRINGUP)
65   // Unifdef it when this change will be relanded: http://165.213.202.130:8080/#/c/68152/
66   ewk_hit_test->imageURI = web_hit_test.absoluteImageURL().string().utf8();
67   ewk_hit_test->linkURI = web_hit_test.absoluteLinkURL().string().utf8();
68   ewk_hit_test->mediaURI = web_hit_test.absoluteMediaURL().string().utf8();
69   ewk_hit_test->linkLabel = web_hit_test.textContent().utf8();
70   ewk_hit_test->linkTitle = web_hit_test.titleDisplayString().utf8();
71   ewk_hit_test->isEditable = web_hit_test.isContentEditable();
72
73   int context = TW_HIT_TEST_RESULT_CONTEXT_DOCUMENT;
74   if (!web_hit_test.absoluteLinkURL().isEmpty())
75     context |= TW_HIT_TEST_RESULT_CONTEXT_LINK;
76   if (!web_hit_test.absoluteImageURL().isEmpty())
77     context |= TW_HIT_TEST_RESULT_CONTEXT_IMAGE;
78   if (!web_hit_test.absoluteMediaURL().isEmpty())
79     context |= TW_HIT_TEST_RESULT_CONTEXT_MEDIA;;
80   if (web_hit_test.isSelected())
81     context |= TW_HIT_TEST_RESULT_CONTEXT_SELECTION;
82   if (web_hit_test.isContentEditable())
83     context |= TW_HIT_TEST_RESULT_CONTEXT_EDITABLE;
84   if (web_hit_test.node().isTextNode())
85     context |= TW_HIT_TEST_RESULT_CONTEXT_TEXT;
86 #else
87   int context = TW_HIT_TEST_RESULT_CONTEXT_DOCUMENT;
88 #endif
89   ewk_hit_test->context = static_cast<tizen_webview::Hit_Test_Result_Context>(context);
90   ewk_hit_test->nodeData.attributeHash = 0;
91
92   if (ewk_hit_test->mode & TW_HIT_TEST_MODE_NODE_DATA) {
93     ewk_hit_test->nodeData.tagName = web_hit_test.node().nodeName().utf8();
94     ewk_hit_test->nodeData.nodeValue = web_hit_test.node().nodeValue().utf8();
95   }
96
97   if ((ewk_hit_test->mode & TW_HIT_TEST_MODE_IMAGE_DATA) &&
98       (ewk_hit_test->context & TW_HIT_TEST_RESULT_CONTEXT_IMAGE)) {
99     blink::WebElement hit_element = web_hit_test.node().toConst<blink::WebElement>();
100     ewk_hit_test->imageData.imageBitmap = hit_element.imageContents().getSkBitmap();
101 #if !defined(EWK_BRINGUP)
102     ewk_hit_test->imageData.fileNameExtension = hit_element.imageFilenameExtension().utf8();
103 #endif
104   }
105 }
106
107 void PopulateNodeAttributesMapFromHitTest(const blink::WebHitTestResult& web_hit_test,
108                                           NodeAttributesMap* attributes)
109 {
110   if (!attributes || !web_hit_test.node().isElementNode())
111     return;
112
113   blink::WebElement hit_element = web_hit_test.node().toConst<blink::WebElement>();
114   for (unsigned int i = 0; i < hit_element.attributeCount(); i++) {
115     attributes->insert(std::pair<std::string, std::string>(
116         hit_element.attributeLocalName(i).utf8(), hit_element.attributeValue(i).utf8()));
117   }
118 }
119
120 }  //namespace
121
122 RenderViewObserverEfl::RenderViewObserverEfl(content::RenderView* render_view)
123   : content::RenderViewObserver(render_view),
124     cached_min_page_scale_factor_(-1.0),
125     cached_max_page_scale_factor_(-1.0)
126 {
127 }
128
129 RenderViewObserverEfl::~RenderViewObserverEfl()
130 {
131 }
132
133 bool RenderViewObserverEfl::OnMessageReceived(const IPC::Message& message)
134 {
135   bool handled = true;
136   IPC_BEGIN_MESSAGE_MAP(RenderViewObserverEfl, message)
137     IPC_MESSAGE_HANDLER(EwkViewMsg_SetCSP, OnSetContentSecurityPolicy)
138     IPC_MESSAGE_HANDLER(EwkViewMsg_Scale, OnScale)
139     IPC_MESSAGE_HANDLER(EwkViewMsg_SetScroll, OnSetScroll)
140     IPC_MESSAGE_HANDLER(EwkViewMsg_UseSettingsFont, OnUseSettingsFont)
141     IPC_MESSAGE_HANDLER(EwkViewMsg_PlainTextGet, OnPlainTextGet)
142     IPC_MESSAGE_HANDLER(EwkViewMsg_GetSelectionStyle, OnGetSelectionStyle);
143     IPC_MESSAGE_HANDLER(EwkViewMsg_SelectClosestWord, OnSelectClosestWord);
144     IPC_MESSAGE_HANDLER(EwkViewMsg_DoHitTest, OnDoHitTest)
145     IPC_MESSAGE_HANDLER(EwkViewMsg_PrintToPdf, OnPrintToPdf)
146     IPC_MESSAGE_HANDLER(EwkViewMsg_GetMHTMLData, OnGetMHTMLData);
147     IPC_MESSAGE_HANDLER(EwkViewMsg_WebAppIconUrlGet, OnWebAppIconUrlGet);
148     IPC_MESSAGE_HANDLER(EwkViewMsg_WebAppIconUrlsGet, OnWebAppIconUrlsGet);
149     IPC_MESSAGE_HANDLER(EwkViewMsg_WebAppCapableGet, OnWebAppCapableGet);
150     IPC_MESSAGE_HANDLER(EwkViewMsg_SetDrawsTransparentBackground, OnSetDrawsTransparentBackground);
151     IPC_MESSAGE_HANDLER(EwkViewMsg_SetBrowserFont, OnSetBrowserFont);
152     IPC_MESSAGE_UNHANDLED(handled = false)
153   IPC_END_MESSAGE_MAP()
154   return handled;
155 }
156
157 void RenderViewObserverEfl::DidCreateDocumentElement(blink::WebLocalFrame* frame)
158 {
159   std::string policy;
160   tizen_webview::ContentSecurityPolicyType type = TW_CSP_DEFAULT_POLICY;
161   Send(new EwkHostMsg_GetContentSecurityPolicy(render_view()->GetRoutingID(), &policy, &type));
162
163 #if !defined(EWK_BRINGUP)
164   // Since, Webkit supports some more types and we cast ewk type to Webkit type.
165   // We allow only ewk types.
166   if (type == TW_CSP_REPORT_ONLY || type == TW_CSP_ENFORCE_POLICY)
167     frame->document().setContentSecurityPolicyUsingHeader(blink::WebString::fromUTF8(policy), type);
168 #endif
169 }
170
171 void RenderViewObserverEfl::OnSetContentSecurityPolicy(const std::string& policy, tizen_webview::ContentSecurityPolicyType header_type)
172 {
173 #if !defined(EWK_BRINGUP)
174   blink::WebView* view = render_view()->GetWebView();
175   DCHECK(view);
176   blink::WebDocument document = view->mainFrame()->document();
177   document.setContentSecurityPolicyUsingHeader(blink::WebString::fromUTF8(policy), header_type);
178 #endif
179 }
180
181 void RenderViewObserverEfl::OnScale(double scale_factor, int x, int y)
182 {
183   blink::WebView* view = render_view()->GetWebView();
184   if (!view)
185     return;
186
187   view->setPageScaleFactor(scale_factor,
188                            blink::WebPoint(x, y));
189 }
190
191 void RenderViewObserverEfl::OnSetScroll(int x, int y)
192 {
193   blink::WebFrame* frame = render_view()->GetWebView()->mainFrame();
194   if (!frame)
195     return;
196
197 #if !defined(EWK_BRINGUP)
198   // I think we should use SetCrollOffset here!
199   frame->setScrollPosition(blink::WebSize(x, y));
200 #endif
201 }
202
203 void RenderViewObserverEfl::OnUseSettingsFont()
204 {
205   blink::FontCache::fontCache()->invalidate();
206
207 #if !defined(EWK_BRINGUP)
208   blink::WebView* view = render_view()->GetWebView();
209   if (view)
210     view->sendResizeEventAndForceLayout();
211 #endif
212 }
213
214 void RenderViewObserverEfl::OnPlainTextGet(int plain_text_get_callback_id)
215 {
216   blink::WebFrame* frame = render_view()->GetWebView()->mainFrame();
217   if (!frame)
218     return;
219   blink::WebString content = frame->contentAsText(INT_MAX);
220   Send(new EwkHostMsg_PlainTextGetContents(render_view()->GetRoutingID(), content.utf8(), plain_text_get_callback_id));
221 }
222
223 #if !defined(EWK_BRINGUP)
224 void RenderViewObserverEfl::DidChangeContentsSize(blink::WebFrame* frame, const blink::WebSize& size)
225 {
226   Send(new EwkHostMsg_DidChangeContentsSize(render_view()->GetRoutingID(),
227                                             size.width,
228                                             size.height));
229 }
230 #endif
231
232 void RenderViewObserverEfl::DidChangeScrollOffset(blink::WebLocalFrame* frame)
233 {
234   if (!frame || (render_view()->GetWebView()->mainFrame() != frame))
235     return;
236
237   if (max_scroll_offset_ != frame->maximumScrollOffset()) { //Check for change in MaxScrollOffset
238     max_scroll_offset_ = frame->maximumScrollOffset();
239     Send(new EwkHostMsg_DidChangeMaxScrollOffset(render_view()->GetRoutingID(),
240                                                  frame->maximumScrollOffset().width,
241                                                  frame->maximumScrollOffset().height));
242   }
243 }
244
245 void RenderViewObserverEfl::OnGetSelectionStyle()
246 {
247   blink::WebView* view = render_view()->GetWebView();
248   if (!view)
249     return;
250
251   blink::WebFrame* frame = view->focusedFrame();
252   if (!frame)
253     return;
254
255 #if !defined(EWK_BRINGUP)
256   // Unifdef it when this change will be relanded: http://165.213.202.130:8080/#/c/68152/
257   SelectionStylePrams params;
258   params.underline_state = frame->stateCommand(blink::WebString::fromUTF8("underline"));
259   params.italic_state = frame->stateCommand(blink::WebString::fromUTF8("italic"));
260   params.bold_state = frame->stateCommand(blink::WebString::fromUTF8("bold"));
261   blink::WebString bg_color = frame->valueCommand(blink::WebString::fromUTF8("BackColor"));
262   GetGRBAValuesFromString(std::string(bg_color.utf8()), &params.bg_color.r, &params.bg_color.g, &params.bg_color.b, &params.bg_color.a);
263   blink::WebString color = frame->valueCommand(blink::WebString::fromUTF8("ForeColor"));
264   GetGRBAValuesFromString(std::string(color.utf8()), &params.color.r, &params.color.g, &params.color.b, &params.color.a);
265   blink::WebString  font_size = frame->valueCommand(blink::WebString::fromUTF8("FontSize"));
266   params.font_size = font_size.utf8();
267   params.order_list_state = frame->stateCommand(blink::WebString::fromUTF8("InsertOrderedList"));
268   params.un_order_list_state = frame->stateCommand(blink::WebString::fromUTF8("InsertUnorderedList"));
269   params.text_align_center_state = frame->stateCommand(blink::WebString::fromUTF8("JustifyCenter"));
270   params.text_align_left_state = frame->stateCommand(blink::WebString::fromUTF8("JustifyLeft"));
271   params.text_align_right_state = frame->stateCommand(blink::WebString::fromUTF8("JustifyRight"));
272   params.text_align_full_state = frame->stateCommand(blink::WebString::fromUTF8("JustifyFull"));
273   params.has_composition = frame->hasMarkedText();
274   Send(new EwkViewMsg_SelectionTextStyleState(render_view()->GetRoutingID(), params));
275 #endif
276 }
277
278 void RenderViewObserverEfl::OnSelectClosestWord(int x, int y)
279 {
280   blink::WebView* view = render_view()->GetWebView();
281   if (!view)
282     return;
283
284   blink::WebFrame* frame = view->focusedFrame();
285   if (!frame)
286     return;
287
288   frame->selectClosestWord(x, y);
289 }
290
291 void RenderViewObserverEfl::OnDoHitTest(int view_x, int view_y, tizen_webview::Hit_Test_Mode mode)
292 {
293   if (!render_view() || !render_view()->GetWebView())
294     return;
295
296   const blink::WebHitTestResult web_hit_test_result =
297       render_view()->GetWebView()->hitTestResultAt(
298           blink::WebPoint(view_x, view_y));
299   _Ewk_Hit_Test ewk_hit_test_result;
300   ewk_hit_test_result.mode = mode;
301
302   PopulateEwkHitTestData(web_hit_test_result, &ewk_hit_test_result);
303   NodeAttributesMap attributes;
304   if (ewk_hit_test_result.mode & TW_HIT_TEST_MODE_NODE_DATA)
305     PopulateNodeAttributesMapFromHitTest(web_hit_test_result, &attributes);
306
307   Send(new EwkViewHostMsg_HitTestReply(routing_id(), ewk_hit_test_result, attributes));
308 }
309
310 void RenderViewObserverEfl::OnPrintToPdf(int width, int height, const base::FilePath& filename)
311 {
312   blink::WebView* web_view = render_view()->GetWebView();
313   DCHECK(web_view);
314   PrintWebViewHelperEfl print_helper(render_view(), filename);
315   print_helper.PrintToPdf(width, height);
316 }
317
318 void RenderViewObserverEfl::OnGetMHTMLData(int callback_id)
319 {
320   blink::WebView* view = render_view()->GetWebView();
321   if (!view)
322     return;
323
324   std::string content_string;
325   blink::WebCString content =  blink::WebPageSerializer::serializeToMHTML(view);
326   if (!content.isEmpty())
327     content_string = content.data();
328
329   Send(new EwkHostMsg_ReadMHTMLData(render_view()->GetRoutingID(), content_string, callback_id));
330 }
331
332 #if !defined(EWK_BRINGUP)
333 void RenderViewObserverEfl::DidChangePageScaleFactor()
334 {
335   blink::WebView* view = render_view()->GetWebView();
336   if (!view)
337     return;
338
339   Send(new EwkHostMsg_DidChangePageScaleFactor(render_view()->GetRoutingID(), view->pageScaleFactor()));
340 }
341 #endif
342
343 void RenderViewObserverEfl::DidUpdateLayout()
344 {
345   blink::WebView* view = render_view()->GetWebView();
346   if (!view)
347     return;
348
349   float min_scale = view->minimumPageScaleFactor();
350   float max_scale = view->maximumPageScaleFactor();
351
352   // Checking for change in minimum and maximum page scale factors
353   if (std::abs(cached_max_page_scale_factor_ - max_scale) < std::numeric_limits<float>::epsilon() &&
354         std::abs(cached_min_page_scale_factor_ - min_scale) < std::numeric_limits<float>::epsilon())
355     return;
356
357   cached_max_page_scale_factor_ = max_scale;
358   cached_min_page_scale_factor_ = min_scale;
359   Send(new EwkHostMsg_DidChangePageScaleRange(render_view()->GetRoutingID(), min_scale, max_scale));
360 }
361
362 void RenderViewObserverEfl::OnSetDrawsTransparentBackground(bool draws_transparent_background)
363 {
364   blink::WebView* view = render_view()->GetWebView();
365   if (!view)
366     return;
367
368   blink::WebColor backgroundColor = draws_transparent_background ?
369       static_cast<blink::WebColor>(0x00000000) : static_cast<blink::WebColor>(0xFFFFFFFF);
370
371   view->setBaseBackgroundColor(backgroundColor);
372 }
373
374 void RenderViewObserverEfl::OnWebAppIconUrlGet(int callback_id)
375 {
376   blink::WebFrame *frame = render_view()->GetWebView()->mainFrame();
377   if (!frame) {
378     return;
379   }
380
381   blink::WebDocument document = frame->document();
382   blink::WebElement head = document.head();
383   if (head.isNull()) {
384     return;
385   }
386
387   std::string iconUrl;
388   std::string appleIconUrl;
389   blink::WebNodeList nodes = head.childNodes();
390   // We're looking for Apple style rel ("apple-touch-*")
391   // and Google style rel ("icon"), but we prefer the Apple one
392   // when both appear, as WebKit-efl was looking only for Apple style rels.
393   for (int i = 0; i < nodes.length(); ++i) {
394     blink::WebNode node = nodes.item(i);
395     if (!node.isElementNode()) {
396       continue;
397     }
398     blink::WebElement elem = node.to<blink::WebElement>();
399     if (!elem.hasHTMLTagName("link")) {
400       continue;
401     }
402     std::string rel = elem.getAttribute("rel").utf8();
403     if (LowerCaseEqualsASCII(rel, "apple-touch-icon") ||              // Apple's way
404         LowerCaseEqualsASCII(rel, "apple-touch-icon-precomposed")) {
405       appleIconUrl = document.completeURL(elem.getAttribute("href")).string().utf8();
406       break;
407     } else if (LowerCaseEqualsASCII(rel, "icon")) {                   // Google's way
408       iconUrl = document.completeURL(elem.getAttribute("href")).string().utf8();
409     }
410   }
411   Send(new EwkHostMsg_WebAppIconUrlGet(render_view()->GetRoutingID(), appleIconUrl.empty() ? iconUrl : appleIconUrl, callback_id));
412 }
413
414 void RenderViewObserverEfl::OnWebAppIconUrlsGet(int callback_id) {
415   blink::WebFrame *frame = render_view()->GetWebView()->mainFrame();
416   if (!frame) {
417     return;
418   }
419
420   blink::WebDocument document = frame->document();
421   blink::WebElement head = document.head();
422   if (head.isNull()) {
423     return;
424   }
425
426   std::map<std::string, std::string> iconUrls;
427   blink::WebNodeList nodes = head.childNodes();
428   for (int i = 0; i < nodes.length(); ++i) {
429     blink::WebNode node = nodes.item(i);
430     if (!node.isElementNode()) {
431       continue;
432     }
433     blink::WebElement elem = node.to<blink::WebElement>();
434     if (!elem.hasHTMLTagName("link")) {
435       continue;
436     }
437     std::string rel = elem.getAttribute("rel").utf8();
438     if (LowerCaseEqualsASCII(rel, "apple-touch-icon") ||              // Apple's way
439         LowerCaseEqualsASCII(rel, "apple-touch-icon-precomposed") ||  // same here
440         LowerCaseEqualsASCII(rel, "icon")) {                          // Google's way
441       std::string iconSize = elem.getAttribute("sizes").utf8();
442       std::string iconUrl = document.completeURL(elem.getAttribute("href")).string().utf8();
443
444       iconUrls[iconSize] = iconUrl;
445     }
446   }
447   Send(new EwkHostMsg_WebAppIconUrlsGet(render_view()->GetRoutingID(), iconUrls, callback_id));
448 }
449
450 void RenderViewObserverEfl::OnWebAppCapableGet(int callback_id) {
451   blink::WebFrame *frame = render_view()->GetWebView()->mainFrame();
452   if (!frame)
453     return;
454
455   blink::WebDocument document = frame->document();
456   blink::WebElement head = document.head();
457   if (head.isNull())
458     return;
459
460   bool capable = false;
461   blink::WebNodeList nodes = head.childNodes();
462   for (int i = 0; i < nodes.length(); ++i) {
463     blink::WebNode node = nodes.item(i);
464     if (!node.isElementNode())
465       continue;
466
467     blink::WebElement elem = node.to<blink::WebElement>();
468     if (!elem.hasHTMLTagName("meta"))
469       continue;
470
471     std::string name = elem.getAttribute("name").utf8();
472     if (LowerCaseEqualsASCII(name, "apple-mobile-web-app-capable") ||   // Apple's way
473         LowerCaseEqualsASCII(name, "mobile-web-app-capable")) {         // Google's way
474       std::string content = elem.getAttribute("content").utf8();
475       if (LowerCaseEqualsASCII(content, "yes")) {
476         capable = true;
477       }
478       break;
479     }
480   }
481   Send(new EwkHostMsg_WebAppCapableGet(render_view()->GetRoutingID(), capable, callback_id));
482 }
483
484 void RenderViewObserverEfl::OrientationChangeEvent()
485 {
486 #if !defined(EWK_BRINGUP)
487   // Previosly OrientationChangeEvent() had orientation parameter.
488   // Now it was removed. Thanks Mounir.
489   // Need to figure out how to get orientation.
490   Send(new EwkHostMsg_OrientationChangeEvent(render_view()->GetRoutingID(), orientation));
491 #endif
492 }
493
494 void RenderViewObserverEfl::WillSubmitForm(blink::WebFrame* frame, const blink::WebFormElement& form)
495 {
496   GURL url(form.action());
497   Send(new EwkHostMsg_FormSubmit(routing_id(),url));
498 }
499
500 void RenderViewObserverEfl::OnSetBrowserFont()
501 {
502 #if !defined(EWK_BRINGUP)
503   blink::WebView* view = render_view()->GetWebView();
504   if (view) {
505     view->setBrowserFont();
506   }
507 #endif
508 }