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