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
28 #include "Document.h"
29 #include "Editor.h"
30 #include "Element.h"
31 #include "EventHandler.h"
32 #include "Frame.h"
33 #include "FrameLoader.h"
34 #include "FrameView.h"
35 #include "HitTestResult.h"
36 #include "HostWindow.h"
37 #include "HTMLFrameOwnerElement.h"
38 #include "markup.h"
39 #include "Page.h"
40 #include "PlatformString.h"
41 #include "RenderTreeAsText.h"
42 #include "RenderObject.h"
43 #include "RenderView.h"
44 #include "ScriptController.h"
45 #include "ScriptValue.h"
46 #include "SubstituteData.h"
47 #include "TextEncoding.h"
48
49 #include "JSDOMBinding.h"
50 #include <runtime/JSValue.h>
51 #include <runtime/UString.h>
52 #include <wtf/text/CString.h>
53
54 #include "EditorClientWx.h"
55 #include "FrameLoaderClientWx.h"
56
57 #include "wx/wxprec.h"
58 #ifndef WX_PRECOMP
59 #include "wx/wx.h"
60 #endif
61
62 #include "WebDOMNode.h"
63
64 #include "WebDOMSelection.h"
65 #include "WebFrame.h"
66 #include "WebView.h"
67 #include "WebFramePrivate.h"
68 #include "WebViewPrivate.h"
69
70 #include <wx/defs.h>
71 #include <wx/dcbuffer.h>
72
73 // Match Safari's min/max zoom sizes by default
74 #define MinimumTextSizeMultiplier 0.5f
75 #define MaximumTextSizeMultiplier 3.0f
76 #define TextSizeMultiplierRatio 1.2f
77
wxWebFrame(wxWebView * container,wxWebFrame * parent,WebViewFrameData * data)78 wxWebFrame::wxWebFrame(wxWebView* container, wxWebFrame* parent, WebViewFrameData* data) :
79 m_textMagnifier(1.0),
80 m_isInitialized(false),
81 m_beingDestroyed(false)
82 {
83
84 m_impl = new WebFramePrivate();
85
86 WebCore::HTMLFrameOwnerElement* parentFrame = 0;
87
88 if (data) {
89 parentFrame = data->ownerElement;
90 }
91
92 WebCore::FrameLoaderClientWx* loaderClient = new WebCore::FrameLoaderClientWx();
93 RefPtr<WebCore::Frame> newFrame = WebCore::Frame::create(container->m_impl->page, parentFrame, loaderClient);
94
95 m_impl->frame = newFrame.get();
96
97 if (data)
98 newFrame->tree()->setName(data->name);
99
100 // Subframes expect to be added to the FrameTree before init is called.
101 if (parentFrame)
102 parentFrame->document()->frame()->tree()->appendChild(newFrame.get());
103
104 loaderClient->setFrame(this);
105 loaderClient->setWebView(container);
106
107 if (data && data->ownerElement)
108 m_impl->frame->ref();
109
110 m_impl->frame->init();
111
112 m_isInitialized = true;
113 }
114
~wxWebFrame()115 wxWebFrame::~wxWebFrame()
116 {
117 if (m_impl)
118 delete m_impl;
119 }
120
GetFrame()121 WebCore::Frame* wxWebFrame::GetFrame()
122 {
123 if (m_impl)
124 return m_impl->frame;
125
126 return 0;
127 }
128
Stop()129 void wxWebFrame::Stop()
130 {
131 if (m_impl->frame && m_impl->frame->loader())
132 m_impl->frame->loader()->stop();
133 }
134
Reload()135 void wxWebFrame::Reload()
136 {
137 if (m_impl->frame && m_impl->frame->loader())
138 m_impl->frame->loader()->reload();
139 }
140
GetPageSource()141 wxString wxWebFrame::GetPageSource()
142 {
143 if (m_impl->frame) {
144 if (m_impl->frame->view() && m_impl->frame->view()->layoutPending())
145 m_impl->frame->view()->layout();
146
147 WebCore::Document* doc = m_impl->frame->document();
148
149 if (doc) {
150 wxString source = createMarkup(doc);
151 return source;
152 }
153 }
154 return wxEmptyString;
155 }
156
SetPageSource(const wxString & source,const wxString & baseUrl,const wxString & mimetype)157 void wxWebFrame::SetPageSource(const wxString& source, const wxString& baseUrl, const wxString& mimetype)
158 {
159 if (m_impl->frame && m_impl->frame->loader()) {
160 WebCore::KURL url(WebCore::KURL(), baseUrl);
161
162 const wxCharBuffer charBuffer(source.utf8_str());
163 const char* contents = charBuffer;
164
165 WTF::PassRefPtr<WebCore::SharedBuffer> sharedBuffer = WebCore::SharedBuffer::create(contents, strlen(contents));
166 WebCore::SubstituteData substituteData(sharedBuffer, mimetype, WTF::String("UTF-8"), WebCore::blankURL(), url);
167
168 m_impl->frame->loader()->stop();
169 m_impl->frame->loader()->load(WebCore::ResourceRequest(url), substituteData, false);
170 }
171 }
172
GetInnerText()173 wxString wxWebFrame::GetInnerText()
174 {
175 if (m_impl->frame->view() && m_impl->frame->view()->layoutPending())
176 m_impl->frame->view()->layout();
177
178 WebCore::Element *documentElement = m_impl->frame->document()->documentElement();
179 return documentElement->innerText();
180 }
181
GetAsMarkup()182 wxString wxWebFrame::GetAsMarkup()
183 {
184 if (!m_impl->frame || !m_impl->frame->document())
185 return wxEmptyString;
186
187 return createMarkup(m_impl->frame->document());
188 }
189
GetExternalRepresentation()190 wxString wxWebFrame::GetExternalRepresentation()
191 {
192 if (m_impl->frame->view() && m_impl->frame->view()->layoutPending())
193 m_impl->frame->view()->layout();
194
195 return externalRepresentation(m_impl->frame);
196 }
197
GetSelectionAsHTML()198 wxString wxWebFrame::GetSelectionAsHTML()
199 {
200 if (m_impl->frame)
201 return m_impl->frame->selection()->toNormalizedRange()->toHTML();
202
203 return wxEmptyString;
204 }
205
GetSelectionAsText()206 wxString wxWebFrame::GetSelectionAsText()
207 {
208 if (m_impl->frame)
209 return m_impl->frame->selection()->toNormalizedRange()->text();
210
211 return wxEmptyString;
212 }
213
GetSelection()214 wxWebKitSelection wxWebFrame::GetSelection()
215 {
216 if (m_impl->frame)
217 return wxWebKitSelection(m_impl->frame->selection());
218
219 return 0;
220 }
221
RunScript(const wxString & javascript)222 wxString wxWebFrame::RunScript(const wxString& javascript)
223 {
224 wxString returnValue = wxEmptyString;
225 if (m_impl->frame && m_impl->frame->loader()) {
226 bool hasLoaded = m_impl->frame->loader()->frameHasLoaded();
227 wxASSERT_MSG(hasLoaded, wxT("Document must be loaded before calling RunScript."));
228 if (hasLoaded) {
229 WebCore::ScriptController* controller = m_impl->frame->script();
230 bool jsEnabled = controller->canExecuteScripts(WebCore::AboutToExecuteScript);
231 wxASSERT_MSG(jsEnabled, wxT("RunScript requires JavaScript to be enabled."));
232 if (jsEnabled) {
233 JSC::JSValue result = controller->executeScript(javascript, true).jsValue();
234 if (result)
235 returnValue = wxString(result.toString(m_impl->frame->script()->globalObject(WebCore::mainThreadNormalWorld())->globalExec()).utf8().data(), wxConvUTF8);
236 }
237 }
238 }
239 return returnValue;
240 }
241
ExecuteEditCommand(const wxString & command,const wxString & parameter)242 bool wxWebFrame::ExecuteEditCommand(const wxString& command, const wxString& parameter)
243 {
244 if (m_impl->frame && IsEditable())
245 return m_impl->frame->editor()->command(command).execute(parameter);
246 }
247
GetEditCommandState(const wxString & command) const248 EditState wxWebFrame::GetEditCommandState(const wxString& command) const
249 {
250 if (m_impl->frame && IsEditable()) {
251 WebCore::TriState state = m_impl->frame->editor()->command(command).state();
252 if (state == WebCore::TrueTriState)
253 return EditStateTrue;
254 if (state == WebCore::FalseTriState)
255 return EditStateFalse;
256
257 return EditStateMixed;
258 }
259
260 return EditStateFalse;
261 }
262
GetEditCommandValue(const wxString & command) const263 wxString wxWebFrame::GetEditCommandValue(const wxString& command) const
264 {
265 if (m_impl->frame && IsEditable())
266 return m_impl->frame->editor()->command(command).value();
267
268 return wxEmptyString;
269 }
270
271
FindString(const wxString & string,bool forward,bool caseSensitive,bool wrapSelection,bool startInSelection)272 bool wxWebFrame::FindString(const wxString& string, bool forward, bool caseSensitive, bool wrapSelection, bool startInSelection)
273 {
274 if (m_impl->frame)
275 return m_impl->frame->editor()->findString(string, forward, caseSensitive, wrapSelection, startInSelection);
276
277 return false;
278 }
279
LoadURL(const wxString & url)280 void wxWebFrame::LoadURL(const wxString& url)
281 {
282 if (m_impl->frame && m_impl->frame->loader()) {
283 WebCore::KURL kurl = WebCore::KURL(WebCore::KURL(), url, WebCore::UTF8Encoding());
284 // NB: This is an ugly fix, but CURL won't load sub-resources if the
285 // protocol is omitted; sadly, it will not emit an error, either, so
286 // there's no way for us to catch this problem the correct way yet.
287 if (kurl.protocol().isEmpty()) {
288 // is it a file on disk?
289 if (wxFileExists(url)) {
290 kurl.setProtocol("file");
291 kurl.setPath("//" + kurl.path());
292 }
293 else {
294 kurl.setProtocol("http");
295 kurl.setPath("//" + kurl.path());
296 }
297 }
298 m_impl->frame->loader()->load(kurl, false);
299 }
300 }
301
GoBack()302 bool wxWebFrame::GoBack()
303 {
304 if (m_impl->frame && m_impl->frame->page())
305 return m_impl->frame->page()->goBack();
306
307 return false;
308 }
309
GoForward()310 bool wxWebFrame::GoForward()
311 {
312 if (m_impl->frame && m_impl->frame->page())
313 return m_impl->frame->page()->goForward();
314
315 return false;
316 }
317
CanGoBack()318 bool wxWebFrame::CanGoBack()
319 {
320 if (m_impl->frame && m_impl->frame->page())
321 return m_impl->frame->page()->canGoBackOrForward(-1);
322
323 return false;
324 }
325
CanGoForward()326 bool wxWebFrame::CanGoForward()
327 {
328 if (m_impl->frame && m_impl->frame->page())
329 return m_impl->frame->page()->canGoBackOrForward(1);
330
331 return false;
332 }
333
Undo()334 void wxWebFrame::Undo()
335 {
336 if (m_impl->frame && m_impl->frame->editor() && CanUndo())
337 return m_impl->frame->editor()->undo();
338 }
339
Redo()340 void wxWebFrame::Redo()
341 {
342 if (m_impl->frame && m_impl->frame->editor() && CanRedo())
343 return m_impl->frame->editor()->redo();
344 }
345
CanUndo()346 bool wxWebFrame::CanUndo()
347 {
348 if (m_impl->frame && m_impl->frame->editor())
349 return m_impl->frame->editor()->canUndo();
350
351 return false;
352 }
353
CanRedo()354 bool wxWebFrame::CanRedo()
355 {
356 if (m_impl->frame && m_impl->frame->editor())
357 return m_impl->frame->editor()->canRedo();
358
359 return false;
360 }
361
CanIncreaseTextSize() const362 bool wxWebFrame::CanIncreaseTextSize() const
363 {
364 if (m_impl->frame && m_impl->frame->view()) {
365 if (m_textMagnifier*TextSizeMultiplierRatio <= MaximumTextSizeMultiplier)
366 return true;
367 }
368 return false;
369 }
370
IncreaseTextSize()371 void wxWebFrame::IncreaseTextSize()
372 {
373 if (CanIncreaseTextSize()) {
374 m_textMagnifier = m_textMagnifier*TextSizeMultiplierRatio;
375 m_impl->frame->setTextZoomFactor(m_textMagnifier);
376 }
377 }
378
CanDecreaseTextSize() const379 bool wxWebFrame::CanDecreaseTextSize() const
380 {
381 if (m_impl->frame && m_impl->frame->view()) {
382 if (m_textMagnifier/TextSizeMultiplierRatio >= MinimumTextSizeMultiplier)
383 return true;
384 }
385 return false;
386 }
387
DecreaseTextSize()388 void wxWebFrame::DecreaseTextSize()
389 {
390 if (CanDecreaseTextSize()) {
391 m_textMagnifier = m_textMagnifier/TextSizeMultiplierRatio;
392 m_impl->frame->setTextZoomFactor(m_textMagnifier);
393 }
394 }
395
ResetTextSize()396 void wxWebFrame::ResetTextSize()
397 {
398 m_textMagnifier = 1.0;
399 if (m_impl->frame)
400 m_impl->frame->setTextZoomFactor(m_textMagnifier);
401 }
402
MakeEditable(bool enable)403 void wxWebFrame::MakeEditable(bool enable)
404 {
405 if (enable != IsEditable() && m_impl->frame && m_impl->frame->page())
406 m_impl->frame->page()->setEditable(enable);
407 }
408
IsEditable() const409 bool wxWebFrame::IsEditable() const
410 {
411 if (m_impl->frame && m_impl->frame->page())
412 return m_impl->frame->page()->isEditable();
413 return false;
414 }
415
CanCopy()416 bool wxWebFrame::CanCopy()
417 {
418 if (m_impl->frame && m_impl->frame->view())
419 return (m_impl->frame->editor()->canCopy() || m_impl->frame->editor()->canDHTMLCopy());
420
421 return false;
422 }
423
Copy()424 void wxWebFrame::Copy()
425 {
426 if (CanCopy())
427 m_impl->frame->editor()->copy();
428 }
429
CanCut()430 bool wxWebFrame::CanCut()
431 {
432 if (m_impl->frame && m_impl->frame->view())
433 return (m_impl->frame->editor()->canCut() || m_impl->frame->editor()->canDHTMLCut());
434
435 return false;
436 }
437
Cut()438 void wxWebFrame::Cut()
439 {
440 if (CanCut())
441 m_impl->frame->editor()->cut();
442 }
443
CanPaste()444 bool wxWebFrame::CanPaste()
445 {
446 if (m_impl->frame && m_impl->frame->view())
447 return (m_impl->frame->editor()->canPaste() || m_impl->frame->editor()->canDHTMLPaste());
448
449 return false;
450 }
451
Paste()452 void wxWebFrame::Paste()
453 {
454 if (CanPaste())
455 m_impl->frame->editor()->paste();
456
457 }
458
HitTest(const wxPoint & pos) const459 wxWebViewDOMElementInfo wxWebFrame::HitTest(const wxPoint& pos) const
460 {
461 wxWebViewDOMElementInfo domInfo;
462
463 if (m_impl->frame->view()) {
464 WebCore::HitTestResult result = m_impl->frame->eventHandler()->hitTestResultAtPoint(m_impl->frame->view()->windowToContents(pos), false);
465 if (result.innerNode()) {
466 domInfo.SetLink(result.absoluteLinkURL().string());
467 domInfo.SetText(result.textContent());
468 domInfo.SetImageSrc(result.absoluteImageURL().string());
469 domInfo.SetSelected(result.isSelected());
470 }
471 }
472
473 return domInfo;
474 }
475
ShouldClose() const476 bool wxWebFrame::ShouldClose() const
477 {
478 if (m_impl->frame)
479 return m_impl->frame->loader()->shouldClose();
480
481 return true;
482 }
483
GetCompatibilityMode() const484 wxWebKitCompatibilityMode wxWebFrame::GetCompatibilityMode() const
485 {
486 if (m_impl->frame && m_impl->frame->document())
487 return (wxWebKitCompatibilityMode)m_impl->frame->document()->compatibilityMode();
488
489 return QuirksMode;
490 }
491
GrantUniversalAccess()492 void wxWebFrame::GrantUniversalAccess()
493 {
494 if (m_impl->frame && m_impl->frame->document())
495 m_impl->frame->document()->securityOrigin()->grantUniversalAccess();
496 }
497