1/* 2 * Copyright (C) 2006 Zack Rusin <zack@kde.org> 3 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. 4 * Copyright (C) 2008 Kenneth Rohde Christiansen 5 * Copyright (C) 2008 Diego Gonzalez 6 * Copyright (C) 2009-2010 ProFUSION embedded systems 7 * Copyright (C) 2009-2010 Samsung Electronics 8 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 9 * 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 29 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34#include "config.h" 35#include "ChromeClientEfl.h" 36 37#if ENABLE(DATABASE) 38#include "DatabaseDetails.h" 39#include "DatabaseTracker.h" 40#endif 41#include "EWebKit.h" 42#include "FileChooser.h" 43#include "FloatRect.h" 44#include "FrameLoader.h" 45#include "FrameLoaderClientEfl.h" 46#include "HitTestResult.h" 47#include "IntRect.h" 48#include "KURL.h" 49#include "NavigationAction.h" 50#include "NotImplemented.h" 51#include "PlatformString.h" 52#include "SecurityOrigin.h" 53#include "PopupMenuEfl.h" 54#include "SearchPopupMenuEfl.h" 55#include "ViewportArguments.h" 56#include "WindowFeatures.h" 57#include "ewk_private.h" 58#include <Ecore_Evas.h> 59#include <Evas.h> 60#include <wtf/text/CString.h> 61 62using namespace WebCore; 63 64static inline Evas_Object* kit(Frame* frame) 65{ 66 if (!frame) 67 return 0; 68 69 FrameLoaderClientEfl* client = static_cast<FrameLoaderClientEfl*>(frame->loader()->client()); 70 return client ? client->webFrame() : 0; 71} 72 73namespace WebCore { 74 75ChromeClientEfl::ChromeClientEfl(Evas_Object* view) 76 : m_view(view) 77{ 78} 79 80ChromeClientEfl::~ChromeClientEfl() 81{ 82} 83 84void ChromeClientEfl::chromeDestroyed() 85{ 86 delete this; 87} 88 89void ChromeClientEfl::focusedNodeChanged(Node*) 90{ 91 notImplemented(); 92} 93 94void ChromeClientEfl::focusedFrameChanged(Frame*) 95{ 96} 97 98FloatRect ChromeClientEfl::windowRect() 99{ 100 Ecore_Evas* ee = 0; 101 int x, y, w, h; 102 103 if (!m_view) 104 return FloatRect(); 105 106 ee = ecore_evas_ecore_evas_get(evas_object_evas_get(m_view)); 107 ecore_evas_geometry_get(ee, &x, &y, &w, &h); 108 return FloatRect(x, y, w, h); 109} 110 111void ChromeClientEfl::setWindowRect(const FloatRect& rect) 112{ 113 Ecore_Evas* ee = 0; 114 IntRect intrect = IntRect(rect); 115 116 if (!m_view) 117 return; 118 119 if (!ewk_view_setting_enable_auto_resize_window_get(m_view)) 120 return; 121 122 ee = ecore_evas_ecore_evas_get(evas_object_evas_get(m_view)); 123 ecore_evas_move(ee, intrect.x(), intrect.y()); 124 ecore_evas_resize(ee, intrect.width(), intrect.height()); 125} 126 127FloatRect ChromeClientEfl::pageRect() 128{ 129 if (!m_view) 130 return FloatRect(); 131 132 return ewk_view_page_rect_get(m_view); 133} 134 135float ChromeClientEfl::scaleFactor() 136{ 137 notImplemented(); 138 return 1.0; 139} 140 141void ChromeClientEfl::focus() 142{ 143 evas_object_focus_set(m_view, EINA_TRUE); 144} 145 146void ChromeClientEfl::unfocus() 147{ 148 evas_object_focus_set(m_view, EINA_FALSE); 149} 150 151Page* ChromeClientEfl::createWindow(Frame*, const FrameLoadRequest& frameLoadRequest, const WindowFeatures& features, const NavigationAction&) 152{ 153 Evas_Object* newView = ewk_view_window_create(m_view, EINA_TRUE, &features); 154 if (!newView) 155 return 0; 156 157 return ewk_view_core_page_get(newView); 158} 159 160void ChromeClientEfl::show() 161{ 162 ewk_view_ready(m_view); 163} 164 165bool ChromeClientEfl::canRunModal() 166{ 167 notImplemented(); 168 return false; 169} 170 171void ChromeClientEfl::runModal() 172{ 173 notImplemented(); 174} 175 176void ChromeClientEfl::setToolbarsVisible(bool visible) 177{ 178 ewk_view_toolbars_visible_set(m_view, visible); 179} 180 181bool ChromeClientEfl::toolbarsVisible() 182{ 183 Eina_Bool visible; 184 185 ewk_view_toolbars_visible_get(m_view, &visible); 186 return visible; 187} 188 189void ChromeClientEfl::setStatusbarVisible(bool visible) 190{ 191 ewk_view_statusbar_visible_set(m_view, visible); 192} 193 194bool ChromeClientEfl::statusbarVisible() 195{ 196 Eina_Bool visible; 197 198 ewk_view_statusbar_visible_get(m_view, &visible); 199 return visible; 200} 201 202void ChromeClientEfl::setScrollbarsVisible(bool visible) 203{ 204 ewk_view_scrollbars_visible_set(m_view, visible); 205} 206 207bool ChromeClientEfl::scrollbarsVisible() 208{ 209 Eina_Bool visible; 210 211 ewk_view_scrollbars_visible_get(m_view, &visible); 212 return visible; 213} 214 215void ChromeClientEfl::setMenubarVisible(bool visible) 216{ 217 ewk_view_menubar_visible_set(m_view, visible); 218} 219 220bool ChromeClientEfl::menubarVisible() 221{ 222 Eina_Bool visible; 223 224 ewk_view_menubar_visible_get(m_view, &visible); 225 return visible; 226} 227 228void ChromeClientEfl::createSelectPopup(PopupMenuClient* client, int selected, const IntRect& rect) 229{ 230 ewk_view_popup_new(m_view, client, selected, rect); 231} 232 233bool ChromeClientEfl::destroySelectPopup() 234{ 235 return ewk_view_popup_destroy(m_view); 236} 237 238void ChromeClientEfl::setResizable(bool) 239{ 240 notImplemented(); 241} 242 243void ChromeClientEfl::closeWindowSoon() 244{ 245 ewk_view_window_close(m_view); 246} 247 248bool ChromeClientEfl::canTakeFocus(FocusDirection) 249{ 250 // This is called when cycling through links/focusable objects and we 251 // reach the last focusable object. 252 return false; 253} 254 255void ChromeClientEfl::takeFocus(FocusDirection) 256{ 257 unfocus(); 258} 259 260bool ChromeClientEfl::canRunBeforeUnloadConfirmPanel() 261{ 262 return true; 263} 264 265bool ChromeClientEfl::runBeforeUnloadConfirmPanel(const String& message, Frame* frame) 266{ 267 return runJavaScriptConfirm(frame, message); 268} 269 270void ChromeClientEfl::addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message, 271 unsigned int lineNumber, const String& sourceID) 272{ 273 ewk_view_add_console_message(m_view, message.utf8().data(), lineNumber, sourceID.utf8().data()); 274} 275 276void ChromeClientEfl::runJavaScriptAlert(Frame* frame, const String& message) 277{ 278 ewk_view_run_javascript_alert(m_view, kit(frame), message.utf8().data()); 279} 280 281bool ChromeClientEfl::runJavaScriptConfirm(Frame* frame, const String& message) 282{ 283 return ewk_view_run_javascript_confirm(m_view, kit(frame), message.utf8().data()); 284} 285 286bool ChromeClientEfl::runJavaScriptPrompt(Frame* frame, const String& message, const String& defaultValue, String& result) 287{ 288 char* value = 0; 289 ewk_view_run_javascript_prompt(m_view, kit(frame), message.utf8().data(), defaultValue.utf8().data(), &value); 290 if (value) { 291 result = String::fromUTF8(value); 292 free(value); 293 return true; 294 } 295 return false; 296} 297 298void ChromeClientEfl::setStatusbarText(const String& string) 299{ 300 ewk_view_statusbar_text_set(m_view, string.utf8().data()); 301} 302 303bool ChromeClientEfl::shouldInterruptJavaScript() 304{ 305 return ewk_view_should_interrupt_javascript(m_view); 306} 307 308KeyboardUIMode ChromeClientEfl::keyboardUIMode() 309{ 310 return KeyboardAccessTabsToLinks; 311} 312 313IntRect ChromeClientEfl::windowResizerRect() const 314{ 315 notImplemented(); 316 // Implementing this function will make repaint being 317 // called during resize, but as this will be done with 318 // a minor delay it adds a weird "filling" effect due 319 // to us using an evas image for showing the cairo 320 // context. So instead of implementing this function 321 // we call paint directly during resize with 322 // the new object size as its argument. 323 return IntRect(); 324} 325 326void ChromeClientEfl::contentsSizeChanged(Frame* frame, const IntSize& size) const 327{ 328 ewk_frame_contents_size_changed(kit(frame), size.width(), size.height()); 329 if (ewk_view_frame_main_get(m_view) == kit(frame)) 330 ewk_view_contents_size_changed(m_view, size.width(), size.height()); 331} 332 333IntRect ChromeClientEfl::windowToScreen(const IntRect& rect) const 334{ 335 notImplemented(); 336 return rect; 337} 338 339IntPoint ChromeClientEfl::screenToWindow(const IntPoint& point) const 340{ 341 notImplemented(); 342 return point; 343} 344 345PlatformPageClient ChromeClientEfl::platformPageClient() const 346{ 347 return m_view; 348} 349 350void ChromeClientEfl::scrollbarsModeDidChange() const 351{ 352} 353 354void ChromeClientEfl::mouseDidMoveOverElement(const HitTestResult& hit, unsigned modifierFlags) 355{ 356 // FIXME, compare with old link, look at Qt impl. 357 bool isLink = hit.isLiveLink(); 358 if (isLink) { 359 KURL url = hit.absoluteLinkURL(); 360 if (!url.isEmpty() && url != m_hoveredLinkURL) { 361 const char* link[2]; 362 TextDirection dir; 363 CString urlStr = url.prettyURL().utf8(); 364 CString titleStr = hit.title(dir).utf8(); 365 link[0] = urlStr.data(); 366 link[1] = titleStr.data(); 367 ewk_view_mouse_link_hover_in(m_view, link); 368 m_hoveredLinkURL = url; 369 } 370 } else if (!isLink && !m_hoveredLinkURL.isEmpty()) { 371 ewk_view_mouse_link_hover_out(m_view); 372 m_hoveredLinkURL = KURL(); 373 } 374} 375 376void ChromeClientEfl::setToolTip(const String& toolTip, TextDirection) 377{ 378 ewk_view_tooltip_text_set(m_view, toolTip.utf8().data()); 379} 380 381void ChromeClientEfl::print(Frame* frame) 382{ 383 notImplemented(); 384} 385 386#if ENABLE(OFFLINE_WEB_APPLICATIONS) 387void ChromeClientEfl::reachedMaxAppCacheSize(int64_t spaceNeeded) 388{ 389 // FIXME: Free some space. 390 notImplemented(); 391} 392 393void ChromeClientEfl::reachedApplicationCacheOriginQuota(SecurityOrigin*) 394{ 395 notImplemented(); 396} 397#endif 398 399#if ENABLE(TOUCH_EVENTS) 400void ChromeClientEfl::needTouchEvents(bool needed) 401{ 402 ewk_view_need_touch_events_set(m_view, needed); 403} 404#endif 405 406#if ENABLE(DATABASE) 407void ChromeClientEfl::exceededDatabaseQuota(Frame* frame, const String& databaseName) 408{ 409 uint64_t quota; 410 SecurityOrigin* origin = frame->document()->securityOrigin(); 411 412 DatabaseDetails details = DatabaseTracker::tracker().detailsForNameAndOrigin(databaseName, origin); 413 quota = ewk_view_exceeded_database_quota(m_view, 414 kit(frame), databaseName.utf8().data(), 415 details.currentUsage(), details.expectedUsage()); 416 417 /* if client did not set quota, and database is being created now, the 418 * default quota is applied 419 */ 420 if (!quota && !DatabaseTracker::tracker().hasEntryForOrigin(origin)) 421 quota = ewk_settings_web_database_default_quota_get(); 422 423 DatabaseTracker::tracker().setQuota(origin, quota); 424} 425#endif 426 427void ChromeClientEfl::runOpenPanel(Frame* frame, PassRefPtr<FileChooser> prpFileChooser) 428{ 429 RefPtr<FileChooser> chooser = prpFileChooser; 430 bool confirm; 431 Eina_List* selectedFilenames = 0; 432 Eina_List* suggestedFilenames = 0; 433 void* filename; 434 Vector<String> filenames; 435 436 for (unsigned i = 0; i < chooser->filenames().size(); i++) { 437 CString str = chooser->filenames()[i].utf8(); 438 filename = strdup(str.data()); 439 suggestedFilenames = eina_list_append(suggestedFilenames, filename); 440 } 441 442 confirm = ewk_view_run_open_panel(m_view, kit(frame), chooser->allowsMultipleFiles(), suggestedFilenames, &selectedFilenames); 443 EINA_LIST_FREE(suggestedFilenames, filename) 444 free(filename); 445 446 if (!confirm) 447 return; 448 449 EINA_LIST_FREE(selectedFilenames, filename) { 450 filenames.append((char *)filename); 451 free(filename); 452 } 453 454 if (chooser->allowsMultipleFiles()) 455 chooser->chooseFiles(filenames); 456 else 457 chooser->chooseFile(filenames[0]); 458} 459 460void ChromeClientEfl::formStateDidChange(const Node*) 461{ 462 notImplemented(); 463} 464 465void ChromeClientEfl::setCursor(const Cursor&) 466{ 467 notImplemented(); 468} 469 470void ChromeClientEfl::requestGeolocationPermissionForFrame(Frame*, Geolocation*) 471{ 472 // See the comment in WebCore/page/ChromeClient.h 473 notImplemented(); 474} 475 476void ChromeClientEfl::cancelGeolocationPermissionRequestForFrame(Frame*, Geolocation*) 477{ 478 notImplemented(); 479} 480 481void ChromeClientEfl::cancelGeolocationPermissionForFrame(Frame*, Geolocation*) 482{ 483 notImplemented(); 484} 485 486void ChromeClientEfl::invalidateContents(const IntRect& updateRect, bool immediate) 487{ 488 notImplemented(); 489} 490 491void ChromeClientEfl::invalidateWindow(const IntRect& updateRect, bool immediate) 492{ 493 notImplemented(); 494} 495 496void ChromeClientEfl::invalidateContentsAndWindow(const IntRect& updateRect, bool immediate) 497{ 498 Evas_Coord x, y, w, h; 499 500 x = updateRect.x(); 501 y = updateRect.y(); 502 w = updateRect.width(); 503 h = updateRect.height(); 504 ewk_view_repaint(m_view, x, y, w, h); 505} 506 507void ChromeClientEfl::invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate) 508{ 509 invalidateContentsAndWindow(updateRect, immediate); 510} 511 512void ChromeClientEfl::scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect) 513{ 514 ewk_view_scroll(m_view, scrollDelta.width(), scrollDelta.height(), rectToScroll.x(), rectToScroll.y(), rectToScroll.width(), rectToScroll.height(), clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height(), EINA_TRUE); 515} 516 517void ChromeClientEfl::cancelGeolocationPermissionRequestForFrame(Frame*) 518{ 519 notImplemented(); 520} 521 522void ChromeClientEfl::iconForFiles(const Vector<String, 0u>&, PassRefPtr<FileChooser>) 523{ 524 notImplemented(); 525} 526 527void ChromeClientEfl::chooseIconForFiles(const Vector<String>&, FileChooser*) 528{ 529 notImplemented(); 530} 531 532void ChromeClientEfl::dispatchViewportDataDidChange(const ViewportArguments& arguments) const 533{ 534 ewk_view_viewport_attributes_set(m_view, arguments); 535} 536 537bool ChromeClientEfl::selectItemWritingDirectionIsNatural() 538{ 539 return true; 540} 541 542bool ChromeClientEfl::selectItemAlignmentFollowsMenuWritingDirection() 543{ 544 return false; 545} 546 547PassRefPtr<PopupMenu> ChromeClientEfl::createPopupMenu(PopupMenuClient* client) const 548{ 549 return adoptRef(new PopupMenuEfl(client)); 550} 551 552PassRefPtr<SearchPopupMenu> ChromeClientEfl::createSearchPopupMenu(PopupMenuClient* client) const 553{ 554 return adoptRef(new SearchPopupMenuEfl(client)); 555} 556 557} 558