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