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