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 "FloatRect.h"
34 #include "FrameLoader.h"
35 #include "FrameLoaderClientWx.h"
36 #include "FrameView.h"
37 #include "GraphicsContext.h"
38 #include "HitTestResult.h"
39 #include "HostWindow.h"
40 #include "HTMLFrameOwnerElement.h"
43 #include "PlatformString.h"
44 #include "PrintContext.h"
45 #include "RenderTreeAsText.h"
46 #include "RenderObject.h"
47 #include "RenderView.h"
48 #include "ScriptController.h"
49 #include "ScriptValue.h"
50 #include "SubstituteData.h"
51 #include "TextEncoding.h"
53 #include "JSDOMBinding.h"
54 #include <runtime/JSValue.h>
55 #include <runtime/UString.h>
56 #include <wtf/text/CString.h>
58 #include "EditorClientWx.h"
59 #include "FrameLoaderClientWx.h"
61 #include "wx/wxprec.h"
66 #include "WebDOMNode.h"
68 #include "WebDOMSelection.h"
71 #include "WebFramePrivate.h"
72 #include "WebViewPrivate.h"
78 #include <wx/dcbuffer.h>
79 #include <wx/dcgraph.h>
80 #include <wx/graphics.h>
82 #include <wx/printdlg.h>
84 // Match Safari's min/max zoom sizes by default
85 #define MinimumTextSizeMultiplier 0.5f
86 #define MaximumTextSizeMultiplier 3.0f
87 #define TextSizeMultiplierRatio 1.2f
91 // we need wxGraphicsContext and wxPrinterDC to work together,
92 // which requires wx 2.9.x.
93 #if wxCHECK_VERSION(2, 9, 1)
94 class wxWebFramePrintout : public wxPrintout {
96 wxWebFramePrintout(WebCore::Frame* frame) :
98 m_printContext(frame),
105 int GetPageCount() { return m_printContext.pageCount(); }
106 void SetFirstPage(int page) { m_fromPage = page; }
107 void SetLastPage(int page) { m_toPage = page; }
109 void InitializeWithPageSize(wxRect pageRect, bool isMM = true)
112 double mmToPixelsX = (double)wxGetDisplaySize().GetWidth() /
113 (double)wxGetDisplaySizeMM().GetWidth();
114 double mmToPixelsY = (double)wxGetDisplaySize().GetHeight() /
115 (double)wxGetDisplaySizeMM().GetHeight();
116 // convert mm to pixels
117 pageRect.x = pageRect.x * mmToPixelsX;
118 pageRect.y = pageRect.y * mmToPixelsY;
119 pageRect.width = pageRect.width * mmToPixelsX;
120 pageRect.height = pageRect.height * mmToPixelsY;
122 m_pageWidth = pageRect.width;
123 m_printContext.begin(m_pageWidth);
125 float pageHeight = pageRect.height;
126 m_printContext.computePageRects(WebCore::FloatRect(pageRect), /* headerHeight */ 0, /* footerHeight */ 0, /* userScaleFactor */ 1.0, pageHeight);
129 void OnBeginPrinting()
131 wxPrinterDC* pdc = dynamic_cast<wxPrinterDC*>(GetDC());
132 pdc->SetMapMode(wxMM_POINTS);
135 pdc->GetSize(&pixelsW, &pixelsH);
136 pixelsW = pdc->DeviceToLogicalXRel(pixelsW);
137 pixelsH = pdc->DeviceToLogicalYRel(pixelsH);
138 InitializeWithPageSize(wxRect(0, 0, pixelsW, pixelsH - 40), false);
141 void GetPageInfo(int *minPage, int *maxPage, int *pageFrom, int *pageTo)
146 *maxPage = m_printContext.pageCount();
148 *pageFrom = m_fromPage;
153 bool HasPage(int pageNum)
155 return pageNum <= m_printContext.pageCount() && pageNum >= m_fromPage && pageNum <= m_toPage;
158 bool OnPrintPage(int pageNum)
160 wxPrinterDC* pdc = dynamic_cast<wxPrinterDC*>(GetDC());
161 #if wxCHECK_VERSION(2, 9, 2) && defined(wxUSE_CAIRO) && wxUSE_CAIRO
162 wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetCairoRenderer();
164 renderer = wxGraphicsRenderer::GetDefaultRenderer();
165 wxGraphicsContext* context = renderer->CreateContext(*pdc);
166 wxGCDC gcdc(context);
173 WebCore::GraphicsContext ctx(&gcdc);
174 m_printContext.spoolPage(ctx, pageNum - 1, m_pageWidth);
181 m_printContext.end();
188 WebCore::Frame *m_frame;
189 WebCore::PrintContext m_printContext;
193 wxWebFrame* kit(WebCore::Frame* frame)
197 if (!frame->loader())
200 WebCore::FrameLoaderClientWx* loaderClient = dynamic_cast<WebCore::FrameLoaderClientWx*>(frame->loader()->client());
202 return loaderClient->webFrame();
207 wxWebFrame::wxWebFrame(wxWebView* container, wxWebFrame* parent, WebViewFrameData* data) :
208 m_textMagnifier(1.0),
209 m_isInitialized(false),
210 m_beingDestroyed(false)
213 m_impl = new WebFramePrivate();
215 WebCore::HTMLFrameOwnerElement* parentFrame = 0;
218 parentFrame = data->ownerElement;
221 WebCore::FrameLoaderClientWx* loaderClient = new WebCore::FrameLoaderClientWx();
222 RefPtr<WebCore::Frame> newFrame = WebCore::Frame::create(container->m_impl->page, parentFrame, loaderClient);
224 m_impl->frame = newFrame.get();
227 newFrame->tree()->setName(data->name);
229 // Subframes expect to be added to the FrameTree before init is called.
231 parentFrame->document()->frame()->tree()->appendChild(newFrame.get());
233 loaderClient->setFrame(this);
234 loaderClient->setWebView(container);
236 if (data && data->ownerElement)
237 m_impl->frame->ref();
239 m_impl->frame->init();
241 m_isInitialized = true;
244 wxWebFrame::~wxWebFrame()
250 wxString wxWebFrame::GetName()
252 if (m_impl && m_impl->frame && m_impl->frame->tree())
253 return m_impl->frame->tree()->name().string();
254 return wxEmptyString;
257 WebCore::Frame* wxWebFrame::GetFrame()
260 return m_impl->frame;
265 void wxWebFrame::Stop()
267 if (m_impl->frame && m_impl->frame->loader())
268 m_impl->frame->loader()->stop();
271 void wxWebFrame::Reload()
273 if (m_impl->frame && m_impl->frame->loader())
274 m_impl->frame->loader()->reload();
277 wxString wxWebFrame::GetPageSource()
280 if (m_impl->frame->view() && m_impl->frame->view()->layoutPending())
281 m_impl->frame->view()->layout();
283 WebCore::Document* doc = m_impl->frame->document();
286 wxString source = createMarkup(doc);
290 return wxEmptyString;
293 void wxWebFrame::SetPageSource(const wxString& source, const wxString& baseUrl, const wxString& mimetype)
295 if (m_impl->frame && m_impl->frame->loader()) {
296 WebCore::KURL url(WebCore::KURL(), baseUrl);
298 const wxCharBuffer charBuffer(source.utf8_str());
299 const char* contents = charBuffer;
301 WTF::PassRefPtr<WebCore::SharedBuffer> sharedBuffer = WebCore::SharedBuffer::create(contents, strlen(contents));
302 WebCore::SubstituteData substituteData(sharedBuffer, mimetype, WTF::String("UTF-8"), WebCore::blankURL(), url);
304 m_impl->frame->loader()->stop();
305 m_impl->frame->loader()->load(WebCore::ResourceRequest(url), substituteData, false);
309 wxString wxWebFrame::GetInnerText()
311 if (m_impl->frame->view() && m_impl->frame->view()->layoutPending())
312 m_impl->frame->view()->layout();
314 WebCore::Element *documentElement = m_impl->frame->document()->documentElement();
315 return documentElement->innerText();
318 wxString wxWebFrame::GetAsMarkup()
320 if (!m_impl->frame || !m_impl->frame->document())
321 return wxEmptyString;
323 return createMarkup(m_impl->frame->document());
326 wxString wxWebFrame::GetExternalRepresentation()
328 if (m_impl->frame->view() && m_impl->frame->view()->layoutPending())
329 m_impl->frame->view()->layout();
331 return externalRepresentation(m_impl->frame);
334 wxString wxWebFrame::GetSelectionAsHTML()
337 return m_impl->frame->selection()->toNormalizedRange()->toHTML();
339 return wxEmptyString;
342 wxString wxWebFrame::GetSelectionAsText()
345 return m_impl->frame->selection()->toNormalizedRange()->text();
347 return wxEmptyString;
350 wxWebKitSelection wxWebFrame::GetSelection()
353 return wxWebKitSelection(m_impl->frame->selection());
358 wxString wxWebFrame::RunScript(const wxString& javascript)
360 wxString returnValue = wxEmptyString;
361 if (m_impl->frame && m_impl->frame->loader()) {
362 bool hasLoaded = m_impl->frame->loader()->frameHasLoaded();
363 wxASSERT_MSG(hasLoaded, wxT("Document must be loaded before calling RunScript."));
365 WebCore::ScriptController* controller = m_impl->frame->script();
366 bool jsEnabled = controller->canExecuteScripts(WebCore::AboutToExecuteScript);
367 wxASSERT_MSG(jsEnabled, wxT("RunScript requires JavaScript to be enabled."));
369 JSC::JSValue result = controller->executeScript(javascript, true).jsValue();
371 returnValue = wxString(result.toString(m_impl->frame->script()->globalObject(WebCore::mainThreadNormalWorld())->globalExec()).utf8().data(), wxConvUTF8);
378 bool wxWebFrame::ExecuteEditCommand(const wxString& command, const wxString& parameter)
380 if (m_impl->frame && IsEditable())
381 return m_impl->frame->editor()->command(command).execute(parameter);
384 EditState wxWebFrame::GetEditCommandState(const wxString& command) const
386 if (m_impl->frame && IsEditable()) {
387 WebCore::TriState state = m_impl->frame->editor()->command(command).state();
388 if (state == WebCore::TrueTriState)
389 return EditStateTrue;
390 if (state == WebCore::FalseTriState)
391 return EditStateFalse;
393 return EditStateMixed;
396 return EditStateFalse;
399 wxString wxWebFrame::GetEditCommandValue(const wxString& command) const
401 if (m_impl->frame && IsEditable())
402 return m_impl->frame->editor()->command(command).value();
404 return wxEmptyString;
408 bool wxWebFrame::FindString(const wxString& string, bool forward, bool caseSensitive, bool wrapSelection, bool startInSelection)
411 return m_impl->frame->editor()->findString(string, forward, caseSensitive, wrapSelection, startInSelection);
416 void wxWebFrame::LoadURL(const wxString& url)
418 if (m_impl->frame && m_impl->frame->loader()) {
419 WebCore::KURL kurl = WebCore::KURL(WebCore::KURL(), url, WebCore::UTF8Encoding());
420 // NB: This is an ugly fix, but CURL won't load sub-resources if the
421 // protocol is omitted; sadly, it will not emit an error, either, so
422 // there's no way for us to catch this problem the correct way yet.
423 if (kurl.protocol().isEmpty()) {
424 // is it a file on disk?
425 if (wxFileExists(url)) {
426 kurl.setProtocol("file");
427 kurl.setPath("//" + kurl.path());
430 kurl.setProtocol("http");
431 kurl.setPath("//" + kurl.path());
434 m_impl->frame->loader()->load(kurl, false);
438 bool wxWebFrame::GoBack()
440 if (m_impl->frame && m_impl->frame->page())
441 return m_impl->frame->page()->goBack();
446 bool wxWebFrame::GoForward()
448 if (m_impl->frame && m_impl->frame->page())
449 return m_impl->frame->page()->goForward();
454 bool wxWebFrame::CanGoBack()
456 if (m_impl->frame && m_impl->frame->page())
457 return m_impl->frame->page()->canGoBackOrForward(-1);
462 bool wxWebFrame::CanGoForward()
464 if (m_impl->frame && m_impl->frame->page())
465 return m_impl->frame->page()->canGoBackOrForward(1);
470 void wxWebFrame::Undo()
472 if (m_impl->frame && m_impl->frame->editor() && CanUndo())
473 return m_impl->frame->editor()->undo();
476 void wxWebFrame::Redo()
478 if (m_impl->frame && m_impl->frame->editor() && CanRedo())
479 return m_impl->frame->editor()->redo();
482 bool wxWebFrame::CanUndo()
484 if (m_impl->frame && m_impl->frame->editor())
485 return m_impl->frame->editor()->canUndo();
490 bool wxWebFrame::CanRedo()
492 if (m_impl->frame && m_impl->frame->editor())
493 return m_impl->frame->editor()->canRedo();
498 bool wxWebFrame::CanIncreaseTextSize() const
500 if (m_impl->frame && m_impl->frame->view()) {
501 if (m_textMagnifier*TextSizeMultiplierRatio <= MaximumTextSizeMultiplier)
507 void wxWebFrame::IncreaseTextSize()
509 if (CanIncreaseTextSize()) {
510 m_textMagnifier = m_textMagnifier*TextSizeMultiplierRatio;
511 m_impl->frame->setTextZoomFactor(m_textMagnifier);
515 bool wxWebFrame::CanDecreaseTextSize() const
517 if (m_impl->frame && m_impl->frame->view()) {
518 if (m_textMagnifier/TextSizeMultiplierRatio >= MinimumTextSizeMultiplier)
524 void wxWebFrame::DecreaseTextSize()
526 if (CanDecreaseTextSize()) {
527 m_textMagnifier = m_textMagnifier/TextSizeMultiplierRatio;
528 m_impl->frame->setTextZoomFactor(m_textMagnifier);
532 void wxWebFrame::ResetTextSize()
534 m_textMagnifier = 1.0;
536 m_impl->frame->setTextZoomFactor(m_textMagnifier);
539 void wxWebFrame::MakeEditable(bool enable)
541 if (enable != IsEditable() && m_impl->frame && m_impl->frame->page())
542 m_impl->frame->page()->setEditable(enable);
545 bool wxWebFrame::IsEditable() const
547 if (m_impl->frame && m_impl->frame->page())
548 return m_impl->frame->page()->isEditable();
552 bool wxWebFrame::CanCopy()
554 if (m_impl->frame && m_impl->frame->view())
555 return (m_impl->frame->editor()->canCopy() || m_impl->frame->editor()->canDHTMLCopy());
560 void wxWebFrame::Copy()
563 m_impl->frame->editor()->copy();
566 bool wxWebFrame::CanCut()
568 if (m_impl->frame && m_impl->frame->view())
569 return (m_impl->frame->editor()->canCut() || m_impl->frame->editor()->canDHTMLCut());
574 void wxWebFrame::Cut()
577 m_impl->frame->editor()->cut();
580 bool wxWebFrame::CanPaste()
582 if (m_impl->frame && m_impl->frame->view())
583 return (m_impl->frame->editor()->canPaste() || m_impl->frame->editor()->canDHTMLPaste());
588 void wxWebFrame::Paste()
591 m_impl->frame->editor()->paste();
595 void wxWebFrame::Print(bool showDialog)
597 #if wxCHECK_VERSION(2, 9, 1)
601 wxPrintDialogData printdata;
602 printdata.GetPrintData().SetPrintMode(wxPRINT_MODE_PRINTER);
603 printdata.GetPrintData().SetNoCopies(1);
604 #if wxCHECK_VERSION(2, 9, 2)
605 printdata.GetPrintData().ConvertFromNative();
607 // due to wx bugs, we cannot get the actual native default paper type before showing the dialog until 2.9.2,
608 // so pick a common default instead.
609 printdata.GetPrintData().SetPaperId(wxPAPER_LETTER);
612 wxPageSetupDialogData pageSetup(printdata.GetPrintData());
614 wxRect paperSize = pageSetup.GetPaperSize();
616 // On Windows, the paper size apparently includes the non-printable areas of the page.
617 // Guesstimate the printable page margins until we find a better solution.
618 paperSize.Deflate(15, 15);
620 wxWebFramePrintout* printout = new wxWebFramePrintout(m_impl->frame);
621 printout->InitializeWithPageSize(paperSize);
623 printdata.SetMinPage(1);
624 printdata.SetMaxPage(printout->GetPageCount());
625 printdata.SetFromPage(1);
626 printdata.SetToPage(printout->GetPageCount());
629 wxPrintDialog dialog(0, &printdata);
630 if (dialog.ShowModal() == wxID_OK) {
631 printdata = dialog.GetPrintDialogData();
632 printout->SetFirstPage(printdata.GetFromPage());
633 printout->SetLastPage(printdata.GetToPage());
638 wxPrinter printer(&printdata);
640 printer.Print(0, printout, false);
643 wxFAIL_MSG(wxT("Printing is only supported in wxWidgets 2.9.1 and above."));
647 wxWebViewDOMElementInfo wxWebFrame::HitTest(const wxPoint& pos) const
649 wxWebViewDOMElementInfo domInfo;
651 if (m_impl->frame->view()) {
652 WebCore::HitTestResult result = m_impl->frame->eventHandler()->hitTestResultAtPoint(m_impl->frame->view()->windowToContents(pos), false);
653 if (result.innerNode()) {
654 domInfo.SetLink(result.absoluteLinkURL().string());
655 domInfo.SetText(result.textContent());
656 domInfo.SetImageSrc(result.absoluteImageURL().string());
657 domInfo.SetSelected(result.isSelected());
664 bool wxWebFrame::ShouldClose() const
667 return m_impl->frame->loader()->shouldClose();
672 wxWebKitCompatibilityMode wxWebFrame::GetCompatibilityMode() const
674 if (m_impl->frame && m_impl->frame->document())
675 return (wxWebKitCompatibilityMode)m_impl->frame->document()->compatibilityMode();
680 void wxWebFrame::GrantUniversalAccess()
682 if (m_impl->frame && m_impl->frame->document())
683 m_impl->frame->document()->securityOrigin()->grantUniversalAccess();