2 * Copyright (C) 2007 Kevin Ollivier All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
31 #include "EventHandler.h"
32 #include "FocusController.h"
34 #include "FrameLoader.h"
35 #include "FrameView.h"
36 #include "GraphicsContext.h"
37 #include "HTMLFrameOwnerElement.h"
41 #include "PlatformKeyboardEvent.h"
42 #include "PlatformMouseEvent.h"
43 #include "PlatformString.h"
44 #include "PlatformWheelEvent.h"
45 #include "RenderObject.h"
46 #include "RenderTreeAsText.h"
47 #include "RenderView.h"
48 #include "SelectionController.h"
50 #include "SubstituteData.h"
52 #include "ChromeClientWx.h"
53 #include "ContextMenuClientWx.h"
54 #include "DragClientWx.h"
55 #include "EditorClientWx.h"
56 #include "FrameLoaderClientWx.h"
57 #include "InspectorClientWx.h"
59 #include "ScriptController.h"
60 #include "JSDOMBinding.h"
61 #include <kjs/JSValue.h>
62 #include <kjs/ustring.h>
64 #include "wx/wxprec.h"
70 #include "WebViewPrivate.h"
73 #include <wx/dcbuffer.h>
75 // Match Safari's min/max zoom sizes by default
76 #define MinimumTextSizeMultiplier 0.5f
77 #define MaximumTextSizeMultiplier 3.0f
78 #define TextSizeMultiplierRatio 1.2f
84 return (int)(val < 0 ? val - 0.5 : val + 0.5);
88 // ----------------------------------------------------------------------------
90 // ----------------------------------------------------------------------------
92 IMPLEMENT_DYNAMIC_CLASS(wxWebViewLoadEvent, wxCommandEvent)
94 DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_LOAD)
96 wxWebViewLoadEvent::wxWebViewLoadEvent(wxWindow* win)
98 SetEventType( wxEVT_WEBVIEW_LOAD);
99 SetEventObject( win );
104 IMPLEMENT_DYNAMIC_CLASS(wxWebViewBeforeLoadEvent, wxCommandEvent)
106 DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_BEFORE_LOAD)
108 wxWebViewBeforeLoadEvent::wxWebViewBeforeLoadEvent(wxWindow* win)
111 SetEventType(wxEVT_WEBVIEW_BEFORE_LOAD);
117 IMPLEMENT_DYNAMIC_CLASS(wxWebViewNewWindowEvent, wxCommandEvent)
119 DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_NEW_WINDOW)
121 wxWebViewNewWindowEvent::wxWebViewNewWindowEvent(wxWindow* win)
123 SetEventType(wxEVT_WEBVIEW_NEW_WINDOW);
129 IMPLEMENT_DYNAMIC_CLASS(wxWebViewRightClickEvent, wxCommandEvent)
131 DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_RIGHT_CLICK)
133 wxWebViewRightClickEvent::wxWebViewRightClickEvent(wxWindow* win)
135 SetEventType(wxEVT_WEBVIEW_RIGHT_CLICK);
141 IMPLEMENT_DYNAMIC_CLASS(wxWebViewConsoleMessageEvent, wxCommandEvent)
143 DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_CONSOLE_MESSAGE)
145 wxWebViewConsoleMessageEvent::wxWebViewConsoleMessageEvent(wxWindow* win)
147 SetEventType(wxEVT_WEBVIEW_CONSOLE_MESSAGE);
153 IMPLEMENT_DYNAMIC_CLASS(wxWebViewReceivedTitleEvent, wxCommandEvent)
155 DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_RECEIVED_TITLE)
157 wxWebViewReceivedTitleEvent::wxWebViewReceivedTitleEvent(wxWindow* win)
159 SetEventType(wxEVT_WEBVIEW_RECEIVED_TITLE);
165 //---------------------------------------------------------
166 // DOM Element info data type
167 //---------------------------------------------------------
169 wxWebViewDOMElementInfo::wxWebViewDOMElementInfo() :
172 m_text(wxEmptyString),
173 m_imageSrc(wxEmptyString),
174 m_link(wxEmptyString)
178 BEGIN_EVENT_TABLE(wxWebView, wxWindow)
179 EVT_PAINT(wxWebView::OnPaint)
180 EVT_SIZE(wxWebView::OnSize)
181 EVT_MOUSE_EVENTS(wxWebView::OnMouseEvents)
182 EVT_KEY_DOWN(wxWebView::OnKeyEvents)
183 EVT_KEY_UP(wxWebView::OnKeyEvents)
184 EVT_CHAR(wxWebView::OnKeyEvents)
185 EVT_SET_FOCUS(wxWebView::OnSetFocus)
186 EVT_KILL_FOCUS(wxWebView::OnKillFocus)
187 EVT_ACTIVATE(wxWebView::OnActivate)
190 IMPLEMENT_DYNAMIC_CLASS(wxWebView, wxWindow)
192 const wxChar* wxWebViewNameStr = wxT("webView");
194 wxWebView::wxWebView() :
195 m_textMagnifier(1.0),
197 m_isInitialized(false),
198 m_beingDestroyed(false),
199 m_title(wxEmptyString)
203 wxWebView::wxWebView(wxWindow* parent, int id, const wxPoint& position,
204 const wxSize& size, long style, const wxString& name,
205 WebViewFrameData* data) :
206 m_textMagnifier(1.0),
208 m_isInitialized(false),
209 m_beingDestroyed(false),
210 m_title(wxEmptyString)
212 Create(parent, id, position, size, style, name, data);
215 bool wxWebView::Create(wxWindow* parent, int id, const wxPoint& position,
216 const wxSize& size, long style, const wxString& name,
217 WebViewFrameData* data)
219 if ( (style & wxBORDER_MASK) == 0)
220 style |= wxBORDER_NONE;
221 style |= wxHSCROLL | wxVSCROLL;
223 if (!wxWindow::Create(parent, id, position, size, style, name))
226 // This is necessary because we are using SharedTimerWin.cpp on Windows,
227 // due to a problem with exceptions getting eaten when using the callback
228 // approach to timers (which wx itself uses).
230 WebCore::Page::setInstanceHandle(wxGetInstance());
233 // this helps reduce flicker on platforms like MSW
234 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
236 m_impl = new WebViewPrivate();
238 WebCore::InitializeLoggingChannelsIfNecessary();
239 WebCore::HTMLFrameOwnerElement* parentFrame = 0;
241 // FIXME: This cast is obviously not as safe as a dynamic
242 // cast, but this allows us to get around requiring RTTI
243 // support for the moment. This is only used for subframes
244 // in any case, which aren't currently supported.
245 wxWebView* parentWebView = static_cast<wxWebView*>(parent);
248 parentFrame = data->ownerElement;
249 m_impl->page = parentWebView->m_impl->frame->page();
252 WebCore::EditorClientWx* editorClient = new WebCore::EditorClientWx();
253 m_impl->page = new WebCore::Page(new WebCore::ChromeClientWx(this), new WebCore::ContextMenuClientWx(), editorClient, new WebCore::DragClientWx(), new WebCore::InspectorClientWx());
254 editorClient->setPage(m_impl->page);
257 WebCore::FrameLoaderClientWx* loaderClient = new WebCore::FrameLoaderClientWx();
259 m_impl->frame = WebCore::Frame::create(m_impl->page, parentFrame, loaderClient);
261 loaderClient->setFrame(m_impl->frame.get());
262 loaderClient->setWebView(this);
264 m_impl->frame->init();
266 // Default settings - we should have wxWebViewSettings class for this
268 WebCore::Settings* settings = m_impl->page->settings();
269 settings->setLoadsImagesAutomatically(true);
270 settings->setDefaultFixedFontSize(13);
271 settings->setDefaultFontSize(16);
272 settings->setSerifFontFamily("Times New Roman");
273 settings->setFixedFontFamily("Courier New");
274 settings->setSansSerifFontFamily("Arial");
275 settings->setStandardFontFamily("Times New Roman");
276 settings->setJavaScriptEnabled(true);
278 m_isInitialized = true;
283 wxWebView::~wxWebView()
285 m_beingDestroyed = true;
287 m_impl->frame->loader()->detachFromParent();
293 void wxWebView::Stop()
295 if (m_impl->frame && m_impl->frame->loader())
296 m_impl->frame->loader()->stop();
299 void wxWebView::Reload()
301 if (m_impl->frame && m_impl->frame->loader())
302 m_impl->frame->loader()->reload();
305 wxString wxWebView::GetPageSource()
308 if (m_impl->frame->view() && m_impl->frame->view()->layoutPending())
309 m_impl->frame->view()->layout();
311 WebCore::Document* doc = m_impl->frame->document();
314 wxString source = createMarkup(doc);
318 return wxEmptyString;
321 void wxWebView::SetPageSource(const wxString& source, const wxString& baseUrl)
323 if (m_impl->frame && m_impl->frame->loader()) {
324 WebCore::FrameLoader* loader = m_impl->frame->loader();
325 loader->begin(WebCore::KURL(static_cast<const char*>(baseUrl.mb_str(wxConvUTF8))));
326 loader->write(source);
331 wxString wxWebView::GetInnerText()
333 if (m_impl->frame->view() && m_impl->frame->view()->layoutPending())
334 m_impl->frame->view()->layout();
336 WebCore::Element *documentElement = m_impl->frame->document()->documentElement();
337 return documentElement->innerText();
340 wxString wxWebView::GetAsMarkup()
342 if (!m_impl->frame || !m_impl->frame->document())
343 return wxEmptyString;
345 return createMarkup(m_impl->frame->document());
348 wxString wxWebView::GetExternalRepresentation()
350 if (m_impl->frame->view() && m_impl->frame->view()->layoutPending())
351 m_impl->frame->view()->layout();
353 return externalRepresentation(m_impl->frame->contentRenderer());
356 wxString wxWebView::RunScript(const wxString& javascript)
358 wxString returnValue = wxEmptyString;
360 KJS::JSValue* result = m_impl->frame->loader()->executeScript(javascript, true);
362 returnValue = wxString(result->toString(m_impl->frame->script()->globalObject()->globalExec()).UTF8String().c_str(), wxConvUTF8);
367 void wxWebView::LoadURL(const wxString& url)
369 if (m_impl->frame && m_impl->frame->loader()) {
370 WebCore::KURL kurl = WebCore::KURL(static_cast<const char*>(url.mb_str(wxConvUTF8)));
371 // NB: This is an ugly fix, but CURL won't load sub-resources if the
372 // protocol is omitted; sadly, it will not emit an error, either, so
373 // there's no way for us to catch this problem the correct way yet.
374 if (kurl.protocol().isEmpty()) {
375 // is it a file on disk?
376 if (wxFileExists(url)) {
377 kurl.setProtocol("file");
378 kurl.setPath("//" + kurl.path());
381 kurl.setProtocol("http");
382 kurl.setPath("//" + kurl.path());
385 m_impl->frame->loader()->load(kurl);
389 bool wxWebView::GoBack()
391 if (m_impl->frame && m_impl->frame->page())
392 return m_impl->frame->page()->goBack();
397 bool wxWebView::GoForward()
399 if (m_impl->frame && m_impl->frame->page())
400 return m_impl->frame->page()->goForward();
405 bool wxWebView::CanGoBack()
407 if (m_impl->frame && m_impl->frame->page() && m_impl->frame->page()->backForwardList())
408 return m_impl->frame->page()->backForwardList()->backItem() != NULL;
413 bool wxWebView::CanGoForward()
415 if (m_impl->frame && m_impl->frame->page() && m_impl->frame->page()->backForwardList())
416 return m_impl->frame->page()->backForwardList()->forwardItem() != NULL;
421 bool wxWebView::CanIncreaseTextSize() const
424 if (m_textMagnifier*TextSizeMultiplierRatio <= MaximumTextSizeMultiplier)
430 void wxWebView::IncreaseTextSize()
432 if (CanIncreaseTextSize()) {
433 m_textMagnifier = m_textMagnifier*TextSizeMultiplierRatio;
434 m_impl->frame->setZoomFactor(m_textMagnifier, true);
438 bool wxWebView::CanDecreaseTextSize() const
441 if (m_textMagnifier/TextSizeMultiplierRatio >= MinimumTextSizeMultiplier)
447 void wxWebView::DecreaseTextSize()
449 if (CanDecreaseTextSize()) {
450 m_textMagnifier = m_textMagnifier/TextSizeMultiplierRatio;
451 m_impl->frame->setZoomFactor(m_textMagnifier, true);
455 void wxWebView::MakeEditable(bool enable)
457 m_isEditable = enable;
462 * Event forwarding functions to send events down to WebCore.
465 void wxWebView::OnPaint(wxPaintEvent& event)
467 if (m_beingDestroyed || !m_impl->frame->view() || !m_impl->frame)
470 wxAutoBufferedPaintDC dc(this);
472 if (IsShown() && m_impl->frame && m_impl->frame->document()) {
478 wxRect paintRect = GetUpdateRegion().GetBox();
480 WebCore::IntSize offset = m_impl->frame->view()->scrollOffset();
482 gcdc.SetDeviceOrigin(-offset.width(), -offset.height());
484 dc.SetDeviceOrigin(-offset.width(), -offset.height());
485 paintRect.Offset(offset.width(), offset.height());
488 WebCore::GraphicsContext* gc = new WebCore::GraphicsContext(&gcdc);
490 WebCore::GraphicsContext* gc = new WebCore::GraphicsContext((wxWindowDC*)&dc);
492 if (gc && m_impl->frame->contentRenderer()) {
493 if (m_impl->frame->view()->needsLayout())
494 m_impl->frame->view()->layout();
496 m_impl->frame->paint(gc, paintRect);
502 void wxWebView::OnSize(wxSizeEvent& event)
504 if (m_isInitialized && m_impl->frame && m_impl->frame->view()) {
505 m_impl->frame->sendResizeEvent();
506 m_impl->frame->view()->layout();
513 void wxWebView::OnMouseEvents(wxMouseEvent& event)
517 if (!m_impl->frame && m_impl->frame->view())
520 wxPoint globalPoint = ClientToScreen(event.GetPosition());
522 wxEventType type = event.GetEventType();
524 if (type == wxEVT_MOUSEWHEEL) {
525 WebCore::PlatformWheelEvent wkEvent(event, globalPoint);
526 m_impl->frame->eventHandler()->handleWheelEvent(wkEvent);
530 WebCore::PlatformMouseEvent wkEvent(event, globalPoint);
532 if (type == wxEVT_LEFT_DOWN || type == wxEVT_MIDDLE_DOWN || type == wxEVT_RIGHT_DOWN)
533 m_impl->frame->eventHandler()->handleMousePressEvent(wkEvent);
535 else if (type == wxEVT_LEFT_UP || type == wxEVT_MIDDLE_UP || type == wxEVT_RIGHT_UP ||
536 type == wxEVT_LEFT_DCLICK || type == wxEVT_MIDDLE_DCLICK || type == wxEVT_RIGHT_DCLICK)
537 m_impl->frame->eventHandler()->handleMouseReleaseEvent(wkEvent);
539 else if (type == wxEVT_MOTION)
540 m_impl->frame->eventHandler()->mouseMoved(wkEvent);
543 bool wxWebView::CanCopy()
545 if (m_impl->frame && m_impl->frame->view())
546 return (m_impl->frame->editor()->canCopy() || m_impl->frame->editor()->canDHTMLCopy());
551 void wxWebView::Copy()
554 m_impl->frame->editor()->copy();
557 bool wxWebView::CanCut()
559 if (m_impl->frame && m_impl->frame->view())
560 return (m_impl->frame->editor()->canCut() || m_impl->frame->editor()->canDHTMLCut());
565 void wxWebView::Cut()
568 m_impl->frame->editor()->cut();
571 bool wxWebView::CanPaste()
573 if (m_impl->frame && m_impl->frame->view())
574 return (m_impl->frame->editor()->canPaste() || m_impl->frame->editor()->canDHTMLPaste());
579 void wxWebView::Paste()
582 m_impl->frame->editor()->paste();
586 void wxWebView::OnKeyEvents(wxKeyEvent& event)
588 if (m_impl->frame && m_impl->frame->view()) {
589 // WebCore doesn't handle these events itself, so we need to do
590 // it and not send the event down or else CTRL+C will erase the text
591 // and replace it with c.
592 if (event.CmdDown() && event.GetKeyCode() == static_cast<int>('C'))
594 else if (event.CmdDown() && event.GetKeyCode() == static_cast<int>('X'))
596 else if (event.CmdDown() && event.GetKeyCode() == static_cast<int>('V'))
599 WebCore::PlatformKeyboardEvent wkEvent(event);
600 if (wkEvent.type() == WebCore::PlatformKeyboardEvent::Char && wkEvent.altKey())
601 m_impl->frame->eventHandler()->handleAccessKey(wkEvent);
603 m_impl->frame->eventHandler()->keyEvent(wkEvent);
607 // make sure we get the character event.
608 if (event.GetEventType() != wxEVT_CHAR)
612 void wxWebView::OnSetFocus(wxFocusEvent& event)
615 m_impl->frame->selection()->setFocused(true);
620 void wxWebView::OnKillFocus(wxFocusEvent& event)
623 m_impl->frame->selection()->setFocused(false);
628 void wxWebView::OnActivate(wxActivateEvent& event)
631 m_impl->page->focusController()->setActive(event.GetActive());