Unreviewed, rolling out r96108, r96111, r96113, and r96116.
[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, bool isMM = true)
110     {
111         if (isMM) {
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;
121         }
122         m_pageWidth = pageRect.width;
123         m_printContext.begin(m_pageWidth);
124
125         float pageHeight = pageRect.height;
126         m_printContext.computePageRects(WebCore::FloatRect(pageRect), /* headerHeight */ 0, /* footerHeight */ 0, /* userScaleFactor */ 1.0, pageHeight);
127     }
128     
129     void OnBeginPrinting()
130     {
131         wxPrinterDC* pdc = dynamic_cast<wxPrinterDC*>(GetDC());
132         pdc->SetMapMode(wxMM_POINTS);
133         int pixelsW = 0;
134         int pixelsH = 0;
135         pdc->GetSize(&pixelsW, &pixelsH);
136         pixelsW = pdc->DeviceToLogicalXRel(pixelsW);
137         pixelsH = pdc->DeviceToLogicalYRel(pixelsH);
138         InitializeWithPageSize(wxRect(0, 0, pixelsW, pixelsH - 40), false);
139     }
140     
141     void GetPageInfo(int *minPage, int *maxPage, int *pageFrom, int *pageTo)
142     {
143         if (minPage)
144             *minPage = 1;
145         if (maxPage)
146             *maxPage = m_printContext.pageCount();
147         if (pageFrom)
148             *pageFrom = m_fromPage;
149         if (pageTo)
150             *pageTo = m_toPage;
151     }
152     
153     bool HasPage(int pageNum)
154     {
155         return pageNum <= m_printContext.pageCount() && pageNum >= m_fromPage && pageNum <= m_toPage;
156     }
157     
158     bool OnPrintPage(int pageNum)
159     {
160         wxPrinterDC* pdc = dynamic_cast<wxPrinterDC*>(GetDC());
161 #if wxCHECK_VERSION(2, 9, 2) && defined(wxUSE_CAIRO) && wxUSE_CAIRO
162         wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetCairoRenderer();
163         if (!renderer)
164             renderer = wxGraphicsRenderer::GetDefaultRenderer();
165         wxGraphicsContext* context = renderer->CreateContext(*pdc);
166         wxGCDC gcdc(context);
167 #else
168         wxGCDC gcdc(pdc);
169 #endif
170         if (!gcdc.IsOk())
171             return false;
172
173         WebCore::GraphicsContext ctx(&gcdc);
174         m_printContext.spoolPage(ctx, pageNum - 1, m_pageWidth);
175         
176         return true;
177     }
178     
179     void OnEndPrinting()
180     {
181         m_printContext.end();   
182     }
183     
184 private:
185     float m_pageWidth;
186     int m_fromPage;
187     int m_toPage;
188     WebCore::Frame *m_frame;
189     WebCore::PrintContext m_printContext;
190 };
191 #endif
192
193 wxWebFrame* kit(WebCore::Frame* frame)
194 {
195     if (!frame)
196         return 0;
197     if (!frame->loader())
198         return 0;
199     
200     WebCore::FrameLoaderClientWx* loaderClient = dynamic_cast<WebCore::FrameLoaderClientWx*>(frame->loader()->client());
201     if (loaderClient)
202         return loaderClient->webFrame();
203     
204     return 0;
205 }
206
207 wxWebFrame::wxWebFrame(wxWebView* container, wxWebFrame* parent, WebViewFrameData* data) :
208     m_textMagnifier(1.0),
209     m_isInitialized(false),
210     m_beingDestroyed(false)
211 {
212
213     m_impl = new WebFramePrivate();
214  
215     WebCore::HTMLFrameOwnerElement* parentFrame = 0;
216     
217     if (data) {
218         parentFrame = data->ownerElement;
219     }
220     
221     WebCore::FrameLoaderClientWx* loaderClient = new WebCore::FrameLoaderClientWx();
222     RefPtr<WebCore::Frame> newFrame = WebCore::Frame::create(container->m_impl->page, parentFrame, loaderClient);
223
224     m_impl->frame = newFrame.get();
225
226     if (data)
227         newFrame->tree()->setName(data->name);
228
229     // Subframes expect to be added to the FrameTree before init is called.
230     if (parentFrame)
231         parentFrame->document()->frame()->tree()->appendChild(newFrame.get());
232     
233     loaderClient->setFrame(this);
234     loaderClient->setWebView(container);
235     
236     if (data && data->ownerElement)
237         m_impl->frame->ref();
238
239     m_impl->frame->init();
240         
241     m_isInitialized = true;
242 }
243
244 wxWebFrame::~wxWebFrame()
245 {
246     if (m_impl)
247         delete m_impl;
248 }
249
250 wxString wxWebFrame::GetName()
251 {
252     if (m_impl && m_impl->frame && m_impl->frame->tree())
253         return m_impl->frame->tree()->name().string();
254     return wxEmptyString;
255 }
256
257 WebCore::Frame* wxWebFrame::GetFrame()
258 {
259     if (m_impl)
260         return m_impl->frame;
261         
262     return 0;
263 }
264
265 void wxWebFrame::Stop()
266 {
267     if (m_impl->frame && m_impl->frame->loader())
268         m_impl->frame->loader()->stop();
269 }
270
271 void wxWebFrame::Reload()
272 {
273     if (m_impl->frame && m_impl->frame->loader())
274         m_impl->frame->loader()->reload();
275 }
276
277 wxString wxWebFrame::GetPageSource()
278 {
279     if (m_impl->frame) {
280         if (m_impl->frame->view() && m_impl->frame->view()->layoutPending())
281             m_impl->frame->view()->layout();
282     
283         WebCore::Document* doc = m_impl->frame->document();
284         
285         if (doc) {
286             wxString source = createMarkup(doc);
287             return source;
288         }
289     }
290     return wxEmptyString;
291 }
292
293 void wxWebFrame::SetPageSource(const wxString& source, const wxString& baseUrl, const wxString& mimetype)
294 {
295     if (m_impl->frame && m_impl->frame->loader()) {
296         WebCore::KURL url(WebCore::KURL(), baseUrl);
297
298         const wxCharBuffer charBuffer(source.utf8_str());
299         const char* contents = charBuffer;
300
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);
303
304         m_impl->frame->loader()->stop();
305         m_impl->frame->loader()->load(WebCore::ResourceRequest(url), substituteData, false);
306     }
307 }
308
309 wxString wxWebFrame::GetInnerText()
310 {
311     if (m_impl->frame->view() && m_impl->frame->view()->layoutPending())
312         m_impl->frame->view()->layout();
313         
314     WebCore::Element *documentElement = m_impl->frame->document()->documentElement();
315     return documentElement->innerText();
316 }
317
318 wxString wxWebFrame::GetAsMarkup()
319 {
320     if (!m_impl->frame || !m_impl->frame->document())
321         return wxEmptyString;
322
323     return createMarkup(m_impl->frame->document());
324 }
325
326 wxString wxWebFrame::GetExternalRepresentation()
327 {
328     if (m_impl->frame->view() && m_impl->frame->view()->layoutPending())
329         m_impl->frame->view()->layout();
330
331     return externalRepresentation(m_impl->frame);
332 }
333
334 wxString wxWebFrame::GetSelectionAsHTML()
335 {
336     if (m_impl->frame)
337         return m_impl->frame->selection()->toNormalizedRange()->toHTML();
338         
339     return wxEmptyString;
340 }
341
342 wxString wxWebFrame::GetSelectionAsText()
343 {
344     if (m_impl->frame)
345         return m_impl->frame->selection()->toNormalizedRange()->text();
346         
347     return wxEmptyString;
348 }
349
350 wxWebKitSelection wxWebFrame::GetSelection()
351 {
352     if (m_impl->frame)
353         return wxWebKitSelection(m_impl->frame->selection());
354         
355     return 0;
356 }
357
358 wxString wxWebFrame::RunScript(const wxString& javascript)
359 {
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."));
364         if (hasLoaded) {
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."));
368             if (jsEnabled) {
369                 JSC::JSValue result = controller->executeScript(javascript, true).jsValue();
370                 if (result)
371                     returnValue = wxString(result.toString(m_impl->frame->script()->globalObject(WebCore::mainThreadNormalWorld())->globalExec()).utf8().data(), wxConvUTF8);        
372             }
373         }
374     }
375     return returnValue;
376 }
377
378 bool wxWebFrame::ExecuteEditCommand(const wxString& command, const wxString& parameter)
379 {
380     if (m_impl->frame && IsEditable())
381         return m_impl->frame->editor()->command(command).execute(parameter);
382 }
383
384 EditState wxWebFrame::GetEditCommandState(const wxString& command) const
385 {
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;
392
393         return EditStateMixed;
394     }
395         
396     return EditStateFalse;
397 }
398
399 wxString wxWebFrame::GetEditCommandValue(const wxString& command) const
400 {
401     if (m_impl->frame && IsEditable())
402         return m_impl->frame->editor()->command(command).value();
403         
404     return wxEmptyString;
405 }
406
407
408 bool wxWebFrame::FindString(const wxString& string, bool forward, bool caseSensitive, bool wrapSelection, bool startInSelection)
409 {
410     if (m_impl->frame)
411         return m_impl->frame->editor()->findString(string, forward, caseSensitive, wrapSelection, startInSelection);
412
413     return false;
414 }
415
416 void wxWebFrame::LoadURL(const wxString& url)
417 {
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());
428             }
429             else {
430                 kurl.setProtocol("http");
431                 kurl.setPath("//" + kurl.path());
432             }
433         }
434         m_impl->frame->loader()->load(kurl, false);
435     }
436 }
437
438 bool wxWebFrame::GoBack()
439 {
440     if (m_impl->frame && m_impl->frame->page())
441         return m_impl->frame->page()->goBack();
442
443     return false;
444 }
445
446 bool wxWebFrame::GoForward()
447 {
448     if (m_impl->frame && m_impl->frame->page())
449         return m_impl->frame->page()->goForward();
450
451     return false;
452 }
453
454 bool wxWebFrame::CanGoBack()
455 {
456     if (m_impl->frame && m_impl->frame->page())
457         return m_impl->frame->page()->canGoBackOrForward(-1);
458
459     return false;
460 }
461
462 bool wxWebFrame::CanGoForward()
463 {
464     if (m_impl->frame && m_impl->frame->page())
465         return m_impl->frame->page()->canGoBackOrForward(1);
466
467     return false;
468 }
469
470 void wxWebFrame::Undo()
471 {
472     if (m_impl->frame && m_impl->frame->editor() && CanUndo())
473         return m_impl->frame->editor()->undo();
474 }
475
476 void wxWebFrame::Redo()
477 {
478     if (m_impl->frame && m_impl->frame->editor() && CanRedo())
479         return m_impl->frame->editor()->redo();
480 }
481
482 bool wxWebFrame::CanUndo()
483 {
484     if (m_impl->frame && m_impl->frame->editor())
485         return m_impl->frame->editor()->canUndo();
486
487     return false;
488 }
489
490 bool wxWebFrame::CanRedo()
491 {
492     if (m_impl->frame && m_impl->frame->editor())
493         return m_impl->frame->editor()->canRedo();
494
495     return false;
496 }
497
498 bool wxWebFrame::CanIncreaseTextSize() const
499 {
500     if (m_impl->frame && m_impl->frame->view()) {
501         if (m_textMagnifier*TextSizeMultiplierRatio <= MaximumTextSizeMultiplier)
502             return true;
503     }
504     return false;
505 }
506
507 void wxWebFrame::IncreaseTextSize()
508 {
509     if (CanIncreaseTextSize()) {
510         m_textMagnifier = m_textMagnifier*TextSizeMultiplierRatio;
511         m_impl->frame->setTextZoomFactor(m_textMagnifier);
512     }
513 }
514
515 bool wxWebFrame::CanDecreaseTextSize() const
516 {
517     if (m_impl->frame && m_impl->frame->view()) {
518         if (m_textMagnifier/TextSizeMultiplierRatio >= MinimumTextSizeMultiplier)
519             return true;
520     }
521     return false;
522 }
523
524 void wxWebFrame::DecreaseTextSize()
525 {        
526     if (CanDecreaseTextSize()) {
527         m_textMagnifier = m_textMagnifier/TextSizeMultiplierRatio;
528         m_impl->frame->setTextZoomFactor(m_textMagnifier);
529     }
530 }
531
532 void wxWebFrame::ResetTextSize()
533 {
534     m_textMagnifier = 1.0;
535     if (m_impl->frame)
536         m_impl->frame->setTextZoomFactor(m_textMagnifier);
537 }
538
539 void wxWebFrame::MakeEditable(bool enable)
540 {
541     if (enable != IsEditable() && m_impl->frame && m_impl->frame->page())
542         m_impl->frame->page()->setEditable(enable);
543 }
544
545 bool wxWebFrame::IsEditable() const
546 {
547     if (m_impl->frame && m_impl->frame->page())
548         return m_impl->frame->page()->isEditable();
549     return false;
550 }
551
552 bool wxWebFrame::CanCopy()
553 {
554     if (m_impl->frame && m_impl->frame->view())
555         return (m_impl->frame->editor()->canCopy() || m_impl->frame->editor()->canDHTMLCopy());
556
557     return false;
558 }
559
560 void wxWebFrame::Copy()
561 {
562     if (CanCopy())
563         m_impl->frame->editor()->copy();
564 }
565
566 bool wxWebFrame::CanCut()
567 {
568     if (m_impl->frame && m_impl->frame->view())
569         return (m_impl->frame->editor()->canCut() || m_impl->frame->editor()->canDHTMLCut());
570
571     return false;
572 }
573
574 void wxWebFrame::Cut()
575 {
576     if (CanCut())
577         m_impl->frame->editor()->cut();
578 }
579
580 bool wxWebFrame::CanPaste()
581 {
582     if (m_impl->frame && m_impl->frame->view())
583         return (m_impl->frame->editor()->canPaste() || m_impl->frame->editor()->canDHTMLPaste());
584
585     return false;
586 }
587
588 void wxWebFrame::Paste()
589 {
590     if (CanPaste())
591         m_impl->frame->editor()->paste();
592
593 }
594
595 void wxWebFrame::Print(bool showDialog)
596 {
597 #if wxCHECK_VERSION(2, 9, 1)
598     if (!m_impl->frame)
599         return;
600     
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();
606 #else
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);
610 #endif
611
612     wxPageSetupDialogData pageSetup(printdata.GetPrintData());
613
614     wxRect paperSize = pageSetup.GetPaperSize();
615 #ifdef __WXMSW__
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);
619 #endif
620     wxWebFramePrintout* printout = new wxWebFramePrintout(m_impl->frame);
621     printout->InitializeWithPageSize(paperSize);
622     
623     printdata.SetMinPage(1);
624     printdata.SetMaxPage(printout->GetPageCount());
625     printdata.SetFromPage(1);
626     printdata.SetToPage(printout->GetPageCount());
627
628     if (showDialog) {
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());
634         } else
635             return;
636     }
637     
638     wxPrinter printer(&printdata);
639         
640     printer.Print(0, printout, false);
641         
642 #else
643     wxFAIL_MSG(wxT("Printing is only supported in wxWidgets 2.9.1 and above."));
644 #endif
645 }
646
647 wxWebViewDOMElementInfo wxWebFrame::HitTest(const wxPoint& pos) const
648 {
649     wxWebViewDOMElementInfo domInfo;
650
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());
658         }
659     }
660
661     return domInfo;
662 }
663
664 bool wxWebFrame::ShouldClose() const
665 {
666     if (m_impl->frame)
667         return m_impl->frame->loader()->shouldClose();
668
669     return true;
670 }
671
672 wxWebKitCompatibilityMode wxWebFrame::GetCompatibilityMode() const
673 {
674     if (m_impl->frame && m_impl->frame->document())
675         return (wxWebKitCompatibilityMode)m_impl->frame->document()->compatibilityMode();
676
677     return QuirksMode;
678 }
679
680 void wxWebFrame::GrantUniversalAccess()
681 {
682     if (m_impl->frame && m_impl->frame->document())
683         m_impl->frame->document()->securityOrigin()->grantUniversalAccess();
684 }