94c760be93f832bca0f4b8e0b573d87aa416b1b1
[WebKit.git] / WebKit / wx / WebView.cpp
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 "CString.h"
28 #include "Document.h"
29 #include "Element.h"
30 #include "Editor.h"
31 #include "EventHandler.h"
32 #include "FocusController.h"
33 #include "Frame.h"
34 #include "FrameLoader.h"
35 #include "FrameView.h"
36 #include "GraphicsContext.h"
37 #include "Logging.h"
38 #include "markup.h"
39 #include "Page.h"
40 #include "ContextMenu.h"
41 #include "ContextMenuItem.h"
42 #include "ContextMenuController.h"
43 #include "PlatformKeyboardEvent.h"
44 #include "PlatformMouseEvent.h"
45 #include "PlatformString.h"
46 #include "PlatformWheelEvent.h"
47 #include "RenderObject.h"
48 #include "RenderView.h"
49 #include "SelectionController.h"
50 #include "Settings.h"
51 #include "SubstituteData.h"
52
53 #include "ChromeClientWx.h"
54 #include "ContextMenuClientWx.h"
55 #include "DragClientWx.h"
56 #include "EditorClientWx.h"
57 #include "FrameLoaderClientWx.h"
58 #include "InspectorClientWx.h"
59
60 #include "ScriptController.h"
61 #include "JSDOMBinding.h"
62 #include <runtime/JSValue.h>
63 #include <runtime/UString.h>
64
65 #include "wx/wxprec.h"
66 #ifndef WX_PRECOMP
67     #include "wx/wx.h"
68 #endif
69
70 #include "WebFrame.h"
71 #include "WebView.h"
72 #include "WebViewPrivate.h"
73
74 #include <wx/defs.h>
75 #include <wx/dcbuffer.h>
76 #include <wx/dcgraph.h>
77
78 #if defined(_MSC_VER)
79 int rint(double val)
80 {
81     return (int)(val < 0 ? val - 0.5 : val + 0.5);
82 }
83 #endif
84
85 // ----------------------------------------------------------------------------
86 // wxWebView Events
87 // ----------------------------------------------------------------------------
88
89 IMPLEMENT_DYNAMIC_CLASS(wxWebViewLoadEvent, wxCommandEvent)
90
91 DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_LOAD)
92
93 wxWebViewLoadEvent::wxWebViewLoadEvent(wxWindow* win)
94 {
95     SetEventType( wxEVT_WEBVIEW_LOAD);
96     SetEventObject( win );
97     if (win)
98         SetId(win->GetId());
99 }
100
101 IMPLEMENT_DYNAMIC_CLASS(wxWebViewBeforeLoadEvent, wxCommandEvent)
102
103 DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_BEFORE_LOAD)
104
105 wxWebViewBeforeLoadEvent::wxWebViewBeforeLoadEvent(wxWindow* win)
106 {
107     m_cancelled = false;
108     SetEventType(wxEVT_WEBVIEW_BEFORE_LOAD);
109     SetEventObject(win);
110     if (win)
111         SetId(win->GetId());
112 }
113
114 IMPLEMENT_DYNAMIC_CLASS(wxWebViewNewWindowEvent, wxCommandEvent)
115
116 DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_NEW_WINDOW)
117
118 wxWebViewNewWindowEvent::wxWebViewNewWindowEvent(wxWindow* win)
119 {
120     SetEventType(wxEVT_WEBVIEW_NEW_WINDOW);
121     SetEventObject(win);
122     if (win)
123         SetId(win->GetId());
124 }
125
126 IMPLEMENT_DYNAMIC_CLASS(wxWebViewRightClickEvent, wxCommandEvent)
127
128 DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_RIGHT_CLICK)
129
130 wxWebViewRightClickEvent::wxWebViewRightClickEvent(wxWindow* win)
131 {
132     SetEventType(wxEVT_WEBVIEW_RIGHT_CLICK);
133     SetEventObject(win);
134     if (win)
135         SetId(win->GetId());
136 }
137
138 IMPLEMENT_DYNAMIC_CLASS(wxWebViewConsoleMessageEvent, wxCommandEvent)
139
140 DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_CONSOLE_MESSAGE)
141
142 wxWebViewConsoleMessageEvent::wxWebViewConsoleMessageEvent(wxWindow* win)
143 {
144     SetEventType(wxEVT_WEBVIEW_CONSOLE_MESSAGE);
145     SetEventObject(win);
146     if (win)
147         SetId(win->GetId());
148 }
149
150 IMPLEMENT_DYNAMIC_CLASS(wxWebViewReceivedTitleEvent, wxCommandEvent)
151
152 DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_RECEIVED_TITLE)
153
154 wxWebViewReceivedTitleEvent::wxWebViewReceivedTitleEvent(wxWindow* win)
155 {
156     SetEventType(wxEVT_WEBVIEW_RECEIVED_TITLE);
157     SetEventObject(win);
158     if (win)
159         SetId(win->GetId());
160 }
161
162 //---------------------------------------------------------
163 // DOM Element info data type
164 //---------------------------------------------------------
165
166 wxWebViewDOMElementInfo::wxWebViewDOMElementInfo() :
167     m_domElement(NULL),
168     m_isSelected(false),
169     m_text(wxEmptyString),
170     m_imageSrc(wxEmptyString),
171     m_link(wxEmptyString)
172 {
173 }
174
175 BEGIN_EVENT_TABLE(wxWebView, wxWindow)
176     EVT_PAINT(wxWebView::OnPaint)
177     EVT_SIZE(wxWebView::OnSize)
178     EVT_MOUSE_EVENTS(wxWebView::OnMouseEvents)
179     EVT_CONTEXT_MENU(wxWebView::OnContextMenuEvents)
180     EVT_MENU(wxID_ANY, wxWebView::OnMenuSelectEvents)
181     EVT_KEY_DOWN(wxWebView::OnKeyEvents)
182     EVT_KEY_UP(wxWebView::OnKeyEvents)
183     EVT_CHAR(wxWebView::OnKeyEvents)
184     EVT_SET_FOCUS(wxWebView::OnSetFocus)
185     EVT_KILL_FOCUS(wxWebView::OnKillFocus)
186     EVT_ACTIVATE(wxWebView::OnActivate)
187 END_EVENT_TABLE()
188
189 IMPLEMENT_DYNAMIC_CLASS(wxWebView, wxWindow)
190
191 const wxChar* wxWebViewNameStr = wxT("webView");
192
193 wxWebView::wxWebView() :
194     m_textMagnifier(1.0),
195     m_isEditable(false),
196     m_isInitialized(false),
197     m_beingDestroyed(false),
198     m_title(wxEmptyString)
199 {
200 }
201
202 wxWebView::wxWebView(wxWindow* parent, int id, const wxPoint& position, 
203                      const wxSize& size, long style, const wxString& name) :
204     m_textMagnifier(1.0),
205     m_isEditable(false),
206     m_isInitialized(false),
207     m_beingDestroyed(false),
208     m_title(wxEmptyString)
209 {
210     Create(parent, id, position, size, style, name);
211 }
212
213 bool wxWebView::Create(wxWindow* parent, int id, const wxPoint& position, 
214                        const wxSize& size, long style, const wxString& name)
215 {
216     if ( (style & wxBORDER_MASK) == 0)
217         style |= wxBORDER_NONE;
218     style |= wxHSCROLL | wxVSCROLL;
219     
220     if (!wxWindow::Create(parent, id, position, size, style, name))
221         return false;
222
223 // This is necessary because we are using SharedTimerWin.cpp on Windows,
224 // due to a problem with exceptions getting eaten when using the callback
225 // approach to timers (which wx itself uses).
226 #if __WXMSW__
227     WebCore::Page::setInstanceHandle(wxGetInstance());
228 #endif
229
230     // this helps reduce flicker on platforms like MSW
231     SetBackgroundStyle(wxBG_STYLE_CUSTOM);
232
233     m_impl = new WebViewPrivate();
234
235     WebCore::InitializeLoggingChannelsIfNecessary();    
236     WebCore::HTMLFrameOwnerElement* parentFrame = 0;
237
238     WebCore::EditorClientWx* editorClient = new WebCore::EditorClientWx();
239     m_impl->page = new WebCore::Page(new WebCore::ChromeClientWx(this), new WebCore::ContextMenuClientWx(), editorClient, new WebCore::DragClientWx(), new WebCore::InspectorClientWx());
240     editorClient->setPage(m_impl->page);
241     
242     m_mainFrame = new wxWebFrame(this);
243
244     // Default settings - we should have wxWebViewSettings class for this
245     // eventually
246     WebCore::Settings* settings = m_impl->page->settings();
247     settings->setLoadsImagesAutomatically(true);
248     settings->setDefaultFixedFontSize(13);
249     settings->setDefaultFontSize(16);
250     settings->setSerifFontFamily("Times New Roman");
251     settings->setFixedFontFamily("Courier New");
252     settings->setSansSerifFontFamily("Arial");
253     settings->setStandardFontFamily("Times New Roman");
254     settings->setJavaScriptEnabled(true);
255
256     m_isInitialized = true;
257
258     return true;
259 }
260
261 wxWebView::~wxWebView()
262 {
263     m_beingDestroyed = true;
264     
265     delete m_mainFrame;
266     
267     delete m_impl->page;
268     m_impl->page = 0;   
269 }
270
271 void wxWebView::Stop()
272 {
273     if (m_mainFrame)
274         m_mainFrame->Stop();
275 }
276
277 void wxWebView::Reload()
278 {
279     if (m_mainFrame)
280         m_mainFrame->Reload();
281 }
282
283 wxString wxWebView::GetPageSource()
284 {
285     if (m_mainFrame)
286         return m_mainFrame->GetPageSource();
287
288     return wxEmptyString;
289 }
290
291 void wxWebView::SetPageSource(const wxString& source, const wxString& baseUrl)
292 {
293     if (m_mainFrame)
294         m_mainFrame->SetPageSource(source, baseUrl);
295 }
296
297 wxString wxWebView::GetInnerText()
298 {
299     if (m_mainFrame)
300         return m_mainFrame->GetInnerText();
301         
302     return wxEmptyString;
303 }
304
305 wxString wxWebView::GetAsMarkup()
306 {
307     if (m_mainFrame)
308         return m_mainFrame->GetAsMarkup();
309         
310     return wxEmptyString;
311 }
312
313 wxString wxWebView::GetExternalRepresentation()
314 {
315     if (m_mainFrame)
316         return m_mainFrame->GetExternalRepresentation();
317         
318     return wxEmptyString;
319 }
320
321 void wxWebView::SetTransparent(bool transparent)
322 {
323     WebCore::Frame* frame = 0;
324     if (m_mainFrame)
325         frame = m_mainFrame->GetFrame();
326     
327     if (!frame || !frame->view())
328         return;
329
330     frame->view()->setTransparent(transparent);
331 }
332
333 bool wxWebView::IsTransparent() const
334 {
335     WebCore::Frame* frame = 0;
336     if (m_mainFrame)
337         frame = m_mainFrame->GetFrame();
338
339    if (!frame || !frame->view())
340         return false;
341
342     return frame->view()->isTransparent();
343 }
344
345 wxString wxWebView::RunScript(const wxString& javascript)
346 {
347     if (m_mainFrame)
348         return m_mainFrame->RunScript(javascript);
349     
350     return wxEmptyString;
351 }
352
353 void wxWebView::LoadURL(const wxString& url)
354 {
355     if (m_mainFrame)
356         m_mainFrame->LoadURL(url);
357 }
358
359 bool wxWebView::GoBack()
360 {
361     if (m_mainFrame)
362         return m_mainFrame->GoBack();
363
364     return false;
365 }
366
367 bool wxWebView::GoForward()
368 {
369     if (m_mainFrame)
370         return m_mainFrame->GoForward();
371
372     return false;
373 }
374
375 bool wxWebView::CanGoBack()
376 {
377     if (m_mainFrame)
378         return m_mainFrame->CanGoBack();
379
380     return false;
381 }
382
383 bool wxWebView::CanGoForward()
384 {
385     if (m_mainFrame)
386         return m_mainFrame->CanGoForward();
387
388     return false;
389 }
390
391 bool wxWebView::CanIncreaseTextSize() const
392 {
393     if (m_mainFrame)
394         return m_mainFrame->CanIncreaseTextSize();
395
396     return false;
397 }
398
399 void wxWebView::IncreaseTextSize()
400 {
401     if (m_mainFrame)
402         m_mainFrame->IncreaseTextSize();
403 }
404
405 bool wxWebView::CanDecreaseTextSize() const
406 {
407     if (m_mainFrame)
408         m_mainFrame->CanDecreaseTextSize();
409
410     return false;
411 }
412
413 void wxWebView::DecreaseTextSize()
414 {        
415     if (m_mainFrame)
416         m_mainFrame->DecreaseTextSize();
417 }
418
419 void wxWebView::MakeEditable(bool enable)
420 {
421     m_isEditable = enable;
422 }
423
424
425 /* 
426  * Event forwarding functions to send events down to WebCore.
427  */
428
429 void wxWebView::OnPaint(wxPaintEvent& event)
430 {
431     
432     if (m_beingDestroyed || !m_mainFrame)
433         return;
434     
435     WebCore::Frame* frame = m_mainFrame->GetFrame();
436     if (!frame || !frame->view())
437         return;
438     
439     wxAutoBufferedPaintDC dc(this);
440
441     if (IsShown() && frame->document()) {
442 #if USE(WXGC)
443         wxGCDC gcdc(dc);
444 #endif
445
446         if (dc.IsOk()) {
447             wxRect paintRect = GetUpdateRegion().GetBox();
448
449             WebCore::IntSize offset = frame->view()->scrollOffset();
450 #if USE(WXGC)
451             gcdc.SetDeviceOrigin(-offset.width(), -offset.height());
452 #endif
453             dc.SetDeviceOrigin(-offset.width(), -offset.height());
454             paintRect.Offset(offset.width(), offset.height());
455
456 #if USE(WXGC)
457             WebCore::GraphicsContext* gc = new WebCore::GraphicsContext(&gcdc);
458 #else
459             WebCore::GraphicsContext* gc = new WebCore::GraphicsContext((wxWindowDC*)&dc);
460 #endif
461             if (gc && frame->contentRenderer()) {
462                 if (frame->view()->needsLayout())
463                     frame->view()->layout();
464
465                 frame->view()->paintContents(gc, paintRect);
466             }
467             delete gc;
468         }
469     }
470 }
471
472 bool wxWebView::FindString(const wxString& string, bool forward, bool caseSensitive, bool wrapSelection, bool startInSelection)
473 {
474     if (m_mainFrame)
475         return m_mainFrame->FindString(string, forward, caseSensitive, wrapSelection, startInSelection);
476
477     return false;
478 }
479
480 void wxWebView::OnSize(wxSizeEvent& event)
481
482     if (m_isInitialized && m_mainFrame) {
483         WebCore::Frame* frame = m_mainFrame->GetFrame();
484         frame->eventHandler()->sendResizeEvent();
485         frame->view()->layout();
486         frame->view()->adjustScrollbars();
487     }
488       
489     event.Skip();
490 }
491
492 void wxWebView::OnMouseEvents(wxMouseEvent& event)
493 {
494     event.Skip();
495     
496     if (!m_mainFrame)
497         return; 
498         
499     WebCore::Frame* frame = m_mainFrame->GetFrame();  
500     if (!frame || !frame->view())
501         return;
502     
503     wxPoint globalPoint = ClientToScreen(event.GetPosition());
504
505     wxEventType type = event.GetEventType();
506     
507     if (type == wxEVT_MOUSEWHEEL) {
508         WebCore::PlatformWheelEvent wkEvent(event, globalPoint);
509         frame->eventHandler()->handleWheelEvent(wkEvent);
510         return;
511     }
512     
513     WebCore::PlatformMouseEvent wkEvent(event, globalPoint);
514
515     if (type == wxEVT_LEFT_DOWN || type == wxEVT_MIDDLE_DOWN || type == wxEVT_RIGHT_DOWN || 
516                 type == wxEVT_LEFT_DCLICK || type == wxEVT_MIDDLE_DCLICK || type == wxEVT_RIGHT_DCLICK)
517         frame->eventHandler()->handleMousePressEvent(wkEvent);
518     
519     else if (type == wxEVT_LEFT_UP || type == wxEVT_MIDDLE_UP || type == wxEVT_RIGHT_UP)
520         frame->eventHandler()->handleMouseReleaseEvent(wkEvent);
521
522     else if (type == wxEVT_MOTION)
523         frame->eventHandler()->mouseMoved(wkEvent);
524 }
525
526 void wxWebView::OnContextMenuEvents(wxContextMenuEvent& event)
527 {
528     m_impl->page->contextMenuController()->clearContextMenu();
529     wxPoint localEventPoint = ScreenToClient(event.GetPosition());
530
531     if (!m_mainFrame)
532         return;
533         
534     WebCore::Frame* focusedFrame = m_mainFrame->GetFrame();
535     if (!focusedFrame->view())
536         return;
537
538     //Create WebCore mouse event from the wxContextMenuEvent
539     wxMouseEvent mouseEvent(wxEVT_RIGHT_DOWN);
540     mouseEvent.m_x = localEventPoint.x;
541     mouseEvent.m_y = localEventPoint.y;
542     WebCore::PlatformMouseEvent wkEvent(mouseEvent, event.GetPosition());
543
544     bool handledEvent = focusedFrame->eventHandler()->sendContextMenuEvent(wkEvent);
545     if (!handledEvent)
546         return;
547
548     WebCore::ContextMenu* coreMenu = m_impl->page->contextMenuController()->contextMenu();
549     if (!coreMenu)
550         return;
551
552     WebCore::PlatformMenuDescription menuWx = coreMenu->platformDescription();
553     if (!menuWx)
554         return;
555
556     PopupMenu(menuWx, localEventPoint);
557 }
558
559 void wxWebView::OnMenuSelectEvents(wxCommandEvent& event)
560 {
561     WebCore::ContextMenuItem* item = WebCore::ContextMenu::itemWithId (event.GetId());
562     if (!item)
563         return;
564
565     m_impl->page->contextMenuController()->contextMenuItemSelected(item);
566     delete item;
567 }
568
569 bool wxWebView::CanCopy()
570 {
571     if (m_mainFrame)
572         return m_mainFrame->CanCopy();
573
574     return false;
575 }
576
577 void wxWebView::Copy()
578 {
579     if (m_mainFrame)
580         m_mainFrame->Copy();
581 }
582
583 bool wxWebView::CanCut()
584 {
585     if (m_mainFrame)
586         m_mainFrame->CanCut();
587
588     return false;
589 }
590
591 void wxWebView::Cut()
592 {
593     if (m_mainFrame)
594         m_mainFrame->Cut();
595 }
596
597 bool wxWebView::CanPaste()
598 {
599     if (m_mainFrame)
600         m_mainFrame->CanPaste();
601
602     return false;
603 }
604
605 void wxWebView::Paste()
606 {
607     if (m_mainFrame)
608         m_mainFrame->Paste();
609
610 }
611
612 void wxWebView::OnKeyEvents(wxKeyEvent& event)
613 {
614     WebCore::Frame* frame = 0;
615     if (m_mainFrame)
616         frame = m_mainFrame->GetFrame();
617         
618     if (frame && frame->view()) {
619         // WebCore doesn't handle these events itself, so we need to do
620         // it and not send the event down or else CTRL+C will erase the text
621         // and replace it with c.
622         if (event.CmdDown() && event.GetEventType() == wxEVT_KEY_UP) {
623             if (event.GetKeyCode() == static_cast<int>('C'))
624                 Copy();
625             else if (event.GetKeyCode() == static_cast<int>('X'))
626                 Cut();
627             else if (event.GetKeyCode() == static_cast<int>('V'))
628                 Paste();
629             else if (event.GetKeyCode() == static_cast<int>('Z')) {
630                 if (event.ShiftDown()) {
631                     if (m_mainFrame->CanRedo())
632                         m_mainFrame->Redo();
633                 }
634                 else {
635                     if (m_mainFrame->CanUndo())
636                         m_mainFrame->Undo();
637                 }
638             }
639         } else {    
640             WebCore::PlatformKeyboardEvent wkEvent(event);
641             if (wkEvent.type() == WebCore::PlatformKeyboardEvent::Char && wkEvent.altKey())
642                 frame->eventHandler()->handleAccessKey(wkEvent);
643             else
644                 frame->eventHandler()->keyEvent(wkEvent);
645         }
646     }
647     
648     // make sure we get the character event.
649     if (event.GetEventType() != wxEVT_CHAR)
650         event.Skip();
651 }
652
653 void wxWebView::OnSetFocus(wxFocusEvent& event)
654 {
655     WebCore::Frame* frame = 0;
656     if (m_mainFrame)
657         frame = m_mainFrame->GetFrame();
658         
659     if (frame) {
660         m_impl->page->focusController()->setActive(true);
661         frame->selection()->setFocused(true);
662     }
663
664     event.Skip();
665 }
666
667 void wxWebView::OnKillFocus(wxFocusEvent& event)
668 {
669     WebCore::Frame* frame = 0;
670     if (m_mainFrame)
671         frame = m_mainFrame->GetFrame();
672         
673     if (frame) {
674         m_impl->page->focusController()->setActive(false);
675         frame->selection()->setFocused(false);
676     }
677     event.Skip();
678 }
679
680 void wxWebView::OnActivate(wxActivateEvent& event)
681 {
682     if (m_impl->page)
683         m_impl->page->focusController()->setActive(event.GetActive());
684
685     event.Skip();
686 }
687
688 wxWebViewDOMElementInfo wxWebView::HitTest(const wxPoint& pos) const
689 {
690     if (m_mainFrame)
691         return m_mainFrame->HitTest(pos);
692
693     return wxWebViewDOMElementInfo();
694 }
695