1/*
2 * Copyright (C) 2007 Kevin Ollivier  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "WebView.h"
28
29#include "ContextMenu.h"
30#include "ContextMenuController.h"
31#include "ContextMenuItem.h"
32#include "Document.h"
33#include "Editor.h"
34#include "Element.h"
35#include "EmptyClients.h"
36#include "EventHandler.h"
37#include "FileChooser.h"
38#include "FocusController.h"
39#include "Frame.h"
40#include "FrameLoader.h"
41#include "FrameView.h"
42#include "GraphicsContext.h"
43#include "HTMLFormElement.h"
44#include "Logging.h"
45#include "MemoryCache.h"
46#include "Page.h"
47#include "PlatformKeyboardEvent.h"
48#include "PlatformMouseEvent.h"
49#include "PlatformString.h"
50#include "PlatformWheelEvent.h"
51#include "PluginHalterClient.h"
52#include "RenderObject.h"
53#include "RenderView.h"
54#include "ResourceHandleManager.h"
55#include "Scrollbar.h"
56#include "SelectionController.h"
57#include "Settings.h"
58#include "SubstituteData.h"
59#include "Threading.h"
60#include "markup.h"
61#if __WXMSW__
62#include "WebCoreInstanceHandle.h"
63#endif
64
65#include "ChromeClientWx.h"
66#include "ContextMenuClientWx.h"
67#include "DragClientWx.h"
68#include "EditorClientWx.h"
69#include "FrameLoaderClientWx.h"
70#include "InspectorClientWx.h"
71
72#include "ScriptController.h"
73#include "JSDOMBinding.h"
74#include <runtime/initializeThreading.h>
75#include <runtime/JSValue.h>
76#include <runtime/UString.h>
77#include <wtf/text/CString.h>
78
79#if ENABLE(DATABASE)
80#include "AbstractDatabase.h"
81#include "DatabaseTracker.h"
82#endif
83
84#include "wx/wxprec.h"
85#ifndef WX_PRECOMP
86    #include "wx/wx.h"
87#endif
88
89#include "WebDOMElement.h"
90#include "WebDOMNode.h"
91
92#include "WebFrame.h"
93#include "WebViewPrivate.h"
94
95#include <wx/defs.h>
96#include <wx/dcbuffer.h>
97#include <wx/dcgraph.h>
98
99#if defined(_MSC_VER)
100int rint(double val)
101{
102    return (int)(val < 0 ? val - 0.5 : val + 0.5);
103}
104#endif
105
106// ----------------------------------------------------------------------------
107// wxWebView Events
108// ----------------------------------------------------------------------------
109
110IMPLEMENT_DYNAMIC_CLASS(wxWebViewLoadEvent, wxCommandEvent)
111
112DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_LOAD)
113
114wxWebViewLoadEvent::wxWebViewLoadEvent(wxWindow* win)
115{
116    SetEventType( wxEVT_WEBVIEW_LOAD);
117    SetEventObject( win );
118    if (win)
119        SetId(win->GetId());
120}
121
122IMPLEMENT_DYNAMIC_CLASS(wxWebViewBeforeLoadEvent, wxCommandEvent)
123
124DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_BEFORE_LOAD)
125
126wxWebViewBeforeLoadEvent::wxWebViewBeforeLoadEvent(wxWindow* win)
127{
128    m_cancelled = false;
129    SetEventType(wxEVT_WEBVIEW_BEFORE_LOAD);
130    SetEventObject(win);
131    if (win)
132        SetId(win->GetId());
133}
134
135IMPLEMENT_DYNAMIC_CLASS(wxWebViewNewWindowEvent, wxCommandEvent)
136
137DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_NEW_WINDOW)
138
139wxWebViewNewWindowEvent::wxWebViewNewWindowEvent(wxWindow* win)
140{
141    SetEventType(wxEVT_WEBVIEW_NEW_WINDOW);
142    SetEventObject(win);
143    if (win)
144        SetId(win->GetId());
145}
146
147IMPLEMENT_DYNAMIC_CLASS(wxWebViewRightClickEvent, wxCommandEvent)
148
149DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_RIGHT_CLICK)
150
151wxWebViewRightClickEvent::wxWebViewRightClickEvent(wxWindow* win)
152{
153    SetEventType(wxEVT_WEBVIEW_RIGHT_CLICK);
154    SetEventObject(win);
155    if (win)
156        SetId(win->GetId());
157}
158
159IMPLEMENT_DYNAMIC_CLASS(wxWebViewConsoleMessageEvent, wxCommandEvent)
160
161DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_CONSOLE_MESSAGE)
162
163wxWebViewConsoleMessageEvent::wxWebViewConsoleMessageEvent(wxWindow* win)
164{
165    SetEventType(wxEVT_WEBVIEW_CONSOLE_MESSAGE);
166    SetEventObject(win);
167    if (win)
168        SetId(win->GetId());
169}
170
171IMPLEMENT_DYNAMIC_CLASS(wxWebViewAlertEvent, wxCommandEvent)
172
173DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_JS_ALERT)
174
175wxWebViewAlertEvent::wxWebViewAlertEvent(wxWindow* win)
176{
177    SetEventType(wxEVT_WEBVIEW_JS_ALERT);
178    SetEventObject(win);
179    if (win)
180        SetId(win->GetId());
181}
182
183IMPLEMENT_DYNAMIC_CLASS(wxWebViewConfirmEvent, wxCommandEvent)
184
185DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_JS_CONFIRM)
186
187wxWebViewConfirmEvent::wxWebViewConfirmEvent(wxWindow* win)
188{
189    SetEventType(wxEVT_WEBVIEW_JS_CONFIRM);
190    SetEventObject(win);
191    if (win)
192        SetId(win->GetId());
193}
194
195IMPLEMENT_DYNAMIC_CLASS(wxWebViewPromptEvent, wxCommandEvent)
196
197DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_JS_PROMPT)
198
199wxWebViewPromptEvent::wxWebViewPromptEvent(wxWindow* win)
200{
201    SetEventType(wxEVT_WEBVIEW_JS_PROMPT);
202    SetEventObject(win);
203    if (win)
204        SetId(win->GetId());
205}
206
207IMPLEMENT_DYNAMIC_CLASS(wxWebViewReceivedTitleEvent, wxCommandEvent)
208
209DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_RECEIVED_TITLE)
210
211wxWebViewReceivedTitleEvent::wxWebViewReceivedTitleEvent(wxWindow* win)
212{
213    SetEventType(wxEVT_WEBVIEW_RECEIVED_TITLE);
214    SetEventObject(win);
215    if (win)
216        SetId(win->GetId());
217}
218
219IMPLEMENT_DYNAMIC_CLASS(wxWebViewWindowObjectClearedEvent, wxCommandEvent)
220
221DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_WINDOW_OBJECT_CLEARED)
222
223wxWebViewWindowObjectClearedEvent::wxWebViewWindowObjectClearedEvent(wxWindow* win)
224{
225    SetEventType(wxEVT_WEBVIEW_WINDOW_OBJECT_CLEARED);
226    SetEventObject(win);
227    if (win)
228        SetId(win->GetId());
229}
230
231IMPLEMENT_DYNAMIC_CLASS(wxWebViewContentsChangedEvent, wxCommandEvent)
232
233DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_CONTENTS_CHANGED)
234
235wxWebViewContentsChangedEvent::wxWebViewContentsChangedEvent(wxWindow* win)
236{
237    SetEventType(wxEVT_WEBVIEW_CONTENTS_CHANGED);
238    SetEventObject(win);
239    if (win)
240        SetId(win->GetId());
241}
242
243IMPLEMENT_DYNAMIC_CLASS(wxWebViewSelectionChangedEvent, wxCommandEvent)
244
245DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_SELECTION_CHANGED)
246
247wxWebViewSelectionChangedEvent::wxWebViewSelectionChangedEvent(wxWindow* win)
248{
249    SetEventType(wxEVT_WEBVIEW_SELECTION_CHANGED);
250    SetEventObject(win);
251    if (win)
252        SetId(win->GetId());
253}
254
255//---------------------------------------------------------
256// DOM Element info data type
257//---------------------------------------------------------
258
259wxWebViewDOMElementInfo::wxWebViewDOMElementInfo() :
260    m_isSelected(false),
261    m_text(wxEmptyString),
262    m_imageSrc(wxEmptyString),
263    m_link(wxEmptyString),
264    m_urlElement(NULL),
265    m_innerNode(NULL)
266{
267}
268
269static wxWebViewCachePolicy gs_cachePolicy;
270
271/* static */
272void wxWebView::SetCachePolicy(const wxWebViewCachePolicy& cachePolicy)
273{
274    WebCore::MemoryCache* globalCache = WebCore::memoryCache();
275    globalCache->setCapacities(cachePolicy.GetMinDeadCapacity(),
276                               cachePolicy.GetMaxDeadCapacity(),
277                               cachePolicy.GetCapacity());
278
279    // store a copy since there is no getter for MemoryCache values
280    gs_cachePolicy = cachePolicy;
281}
282
283/* static */
284wxWebViewCachePolicy wxWebView::GetCachePolicy()
285{
286    return gs_cachePolicy;
287}
288
289wxWebViewDOMElementInfo::wxWebViewDOMElementInfo(const wxWebViewDOMElementInfo& other)
290{
291    m_isSelected = other.m_isSelected;
292    m_text = other.m_text;
293    m_imageSrc = other.m_imageSrc;
294    m_link = other.m_link;
295    m_innerNode = other.m_innerNode;
296    m_urlElement = other.m_urlElement;
297}
298
299wxWebViewDOMElementInfo::~wxWebViewDOMElementInfo()
300{
301    if (m_innerNode)
302        delete m_innerNode;
303
304    if (m_urlElement)
305        delete m_urlElement;
306}
307
308#if OS(DARWIN)
309// prototype - function is in WebSystemInterface.mm
310void InitWebCoreSystemInterface(void);
311#endif
312
313BEGIN_EVENT_TABLE(wxWebView, wxWindow)
314    EVT_PAINT(wxWebView::OnPaint)
315    EVT_SIZE(wxWebView::OnSize)
316    EVT_MOUSE_EVENTS(wxWebView::OnMouseEvents)
317    EVT_CONTEXT_MENU(wxWebView::OnContextMenuEvents)
318    EVT_KEY_DOWN(wxWebView::OnKeyEvents)
319    EVT_KEY_UP(wxWebView::OnKeyEvents)
320    EVT_CHAR(wxWebView::OnKeyEvents)
321    EVT_SET_FOCUS(wxWebView::OnSetFocus)
322    EVT_KILL_FOCUS(wxWebView::OnKillFocus)
323END_EVENT_TABLE()
324
325IMPLEMENT_DYNAMIC_CLASS(wxWebView, wxWindow)
326
327const wxChar* wxWebViewNameStr = wxT("webView");
328
329wxWebView::wxWebView() :
330    m_textMagnifier(1.0),
331    m_isInitialized(false),
332    m_beingDestroyed(false),
333    m_mouseWheelZooms(false),
334    m_title(wxEmptyString)
335{
336}
337
338wxWebView::wxWebView(wxWindow* parent, int id, const wxPoint& position,
339                     const wxSize& size, long style, const wxString& name) :
340    m_textMagnifier(1.0),
341    m_isInitialized(false),
342    m_beingDestroyed(false),
343    m_mouseWheelZooms(false),
344    m_title(wxEmptyString)
345{
346    Create(parent, id, position, size, style, name);
347}
348
349bool wxWebView::Create(wxWindow* parent, int id, const wxPoint& position,
350                       const wxSize& size, long style, const wxString& name)
351{
352#if OS(DARWIN)
353    InitWebCoreSystemInterface();
354#endif
355
356    if ( (style & wxBORDER_MASK) == 0)
357        style |= wxBORDER_NONE;
358
359    if (!wxWindow::Create(parent, id, position, size, style, name))
360        return false;
361
362    JSC::initializeThreading();
363    WTF::initializeMainThread();
364
365// This is necessary because we are using SharedTimerWin.cpp on Windows,
366// due to a problem with exceptions getting eaten when using the callback
367// approach to timers (which wx itself uses).
368#if __WXMSW__
369    WebCore::setInstanceHandle(wxGetInstance());
370#endif
371
372    // this helps reduce flicker on platforms like MSW
373    SetBackgroundStyle(wxBG_STYLE_CUSTOM);
374
375    m_impl = new WebViewPrivate();
376
377    WebCore::InitializeLoggingChannelsIfNecessary();
378    WebCore::HTMLFrameOwnerElement* parentFrame = 0;
379
380    WebCore::EditorClientWx* editorClient = new WebCore::EditorClientWx();
381
382    WebCore::Page::PageClients pageClients;
383    pageClients.chromeClient = new WebCore::ChromeClientWx(this);
384    pageClients.contextMenuClient = new WebCore::ContextMenuClientWx();
385    pageClients.editorClient = editorClient;
386    pageClients.dragClient = new WebCore::DragClientWx();
387    pageClients.inspectorClient = new WebCore::InspectorClientWx();
388    m_impl->page = new WebCore::Page(pageClients);
389    editorClient->setPage(m_impl->page);
390
391    m_mainFrame = new wxWebFrame(this);
392
393    // Default settings - we should have wxWebViewSettings class for this
394    // eventually
395    WebCore::Settings* settings = m_impl->page->settings();
396    settings->setLoadsImagesAutomatically(true);
397    settings->setDefaultFixedFontSize(13);
398    settings->setDefaultFontSize(16);
399    settings->setSerifFontFamily("Times New Roman");
400    settings->setFixedFontFamily("Courier New");
401    settings->setSansSerifFontFamily("Arial");
402    settings->setStandardFontFamily("Times New Roman");
403    settings->setJavaScriptEnabled(true);
404
405#if ENABLE(DATABASE)
406    SetDatabasesEnabled(true);
407#endif
408
409    // we need to do this so that objects like the focusController are properly
410    // initialized so that the activate handler is run properly.
411    LoadURL(wxT("about:blank"));
412
413    m_isInitialized = true;
414
415    return true;
416}
417
418wxWebView::~wxWebView()
419{
420    m_beingDestroyed = true;
421
422    while (HasCapture())
423        ReleaseMouse();
424
425    if (m_mainFrame && m_mainFrame->GetFrame())
426        m_mainFrame->GetFrame()->loader()->detachFromParent();
427
428    delete m_impl->page;
429    m_impl->page = 0;
430}
431
432// NOTE: binding to this event in the wxWebView constructor is too early in
433// some cases, but leave the event handler here so that users can bind to it
434// at a later time if they have activation state problems.
435void wxWebView::OnTLWActivated(wxActivateEvent& event)
436{
437    if (m_impl && m_impl->page && m_impl->page->focusController())
438        m_impl->page->focusController()->setActive(event.GetActive());
439
440    event.Skip();
441
442}
443
444void wxWebView::Stop()
445{
446    if (m_mainFrame)
447        m_mainFrame->Stop();
448}
449
450void wxWebView::Reload()
451{
452    if (m_mainFrame)
453        m_mainFrame->Reload();
454}
455
456wxString wxWebView::GetPageSource()
457{
458    if (m_mainFrame)
459        return m_mainFrame->GetPageSource();
460
461    return wxEmptyString;
462}
463
464void wxWebView::SetPageSource(const wxString& source, const wxString& baseUrl, const wxString& mimetype)
465{
466    if (m_mainFrame)
467        m_mainFrame->SetPageSource(source, baseUrl, mimetype);
468}
469
470wxString wxWebView::GetInnerText()
471{
472    if (m_mainFrame)
473        return m_mainFrame->GetInnerText();
474
475    return wxEmptyString;
476}
477
478wxString wxWebView::GetAsMarkup()
479{
480    if (m_mainFrame)
481        return m_mainFrame->GetAsMarkup();
482
483    return wxEmptyString;
484}
485
486wxString wxWebView::GetExternalRepresentation()
487{
488    if (m_mainFrame)
489        return m_mainFrame->GetExternalRepresentation();
490
491    return wxEmptyString;
492}
493
494wxWebKitSelection wxWebView::GetSelection()
495{
496    if (m_mainFrame)
497        return m_mainFrame->GetSelection();
498
499    return 0;
500}
501
502wxString wxWebView::GetSelectionAsHTML()
503{
504    if (m_mainFrame)
505        return m_mainFrame->GetSelectionAsHTML();
506
507    return wxEmptyString;
508}
509
510wxString wxWebView::GetSelectionAsText()
511{
512    if (m_mainFrame)
513        return m_mainFrame->GetSelectionAsText();
514
515    return wxEmptyString;
516}
517
518void wxWebView::SetTransparent(bool transparent)
519{
520    WebCore::Frame* frame = 0;
521    if (m_mainFrame)
522        frame = m_mainFrame->GetFrame();
523
524    if (!frame || !frame->view())
525        return;
526
527    frame->view()->setTransparent(transparent);
528}
529
530bool wxWebView::IsTransparent() const
531{
532    WebCore::Frame* frame = 0;
533    if (m_mainFrame)
534        frame = m_mainFrame->GetFrame();
535
536   if (!frame || !frame->view())
537        return false;
538
539    return frame->view()->isTransparent();
540}
541
542wxString wxWebView::RunScript(const wxString& javascript)
543{
544    if (m_mainFrame)
545        return m_mainFrame->RunScript(javascript);
546
547    return wxEmptyString;
548}
549
550bool wxWebView::ExecuteEditCommand(const wxString& command, const wxString& parameter)
551{
552    if (m_mainFrame)
553        return m_mainFrame->ExecuteEditCommand(command, parameter);
554}
555
556EditState wxWebView::GetEditCommandState(const wxString& command) const
557{
558    if (m_mainFrame)
559        return m_mainFrame->GetEditCommandState(command);
560}
561
562wxString wxWebView::GetEditCommandValue(const wxString& command) const
563{
564    if (m_mainFrame)
565        return m_mainFrame->GetEditCommandValue(command);
566
567    return wxEmptyString;
568}
569
570void wxWebView::LoadURL(const wxString& url)
571{
572    if (m_mainFrame)
573        m_mainFrame->LoadURL(url);
574}
575
576bool wxWebView::GoBack()
577{
578    if (m_mainFrame)
579        return m_mainFrame->GoBack();
580
581    return false;
582}
583
584bool wxWebView::GoForward()
585{
586    if (m_mainFrame)
587        return m_mainFrame->GoForward();
588
589    return false;
590}
591
592bool wxWebView::CanGoBack()
593{
594    if (m_mainFrame)
595        return m_mainFrame->CanGoBack();
596
597    return false;
598}
599
600bool wxWebView::CanGoForward()
601{
602    if (m_mainFrame)
603        return m_mainFrame->CanGoForward();
604
605    return false;
606}
607
608bool wxWebView::CanIncreaseTextSize() const
609{
610    if (m_mainFrame)
611        return m_mainFrame->CanIncreaseTextSize();
612
613    return false;
614}
615
616void wxWebView::IncreaseTextSize()
617{
618    if (m_mainFrame)
619        m_mainFrame->IncreaseTextSize();
620}
621
622bool wxWebView::CanDecreaseTextSize() const
623{
624    if (m_mainFrame)
625        m_mainFrame->CanDecreaseTextSize();
626
627    return false;
628}
629
630void wxWebView::DecreaseTextSize()
631{
632    if (m_mainFrame)
633        m_mainFrame->DecreaseTextSize();
634}
635
636void wxWebView::ResetTextSize()
637{
638    if (m_mainFrame)
639        m_mainFrame->ResetTextSize();
640}
641
642void wxWebView::MakeEditable(bool enable)
643{
644    if (m_mainFrame)
645        m_mainFrame->MakeEditable(enable);
646}
647
648bool wxWebView::IsEditable() const
649{
650    if (m_mainFrame)
651        return m_mainFrame->IsEditable();
652
653    return false;
654}
655
656
657
658/*
659 * Event forwarding functions to send events down to WebCore.
660 */
661
662void wxWebView::OnPaint(wxPaintEvent& event)
663{
664    if (m_beingDestroyed || !m_mainFrame)
665        return;
666
667    WebCore::Frame* frame = m_mainFrame->GetFrame();
668    if (!frame || !frame->view())
669        return;
670
671    wxAutoBufferedPaintDC dc(this);
672
673    if (IsShown() && frame->document()) {
674#if USE(WXGC)
675        wxGCDC gcdc(dc);
676#endif
677
678        if (dc.IsOk()) {
679            wxRect paintRect = GetUpdateRegion().GetBox();
680
681#if USE(WXGC)
682            WebCore::GraphicsContext gc(&gcdc);
683#else
684            WebCore::GraphicsContext gc(&dc);
685#endif
686            if (frame->contentRenderer()) {
687                frame->view()->updateLayoutAndStyleIfNeededRecursive();
688                frame->view()->paint(&gc, paintRect);
689            }
690        }
691    }
692}
693
694bool wxWebView::FindString(const wxString& string, bool forward, bool caseSensitive, bool wrapSelection, bool startInSelection)
695{
696    if (m_mainFrame)
697        return m_mainFrame->FindString(string, forward, caseSensitive, wrapSelection, startInSelection);
698
699    return false;
700}
701
702void wxWebView::OnSize(wxSizeEvent& event)
703{
704    if (m_isInitialized && m_mainFrame) {
705        WebCore::Frame* frame = m_mainFrame->GetFrame();
706        frame->view()->resize(event.GetSize());
707        frame->view()->adjustViewSize();
708    }
709
710    event.Skip();
711}
712
713static int getDoubleClickTime()
714{
715#if __WXMSW__
716    return ::GetDoubleClickTime();
717#else
718    return 500;
719#endif
720}
721
722void wxWebView::OnMouseEvents(wxMouseEvent& event)
723{
724    event.Skip();
725
726    if (!m_impl->page)
727        return;
728
729    WebCore::Frame* frame = m_mainFrame->GetFrame();
730    if (!frame || !frame->view())
731        return;
732
733    wxPoint globalPoint = ClientToScreen(event.GetPosition());
734
735    wxEventType type = event.GetEventType();
736
737    if (type == wxEVT_MOUSEWHEEL) {
738        if (m_mouseWheelZooms && event.ControlDown() && !event.AltDown() && !event.ShiftDown()) {
739            if (event.GetWheelRotation() < 0)
740                DecreaseTextSize();
741            else if (event.GetWheelRotation() > 0)
742                IncreaseTextSize();
743        } else {
744            WebCore::PlatformWheelEvent wkEvent(event, globalPoint);
745            frame->eventHandler()->handleWheelEvent(wkEvent);
746        }
747
748        return;
749    }
750
751    // If an event, such as a right-click event, leads to a focus change (e.g. it
752    // raises a dialog), WebKit never gets the mouse up event and never relinquishes
753    // mouse capture. This leads to WebKit handling mouse events, such as modifying
754    // the selection, while other controls or top level windows have the focus.
755    // I'm not sure if this is the right place to handle this, but I can't seem to
756    // find a precedent on how to handle this in other ports.
757    if (wxWindow::FindFocus() != this) {
758        while (HasCapture())
759            ReleaseMouse();
760
761        frame->eventHandler()->setMousePressed(false);
762
763        return;
764    }
765
766    int clickCount = event.ButtonDClick() ? 2 : 1;
767
768    if (clickCount == 1 && m_impl->tripleClickTimer.IsRunning()) {
769        wxPoint diff(event.GetPosition() - m_impl->tripleClickPos);
770        if (abs(diff.x) <= wxSystemSettings::GetMetric(wxSYS_DCLICK_X) &&
771            abs(diff.y) <= wxSystemSettings::GetMetric(wxSYS_DCLICK_Y)) {
772            clickCount = 3;
773        }
774    } else if (clickCount == 2) {
775        m_impl->tripleClickTimer.Start(getDoubleClickTime(), false);
776        m_impl->tripleClickPos = event.GetPosition();
777    }
778
779    WebCore::PlatformMouseEvent wkEvent(event, globalPoint, clickCount);
780
781    if (type == wxEVT_LEFT_DOWN || type == wxEVT_MIDDLE_DOWN || type == wxEVT_RIGHT_DOWN ||
782                type == wxEVT_LEFT_DCLICK || type == wxEVT_MIDDLE_DCLICK || type == wxEVT_RIGHT_DCLICK) {
783        frame->eventHandler()->handleMousePressEvent(wkEvent);
784        if (!HasCapture())
785            CaptureMouse();
786    } else if (type == wxEVT_LEFT_UP || type == wxEVT_MIDDLE_UP || type == wxEVT_RIGHT_UP) {
787        frame->eventHandler()->handleMouseReleaseEvent(wkEvent);
788        while (HasCapture())
789            ReleaseMouse();
790    } else if (type == wxEVT_MOTION || type == wxEVT_ENTER_WINDOW || type == wxEVT_LEAVE_WINDOW)
791        frame->eventHandler()->mouseMoved(wkEvent);
792}
793
794void wxWebView::OnContextMenuEvents(wxContextMenuEvent& event)
795{
796    Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(wxWebView::OnMenuSelectEvents), NULL, this);
797    m_impl->page->contextMenuController()->clearContextMenu();
798    wxPoint localEventPoint = ScreenToClient(event.GetPosition());
799
800    if (!m_impl->page)
801        return;
802
803    WebCore::Frame* focusedFrame = m_impl->page->focusController()->focusedOrMainFrame();
804    if (!focusedFrame->view())
805        return;
806
807    //Create WebCore mouse event from the wxContextMenuEvent
808    wxMouseEvent mouseEvent(wxEVT_RIGHT_DOWN);
809    mouseEvent.m_x = localEventPoint.x;
810    mouseEvent.m_y = localEventPoint.y;
811    WebCore::PlatformMouseEvent wkEvent(mouseEvent, event.GetPosition(), 1);
812
813    bool handledEvent = focusedFrame->eventHandler()->sendContextMenuEvent(wkEvent);
814    if (!handledEvent)
815        return;
816
817    WebCore::ContextMenu* coreMenu = m_impl->page->contextMenuController()->contextMenu();
818    if (!coreMenu)
819        return;
820
821    WebCore::PlatformMenuDescription menuWx = coreMenu->platformDescription();
822    if (!menuWx)
823        return;
824
825    PopupMenu(menuWx, localEventPoint);
826
827    Disconnect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(wxWebView::OnMenuSelectEvents), NULL, this);
828}
829
830void wxWebView::OnMenuSelectEvents(wxCommandEvent& event)
831{
832    // we shouldn't hit this unless there's a context menu showing
833    WebCore::ContextMenu* coreMenu = m_impl->page->contextMenuController()->contextMenu();
834    ASSERT(coreMenu);
835    if (!coreMenu)
836        return;
837
838    WebCore::ContextMenuItem* item = WebCore::ContextMenu::itemWithId (event.GetId());
839    if (!item)
840        return;
841
842    m_impl->page->contextMenuController()->contextMenuItemSelected(item);
843    delete item;
844}
845
846bool wxWebView::CanCopy()
847{
848    if (m_mainFrame)
849        return m_mainFrame->CanCopy();
850
851    return false;
852}
853
854void wxWebView::Copy()
855{
856    if (m_mainFrame)
857        m_mainFrame->Copy();
858}
859
860bool wxWebView::CanCut()
861{
862    if (m_mainFrame)
863        return m_mainFrame->CanCut();
864
865    return false;
866}
867
868void wxWebView::Cut()
869{
870    if (m_mainFrame)
871        m_mainFrame->Cut();
872}
873
874bool wxWebView::CanPaste()
875{
876    if (m_mainFrame)
877        return m_mainFrame->CanPaste();
878
879    return false;
880}
881
882void wxWebView::Paste()
883{
884    if (m_mainFrame)
885        m_mainFrame->Paste();
886}
887
888void wxWebView::OnKeyEvents(wxKeyEvent& event)
889{
890    WebCore::Frame* frame = 0;
891    if (m_impl->page)
892        frame = m_impl->page->focusController()->focusedOrMainFrame();
893
894    if (!(frame && frame->view()))
895        return;
896
897    WebCore::PlatformKeyboardEvent wkEvent(event);
898
899    if (frame->eventHandler()->keyEvent(wkEvent))
900        return;
901
902    //Some things WebKit won't do for us... Copy/Cut/Paste and KB scrolling
903    if (event.GetEventType() == wxEVT_KEY_DOWN) {
904        switch (event.GetKeyCode()) {
905        case 67: //"C"
906            if (CanCopy() && event.GetModifiers() == wxMOD_CMD) {
907                Copy();
908                return;
909            }
910            break;
911        case 86: //"V"
912            if (CanPaste() && event.GetModifiers() == wxMOD_CMD) {
913                Paste();
914                return;
915            }
916            break;
917        case 88: //"X"
918            if (CanCut() && event.GetModifiers() == wxMOD_CMD) {
919                Cut();
920                return;
921            }
922            break;
923        case WXK_INSERT:
924            if (CanCopy() && event.GetModifiers() == wxMOD_CMD) {
925                Copy();
926                return;
927            }
928            if (CanPaste() && event.GetModifiers() == wxMOD_SHIFT) {
929                Paste();
930                return;
931            }
932            return; //Insert shall not become a char
933        case WXK_DELETE:
934            if (CanCut() && event.GetModifiers() == wxMOD_SHIFT) {
935                Cut();
936                return;
937            }
938            break;
939        case WXK_LEFT:
940        case WXK_NUMPAD_LEFT:
941            frame->view()->scrollBy(WebCore::IntSize(-WebCore::Scrollbar::pixelsPerLineStep(), 0));
942            return;
943        case WXK_UP:
944        case WXK_NUMPAD_UP:
945            frame->view()->scrollBy(WebCore::IntSize(0, -WebCore::Scrollbar::pixelsPerLineStep()));
946            return;
947        case WXK_RIGHT:
948        case WXK_NUMPAD_RIGHT:
949            frame->view()->scrollBy(WebCore::IntSize(WebCore::Scrollbar::pixelsPerLineStep(), 0));
950            return;
951        case WXK_DOWN:
952        case WXK_NUMPAD_DOWN:
953            frame->view()->scrollBy(WebCore::IntSize(0, WebCore::Scrollbar::pixelsPerLineStep()));
954            return;
955        case WXK_END:
956        case WXK_NUMPAD_END:
957            frame->view()->setScrollPosition(WebCore::IntPoint(frame->view()->scrollX(), frame->view()->maximumScrollPosition().y()));
958            return;
959        case WXK_HOME:
960        case WXK_NUMPAD_HOME:
961            frame->view()->setScrollPosition(WebCore::IntPoint(frame->view()->scrollX(), 0));
962            return;
963        case WXK_PAGEUP:
964        case WXK_NUMPAD_PAGEUP:
965            frame->view()->scrollBy(WebCore::IntSize(0, -frame->view()->visibleHeight() * WebCore::Scrollbar::minFractionToStepWhenPaging()));
966            return;
967        case WXK_PAGEDOWN:
968        case WXK_NUMPAD_PAGEDOWN:
969            frame->view()->scrollBy(WebCore::IntSize(0, frame->view()->visibleHeight() * WebCore::Scrollbar::minFractionToStepWhenPaging()));
970            return;
971        //These we don't want turning into char events, stuff 'em
972        case WXK_ESCAPE:
973        case WXK_LBUTTON:
974        case WXK_RBUTTON:
975        case WXK_CANCEL:
976        case WXK_MENU:
977        case WXK_MBUTTON:
978        case WXK_CLEAR:
979        case WXK_PAUSE:
980        case WXK_SELECT:
981        case WXK_PRINT:
982        case WXK_EXECUTE:
983        case WXK_SNAPSHOT:
984        case WXK_HELP:
985        case WXK_F1:
986        case WXK_F2:
987        case WXK_F3:
988        case WXK_F4:
989        case WXK_F5:
990        case WXK_F6:
991        case WXK_F7:
992        case WXK_F8:
993        case WXK_F9:
994        case WXK_F10:
995        case WXK_F11:
996        case WXK_F12:
997        case WXK_F13:
998        case WXK_F14:
999        case WXK_F15:
1000        case WXK_F16:
1001        case WXK_F17:
1002        case WXK_F18:
1003        case WXK_F19:
1004        case WXK_F20:
1005        case WXK_F21:
1006        case WXK_F22:
1007        case WXK_F23:
1008        case WXK_F24:
1009        case WXK_NUMPAD_F1:
1010        case WXK_NUMPAD_F2:
1011        case WXK_NUMPAD_F3:
1012        case WXK_NUMPAD_F4:
1013        //When numlock is off Numpad 5 becomes BEGIN, or HOME on Char
1014        case WXK_NUMPAD_BEGIN:
1015        case WXK_NUMPAD_INSERT:
1016            return;
1017        }
1018    }
1019
1020    event.Skip();
1021}
1022
1023void wxWebView::OnSetFocus(wxFocusEvent& event)
1024{
1025    if (m_impl && m_impl->page && m_impl->page->focusController()) {
1026        m_impl->page->focusController()->setFocused(true);
1027        m_impl->page->focusController()->setActive(true);
1028
1029        if (!m_impl->page->focusController()->focusedFrame() && m_mainFrame)
1030            m_impl->page->focusController()->setFocusedFrame(m_mainFrame->GetFrame());
1031    }
1032
1033    event.Skip();
1034}
1035
1036void wxWebView::OnKillFocus(wxFocusEvent& event)
1037{
1038    if (m_impl && m_impl->page && m_impl->page->focusController()) {
1039        m_impl->page->focusController()->setFocused(false);
1040
1041        // We also handle active state in OnTLWActivated, but if a user does not
1042        // call event.Skip() in their own EVT_ACTIVATE handler, we won't get those
1043        // callbacks. So we handle active state here as well as a fallback.
1044        wxTopLevelWindow* tlw = dynamic_cast<wxTopLevelWindow*>(wxGetTopLevelParent(this));
1045        if (tlw && tlw->IsActive())
1046            m_impl->page->focusController()->setActive(true);
1047        else
1048            m_impl->page->focusController()->setActive(false);
1049    }
1050
1051    while (HasCapture())
1052        ReleaseMouse();
1053
1054    event.Skip();
1055}
1056
1057wxWebViewDOMElementInfo wxWebView::HitTest(const wxPoint& pos) const
1058{
1059    if (m_mainFrame)
1060        return m_mainFrame->HitTest(pos);
1061
1062    return wxWebViewDOMElementInfo();
1063}
1064
1065bool wxWebView::ShouldClose() const
1066{
1067    if (m_mainFrame)
1068        return m_mainFrame->ShouldClose();
1069
1070    return true;
1071}
1072
1073/* static */
1074void wxWebView::SetDatabaseDirectory(const wxString& databaseDirectory)
1075{
1076#if ENABLE(DATABASE)
1077    WebCore::DatabaseTracker::tracker().setDatabaseDirectoryPath(databaseDirectory);
1078#endif
1079}
1080
1081/* static */
1082wxString wxWebView::GetDatabaseDirectory()
1083{
1084#if ENABLE(DATABASE)
1085    return WebCore::DatabaseTracker::tracker().databaseDirectoryPath();
1086#else
1087    return wxEmptyString;
1088#endif
1089}
1090
1091/* static */
1092void wxWebView::SetDatabasesEnabled(bool enabled)
1093{
1094#if ENABLE(DATABASE)
1095    WebCore::AbstractDatabase::setIsAvailable(enabled);
1096#endif
1097}
1098
1099/* static */
1100bool wxWebView::AreDatabasesEnabled()
1101{
1102#if ENABLE(DATABASE)
1103    return WebCore::AbstractDatabase::isAvailable();
1104#endif
1105    return false;
1106}
1107
1108static WebCore::ResourceHandleManager::ProxyType curlProxyType(wxProxyType type)
1109{
1110    switch (type) {
1111        case HTTP: return WebCore::ResourceHandleManager::HTTP;
1112        case Socks4: return WebCore::ResourceHandleManager::Socks4;
1113        case Socks4A: return WebCore::ResourceHandleManager::Socks4A;
1114        case Socks5: return WebCore::ResourceHandleManager::Socks5;
1115        case Socks5Hostname: return WebCore::ResourceHandleManager::Socks5Hostname;
1116        default:
1117            ASSERT_NOT_REACHED();
1118            return WebCore::ResourceHandleManager::HTTP;
1119    }
1120}
1121
1122/* static */
1123void wxWebView::SetProxyInfo(const wxString& host,
1124                             unsigned long port,
1125                             wxProxyType type,
1126                             const wxString& username,
1127                             const wxString& password)
1128{
1129    using WebCore::ResourceHandleManager;
1130    if (ResourceHandleManager* mgr = ResourceHandleManager::sharedInstance())
1131        mgr->setProxyInfo(host, port, curlProxyType(type), username, password);
1132}
1133
1134wxWebSettings wxWebView::GetWebSettings()
1135{
1136    ASSERT(m_impl->page);
1137    if (m_impl->page)
1138        return wxWebSettings(m_impl->page->settings());
1139
1140    return wxWebSettings();
1141}
1142
1143wxWebKitCompatibilityMode wxWebView::GetCompatibilityMode() const
1144{
1145    if (m_mainFrame)
1146        return m_mainFrame->GetCompatibilityMode();
1147
1148    return QuirksMode;
1149}
1150
1151void wxWebView::GrantUniversalAccess()
1152{
1153    if (m_mainFrame)
1154        m_mainFrame->GrantUniversalAccess();
1155}
1156