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