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