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 <kjs/JSValue.h>
60 #include <kjs/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 wxString wxWebView::RunScript(const wxString& javascript)
316 {
317     if (m_mainFrame)
318         return m_mainFrame->RunScript(javascript);
319     
320     return wxEmptyString;
321 }
322
323 void wxWebView::LoadURL(const wxString& url)
324 {
325     if (m_mainFrame)
326         m_mainFrame->LoadURL(url);
327 }
328
329 bool wxWebView::GoBack()
330 {
331     if (m_mainFrame)
332         return m_mainFrame->GoBack();
333
334     return false;
335 }
336
337 bool wxWebView::GoForward()
338 {
339     if (m_mainFrame)
340         return m_mainFrame->GoForward();
341
342     return false;
343 }
344
345 bool wxWebView::CanGoBack()
346 {
347     if (m_mainFrame)
348         return m_mainFrame->CanGoBack();
349
350     return false;
351 }
352
353 bool wxWebView::CanGoForward()
354 {
355     if (m_mainFrame)
356         return m_mainFrame->CanGoForward();
357
358     return false;
359 }
360
361 bool wxWebView::CanIncreaseTextSize() const
362 {
363     if (m_mainFrame)
364         return m_mainFrame->CanIncreaseTextSize();
365
366     return false;
367 }
368
369 void wxWebView::IncreaseTextSize()
370 {
371     if (m_mainFrame)
372         m_mainFrame->IncreaseTextSize();
373 }
374
375 bool wxWebView::CanDecreaseTextSize() const
376 {
377     if (m_mainFrame)
378         m_mainFrame->CanDecreaseTextSize();
379
380     return false;
381 }
382
383 void wxWebView::DecreaseTextSize()
384 {        
385     if (m_mainFrame)
386         m_mainFrame->DecreaseTextSize();
387 }
388
389 void wxWebView::MakeEditable(bool enable)
390 {
391     m_isEditable = enable;
392 }
393
394
395 /* 
396  * Event forwarding functions to send events down to WebCore.
397  */
398
399 void wxWebView::OnPaint(wxPaintEvent& event)
400 {
401     
402     if (m_beingDestroyed || !m_mainFrame)
403         return;
404     
405     WebCore::Frame* frame = m_mainFrame->GetFrame();
406     if (!frame || !frame->view())
407         return;
408     
409     wxAutoBufferedPaintDC dc(this);
410
411     if (IsShown() && frame->document()) {
412 #if USE(WXGC)
413         wxGCDC gcdc(dc);
414 #endif
415
416         if (dc.IsOk()) {
417             wxRect paintRect = GetUpdateRegion().GetBox();
418
419             WebCore::IntSize offset = frame->view()->scrollOffset();
420 #if USE(WXGC)
421             gcdc.SetDeviceOrigin(-offset.width(), -offset.height());
422 #endif
423             dc.SetDeviceOrigin(-offset.width(), -offset.height());
424             paintRect.Offset(offset.width(), offset.height());
425
426 #if USE(WXGC)
427             WebCore::GraphicsContext* gc = new WebCore::GraphicsContext(&gcdc);
428 #else
429             WebCore::GraphicsContext* gc = new WebCore::GraphicsContext((wxWindowDC*)&dc);
430 #endif
431             if (gc && frame->contentRenderer()) {
432                 if (frame->view()->needsLayout())
433                     frame->view()->layout();
434
435                 frame->paint(gc, paintRect);
436             }
437         }
438     }
439 }
440
441 void wxWebView::OnSize(wxSizeEvent& event)
442
443     if (m_isInitialized && m_mainFrame) {
444         WebCore::Frame* frame = m_mainFrame->GetFrame();
445         frame->sendResizeEvent();
446         frame->view()->layout();
447     }
448       
449     event.Skip();
450 }
451
452 void wxWebView::OnMouseEvents(wxMouseEvent& event)
453 {
454     event.Skip();
455     
456     if (!m_mainFrame)
457         return; 
458         
459     WebCore::Frame* frame = m_mainFrame->GetFrame();  
460     if (!frame || !frame->view())
461         return;
462     
463     wxPoint globalPoint = ClientToScreen(event.GetPosition());
464
465     wxEventType type = event.GetEventType();
466     
467     if (type == wxEVT_MOUSEWHEEL) {
468         WebCore::PlatformWheelEvent wkEvent(event, globalPoint);
469         frame->eventHandler()->handleWheelEvent(wkEvent);
470         return;
471     }
472     
473     WebCore::PlatformMouseEvent wkEvent(event, globalPoint);
474
475     if (type == wxEVT_LEFT_DOWN || type == wxEVT_MIDDLE_DOWN || type == wxEVT_RIGHT_DOWN)
476         frame->eventHandler()->handleMousePressEvent(wkEvent);
477     
478     else if (type == wxEVT_LEFT_UP || type == wxEVT_MIDDLE_UP || type == wxEVT_RIGHT_UP || 
479                 type == wxEVT_LEFT_DCLICK || type == wxEVT_MIDDLE_DCLICK || type == wxEVT_RIGHT_DCLICK)
480         frame->eventHandler()->handleMouseReleaseEvent(wkEvent);
481
482     else if (type == wxEVT_MOTION)
483         frame->eventHandler()->mouseMoved(wkEvent);
484 }
485
486 bool wxWebView::CanCopy()
487 {
488     if (m_mainFrame)
489         return m_mainFrame->CanCopy();
490
491     return false;
492 }
493
494 void wxWebView::Copy()
495 {
496     if (m_mainFrame)
497         m_mainFrame->Copy();
498 }
499
500 bool wxWebView::CanCut()
501 {
502     if (m_mainFrame)
503         m_mainFrame->CanCut();
504
505     return false;
506 }
507
508 void wxWebView::Cut()
509 {
510     if (m_mainFrame)
511         m_mainFrame->Cut();
512 }
513
514 bool wxWebView::CanPaste()
515 {
516     if (m_mainFrame)
517         m_mainFrame->CanPaste();
518
519     return false;
520 }
521
522 void wxWebView::Paste()
523 {
524     if (m_mainFrame)
525         m_mainFrame->Paste();
526
527 }
528
529 void wxWebView::OnKeyEvents(wxKeyEvent& event)
530 {
531     WebCore::Frame* frame = 0;
532     if (m_mainFrame)
533         frame = m_mainFrame->GetFrame();
534         
535     if (frame && frame->view()) {
536         // WebCore doesn't handle these events itself, so we need to do
537         // it and not send the event down or else CTRL+C will erase the text
538         // and replace it with c.
539         if (event.CmdDown() && event.GetKeyCode() == static_cast<int>('C'))
540             Copy();
541         else if (event.CmdDown() && event.GetKeyCode() == static_cast<int>('X'))
542             Cut();
543         else if (event.CmdDown() && event.GetKeyCode() == static_cast<int>('V'))
544             Paste();
545         else {    
546             WebCore::PlatformKeyboardEvent wkEvent(event);
547             if (wkEvent.type() == WebCore::PlatformKeyboardEvent::Char && wkEvent.altKey())
548                 frame->eventHandler()->handleAccessKey(wkEvent);
549             else
550                 frame->eventHandler()->keyEvent(wkEvent);
551         }
552     }
553     
554     // make sure we get the character event.
555     if (event.GetEventType() != wxEVT_CHAR)
556         event.Skip();
557 }
558
559 void wxWebView::OnSetFocus(wxFocusEvent& event)
560 {
561     WebCore::Frame* frame = 0;
562     if (m_mainFrame)
563         frame = m_mainFrame->GetFrame();
564         
565     if (frame)
566         frame->selection()->setFocused(true);
567
568     event.Skip();
569 }
570
571 void wxWebView::OnKillFocus(wxFocusEvent& event)
572 {
573     WebCore::Frame* frame = 0;
574     if (m_mainFrame)
575         frame = m_mainFrame->GetFrame();
576         
577     if (frame)
578         frame->selection()->setFocused(false);
579
580     event.Skip();
581 }
582
583 void wxWebView::OnActivate(wxActivateEvent& event)
584 {
585     if (m_impl->page)
586         m_impl->page->focusController()->setActive(event.GetActive());
587
588     event.Skip();
589 }