| /* |
| * Copyright (C) 2007 Kevin Ollivier All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| |
| #include "Document.h" |
| #include "Editor.h" |
| #include "Element.h" |
| #include "EventHandler.h" |
| #include "Frame.h" |
| #include "FrameLoader.h" |
| #include "FrameView.h" |
| #include "HitTestResult.h" |
| #include "HostWindow.h" |
| #include "HTMLFrameOwnerElement.h" |
| #include "markup.h" |
| #include "Page.h" |
| #include "PlatformString.h" |
| #include "RenderTreeAsText.h" |
| #include "RenderObject.h" |
| #include "RenderView.h" |
| #include "ScriptController.h" |
| #include "ScriptValue.h" |
| #include "SubstituteData.h" |
| #include "TextEncoding.h" |
| |
| #include "JSDOMBinding.h" |
| #include <runtime/JSValue.h> |
| #include <runtime/UString.h> |
| #include <wtf/text/CString.h> |
| |
| #include "EditorClientWx.h" |
| #include "FrameLoaderClientWx.h" |
| |
| #include "wx/wxprec.h" |
| #ifndef WX_PRECOMP |
| #include "wx/wx.h" |
| #endif |
| |
| #include "WebDOMNode.h" |
| |
| #include "WebDOMSelection.h" |
| #include "WebFrame.h" |
| #include "WebView.h" |
| #include "WebFramePrivate.h" |
| #include "WebViewPrivate.h" |
| |
| #include <wx/defs.h> |
| #include <wx/dcbuffer.h> |
| |
| // Match Safari's min/max zoom sizes by default |
| #define MinimumTextSizeMultiplier 0.5f |
| #define MaximumTextSizeMultiplier 3.0f |
| #define TextSizeMultiplierRatio 1.2f |
| |
| wxWebFrame::wxWebFrame(wxWebView* container, wxWebFrame* parent, WebViewFrameData* data) : |
| m_textMagnifier(1.0), |
| m_isInitialized(false), |
| m_beingDestroyed(false) |
| { |
| |
| m_impl = new WebFramePrivate(); |
| |
| WebCore::HTMLFrameOwnerElement* parentFrame = 0; |
| |
| if (data) { |
| parentFrame = data->ownerElement; |
| } |
| |
| WebCore::FrameLoaderClientWx* loaderClient = new WebCore::FrameLoaderClientWx(); |
| RefPtr<WebCore::Frame> newFrame = WebCore::Frame::create(container->m_impl->page, parentFrame, loaderClient); |
| |
| m_impl->frame = newFrame.get(); |
| |
| if (data) |
| newFrame->tree()->setName(data->name); |
| |
| // Subframes expect to be added to the FrameTree before init is called. |
| if (parentFrame) |
| parentFrame->document()->frame()->tree()->appendChild(newFrame.get()); |
| |
| loaderClient->setFrame(this); |
| loaderClient->setWebView(container); |
| |
| if (data && data->ownerElement) |
| m_impl->frame->ref(); |
| |
| m_impl->frame->init(); |
| |
| m_isInitialized = true; |
| } |
| |
| wxWebFrame::~wxWebFrame() |
| { |
| if (m_impl) |
| delete m_impl; |
| } |
| |
| WebCore::Frame* wxWebFrame::GetFrame() |
| { |
| if (m_impl) |
| return m_impl->frame; |
| |
| return 0; |
| } |
| |
| void wxWebFrame::Stop() |
| { |
| if (m_impl->frame && m_impl->frame->loader()) |
| m_impl->frame->loader()->stop(); |
| } |
| |
| void wxWebFrame::Reload() |
| { |
| if (m_impl->frame && m_impl->frame->loader()) |
| m_impl->frame->loader()->reload(); |
| } |
| |
| wxString wxWebFrame::GetPageSource() |
| { |
| if (m_impl->frame) { |
| if (m_impl->frame->view() && m_impl->frame->view()->layoutPending()) |
| m_impl->frame->view()->layout(); |
| |
| WebCore::Document* doc = m_impl->frame->document(); |
| |
| if (doc) { |
| wxString source = createMarkup(doc); |
| return source; |
| } |
| } |
| return wxEmptyString; |
| } |
| |
| void wxWebFrame::SetPageSource(const wxString& source, const wxString& baseUrl, const wxString& mimetype) |
| { |
| if (m_impl->frame && m_impl->frame->loader()) { |
| WebCore::KURL url(WebCore::KURL(), baseUrl); |
| |
| const wxCharBuffer charBuffer(source.utf8_str()); |
| const char* contents = charBuffer; |
| |
| WTF::PassRefPtr<WebCore::SharedBuffer> sharedBuffer = WebCore::SharedBuffer::create(contents, strlen(contents)); |
| WebCore::SubstituteData substituteData(sharedBuffer, mimetype, WTF::String("UTF-8"), WebCore::blankURL(), url); |
| |
| m_impl->frame->loader()->stop(); |
| m_impl->frame->loader()->load(WebCore::ResourceRequest(url), substituteData, false); |
| } |
| } |
| |
| wxString wxWebFrame::GetInnerText() |
| { |
| if (m_impl->frame->view() && m_impl->frame->view()->layoutPending()) |
| m_impl->frame->view()->layout(); |
| |
| WebCore::Element *documentElement = m_impl->frame->document()->documentElement(); |
| return documentElement->innerText(); |
| } |
| |
| wxString wxWebFrame::GetAsMarkup() |
| { |
| if (!m_impl->frame || !m_impl->frame->document()) |
| return wxEmptyString; |
| |
| return createMarkup(m_impl->frame->document()); |
| } |
| |
| wxString wxWebFrame::GetExternalRepresentation() |
| { |
| if (m_impl->frame->view() && m_impl->frame->view()->layoutPending()) |
| m_impl->frame->view()->layout(); |
| |
| return externalRepresentation(m_impl->frame); |
| } |
| |
| wxString wxWebFrame::GetSelectionAsHTML() |
| { |
| if (m_impl->frame) |
| return m_impl->frame->selection()->toNormalizedRange()->toHTML(); |
| |
| return wxEmptyString; |
| } |
| |
| wxString wxWebFrame::GetSelectionAsText() |
| { |
| if (m_impl->frame) |
| return m_impl->frame->selection()->toNormalizedRange()->text(); |
| |
| return wxEmptyString; |
| } |
| |
| wxWebKitSelection wxWebFrame::GetSelection() |
| { |
| if (m_impl->frame) |
| return wxWebKitSelection(m_impl->frame->selection()); |
| |
| return 0; |
| } |
| |
| wxString wxWebFrame::RunScript(const wxString& javascript) |
| { |
| wxString returnValue = wxEmptyString; |
| if (m_impl->frame && m_impl->frame->loader()) { |
| bool hasLoaded = m_impl->frame->loader()->frameHasLoaded(); |
| wxASSERT_MSG(hasLoaded, wxT("Document must be loaded before calling RunScript.")); |
| if (hasLoaded) { |
| WebCore::ScriptController* controller = m_impl->frame->script(); |
| bool jsEnabled = controller->canExecuteScripts(WebCore::AboutToExecuteScript); |
| wxASSERT_MSG(jsEnabled, wxT("RunScript requires JavaScript to be enabled.")); |
| if (jsEnabled) { |
| JSC::JSValue result = controller->executeScript(javascript, true).jsValue(); |
| if (result) |
| returnValue = wxString(result.toString(m_impl->frame->script()->globalObject(WebCore::mainThreadNormalWorld())->globalExec()).utf8().data(), wxConvUTF8); |
| } |
| } |
| } |
| return returnValue; |
| } |
| |
| bool wxWebFrame::ExecuteEditCommand(const wxString& command, const wxString& parameter) |
| { |
| if (m_impl->frame && IsEditable()) |
| return m_impl->frame->editor()->command(command).execute(parameter); |
| } |
| |
| EditState wxWebFrame::GetEditCommandState(const wxString& command) const |
| { |
| if (m_impl->frame && IsEditable()) { |
| WebCore::TriState state = m_impl->frame->editor()->command(command).state(); |
| if (state == WebCore::TrueTriState) |
| return EditStateTrue; |
| if (state == WebCore::FalseTriState) |
| return EditStateFalse; |
| |
| return EditStateMixed; |
| } |
| |
| return EditStateFalse; |
| } |
| |
| wxString wxWebFrame::GetEditCommandValue(const wxString& command) const |
| { |
| if (m_impl->frame && IsEditable()) |
| return m_impl->frame->editor()->command(command).value(); |
| |
| return wxEmptyString; |
| } |
| |
| |
| bool wxWebFrame::FindString(const wxString& string, bool forward, bool caseSensitive, bool wrapSelection, bool startInSelection) |
| { |
| if (m_impl->frame) |
| return m_impl->frame->editor()->findString(string, forward, caseSensitive, wrapSelection, startInSelection); |
| |
| return false; |
| } |
| |
| void wxWebFrame::LoadURL(const wxString& url) |
| { |
| if (m_impl->frame && m_impl->frame->loader()) { |
| WebCore::KURL kurl = WebCore::KURL(WebCore::KURL(), url, WebCore::UTF8Encoding()); |
| // NB: This is an ugly fix, but CURL won't load sub-resources if the |
| // protocol is omitted; sadly, it will not emit an error, either, so |
| // there's no way for us to catch this problem the correct way yet. |
| if (kurl.protocol().isEmpty()) { |
| // is it a file on disk? |
| if (wxFileExists(url)) { |
| kurl.setProtocol("file"); |
| kurl.setPath("//" + kurl.path()); |
| } |
| else { |
| kurl.setProtocol("http"); |
| kurl.setPath("//" + kurl.path()); |
| } |
| } |
| m_impl->frame->loader()->load(kurl, false); |
| } |
| } |
| |
| bool wxWebFrame::GoBack() |
| { |
| if (m_impl->frame && m_impl->frame->page()) |
| return m_impl->frame->page()->goBack(); |
| |
| return false; |
| } |
| |
| bool wxWebFrame::GoForward() |
| { |
| if (m_impl->frame && m_impl->frame->page()) |
| return m_impl->frame->page()->goForward(); |
| |
| return false; |
| } |
| |
| bool wxWebFrame::CanGoBack() |
| { |
| if (m_impl->frame && m_impl->frame->page()) |
| return m_impl->frame->page()->canGoBackOrForward(-1); |
| |
| return false; |
| } |
| |
| bool wxWebFrame::CanGoForward() |
| { |
| if (m_impl->frame && m_impl->frame->page()) |
| return m_impl->frame->page()->canGoBackOrForward(1); |
| |
| return false; |
| } |
| |
| void wxWebFrame::Undo() |
| { |
| if (m_impl->frame && m_impl->frame->editor() && CanUndo()) |
| return m_impl->frame->editor()->undo(); |
| } |
| |
| void wxWebFrame::Redo() |
| { |
| if (m_impl->frame && m_impl->frame->editor() && CanRedo()) |
| return m_impl->frame->editor()->redo(); |
| } |
| |
| bool wxWebFrame::CanUndo() |
| { |
| if (m_impl->frame && m_impl->frame->editor()) |
| return m_impl->frame->editor()->canUndo(); |
| |
| return false; |
| } |
| |
| bool wxWebFrame::CanRedo() |
| { |
| if (m_impl->frame && m_impl->frame->editor()) |
| return m_impl->frame->editor()->canRedo(); |
| |
| return false; |
| } |
| |
| bool wxWebFrame::CanIncreaseTextSize() const |
| { |
| if (m_impl->frame && m_impl->frame->view()) { |
| if (m_textMagnifier*TextSizeMultiplierRatio <= MaximumTextSizeMultiplier) |
| return true; |
| } |
| return false; |
| } |
| |
| void wxWebFrame::IncreaseTextSize() |
| { |
| if (CanIncreaseTextSize()) { |
| m_textMagnifier = m_textMagnifier*TextSizeMultiplierRatio; |
| m_impl->frame->setTextZoomFactor(m_textMagnifier); |
| } |
| } |
| |
| bool wxWebFrame::CanDecreaseTextSize() const |
| { |
| if (m_impl->frame && m_impl->frame->view()) { |
| if (m_textMagnifier/TextSizeMultiplierRatio >= MinimumTextSizeMultiplier) |
| return true; |
| } |
| return false; |
| } |
| |
| void wxWebFrame::DecreaseTextSize() |
| { |
| if (CanDecreaseTextSize()) { |
| m_textMagnifier = m_textMagnifier/TextSizeMultiplierRatio; |
| m_impl->frame->setTextZoomFactor(m_textMagnifier); |
| } |
| } |
| |
| void wxWebFrame::ResetTextSize() |
| { |
| m_textMagnifier = 1.0; |
| if (m_impl->frame) |
| m_impl->frame->setTextZoomFactor(m_textMagnifier); |
| } |
| |
| void wxWebFrame::MakeEditable(bool enable) |
| { |
| if (enable != IsEditable() && m_impl->frame && m_impl->frame->page()) |
| m_impl->frame->page()->setEditable(enable); |
| } |
| |
| bool wxWebFrame::IsEditable() const |
| { |
| if (m_impl->frame && m_impl->frame->page()) |
| return m_impl->frame->page()->isEditable(); |
| return false; |
| } |
| |
| bool wxWebFrame::CanCopy() |
| { |
| if (m_impl->frame && m_impl->frame->view()) |
| return (m_impl->frame->editor()->canCopy() || m_impl->frame->editor()->canDHTMLCopy()); |
| |
| return false; |
| } |
| |
| void wxWebFrame::Copy() |
| { |
| if (CanCopy()) |
| m_impl->frame->editor()->copy(); |
| } |
| |
| bool wxWebFrame::CanCut() |
| { |
| if (m_impl->frame && m_impl->frame->view()) |
| return (m_impl->frame->editor()->canCut() || m_impl->frame->editor()->canDHTMLCut()); |
| |
| return false; |
| } |
| |
| void wxWebFrame::Cut() |
| { |
| if (CanCut()) |
| m_impl->frame->editor()->cut(); |
| } |
| |
| bool wxWebFrame::CanPaste() |
| { |
| if (m_impl->frame && m_impl->frame->view()) |
| return (m_impl->frame->editor()->canPaste() || m_impl->frame->editor()->canDHTMLPaste()); |
| |
| return false; |
| } |
| |
| void wxWebFrame::Paste() |
| { |
| if (CanPaste()) |
| m_impl->frame->editor()->paste(); |
| |
| } |
| |
| wxWebViewDOMElementInfo wxWebFrame::HitTest(const wxPoint& pos) const |
| { |
| wxWebViewDOMElementInfo domInfo; |
| |
| if (m_impl->frame->view()) { |
| WebCore::HitTestResult result = m_impl->frame->eventHandler()->hitTestResultAtPoint(m_impl->frame->view()->windowToContents(pos), false); |
| if (result.innerNode()) { |
| domInfo.SetLink(result.absoluteLinkURL().string()); |
| domInfo.SetText(result.textContent()); |
| domInfo.SetImageSrc(result.absoluteImageURL().string()); |
| domInfo.SetSelected(result.isSelected()); |
| } |
| } |
| |
| return domInfo; |
| } |
| |
| bool wxWebFrame::ShouldClose() const |
| { |
| if (m_impl->frame) |
| return m_impl->frame->loader()->shouldClose(); |
| |
| return true; |
| } |
| |
| wxWebKitCompatibilityMode wxWebFrame::GetCompatibilityMode() const |
| { |
| if (m_impl->frame && m_impl->frame->document()) |
| return (wxWebKitCompatibilityMode)m_impl->frame->document()->compatibilityMode(); |
| |
| return QuirksMode; |
| } |
| |
| void wxWebFrame::GrantUniversalAccess() |
| { |
| if (m_impl->frame && m_impl->frame->document()) |
| m_impl->frame->document()->securityOrigin()->grantUniversalAccess(); |
| } |