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-2012 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#include "ApplicationCacheStorage.h" 38#include "FileChooser.h" 39#include "FileIconLoader.h" 40#include "FloatRect.h" 41#include "Frame.h" 42#include "FrameLoader.h" 43#include "FrameLoaderClientEfl.h" 44#include "HitTestResult.h" 45#include "IntRect.h" 46#include "KURL.h" 47#include "NavigationAction.h" 48#include "NotImplemented.h" 49#include "PopupMenuEfl.h" 50#include "SearchPopupMenuEfl.h" 51#include "SecurityOrigin.h" 52#include "ViewportArguments.h" 53#include "WindowFeatures.h" 54#include "ewk_custom_handler_private.h" 55#include "ewk_file_chooser_private.h" 56#include "ewk_frame_private.h" 57#include "ewk_private.h" 58#include "ewk_security_origin_private.h" 59#include "ewk_view_private.h" 60#include <Ecore_Evas.h> 61#include <Evas.h> 62#include <wtf/text/CString.h> 63#include <wtf/text/WTFString.h> 64 65#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS) 66#include "NotificationPresenterClientEfl.h" 67#endif 68 69#if ENABLE(SQL_DATABASE) 70#include "DatabaseDetails.h" 71#include "DatabaseManager.h" 72#endif 73 74#if ENABLE(INPUT_TYPE_COLOR) 75#include "ColorChooserEfl.h" 76#endif 77 78#if ENABLE(FULLSCREEN_API) 79#include "Settings.h" 80#endif 81 82using namespace WebCore; 83 84static inline Evas_Object* kit(Frame* frame) 85{ 86 if (!frame) 87 return 0; 88 89 FrameLoaderClientEfl* client = static_cast<FrameLoaderClientEfl*>(frame->loader()->client()); 90 return client ? client->webFrame() : 0; 91} 92 93namespace WebCore { 94 95ChromeClientEfl::ChromeClientEfl(Evas_Object* view) 96 : m_view(view) 97{ 98 ASSERT(m_view); 99} 100 101ChromeClientEfl::~ChromeClientEfl() 102{ 103} 104 105void ChromeClientEfl::chromeDestroyed() 106{ 107 delete this; 108} 109 110void ChromeClientEfl::focusedNodeChanged(Node*) 111{ 112 notImplemented(); 113} 114 115void ChromeClientEfl::focusedFrameChanged(Frame*) 116{ 117} 118 119FloatRect ChromeClientEfl::windowRect() 120{ 121 int x, y, width, height; 122 123 Ecore_Evas* ee = ecore_evas_ecore_evas_get(evas_object_evas_get(m_view)); 124 ecore_evas_request_geometry_get(ee, &x, &y, &width, &height); 125 126 return FloatRect(x, y, width, height); 127} 128 129void ChromeClientEfl::setWindowRect(const FloatRect& rect) 130{ 131 if (!ewk_view_setting_enable_auto_resize_window_get(m_view)) 132 return; 133 134 Ecore_Evas* ee = ecore_evas_ecore_evas_get(evas_object_evas_get(m_view)); 135 ecore_evas_move_resize(ee, rect.x(), rect.y(), rect.width(), rect.height()); 136} 137 138FloatRect ChromeClientEfl::pageRect() 139{ 140 return ewk_view_page_rect_get(m_view); 141} 142 143void ChromeClientEfl::focus() 144{ 145 evas_object_focus_set(m_view, EINA_TRUE); 146} 147 148void ChromeClientEfl::unfocus() 149{ 150 evas_object_focus_set(m_view, EINA_FALSE); 151} 152 153Page* ChromeClientEfl::createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures& features, const NavigationAction&) 154{ 155 Evas_Object* newView = ewk_view_window_create(m_view, EINA_TRUE, &features); 156 if (!newView) 157 return 0; 158 159 return EWKPrivate::corePage(newView); 160} 161 162void ChromeClientEfl::show() 163{ 164 ewk_view_ready(m_view); 165} 166 167bool ChromeClientEfl::canRunModal() 168{ 169 notImplemented(); 170 return false; 171} 172 173void ChromeClientEfl::runModal() 174{ 175 notImplemented(); 176} 177 178void ChromeClientEfl::setToolbarsVisible(bool visible) 179{ 180 ewk_view_toolbars_visible_set(m_view, visible); 181} 182 183bool ChromeClientEfl::toolbarsVisible() 184{ 185 bool visible; 186 187 ewk_view_toolbars_visible_get(m_view, &visible); 188 return visible; 189} 190 191void ChromeClientEfl::setStatusbarVisible(bool visible) 192{ 193 ewk_view_statusbar_visible_set(m_view, visible); 194} 195 196bool ChromeClientEfl::statusbarVisible() 197{ 198 bool visible; 199 200 ewk_view_statusbar_visible_get(m_view, &visible); 201 return visible; 202} 203 204void ChromeClientEfl::setScrollbarsVisible(bool visible) 205{ 206 ewk_view_scrollbars_visible_set(m_view, visible); 207} 208 209bool ChromeClientEfl::scrollbarsVisible() 210{ 211 bool visible; 212 213 ewk_view_scrollbars_visible_get(m_view, &visible); 214 return visible; 215} 216 217void ChromeClientEfl::setMenubarVisible(bool visible) 218{ 219 ewk_view_menubar_visible_set(m_view, visible); 220} 221 222bool ChromeClientEfl::menubarVisible() 223{ 224 bool visible; 225 226 ewk_view_menubar_visible_get(m_view, &visible); 227 return visible; 228} 229 230void ChromeClientEfl::createSelectPopup(PopupMenuClient* client, int selected, const IntRect& rect) 231{ 232 ewk_view_popup_new(m_view, client, selected, rect); 233} 234 235bool ChromeClientEfl::destroySelectPopup() 236{ 237 return ewk_view_popup_destroy(m_view); 238} 239 240void ChromeClientEfl::setResizable(bool) 241{ 242 notImplemented(); 243} 244 245void ChromeClientEfl::closeWindowSoon() 246{ 247 ewk_view_window_close(m_view); 248} 249 250bool ChromeClientEfl::canTakeFocus(FocusDirection coreDirection) 251{ 252 // This is called when cycling through links/focusable objects and we 253 // reach the last focusable object. 254 ASSERT(coreDirection == FocusDirectionForward || coreDirection == FocusDirectionBackward); 255 256 Ewk_Focus_Direction direction = static_cast<Ewk_Focus_Direction>(coreDirection); 257 258 return !ewk_view_focus_can_cycle(m_view, direction); 259} 260 261void ChromeClientEfl::takeFocus(FocusDirection) 262{ 263 unfocus(); 264} 265 266bool ChromeClientEfl::canRunBeforeUnloadConfirmPanel() 267{ 268 return true; 269} 270 271bool ChromeClientEfl::runBeforeUnloadConfirmPanel(const String& message, Frame* frame) 272{ 273 return ewk_view_run_before_unload_confirm(m_view, kit(frame), message.utf8().data()); 274} 275 276void ChromeClientEfl::addMessageToConsole(MessageSource, MessageLevel, const String& message, 277 unsigned lineNumber, unsigned columnNumber, const String& sourceID) 278{ 279 UNUSED_PARAM(columnNumber); 280 ewk_view_add_console_message(m_view, message.utf8().data(), lineNumber, sourceID.utf8().data()); 281} 282 283void ChromeClientEfl::runJavaScriptAlert(Frame* frame, const String& message) 284{ 285 ewk_view_run_javascript_alert(m_view, kit(frame), message.utf8().data()); 286} 287 288bool ChromeClientEfl::runJavaScriptConfirm(Frame* frame, const String& message) 289{ 290 return ewk_view_run_javascript_confirm(m_view, kit(frame), message.utf8().data()); 291} 292 293bool ChromeClientEfl::runJavaScriptPrompt(Frame* frame, const String& message, const String& defaultValue, String& result) 294{ 295 const char* value = 0; 296 ewk_view_run_javascript_prompt(m_view, kit(frame), message.utf8().data(), defaultValue.utf8().data(), &value); 297 if (value) { 298 result = String::fromUTF8(value); 299 eina_stringshare_del(value); 300 return true; 301 } 302 return false; 303} 304 305void ChromeClientEfl::setStatusbarText(const String& string) 306{ 307 ewk_view_statusbar_text_set(m_view, string.utf8().data()); 308} 309 310bool ChromeClientEfl::shouldInterruptJavaScript() 311{ 312 return ewk_view_should_interrupt_javascript(m_view); 313} 314 315KeyboardUIMode ChromeClientEfl::keyboardUIMode() 316{ 317 return ewk_view_setting_include_links_in_focus_chain_get(m_view) ? KeyboardAccessTabsToLinks : KeyboardAccessDefault; 318} 319 320IntRect ChromeClientEfl::windowResizerRect() const 321{ 322 notImplemented(); 323 // Implementing this function will make repaint being 324 // called during resize, but as this will be done with 325 // a minor delay it adds a weird "filling" effect due 326 // to us using an evas image for showing the cairo 327 // context. So instead of implementing this function 328 // we call paint directly during resize with 329 // the new object size as its argument. 330 return IntRect(); 331} 332 333void ChromeClientEfl::contentsSizeChanged(Frame* frame, const IntSize& size) const 334{ 335 ewk_frame_contents_size_changed(kit(frame), size.width(), size.height()); 336 if (ewk_view_frame_main_get(m_view) == kit(frame)) 337 ewk_view_contents_size_changed(m_view, size.width(), size.height()); 338} 339 340IntRect ChromeClientEfl::rootViewToScreen(const IntRect& rect) const 341{ 342 notImplemented(); 343 return rect; 344} 345 346IntPoint ChromeClientEfl::screenToRootView(const IntPoint& point) const 347{ 348 notImplemented(); 349 return point; 350} 351 352PlatformPageClient ChromeClientEfl::platformPageClient() const 353{ 354 return EWKPrivate::corePageClient(m_view); 355} 356 357void ChromeClientEfl::scrollbarsModeDidChange() const 358{ 359} 360 361void ChromeClientEfl::mouseDidMoveOverElement(const HitTestResult& hit, unsigned /*modifierFlags*/) 362{ 363 // FIXME, compare with old link, look at Qt impl. 364 bool isLink = hit.isLiveLink(); 365 if (isLink) { 366 KURL url = hit.absoluteLinkURL(); 367 if (!url.isEmpty() && url != m_hoveredLinkURL) { 368 const char* link[2]; 369 TextDirection dir; 370 CString urlStr = url.string().utf8(); 371 CString titleStr = hit.title(dir).utf8(); 372 link[0] = urlStr.data(); 373 link[1] = titleStr.data(); 374 ewk_view_mouse_link_hover_in(m_view, link); 375 m_hoveredLinkURL = url; 376 } 377 } else if (!isLink && !m_hoveredLinkURL.isEmpty()) { 378 ewk_view_mouse_link_hover_out(m_view); 379 m_hoveredLinkURL = KURL(); 380 } 381} 382 383void ChromeClientEfl::setToolTip(const String& toolTip, TextDirection) 384{ 385 ewk_view_tooltip_text_set(m_view, toolTip.utf8().data()); 386} 387 388void ChromeClientEfl::print(Frame*) 389{ 390 notImplemented(); 391} 392 393void ChromeClientEfl::reachedMaxAppCacheSize(int64_t /*spaceNeeded*/) 394{ 395 // FIXME: Free some space. 396 notImplemented(); 397} 398 399void ChromeClientEfl::reachedApplicationCacheOriginQuota(SecurityOrigin* origin, int64_t totalSpaceNeeded) 400{ 401 Ewk_Security_Origin* ewkOrigin = ewk_security_origin_new(origin); 402 int64_t defaultOriginQuota = WebCore::cacheStorage().defaultOriginQuota(); 403 404 int64_t newQuota = ewk_view_exceeded_application_cache_quota(m_view, ewkOrigin, defaultOriginQuota, totalSpaceNeeded); 405 if (newQuota) 406 ewk_security_origin_application_cache_quota_set(ewkOrigin, newQuota); 407 408 ewk_security_origin_free(ewkOrigin); 409} 410 411void ChromeClientEfl::populateVisitedLinks() 412{ 413 evas_object_smart_callback_call(m_view, "populate,visited,links", 0); 414} 415 416#if ENABLE(TOUCH_EVENTS) 417void ChromeClientEfl::needTouchEvents(bool needed) 418{ 419 ewk_view_need_touch_events_set(m_view, needed); 420} 421#endif 422 423#if ENABLE(SQL_DATABASE) 424void ChromeClientEfl::exceededDatabaseQuota(Frame* frame, const String& databaseName, DatabaseDetails details) 425{ 426 uint64_t quota; 427 SecurityOrigin* origin = frame->document()->securityOrigin(); 428 429 quota = ewk_view_exceeded_database_quota(m_view, 430 kit(frame), databaseName.utf8().data(), 431 details.currentUsage(), details.expectedUsage()); 432 433 /* if client did not set quota, and database is being created now, the 434 * default quota is applied 435 */ 436 if (!quota && !DatabaseManager::manager().hasEntryForOrigin(origin)) 437 quota = ewk_settings_web_database_default_quota_get(); 438 439 DatabaseManager::manager().setQuota(origin, quota); 440} 441#endif 442 443#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS) 444NotificationClient* ChromeClientEfl::notificationPresenter() const 445{ 446 notImplemented(); 447 return 0; 448} 449#endif 450 451#if ENABLE(INPUT_TYPE_COLOR) 452PassOwnPtr<ColorChooser> ChromeClientEfl::createColorChooser(ColorChooserClient* colorChooserClient, const Color& initialColor) 453{ 454 ewk_view_color_chooser_new(m_view, colorChooserClient, initialColor); 455 456 return adoptPtr(new ColorChooserEfl(this)); 457} 458 459void ChromeClientEfl::removeColorChooser() 460{ 461 ewk_view_color_chooser_destroy(m_view); 462} 463 464void ChromeClientEfl::updateColorChooser(const Color& color) 465{ 466 ewk_view_color_chooser_changed(m_view, color); 467} 468#endif 469 470void ChromeClientEfl::runOpenPanel(Frame* frame, PassRefPtr<FileChooser> prpFileChooser) 471{ 472 RefPtr<FileChooser> chooser = prpFileChooser; 473 Eina_List* selectedFilenames = 0; 474 Ewk_File_Chooser* fileChooser = ewk_file_chooser_new(chooser.get()); 475 bool confirm = ewk_view_run_open_panel(m_view, kit(frame), fileChooser, &selectedFilenames); 476 ewk_file_chooser_free(fileChooser); 477 if (!confirm) 478 return; 479 480 void* filename; 481 Vector<String> filenames; 482 EINA_LIST_FREE(selectedFilenames, filename) { 483 filenames.append(String::fromUTF8(static_cast<char*>(filename))); 484 free(filename); 485 } 486 487 if (chooser->settings().allowsMultipleFiles) 488 chooser->chooseFiles(filenames); 489 else 490 chooser->chooseFile(filenames[0]); 491} 492 493void ChromeClientEfl::formStateDidChange(const Node*) 494{ 495 notImplemented(); 496} 497 498void ChromeClientEfl::setCursor(const Cursor& cursor) 499{ 500 ewk_view_cursor_set(m_view, cursor); 501} 502 503void ChromeClientEfl::setCursorHiddenUntilMouseMoves(bool) 504{ 505 notImplemented(); 506} 507 508#if ENABLE(REQUEST_ANIMATION_FRAME) && !USE(REQUEST_ANIMATION_FRAME_TIMER) 509void ChromeClientEfl::scheduleAnimation() 510{ 511 notImplemented(); 512} 513 514void ChromeClientEfl::serviceScriptedAnimations() 515{ 516 notImplemented(); 517} 518#endif 519 520void ChromeClientEfl::cancelGeolocationPermissionForFrame(Frame*, Geolocation*) 521{ 522 notImplemented(); 523} 524 525void ChromeClientEfl::invalidateContents(const IntRect& /*updateRect*/, bool /*immediate*/) 526{ 527 notImplemented(); 528} 529 530void ChromeClientEfl::invalidateRootView(const IntRect& updateRect, bool /*immediate*/) 531{ 532#if USE(TILED_BACKING_STORE) 533 ewk_view_tiled_backing_store_invalidate(m_view, updateRect); 534#else 535 UNUSED_PARAM(updateRect); 536 notImplemented(); 537#endif 538} 539 540void ChromeClientEfl::invalidateContentsAndRootView(const IntRect& updateRect, bool /*immediate*/) 541{ 542 if (updateRect.isEmpty()) 543 return; 544 545 Evas_Coord x, y, w, h; 546 547 x = updateRect.x(); 548 y = updateRect.y(); 549 w = updateRect.width(); 550 h = updateRect.height(); 551 ewk_view_repaint(m_view, x, y, w, h); 552} 553 554void ChromeClientEfl::invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate) 555{ 556 invalidateContentsAndRootView(updateRect, immediate); 557} 558 559void ChromeClientEfl::scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect) 560{ 561 ewk_view_scroll(m_view, scrollDelta, rectToScroll, clipRect); 562} 563 564void ChromeClientEfl::cancelGeolocationPermissionRequestForFrame(Frame*) 565{ 566 notImplemented(); 567} 568 569void ChromeClientEfl::iconForFiles(const Vector<String, 0u>&, PassRefPtr<FileChooser>) 570{ 571 notImplemented(); 572} 573 574void ChromeClientEfl::loadIconForFiles(const Vector<String>&, FileIconLoader*) 575{ 576 notImplemented(); 577} 578 579void ChromeClientEfl::dispatchViewportPropertiesDidChange(const ViewportArguments& arguments) const 580{ 581 ewk_view_viewport_attributes_set(m_view, arguments); 582} 583 584bool ChromeClientEfl::selectItemWritingDirectionIsNatural() 585{ 586 return true; 587} 588 589bool ChromeClientEfl::selectItemAlignmentFollowsMenuWritingDirection() 590{ 591 return false; 592} 593 594bool ChromeClientEfl::hasOpenedPopup() const 595{ 596 notImplemented(); 597 return false; 598} 599 600PassRefPtr<PopupMenu> ChromeClientEfl::createPopupMenu(PopupMenuClient* client) const 601{ 602 return adoptRef(new PopupMenuEfl(client)); 603} 604 605PassRefPtr<SearchPopupMenu> ChromeClientEfl::createSearchPopupMenu(PopupMenuClient* client) const 606{ 607 return adoptRef(new SearchPopupMenuEfl(client)); 608} 609 610#if USE(ACCELERATED_COMPOSITING) 611void ChromeClientEfl::attachRootGraphicsLayer(Frame*, GraphicsLayer* rootLayer) 612{ 613 ewk_view_root_graphics_layer_set(m_view, rootLayer); 614} 615 616void ChromeClientEfl::setNeedsOneShotDrawingSynchronization() 617{ 618 ewk_view_mark_for_sync(m_view); 619} 620 621void ChromeClientEfl::scheduleCompositingLayerFlush() 622{ 623 ewk_view_mark_for_sync(m_view); 624} 625 626ChromeClient::CompositingTriggerFlags ChromeClientEfl::allowedCompositingTriggers() const 627{ 628 return AllTriggers; 629} 630#endif 631 632#if ENABLE(FULLSCREEN_API) 633bool ChromeClientEfl::supportsFullScreenForElement(const WebCore::Element* element, bool withKeyboard) 634{ 635 UNUSED_PARAM(withKeyboard); 636 637 if (!element->document()->page()) 638 return false; 639 return element->document()->page()->settings()->fullScreenEnabled(); 640} 641 642void ChromeClientEfl::enterFullScreenForElement(WebCore::Element* element) 643{ 644 // Keep a reference to the element to use it later in 645 // exitFullScreenForElement(). 646 m_fullScreenElement = element; 647 648 element->document()->webkitWillEnterFullScreenForElement(element); 649 ewk_view_fullscreen_enter(m_view); 650 element->document()->webkitDidEnterFullScreenForElement(element); 651} 652 653void ChromeClientEfl::exitFullScreenForElement(WebCore::Element*) 654{ 655 // The element passed into this function is not reliable, i.e. it could 656 // be null. In addition the parameter may be disappearing in the future. 657 // So we use the reference to the element we saved above. 658 ASSERT(m_fullScreenElement); 659 660 m_fullScreenElement->document()->webkitWillExitFullScreenForElement(m_fullScreenElement.get()); 661 ewk_view_fullscreen_exit(m_view); 662 m_fullScreenElement->document()->webkitDidExitFullScreenForElement(m_fullScreenElement.get()); 663 664 m_fullScreenElement.clear(); 665} 666#endif 667 668#if USE(TILED_BACKING_STORE) 669void ChromeClientEfl::delegatedScrollRequested(const IntPoint&) 670{ 671 notImplemented(); 672} 673 674IntRect ChromeClientEfl::visibleRectForTiledBackingStore() const 675{ 676 WebCore::FloatRect rect = ewk_view_page_rect_get(m_view); 677 const Evas_Object* frame = ewk_view_frame_main_get(m_view); 678 679 int x, y; 680 ewk_frame_scroll_pos_get(frame, &x, &y); 681 return IntRect(x, y, rect.width(), rect.height()); 682} 683#endif 684 685} 686