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.
27 #include "DeprecatedString.h"
30 #include "EventHandler.h"
32 #include "FrameLoader.h"
33 #include "FrameView.h"
34 #include "GraphicsContext.h"
35 #include "HTMLFrameOwnerElement.h"
38 #include "PlatformKeyboardEvent.h"
39 #include "PlatformMouseEvent.h"
40 #include "PlatformString.h"
41 #include "PlatformWheelEvent.h"
42 #include "RenderObject.h"
45 #include "ChromeClientWx.h"
46 #include "ContextMenuClientWx.h"
47 #include "DragClientWx.h"
48 #include "EditorClientWx.h"
49 #include "FrameLoaderClientWx.h"
50 #include "InspectorClientWx.h"
52 #include "kjs_proxy.h"
53 #include "kjs_binding.h"
54 #include <kjs/value.h>
55 #include <kjs/ustring.h>
57 #include "wx/wxprec.h"
63 #include "WebViewPrivate.h"
66 #include <wx/dcbuffer.h>
68 // Match Safari's min/max zoom sizes by default
69 #define MinimumTextSizeMultiplier 0.5f
70 #define MaximumTextSizeMultiplier 3.0f
71 #define TextSizeMultiplierRatio 1.2f
77 return (int)(val < 0 ? val - 0.5 : val + 0.5);
81 // ----------------------------------------------------------------------------
83 // ----------------------------------------------------------------------------
85 IMPLEMENT_DYNAMIC_CLASS(wxWebViewStateChangedEvent, wxCommandEvent)
87 DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_STATE_CHANGED)
89 wxWebViewStateChangedEvent::wxWebViewStateChangedEvent(wxWindow* win)
91 SetEventType( wxEVT_WEBVIEW_STATE_CHANGED);
92 SetEventObject( win );
96 IMPLEMENT_DYNAMIC_CLASS(wxWebViewBeforeLoadEvent, wxCommandEvent)
98 DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_BEFORE_LOAD)
100 wxWebViewBeforeLoadEvent::wxWebViewBeforeLoadEvent(wxWindow* win)
103 SetEventType(wxEVT_WEBVIEW_BEFORE_LOAD);
108 IMPLEMENT_DYNAMIC_CLASS(wxWebViewNewWindowEvent, wxCommandEvent)
110 DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_NEW_WINDOW)
112 wxWebViewNewWindowEvent::wxWebViewNewWindowEvent(wxWindow* win)
114 SetEventType(wxEVT_WEBVIEW_NEW_WINDOW);
119 IMPLEMENT_DYNAMIC_CLASS(wxWebViewRightClickEvent, wxCommandEvent)
121 DEFINE_EVENT_TYPE(wxEVT_WEBVIEW_RIGHT_CLICK)
123 wxWebViewRightClickEvent::wxWebViewRightClickEvent(wxWindow* win)
125 SetEventType(wxEVT_WEBVIEW_RIGHT_CLICK);
130 //---------------------------------------------------------
131 // DOM Element info data type
132 //---------------------------------------------------------
134 wxWebViewDOMElementInfo::wxWebViewDOMElementInfo() :
137 m_text(wxEmptyString),
138 m_imageSrc(wxEmptyString),
139 m_link(wxEmptyString)
143 BEGIN_EVENT_TABLE(wxWebView, wxScrolledWindow)
144 EVT_PAINT(wxWebView::OnPaint)
145 EVT_SIZE(wxWebView::OnSize)
146 EVT_MOUSE_EVENTS(wxWebView::OnMouseEvents)
147 EVT_KEY_DOWN(wxWebView::OnKeyEvents)
148 EVT_KEY_UP(wxWebView::OnKeyEvents)
149 EVT_CHAR(wxWebView::OnKeyEvents)
150 EVT_SET_FOCUS(wxWebView::OnSetFocus)
151 EVT_KILL_FOCUS(wxWebView::OnKillFocus)
152 EVT_ACTIVATE(wxWebView::OnActivate)
155 wxWebView::wxWebView(wxWindow* parent, int id, const wxPoint& position,
156 const wxSize& size, WebViewFrameData* data) :
157 m_textMagnifier(1.0),
159 m_isInitialized(false),
160 m_beingDestroyed(false),
161 m_title(wxEmptyString)
163 if (!wxScrolledWindow::Create(parent, id, position, size))
166 // this helps reduce flicker on platforms like MSW
167 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
169 m_impl = new WebViewPrivate();
171 WebCore::InitializeLoggingChannelsIfNecessary();
172 WebCore::HTMLFrameOwnerElement* parentFrame = 0;
174 // FIXME: This cast is obviously not as safe as a dynamic
175 // cast, but this allows us to get around requiring RTTI
176 // support for the moment. This is only used for subframes
177 // in any case, which aren't currently supported.
178 wxWebView* parentWebView = static_cast<wxWebView*>(parent);
181 parentFrame = data->ownerElement;
182 m_impl->page = parentWebView->m_impl->frame->page();
185 WebCore::EditorClientWx* editorClient = new WebCore::EditorClientWx();
186 m_impl->page = new WebCore::Page(new WebCore::ChromeClientWx(), new WebCore::ContextMenuClientWx(), editorClient, new WebCore::DragClientWx(), new WebCore::InspectorClientWx());
187 editorClient->setPage(m_impl->page);
190 WebCore::FrameLoaderClientWx* loaderClient = new WebCore::FrameLoaderClientWx();
192 m_impl->frame = new WebCore::Frame(m_impl->page, parentFrame, loaderClient);
193 m_impl->frame->deref();
194 m_impl->frameView = new WebCore::FrameView(m_impl->frame.get());
195 m_impl->frameView->deref();
197 m_impl->frame->setView(m_impl->frameView.get());
198 m_impl->frame->init();
200 m_impl->frameView->setNativeWindow(this);
201 loaderClient->setFrame(m_impl->frame.get());
203 // Default settings - we should have wxWebViewSettings class for this
205 WebCore::Settings* settings = m_impl->page->settings();
206 settings->setLoadsImagesAutomatically(true);
207 settings->setDefaultFixedFontSize(13);
208 settings->setDefaultFontSize(16);
209 settings->setSerifFontFamily("Times New Roman");
210 settings->setFixedFontFamily("Courier New");
211 settings->setSansSerifFontFamily("Arial");
212 settings->setStandardFontFamily("Times New Roman");
213 settings->setJavaScriptEnabled(true);
215 m_isInitialized = true;
218 wxWebView::~wxWebView()
220 m_beingDestroyed = true;
222 m_impl->frame->loader()->detachFromParent();
226 // Since frameView has the last reference to Frame, once it is
227 // destroyed the destructor for Frame will happen as well.
228 m_impl->frameView = 0;
231 void wxWebView::Stop()
233 if (m_impl->frame && m_impl->frame->loader())
234 m_impl->frame->loader()->stop();
237 void wxWebView::Reload()
239 if (m_impl->frame && m_impl->frame->loader())
240 m_impl->frame->loader()->reload();
243 wxString wxWebView::GetPageSource()
246 WebCore::Document* doc = m_impl->frame->document();
249 wxString source = doc->toString();
253 return wxEmptyString;
256 void wxWebView::SetPageSource(const wxString& source, const wxString& baseUrl)
258 if (m_impl->frame && m_impl->frame->loader()) {
259 WebCore::FrameLoader* loader = m_impl->frame->loader();
260 loader->begin(WebCore::KURL(static_cast<const char*>(baseUrl.mb_str(wxConvUTF8))));
261 loader->write(source);
266 wxString wxWebView::RunScript(const wxString& javascript)
268 wxString returnValue = wxEmptyString;
270 KJS::JSValue* result = m_impl->frame->loader()->executeScript(javascript, true);
272 returnValue = wxString(result->toString(m_impl->frame->scriptProxy()->globalObject()->globalExec()).UTF8String().c_str(), wxConvUTF8);
277 void wxWebView::LoadURL(wxString url)
279 if (m_impl->frame && m_impl->frame->loader()) {
280 WebCore::KURL kurl = WebCore::KURL(static_cast<const char*>(url.mb_str(wxConvUTF8)));
281 // NB: This is an ugly fix, but CURL won't load sub-resources if the
282 // protocol is omitted; sadly, it will not emit an error, either, so
283 // there's no way for us to catch this problem the correct way yet.
284 if (kurl.protocol().isEmpty()) {
285 // is it a file on disk?
286 if (wxFileExists(url)) {
287 kurl.setProtocol("file");
288 kurl.setPath("//" + kurl.path());
291 kurl.setProtocol("http");
292 kurl.setPath("//" + kurl.path());
295 m_impl->frame->loader()->load(kurl);
299 bool wxWebView::GoBack()
301 if (m_impl->frame && m_impl->frame->page()) {
302 return m_impl->frame->page()->goBack();
306 bool wxWebView::GoForward()
308 if (m_impl->frame && m_impl->frame->page())
309 return m_impl->frame->page()->goForward();
312 bool wxWebView::CanIncreaseTextSize() const
315 if (m_textMagnifier*TextSizeMultiplierRatio <= MaximumTextSizeMultiplier)
321 void wxWebView::IncreaseTextSize()
323 if (CanIncreaseTextSize()) {
324 m_textMagnifier = m_textMagnifier*TextSizeMultiplierRatio;
325 m_impl->frame->setZoomFactor((int)rint(m_textMagnifier*100));
329 bool wxWebView::CanDecreaseTextSize() const
332 if (m_textMagnifier/TextSizeMultiplierRatio >= MinimumTextSizeMultiplier)
338 void wxWebView::DecreaseTextSize()
340 if (CanDecreaseTextSize()) {
341 m_textMagnifier = m_textMagnifier/TextSizeMultiplierRatio;
342 m_impl->frame->setZoomFactor( (int)rint(m_textMagnifier*100));
346 void wxWebView::MakeEditable(bool enable)
348 m_isEditable = enable;
353 * Event forwarding functions to send events down to WebCore.
356 void wxWebView::OnPaint(wxPaintEvent& event)
358 if (m_beingDestroyed || !m_impl->frameView || !m_impl->frame)
361 wxAutoBufferedPaintDC dc(this);
363 if (IsShown() && m_impl->frame && m_impl->frame->document()) {
372 wxRect paintRect = GetUpdateRegion().GetBox();
375 GetViewStart(&x, &y);
378 GetScrollPixelsPerUnit(&unitX, &unitY);
379 paintRect.Offset(x * unitX, y * unitY);
382 WebCore::GraphicsContext* gc = new WebCore::GraphicsContext(&gcdc);
384 WebCore::GraphicsContext* gc = new WebCore::GraphicsContext((wxWindowDC*)&dc);
386 if (gc && m_impl->frame->renderer()) {
387 // FIXME: Replace this with layoutIfNeededRecursive
388 if (m_impl->frameView->needsLayout())
389 m_impl->frameView->layout();
391 m_impl->frame->paint(gc, paintRect);
397 void wxWebView::OnSize(wxSizeEvent& event)
399 // NOTE: this call can be expensive on heavy pages, particularly on Mac,
400 // so we probably should set a timer not put x ms between layouts.
402 if (m_isInitialized && m_impl->frame && m_impl->frameView) {
403 m_impl->frameView->layout();
410 void wxWebView::OnMouseEvents(wxMouseEvent& event)
414 if (!m_impl->frame && m_impl->frameView)
417 wxPoint globalPoint = ClientToScreen(event.GetPosition());
419 wxEventType type = event.GetEventType();
421 if (type == wxEVT_MOUSEWHEEL) {
422 WebCore::PlatformWheelEvent wkEvent(event, globalPoint);
423 m_impl->frame->eventHandler()->handleWheelEvent(wkEvent);
427 WebCore::PlatformMouseEvent wkEvent(event, globalPoint);
429 if (type == wxEVT_LEFT_DOWN || type == wxEVT_MIDDLE_DOWN || type == wxEVT_RIGHT_DOWN)
430 m_impl->frame->eventHandler()->handleMousePressEvent(wkEvent);
432 else if (type == wxEVT_LEFT_UP || type == wxEVT_MIDDLE_UP || type == wxEVT_RIGHT_UP ||
433 type == wxEVT_LEFT_DCLICK || type == wxEVT_MIDDLE_DCLICK || type == wxEVT_RIGHT_DCLICK)
434 m_impl->frame->eventHandler()->handleMouseReleaseEvent(wkEvent);
436 else if (type == wxEVT_MOTION)
437 m_impl->frame->eventHandler()->handleMouseMoveEvent(wkEvent);
440 bool wxWebView::CanCopy()
442 if (m_impl->frame && m_impl->frameView) {
443 return (m_impl->frame->editor()->canCopy() || m_impl->frame->editor()->canDHTMLCopy());
448 void wxWebView::Copy()
451 m_impl->frame->editor()->copy();
455 bool wxWebView::CanCut()
457 if (m_impl->frame && m_impl->frameView) {
458 return (m_impl->frame->editor()->canCut() || m_impl->frame->editor()->canDHTMLCut());
463 void wxWebView::Cut()
466 m_impl->frame->editor()->cut();
470 bool wxWebView::CanPaste()
472 if (m_impl->frame && m_impl->frameView) {
473 return (m_impl->frame->editor()->canPaste() || m_impl->frame->editor()->canDHTMLPaste());
478 void wxWebView::Paste()
481 m_impl->frame->editor()->paste();
485 void wxWebView::OnKeyEvents(wxKeyEvent& event)
487 if (m_impl->frame && m_impl->frameView) {
488 // WebCore doesn't handle these events itself, so we need to do
489 // it and not send the event down or else CTRL+C will erase the text
490 // and replace it with c.
491 if (event.CmdDown() && event.GetKeyCode() == static_cast<int>('C')) {
494 else if (event.CmdDown() && event.GetKeyCode() == static_cast<int>('X')) {
497 else if (event.CmdDown() && event.GetKeyCode() == static_cast<int>('V')) {
501 WebCore::PlatformKeyboardEvent wkEvent(event);
502 if (wkEvent.type() == WebCore::PlatformKeyboardEvent::Char && wkEvent.altKey())
503 m_impl->frame->eventHandler()->handleAccessKey(wkEvent);
505 m_impl->frame->eventHandler()->keyEvent(wkEvent);
509 // make sure we get the character event.
510 if (event.GetEventType() != wxEVT_CHAR)
514 void wxWebView::OnSetFocus(wxFocusEvent& event)
517 m_impl->frame->setWindowHasFocus(true);
522 void wxWebView::OnKillFocus(wxFocusEvent& event)
525 m_impl->frame->setWindowHasFocus(false);
530 void wxWebView::OnActivate(wxActivateEvent& event)
533 m_impl->frame->setIsActive(event.GetActive());