8c621427be7d80b53a135caf3ad2e041647cd601
[WebKit-https.git] / Source / WebKit / wx / WebFrame.cpp
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 "FloatRect.h"
33 #include "Frame.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"
41 #include "markup.h"
42 #include "Page.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"
52
53 #include "JSDOMBinding.h"
54 #include <runtime/JSValue.h>
55 #include <runtime/UString.h>
56 #include <wtf/text/CString.h>
57
58 #include "EditorClientWx.h"
59 #include "FrameLoaderClientWx.h"
60
61 #include "wx/wxprec.h"
62 #ifndef WX_PRECOMP
63     #include "wx/wx.h"
64 #endif
65
66 #include "WebDOMNode.h"
67
68 #include "WebDOMSelection.h"
69 #include "WebFrame.h"
70 #include "WebView.h"
71 #include "WebFramePrivate.h"
72 #include "WebViewPrivate.h"
73
74 #include <algorithm>
75
76 #include <wx/defs.h>
77 #include <wx/dc.h>
78 #include <wx/dcbuffer.h>
79 #include <wx/dcgraph.h>
80 #include <wx/graphics.h>
81 #include <wx/print.h>
82 #include <wx/printdlg.h>
83
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
88
89 using namespace std;
90
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 {
95 public:
96     wxWebFramePrintout(WebCore::Frame* frame) :
97         m_frame(frame),
98         m_printContext(frame),
99         m_pageWidth(0.0),
100         m_fromPage(1),
101         m_toPage(1)
102     {
103     }
104
105     int GetPageCount() { return m_printContext.pageCount(); }
106     void SetFirstPage(int page) { m_fromPage = page; }
107     void SetLastPage(int page) { m_toPage = page; }
108
109     void InitializeWithPageSize(wxRect pageRect)
110     {
111         double mmToPixelsX = (double)wxGetDisplaySize().GetWidth() /
112                                 (double)wxGetDisplaySizeMM().GetWidth();
113         double mmToPixelsY = (double)wxGetDisplaySize().GetHeight() /
114                                 (double)wxGetDisplaySizeMM().GetHeight();
115         // convert mm to pixels
116         pageRect.x = pageRect.x * mmToPixelsX;
117         pageRect.y = pageRect.y * mmToPixelsY;
118         pageRect.width = pageRect.width * mmToPixelsX;
119         pageRect.height = pageRect.height * mmToPixelsY;
120         
121         m_pageWidth = pageRect.width;
122         m_printContext.begin(m_pageWidth);
123         
124         float pageHeight = pageRect.height;
125         m_printContext.computePageRects(WebCore::FloatRect(pageRect), /* headerHeight */ 0, /* footerHeight */ 0, /* userScaleFactor */ 1.0, pageHeight);
126     }
127     
128     void OnBeginPrinting()
129     {
130         wxPrinterDC* pdc = dynamic_cast<wxPrinterDC*>(GetDC());
131         pdc->SetMapMode(wxMM_POINTS);
132         int pageWidth = 0;
133         int pageHeight = 0;
134         GetPageSizeMM(&pageWidth, &pageHeight);
135         
136         InitializeWithPageSize(wxRect(0, 0, pageWidth, pageHeight));
137     }
138     
139     void GetPageInfo(int *minPage, int *maxPage, int *pageFrom, int *pageTo)
140     {
141         if (minPage)
142             *minPage = 1;
143         if (maxPage)
144             *maxPage = m_printContext.pageCount();
145         if (pageFrom)
146             *pageFrom = m_fromPage;
147         if (pageTo)
148             *pageTo = m_toPage;
149     }
150     
151     bool HasPage(int pageNum)
152     {
153         return pageNum <= m_printContext.pageCount() && pageNum >= m_fromPage && pageNum <= m_toPage;
154     }
155     
156     bool OnPrintPage(int pageNum)
157     {
158         wxPrinterDC* pdc = dynamic_cast<wxPrinterDC*>(GetDC());
159         
160         wxGCDC gcdc(*pdc);
161         if (!gcdc.IsOk())
162             return false;
163
164         WebCore::GraphicsContext ctx(&gcdc);
165         m_printContext.spoolPage(ctx, pageNum - 1, m_pageWidth);
166         
167         return true;
168     }
169     
170     void OnEndPrinting()
171     {
172         m_printContext.end();   
173     }
174     
175 private:
176     float m_pageWidth;
177     int m_fromPage;
178     int m_toPage;
179     WebCore::Frame *m_frame;
180     WebCore::PrintContext m_printContext;
181 };
182 #endif
183
184 wxWebFrame* kit(WebCore::Frame* frame)
185 {
186     if (!frame)
187         return 0;
188     if (!frame->loader())
189         return 0;
190     
191     WebCore::FrameLoaderClientWx* loaderClient = dynamic_cast<WebCore::FrameLoaderClientWx*>(frame->loader()->client());
192     if (loaderClient)
193         return loaderClient->webFrame();
194     
195     return 0;
196 }
197
198 wxWebFrame::wxWebFrame(wxWebView* container, wxWebFrame* parent, WebViewFrameData* data) :
199     m_textMagnifier(1.0),
200     m_isInitialized(false),
201     m_beingDestroyed(false)
202 {
203
204     m_impl = new WebFramePrivate();
205  
206     WebCore::HTMLFrameOwnerElement* parentFrame = 0;
207     
208     if (data) {
209         parentFrame = data->ownerElement;
210     }
211     
212     WebCore::FrameLoaderClientWx* loaderClient = new WebCore::FrameLoaderClientWx();
213     RefPtr<WebCore::Frame> newFrame = WebCore::Frame::create(container->m_impl->page, parentFrame, loaderClient);
214
215     m_impl->frame = newFrame.get();
216
217     if (data)
218         newFrame->tree()->setName(data->name);
219
220     // Subframes expect to be added to the FrameTree before init is called.
221     if (parentFrame)
222         parentFrame->document()->frame()->tree()->appendChild(newFrame.get());
223     
224     loaderClient->setFrame(this);
225     loaderClient->setWebView(container);
226     
227     if (data && data->ownerElement)
228         m_impl->frame->ref();
229
230     m_impl->frame->init();
231         
232     m_isInitialized = true;
233 }
234
235 wxWebFrame::~wxWebFrame()
236 {
237     if (m_impl)
238         delete m_impl;
239 }
240
241 wxString wxWebFrame::GetName()
242 {
243     if (m_impl && m_impl->frame && m_impl->frame->tree())
244         return m_impl->frame->tree()->name().string();
245     return wxEmptyString;
246 }
247
248 WebCore::Frame* wxWebFrame::GetFrame()
249 {
250     if (m_impl)
251         return m_impl->frame;
252         
253     return 0;
254 }
255
256 void wxWebFrame::Stop()
257 {
258     if (m_impl->frame && m_impl->frame->loader())
259         m_impl->frame->loader()->stop();
260 }
261
262 void wxWebFrame::Reload()
263 {
264     if (m_impl->frame && m_impl->frame->loader())
265         m_impl->frame->loader()->reload();
266 }
267
268 wxString wxWebFrame::GetPageSource()
269 {
270     if (m_impl->frame) {
271         if (m_impl->frame->view() && m_impl->frame->view()->layoutPending())
272             m_impl->frame->view()->layout();
273     
274         WebCore::Document* doc = m_impl->frame->document();
275         
276         if (doc) {
277             wxString source = createMarkup(doc);
278             return source;
279         }
280     }
281     return wxEmptyString;
282 }
283
284 void wxWebFrame::SetPageSource(const wxString& source, const wxString& baseUrl, const wxString& mimetype)
285 {
286     if (m_impl->frame && m_impl->frame->loader()) {
287         WebCore::KURL url(WebCore::KURL(), baseUrl);
288
289         const wxCharBuffer charBuffer(source.utf8_str());
290         const char* contents = charBuffer;
291
292         WTF::PassRefPtr<WebCore::SharedBuffer> sharedBuffer = WebCore::SharedBuffer::create(contents, strlen(contents));
293         WebCore::SubstituteData substituteData(sharedBuffer, mimetype, WTF::String("UTF-8"), WebCore::blankURL(), url);
294
295         m_impl->frame->loader()->stop();
296         m_impl->frame->loader()->load(WebCore::ResourceRequest(url), substituteData, false);
297     }
298 }
299
300 wxString wxWebFrame::GetInnerText()
301 {
302     if (m_impl->frame->view() && m_impl->frame->view()->layoutPending())
303         m_impl->frame->view()->layout();
304         
305     WebCore::Element *documentElement = m_impl->frame->document()->documentElement();
306     return documentElement->innerText();
307 }
308
309 wxString wxWebFrame::GetAsMarkup()
310 {
311     if (!m_impl->frame || !m_impl->frame->document())
312         return wxEmptyString;
313
314     return createMarkup(m_impl->frame->document());
315 }
316
317 wxString wxWebFrame::GetExternalRepresentation()
318 {
319     if (m_impl->frame->view() && m_impl->frame->view()->layoutPending())
320         m_impl->frame->view()->layout();
321
322     return externalRepresentation(m_impl->frame);
323 }
324
325 wxString wxWebFrame::GetSelectionAsHTML()
326 {
327     if (m_impl->frame)
328         return m_impl->frame->selection()->toNormalizedRange()->toHTML();
329         
330     return wxEmptyString;
331 }
332
333 wxString wxWebFrame::GetSelectionAsText()
334 {
335     if (m_impl->frame)
336         return m_impl->frame->selection()->toNormalizedRange()->text();
337         
338     return wxEmptyString;
339 }
340
341 wxWebKitSelection wxWebFrame::GetSelection()
342 {
343     if (m_impl->frame)
344         return wxWebKitSelection(m_impl->frame->selection());
345         
346     return 0;
347 }
348
349 wxString wxWebFrame::RunScript(const wxString& javascript)
350 {
351     wxString returnValue = wxEmptyString;
352     if (m_impl->frame && m_impl->frame->loader()) {
353         bool hasLoaded = m_impl->frame->loader()->frameHasLoaded();
354         wxASSERT_MSG(hasLoaded, wxT("Document must be loaded before calling RunScript."));
355         if (hasLoaded) {
356             WebCore::ScriptController* controller = m_impl->frame->script();
357             bool jsEnabled = controller->canExecuteScripts(WebCore::AboutToExecuteScript); 
358             wxASSERT_MSG(jsEnabled, wxT("RunScript requires JavaScript to be enabled."));
359             if (jsEnabled) {
360                 JSC::JSValue result = controller->executeScript(javascript, true).jsValue();
361                 if (result)
362                     returnValue = wxString(result.toString(m_impl->frame->script()->globalObject(WebCore::mainThreadNormalWorld())->globalExec()).utf8().data(), wxConvUTF8);        
363             }
364         }
365     }
366     return returnValue;
367 }
368
369 bool wxWebFrame::ExecuteEditCommand(const wxString& command, const wxString& parameter)
370 {
371     if (m_impl->frame && IsEditable())
372         return m_impl->frame->editor()->command(command).execute(parameter);
373 }
374
375 EditState wxWebFrame::GetEditCommandState(const wxString& command) const
376 {
377     if (m_impl->frame && IsEditable()) { 
378         WebCore::TriState state = m_impl->frame->editor()->command(command).state();
379         if (state == WebCore::TrueTriState)
380             return EditStateTrue;
381         if (state == WebCore::FalseTriState)
382             return EditStateFalse;
383
384         return EditStateMixed;
385     }
386         
387     return EditStateFalse;
388 }
389
390 wxString wxWebFrame::GetEditCommandValue(const wxString& command) const
391 {
392     if (m_impl->frame && IsEditable())
393         return m_impl->frame->editor()->command(command).value();
394         
395     return wxEmptyString;
396 }
397
398
399 bool wxWebFrame::FindString(const wxString& string, bool forward, bool caseSensitive, bool wrapSelection, bool startInSelection)
400 {
401     if (m_impl->frame)
402         return m_impl->frame->editor()->findString(string, forward, caseSensitive, wrapSelection, startInSelection);
403
404     return false;
405 }
406
407 void wxWebFrame::LoadURL(const wxString& url)
408 {
409     if (m_impl->frame && m_impl->frame->loader()) {
410         WebCore::KURL kurl = WebCore::KURL(WebCore::KURL(), url, WebCore::UTF8Encoding());
411         // NB: This is an ugly fix, but CURL won't load sub-resources if the
412         // protocol is omitted; sadly, it will not emit an error, either, so
413         // there's no way for us to catch this problem the correct way yet.
414         if (kurl.protocol().isEmpty()) {
415             // is it a file on disk?
416             if (wxFileExists(url)) {
417                 kurl.setProtocol("file");
418                 kurl.setPath("//" + kurl.path());
419             }
420             else {
421                 kurl.setProtocol("http");
422                 kurl.setPath("//" + kurl.path());
423             }
424         }
425         m_impl->frame->loader()->load(kurl, false);
426     }
427 }
428
429 bool wxWebFrame::GoBack()
430 {
431     if (m_impl->frame && m_impl->frame->page())
432         return m_impl->frame->page()->goBack();
433
434     return false;
435 }
436
437 bool wxWebFrame::GoForward()
438 {
439     if (m_impl->frame && m_impl->frame->page())
440         return m_impl->frame->page()->goForward();
441
442     return false;
443 }
444
445 bool wxWebFrame::CanGoBack()
446 {
447     if (m_impl->frame && m_impl->frame->page())
448         return m_impl->frame->page()->canGoBackOrForward(-1);
449
450     return false;
451 }
452
453 bool wxWebFrame::CanGoForward()
454 {
455     if (m_impl->frame && m_impl->frame->page())
456         return m_impl->frame->page()->canGoBackOrForward(1);
457
458     return false;
459 }
460
461 void wxWebFrame::Undo()
462 {
463     if (m_impl->frame && m_impl->frame->editor() && CanUndo())
464         return m_impl->frame->editor()->undo();
465 }
466
467 void wxWebFrame::Redo()
468 {
469     if (m_impl->frame && m_impl->frame->editor() && CanRedo())
470         return m_impl->frame->editor()->redo();
471 }
472
473 bool wxWebFrame::CanUndo()
474 {
475     if (m_impl->frame && m_impl->frame->editor())
476         return m_impl->frame->editor()->canUndo();
477
478     return false;
479 }
480
481 bool wxWebFrame::CanRedo()
482 {
483     if (m_impl->frame && m_impl->frame->editor())
484         return m_impl->frame->editor()->canRedo();
485
486     return false;
487 }
488
489 bool wxWebFrame::CanIncreaseTextSize() const
490 {
491     if (m_impl->frame && m_impl->frame->view()) {
492         if (m_textMagnifier*TextSizeMultiplierRatio <= MaximumTextSizeMultiplier)
493             return true;
494     }
495     return false;
496 }
497
498 void wxWebFrame::IncreaseTextSize()
499 {
500     if (CanIncreaseTextSize()) {
501         m_textMagnifier = m_textMagnifier*TextSizeMultiplierRatio;
502         m_impl->frame->setTextZoomFactor(m_textMagnifier);
503     }
504 }
505
506 bool wxWebFrame::CanDecreaseTextSize() const
507 {
508     if (m_impl->frame && m_impl->frame->view()) {
509         if (m_textMagnifier/TextSizeMultiplierRatio >= MinimumTextSizeMultiplier)
510             return true;
511     }
512     return false;
513 }
514
515 void wxWebFrame::DecreaseTextSize()
516 {        
517     if (CanDecreaseTextSize()) {
518         m_textMagnifier = m_textMagnifier/TextSizeMultiplierRatio;
519         m_impl->frame->setTextZoomFactor(m_textMagnifier);
520     }
521 }
522
523 void wxWebFrame::ResetTextSize()
524 {
525     m_textMagnifier = 1.0;
526     if (m_impl->frame)
527         m_impl->frame->setTextZoomFactor(m_textMagnifier);
528 }
529
530 void wxWebFrame::MakeEditable(bool enable)
531 {
532     if (enable != IsEditable() && m_impl->frame && m_impl->frame->page())
533         m_impl->frame->page()->setEditable(enable);
534 }
535
536 bool wxWebFrame::IsEditable() const
537 {
538     if (m_impl->frame && m_impl->frame->page())
539         return m_impl->frame->page()->isEditable();
540     return false;
541 }
542
543 bool wxWebFrame::CanCopy()
544 {
545     if (m_impl->frame && m_impl->frame->view())
546         return (m_impl->frame->editor()->canCopy() || m_impl->frame->editor()->canDHTMLCopy());
547
548     return false;
549 }
550
551 void wxWebFrame::Copy()
552 {
553     if (CanCopy())
554         m_impl->frame->editor()->copy();
555 }
556
557 bool wxWebFrame::CanCut()
558 {
559     if (m_impl->frame && m_impl->frame->view())
560         return (m_impl->frame->editor()->canCut() || m_impl->frame->editor()->canDHTMLCut());
561
562     return false;
563 }
564
565 void wxWebFrame::Cut()
566 {
567     if (CanCut())
568         m_impl->frame->editor()->cut();
569 }
570
571 bool wxWebFrame::CanPaste()
572 {
573     if (m_impl->frame && m_impl->frame->view())
574         return (m_impl->frame->editor()->canPaste() || m_impl->frame->editor()->canDHTMLPaste());
575
576     return false;
577 }
578
579 void wxWebFrame::Paste()
580 {
581     if (CanPaste())
582         m_impl->frame->editor()->paste();
583
584 }
585
586 void wxWebFrame::Print(bool showDialog)
587 {
588 #if wxCHECK_VERSION(2, 9, 1)
589     if (!m_impl->frame)
590         return;
591     
592     wxPrintDialogData printdata;
593     printdata.GetPrintData().SetPrintMode(wxPRINT_MODE_PRINTER);
594     printdata.GetPrintData().SetNoCopies(1);
595     printdata.GetPrintData().ConvertFromNative();
596     
597     wxPageSetupDialogData pageSetup(printdata.GetPrintData());
598
599     wxRect paperSize = pageSetup.GetPaperSize();
600 #ifdef __WXMSW__
601     // On Windows, the paper size apparently includes the non-printable areas of the page.
602     // Guesstimate the printable page margins until we find a better solution.
603     paperSize.Deflate(15, 15);
604 #endif
605     wxWebFramePrintout* printout = new wxWebFramePrintout(m_impl->frame);
606     printout->InitializeWithPageSize(paperSize);
607     
608     printdata.SetMinPage(1);
609     printdata.SetMaxPage(printout->GetPageCount());
610     printdata.SetFromPage(1);
611     printdata.SetToPage(printout->GetPageCount());
612
613     if (showDialog) {
614         wxPrintDialog dialog(0, &printdata);
615         if (dialog.ShowModal() == wxID_OK) {
616             wxPrintDialogData updatedPrintdata = dialog.GetPrintDialogData();            
617             printout->SetFirstPage(updatedPrintdata.GetFromPage());
618             printout->SetLastPage(updatedPrintdata.GetToPage());
619         } else
620             return;
621     }
622     
623     wxPrinter printer(&printdata);
624         
625     printer.Print(0, printout, false);
626         
627 #else
628     wxFAIL_MSG(wxT("Printing is only supported in wxWidgets 2.9.1 and above."));
629 #endif
630 }
631
632 wxWebViewDOMElementInfo wxWebFrame::HitTest(const wxPoint& pos) const
633 {
634     wxWebViewDOMElementInfo domInfo;
635
636     if (m_impl->frame->view()) {
637         WebCore::HitTestResult result = m_impl->frame->eventHandler()->hitTestResultAtPoint(m_impl->frame->view()->windowToContents(pos), false);
638         if (result.innerNode()) {
639             domInfo.SetLink(result.absoluteLinkURL().string());
640             domInfo.SetText(result.textContent());
641             domInfo.SetImageSrc(result.absoluteImageURL().string());
642             domInfo.SetSelected(result.isSelected());
643         }
644     }
645
646     return domInfo;
647 }
648
649 bool wxWebFrame::ShouldClose() const
650 {
651     if (m_impl->frame)
652         return m_impl->frame->loader()->shouldClose();
653
654     return true;
655 }
656
657 wxWebKitCompatibilityMode wxWebFrame::GetCompatibilityMode() const
658 {
659     if (m_impl->frame && m_impl->frame->document())
660         return (wxWebKitCompatibilityMode)m_impl->frame->document()->compatibilityMode();
661
662     return QuirksMode;
663 }
664
665 void wxWebFrame::GrantUniversalAccess()
666 {
667     if (m_impl->frame && m_impl->frame->document())
668         m_impl->frame->document()->securityOrigin()->grantUniversalAccess();
669 }