1 /* This file is part of the KDE project
3 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
4 * 1999 Lars Knoll <knoll@kde.org>
5 * 1999 Antti Koivisto <koivisto@kde.org>
6 * 2000 Simon Hausmann <hausmann@kde.org>
7 * 2000 Stefan Schimanski <1Stein@gmx.de>
8 * 2001 George Staikos <staikos@kde.org>
9 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
10 * Copyright (C) 2005 Alexey Proskuryakov <ap@nypop.com>
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public License
23 * along with this library; see the file COPYING.LIB. If not, write to
24 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 * Boston, MA 02111-1307, USA.
30 #include "FramePrivate.h"
32 #include "ApplyStyleCommand.h"
33 #include "CSSComputedStyleDeclaration.h"
34 #include "CSSProperty.h"
35 #include "CSSPropertyNames.h"
37 #include "CachedCSSStyleSheet.h"
38 #include "DOMImplementation.h"
39 #include "DOMWindow.h"
41 #include "DocLoader.h"
42 #include "DocumentType.h"
43 #include "EditingText.h"
45 #include "EventNames.h"
46 #include "FloatRect.h"
48 #include "GraphicsContext.h"
49 #include "HTMLFormElement.h"
50 #include "HTMLFrameElement.h"
51 #include "HTMLGenericFormElement.h"
52 #include "HTMLInputElement.h"
53 #include "HTMLNames.h"
54 #include "HTMLObjectElement.h"
55 #include "HTMLViewSourceDocument.h"
56 #include "ImageDocument.h"
57 #include "MediaFeatureNames.h"
58 #include "MouseEventWithHitTestResults.h"
61 #include "PlatformScrollBar.h"
62 #include "PlugInInfoStore.h"
64 #include "PluginDocument.h"
65 #include "RenderPart.h"
66 #include "RenderTextControl.h"
67 #include "RenderTheme.h"
68 #include "RenderView.h"
69 #include "SegmentedString.h"
70 #include "TextDocument.h"
71 #include "TextIterator.h"
72 #include "TypingCommand.h"
73 #include "XMLTokenizer.h"
74 #include "cssstyleselector.h"
75 #include "htmlediting.h"
76 #include "kjs_window.h"
78 #include "visible_units.h"
79 #include "xmlhttprequest.h"
81 #include <sys/types.h>
82 #include <wtf/Platform.h>
90 #include "XLinkNames.h"
92 #include "SVGDocument.h"
93 #include "SVGDocumentExtensions.h"
101 using KJS::PausedTimeouts;
102 using KJS::SavedProperties;
103 using KJS::SavedBuiltins;
109 using namespace EventNames;
110 using namespace HTMLNames;
112 const double caretBlinkFrequency = 0.5;
113 const double autoscrollInterval = 0.1;
115 class UserStyleSheetLoader : public CachedResourceClient {
117 UserStyleSheetLoader(Frame* frame, const String& url, DocLoader* dl)
119 , m_cachedSheet(Cache::requestStyleSheet(dl, url, false, 0, ""))
121 m_cachedSheet->ref(this);
123 ~UserStyleSheetLoader()
125 m_cachedSheet->deref(this);
128 virtual void setStyleSheet(const String& /*URL*/, const String& sheet)
130 m_frame->setUserStyleSheet(sheet.deprecatedString());
133 CachedCSSStyleSheet* m_cachedSheet;
137 struct FrameCounter {
139 ~FrameCounter() { if (count != 0) fprintf(stderr, "LEAK: %d Frame\n", count); }
141 int FrameCounter::count = 0;
142 static FrameCounter frameCounter;
145 static inline Frame* parentFromOwnerElement(Element* ownerElement)
149 return ownerElement->document()->frame();
152 Frame::Frame(Page* page, Element* ownerElement)
153 : d(new FramePrivate(page, parentFromOwnerElement(ownerElement), this, ownerElement))
155 AtomicString::init();
159 QualifiedName::init();
160 MediaFeatureNames::init();
168 if (d->m_ownerElement)
169 d->m_page->incrementFrameCount();
171 // FIXME: Frames were originally created with a refcount of 1, leave this
172 // ref call here until we can straighten that out.
175 ++FrameCounter::count;
181 ASSERT(!d->m_lifeSupportTimer.isActive());
184 --FrameCounter::count;
194 if (d->m_jscript && d->m_jscript->haveInterpreter())
195 if (Window* w = Window::retrieveWindow(this)) {
196 w->disconnectFrame();
197 // Must clear the window pointer, otherwise we will not
198 // garbage-collect collect the window (inside the call to
203 disconnectOwnerElement();
206 d->m_domWindow->disconnectFrame();
209 HashSet<Frame*> openedBy = d->m_openedFrames;
210 HashSet<Frame*>::iterator end = openedBy.end();
211 for (HashSet<Frame*>::iterator it = openedBy.begin(); it != end; ++it)
216 d->m_view->m_frame = 0;
219 ASSERT(!d->m_lifeSupportTimer.isActive());
221 delete d->m_userStyleSheetLoader;
226 bool Frame::didOpenURL(const KURL& url)
228 if (d->m_scheduledRedirection == locationChangeScheduledDuringLoad) {
229 // A redirect was shceduled before the document was created. This can happen
230 // when one frame changes another frame's location.
236 // clear last edit command
237 d->m_lastEditCommand = 0;
241 d->m_bComplete = false;
242 d->m_bLoadingMainResource = true;
243 d->m_bLoadEventEmitted = false;
245 d->m_kjsStatusBarText = String();
246 d->m_kjsDefaultStatusBarText = String();
248 d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled();
249 d->m_bJavaEnabled = d->m_settings->isJavaEnabled();
250 d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled();
252 // initializing d->m_url to the new url breaks relative links when opening such a link after this call and _before_ begin() is called (when the first
253 // data arrives) (Simon)
255 if (d->m_url.protocol().startsWith("http") && !d->m_url.host().isEmpty() && d->m_url.path().isEmpty())
256 d->m_url.setPath("/");
257 d->m_workingURL = d->m_url;
264 void Frame::didExplicitOpen()
266 d->m_bComplete = false;
267 d->m_bLoadEventEmitted = false;
269 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
270 // from a subsequent window.document.open / window.document.write call.
271 // Cancelling redirection here works for all cases because document.open
272 // implicitly precedes document.write.
274 d->m_url = d->m_doc->URL();
277 void Frame::stopLoading(bool sendUnload)
279 if (d->m_doc && d->m_doc->tokenizer())
280 d->m_doc->tokenizer()->stopParsing();
282 d->m_metaData.clear();
286 if (d->m_bLoadEventEmitted && !d->m_bUnloadEventEmitted) {
287 Node* currentFocusNode = d->m_doc->focusNode();
288 if (currentFocusNode)
289 currentFocusNode->aboutToUnload();
290 d->m_doc->dispatchWindowEvent(unloadEvent, false, false);
292 d->m_doc->updateRendering();
293 d->m_bUnloadEventEmitted = true;
297 if (d->m_doc && !d->m_doc->inPageCache())
298 d->m_doc->removeAllEventListenersFromAllNodes();
301 d->m_bComplete = true; // to avoid calling completed() in finishedParsing() (David)
302 d->m_bLoadingMainResource = false;
303 d->m_bLoadEventEmitted = true; // don't want that one either
304 d->m_cachePolicy = CachePolicyVerify; // Why here?
306 if (d->m_doc && d->m_doc->parsing()) {
308 d->m_doc->setParsing(false);
311 d->m_workingURL = KURL();
313 if (Document *doc = d->m_doc.get()) {
314 if (DocLoader *docLoader = doc->docLoader())
315 Cache::loader()->cancelRequests(docLoader);
316 XMLHttpRequest::cancelRequests(doc);
319 // tell all subframes to stop as well
320 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
321 child->stopLoading(sendUnload);
323 d->m_bPendingChildRedirection = false;
328 BrowserExtension *Frame::browserExtension() const
330 return d->m_extension;
333 FrameView* Frame::view() const
335 return d->m_view.get();
338 void Frame::setView(FrameView* view)
343 bool Frame::jScriptEnabled() const
345 return d->m_bJScriptEnabled;
348 KJSProxy *Frame::jScript()
350 if (!d->m_bJScriptEnabled)
354 d->m_jscript = new KJSProxy(this);
359 static bool getString(JSValue* result, DeprecatedString& string)
365 if (!result->getString(ustring))
371 void Frame::replaceContentsWithScriptResult(const KURL& url)
373 JSValue* ret = executeScript(0, KURL::decode_string(url.url().mid(strlen("javascript:"))));
374 DeprecatedString scriptResult;
375 if (getString(ret, scriptResult)) {
382 JSValue* Frame::executeScript(Node* n, const DeprecatedString& script, bool forceUserGesture)
384 KJSProxy *proxy = jScript();
389 d->m_runningScripts++;
390 // If forceUserGesture is true, then make the script interpreter
391 // treat it as if triggered by a user gesture even if there is no
392 // current DOM event being processed.
393 JSValue* ret = proxy->evaluate(forceUserGesture ? DeprecatedString::null : d->m_url.url(), 0, script, n);
394 d->m_runningScripts--;
396 if (!d->m_runningScripts)
399 Document::updateDocumentsRendering();
404 bool Frame::javaEnabled() const
406 return d->m_settings->isJavaEnabled();
409 bool Frame::pluginsEnabled() const
411 return d->m_bPluginsEnabled;
414 void Frame::setAutoloadImages(bool enable)
416 if (d->m_doc && d->m_doc->docLoader()->autoloadImages() == enable)
420 d->m_doc->docLoader()->setAutoloadImages(enable);
423 bool Frame::autoloadImages() const
426 return d->m_doc->docLoader()->autoloadImages();
431 void Frame::clear(bool clearWindowProperties)
435 d->m_bCleared = true;
436 d->m_mousePressNode = 0;
439 d->m_doc->cancelParsing();
443 // Moving past doc so that onUnload works.
444 if (clearWindowProperties && d->m_jscript)
445 d->m_jscript->clear();
450 // do not drop the document before the jscript and view are cleared, as some destructors
451 // might still try to access the document.
455 d->m_plugins.clear();
457 d->m_scheduledRedirection = noRedirectionScheduled;
458 d->m_delayRedirect = 0;
459 d->m_redirectURL = DeprecatedString::null;
460 d->m_redirectReferrer = DeprecatedString::null;
461 d->m_redirectLockHistory = true;
462 d->m_redirectUserGesture = false;
463 d->m_bHTTPRefresh = false;
464 d->m_bFirstData = true;
466 d->m_bMousePressed = false;
468 if (!d->m_haveEncoding)
469 d->m_encoding = DeprecatedString::null;
472 Document *Frame::document() const
475 return d->m_doc.get();
479 void Frame::setDocument(Document* newDoc)
490 void Frame::receivedFirstData()
492 begin(d->m_workingURL);
494 d->m_doc->docLoader()->setCachePolicy(d->m_cachePolicy);
495 d->m_workingURL = KURL();
497 // When the first data arrives, the metadata has just been made available
498 DeprecatedString qData;
500 // Support for http-refresh
501 qData = d->m_metaData.get("http-refresh").deprecatedString();
502 if (!qData.isEmpty()) {
504 int pos = qData.find(';');
506 pos = qData.find(',');
509 delay = qData.stripWhiteSpace().toDouble();
510 // We want a new history item if the refresh timeout > 1 second
511 scheduleRedirection(delay, d->m_url.url(), delay <= 1);
513 int end_pos = qData.length();
514 delay = qData.left(pos).stripWhiteSpace().toDouble();
515 while (qData[++pos] == ' ');
516 if (qData.find("url", pos, false) == pos) {
518 while (qData[pos] == ' ' || qData[pos] == '=')
520 if (qData[pos] == '"') {
522 int index = end_pos-1;
523 while (index > pos) {
524 if (qData[index] == '"')
532 // We want a new history item if the refresh timeout > 1 second
533 scheduleRedirection(delay, d->m_doc->completeURL(qData.mid(pos, end_pos)), delay <= 1);
535 d->m_bHTTPRefresh = true;
538 // Support for http last-modified
539 d->m_lastModified = d->m_metaData.get("modified");
542 void Frame::childBegin()
544 // We need to do this when the child is created so as to avoid the parent thining the child
545 // is complete before it has even started loading.
546 // FIXME: do we really still need this?
547 d->m_bComplete = false;
550 void Frame::setResourceRequest(const ResourceRequest& request)
552 d->m_request = request;
555 const ResourceRequest& Frame::resourceRequest() const
560 void Frame::begin(const KURL& url)
562 if (d->m_workingURL.isEmpty())
563 createEmptyDocument(); // Creates an empty document if we don't have one already
566 partClearedInBegin();
568 d->m_bCleared = false;
569 d->m_bComplete = false;
570 d->m_bLoadEventEmitted = false;
571 d->m_bLoadingMainResource = true;
574 ref.setUser(DeprecatedString());
575 ref.setPass(DeprecatedString());
576 ref.setRef(DeprecatedString());
577 d->m_referrer = ref.url();
581 // We don't need KDE chained URI handling or window caption setting
582 if (!d->m_url.isEmpty())
586 if (d->m_request.m_responseMIMEType == "image/svg+xml")
587 d->m_doc = DOMImplementation::instance()->createSVGDocument(d->m_view.get());
590 if (DOMImplementation::isXMLMIMEType(d->m_request.m_responseMIMEType))
591 d->m_doc = DOMImplementation::instance()->createDocument(d->m_view.get());
592 else if (DOMImplementation::isTextMIMEType(d->m_request.m_responseMIMEType))
593 d->m_doc = new TextDocument(DOMImplementation::instance(), d->m_view.get());
594 else if ((d->m_request.m_responseMIMEType == "application/pdf" || d->m_request.m_responseMIMEType == "text/pdf") && PlugInInfoStore::supportsMIMEType(d->m_request.m_responseMIMEType))
595 d->m_doc = new PluginDocument(DOMImplementation::instance(), d->m_view.get());
596 else if (Image::supportsType(d->m_request.m_responseMIMEType))
597 d->m_doc = new ImageDocument(DOMImplementation::instance(), d->m_view.get());
598 else if (PlugInInfoStore::supportsMIMEType(d->m_request.m_responseMIMEType))
599 d->m_doc = new PluginDocument(DOMImplementation::instance(), d->m_view.get());
600 else if (inViewSourceMode())
601 d->m_doc = new HTMLViewSourceDocument(DOMImplementation::instance(), d->m_view.get());
603 d->m_doc = DOMImplementation::instance()->createHTMLDocument(d->m_view.get());
605 if (!d->m_doc->attached())
607 d->m_doc->setURL(d->m_url.url());
608 // We prefer m_baseURL over d->m_url because d->m_url changes when we are
609 // about to load a new page.
610 d->m_doc->setBaseURL(baseurl.url());
612 d->m_doc->setDecoder(d->m_decoder.get());
614 updatePolicyBaseURL();
616 setAutoloadImages(d->m_settings->autoLoadImages());
617 const KURL& userStyleSheet = d->m_settings->userStyleSheetLocation();
619 if (!userStyleSheet.isEmpty())
620 setUserStyleSheetLocation(KURL(userStyleSheet));
622 restoreDocumentState();
624 d->m_doc->implicitOpen();
627 d->m_view->resizeContents(0, 0);
630 void Frame::write(const char* str, int len)
638 if (Tokenizer* t = d->m_doc->tokenizer()) {
639 if (t->wantsRawData()) {
640 t->writeRawData(str, len);
646 d->m_decoder = new Decoder(d->m_request.m_responseMIMEType, settings()->encoding().latin1());
647 if (!d->m_encoding.isNull())
648 d->m_decoder->setEncodingName(d->m_encoding.latin1(),
649 d->m_haveEncoding ? Decoder::UserChosenEncoding : Decoder::EncodingFromHTTPHeader);
652 d->m_doc->setDecoder(d->m_decoder.get());
654 DeprecatedString decoded = d->m_decoder->decode(str, len);
656 if (decoded.isEmpty())
659 if (d->m_bFirstData) {
660 // determine the parse mode
661 d->m_doc->determineParseMode(decoded);
662 d->m_bFirstData = false;
664 // ### this is still quite hacky, but should work a lot better than the old solution
665 if (d->m_decoder->visuallyOrdered()) d->m_doc->setVisuallyOrdered();
666 d->m_doc->recalcStyle(Node::Force);
669 if (Tokenizer* t = d->m_doc->tokenizer()) {
670 ASSERT(!t->wantsRawData());
671 t->write(decoded, true);
675 void Frame::write(const DeprecatedString& str)
680 if (d->m_bFirstData) {
681 // determine the parse mode
682 d->m_doc->setParseMode(Document::Strict);
683 d->m_bFirstData = false;
685 Tokenizer* t = d->m_doc->tokenizer();
692 d->m_bLoadingMainResource = false;
696 void Frame::endIfNotLoading()
698 if (d->m_bLoadingMainResource)
701 // make sure nothing's left in there...
704 DeprecatedString decoded = d->m_decoder->flush();
705 if (d->m_bFirstData) {
706 d->m_doc->determineParseMode(decoded);
707 d->m_bFirstData = false;
711 d->m_doc->finishParsing();
713 // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but
714 // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
715 // become true. An example is when a subframe is a pure text doc, and that subframe is the
716 // last one to complete.
723 if (d->m_doc->tokenizer())
724 d->m_doc->tokenizer()->stopParsing();
725 d->m_doc->finishParsing();
727 // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but
728 // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
729 // become true. An example is when a subframe is a pure text doc, and that subframe is the
730 // last one to complete.
734 void Frame::gotoAnchor()
736 // If our URL has no ref, then we have no place we need to jump to.
737 if (!d->m_url.hasRef())
740 DeprecatedString ref = d->m_url.encodedHtmlRef();
741 if (!gotoAnchor(ref)) {
742 // Can't use htmlRef() here because it doesn't know which encoding to use to decode.
743 // Decoding here has to match encoding in completeURL, which means it has to use the
744 // page's encoding rather than UTF-8.
746 gotoAnchor(KURL::decode_string(ref, d->m_decoder->encoding()));
750 void Frame::finishedParsing()
752 RefPtr<Frame> protector(this);
756 return; // We are being destroyed by something checkCompleted called.
758 // check if the scrollbars are really needed for the content
759 // if not, remove them, relayout, and repaint
761 d->m_view->restoreScrollBar();
765 void Frame::loadDone()
771 void Frame::checkCompleted()
773 // Any frame that hasn't completed yet ?
774 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
775 if (!child->d->m_bComplete)
778 // Have we completed before?
782 // Are we still parsing?
783 if (d->m_doc && d->m_doc->parsing())
786 // Still waiting for images/scripts from the loader ?
788 if (d->m_doc && d->m_doc->docLoader())
789 requests = Cache::loader()->numRequests(d->m_doc->docLoader());
795 // Now do what should be done when we are really completed.
796 d->m_bComplete = true;
798 checkEmitLoadEvent(); // if we didn't do it before
800 if (d->m_scheduledRedirection != noRedirectionScheduled) {
801 // Do not start redirection for frames here! That action is
802 // deferred until the parent emits a completed signal.
803 if (!tree()->parent())
804 startRedirectionTimer();
808 completed(d->m_bPendingChildRedirection);
812 void Frame::checkEmitLoadEvent()
814 if (d->m_bLoadEventEmitted || !d->m_doc || d->m_doc->parsing())
817 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
818 if (!child->d->m_bComplete) // still got a frame running -> too early
821 // All frames completed -> set their domain to the frameset's domain
822 // This must only be done when loading the frameset initially (#22039),
823 // not when following a link in a frame (#44162).
825 String domain = d->m_doc->domain();
826 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
828 child->d->m_doc->setDomain(domain);
831 d->m_bLoadEventEmitted = true;
832 d->m_bUnloadEventEmitted = false;
834 d->m_doc->implicitClose();
837 const Settings *Frame::settings() const
839 return d->m_settings;
842 KURL Frame::baseURL() const
846 return d->m_doc->baseURL();
849 String Frame::baseTarget() const
852 return DeprecatedString();
853 return d->m_doc->baseTarget();
856 KURL Frame::completeURL(const DeprecatedString& url)
861 return KURL(d->m_doc->completeURL(url));
864 void Frame::scheduleRedirection(double delay, const DeprecatedString& url, bool doLockHistory)
866 if (delay < 0 || delay > INT_MAX / 1000)
868 if (d->m_scheduledRedirection == noRedirectionScheduled || delay <= d->m_delayRedirect)
870 d->m_scheduledRedirection = redirectionScheduled;
871 d->m_delayRedirect = delay;
872 d->m_redirectURL = url;
873 d->m_redirectReferrer = DeprecatedString::null;
874 d->m_redirectLockHistory = doLockHistory;
875 d->m_redirectUserGesture = false;
877 stopRedirectionTimer();
879 startRedirectionTimer();
883 void Frame::scheduleLocationChange(const DeprecatedString& url, const DeprecatedString& referrer, bool lockHistory, bool userGesture)
887 // If the URL we're going to navigate to is the same as the current one, except for the
888 // fragment part, we don't need to schedule the location change.
889 if (u.hasRef() && equalIgnoringRef(d->m_url, u)) {
890 changeLocation(url, referrer, lockHistory, userGesture);
894 // Handle a location change of a page with no document as a special case.
895 // This may happen when a frame changes the location of another frame.
896 d->m_scheduledRedirection = d->m_doc ? locationChangeScheduled : locationChangeScheduledDuringLoad;
898 // If a redirect was scheduled during a load, then stop the current load.
899 // Otherwise when the current load transitions from a provisional to a
900 // committed state, pending redirects may be cancelled.
901 if (d->m_scheduledRedirection == locationChangeScheduledDuringLoad) {
905 d->m_delayRedirect = 0;
906 d->m_redirectURL = url;
907 d->m_redirectReferrer = referrer;
908 d->m_redirectLockHistory = lockHistory;
909 d->m_redirectUserGesture = userGesture;
910 stopRedirectionTimer();
912 startRedirectionTimer();
915 void Frame::scheduleRefresh(bool userGesture)
917 // Handle a location change of a page with no document as a special case.
918 // This may happen when a frame requests a refresh of another frame.
919 d->m_scheduledRedirection = d->m_doc ? locationChangeScheduled : locationChangeScheduledDuringLoad;
921 // If a refresh was scheduled during a load, then stop the current load.
922 // Otherwise when the current load transitions from a provisional to a
923 // committed state, pending redirects may be cancelled.
924 if (d->m_scheduledRedirection == locationChangeScheduledDuringLoad)
927 d->m_delayRedirect = 0;
928 d->m_redirectURL = url().url();
929 d->m_redirectReferrer = referrer();
930 d->m_redirectLockHistory = true;
931 d->m_redirectUserGesture = userGesture;
932 d->m_cachePolicy = CachePolicyRefresh;
933 stopRedirectionTimer();
935 startRedirectionTimer();
938 bool Frame::isScheduledLocationChangePending() const
940 switch (d->m_scheduledRedirection) {
941 case noRedirectionScheduled:
942 case redirectionScheduled:
944 case historyNavigationScheduled:
945 case locationChangeScheduled:
946 case locationChangeScheduledDuringLoad:
952 void Frame::scheduleHistoryNavigation(int steps)
954 // navigation will always be allowed in the 0 steps case, which is OK because
955 // that's supposed to force a reload.
956 if (!canGoBackOrForward(steps)) {
961 // If the URL we're going to navigate to is the same as the current one, except for the
962 // fragment part, we don't need to schedule the navigation.
963 if (d->m_extension) {
964 KURL u = d->m_extension->historyURL(steps);
966 if (equalIgnoringRef(d->m_url, u)) {
967 d->m_extension->goBackOrForward(steps);
972 d->m_scheduledRedirection = historyNavigationScheduled;
973 d->m_delayRedirect = 0;
974 d->m_redirectURL = DeprecatedString::null;
975 d->m_redirectReferrer = DeprecatedString::null;
976 d->m_scheduledHistoryNavigationSteps = steps;
977 stopRedirectionTimer();
979 startRedirectionTimer();
982 void Frame::cancelRedirection(bool cancelWithLoadInProgress)
985 d->m_cancelWithLoadInProgress = cancelWithLoadInProgress;
986 d->m_scheduledRedirection = noRedirectionScheduled;
987 stopRedirectionTimer();
991 void Frame::changeLocation(const DeprecatedString& URL, const DeprecatedString& referrer, bool lockHistory, bool userGesture)
993 if (URL.find("javascript:", 0, false) == 0) {
994 DeprecatedString script = KURL::decode_string(URL.mid(11));
995 JSValue* result = executeScript(0, script, userGesture);
996 DeprecatedString scriptResult;
997 if (getString(result, scriptResult)) {
1005 ResourceRequest request(completeURL(URL));
1006 request.setLockHistory(lockHistory);
1007 if (!referrer.isEmpty())
1008 request.setReferrer(referrer);
1010 request.reload = (d->m_cachePolicy == CachePolicyReload) || (d->m_cachePolicy == CachePolicyRefresh);
1012 urlSelected(request, "_self");
1015 void Frame::redirectionTimerFired(Timer<Frame>*)
1017 if (d->m_scheduledRedirection == historyNavigationScheduled) {
1018 d->m_scheduledRedirection = noRedirectionScheduled;
1020 // Special case for go(0) from a frame -> reload only the frame
1021 // go(i!=0) from a frame navigates into the history of the frame only,
1022 // in both IE and NS (but not in Mozilla).... we can't easily do that
1024 if (d->m_scheduledHistoryNavigationSteps == 0) // add && parent() to get only frames, but doesn't matter
1025 openURL(url()); /// ## need args.reload=true?
1027 if (d->m_extension) {
1028 d->m_extension->goBackOrForward(d->m_scheduledHistoryNavigationSteps);
1034 DeprecatedString URL = d->m_redirectURL;
1035 DeprecatedString referrer = d->m_redirectReferrer;
1036 bool lockHistory = d->m_redirectLockHistory;
1037 bool userGesture = d->m_redirectUserGesture;
1039 d->m_scheduledRedirection = noRedirectionScheduled;
1040 d->m_delayRedirect = 0;
1041 d->m_redirectURL = DeprecatedString::null;
1042 d->m_redirectReferrer = DeprecatedString::null;
1044 changeLocation(URL, referrer, lockHistory, userGesture);
1047 DeprecatedString Frame::encoding() const
1049 if (d->m_haveEncoding && !d->m_encoding.isEmpty())
1050 return d->m_encoding;
1052 if (d->m_decoder && d->m_decoder->encoding().isValid())
1053 return d->m_decoder->encodingName();
1055 return settings()->encoding();
1058 void Frame::setUserStyleSheetLocation(const KURL& url)
1060 delete d->m_userStyleSheetLoader;
1061 d->m_userStyleSheetLoader = 0;
1062 if (d->m_doc && d->m_doc->docLoader())
1063 d->m_userStyleSheetLoader = new UserStyleSheetLoader(this, url.url(), d->m_doc->docLoader());
1066 void Frame::setUserStyleSheet(const String& styleSheet)
1068 delete d->m_userStyleSheetLoader;
1069 d->m_userStyleSheetLoader = 0;
1071 d->m_doc->setUserStyleSheet(styleSheet);
1074 bool Frame::gotoAnchor(const String& name)
1079 Node *n = d->m_doc->getElementById(AtomicString(name));
1081 n = d->m_doc->anchors()->namedItem(name, !d->m_doc->inCompatMode());
1083 d->m_doc->setCSSTarget(n); // Setting to null will clear the current target.
1085 // Implement the rule that "" and "top" both mean top of page as in other browsers.
1086 if (!n && !(name.isEmpty() || name.lower() == "top"))
1089 // We need to update the layout before scrolling, otherwise we could
1090 // really mess things up if an anchor scroll comes at a bad moment.
1092 d->m_doc->updateRendering();
1093 // Only do a layout if changes have occurred that make it necessary.
1094 if (d->m_view && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout()) {
1095 d->m_view->layout();
1099 // Scroll nested layers and frames to reveal the anchor.
1100 RenderObject *renderer;
1103 renderer = n->renderer();
1104 rect = n->getRect();
1106 // If there's no node, we should scroll to the top of the document.
1107 renderer = d->m_doc->renderer();
1112 // Align to the top and to the closest side (this matches other browsers).
1113 renderer->enclosingLayer()->scrollRectToVisible(rect, RenderLayer::gAlignToEdgeIfNeeded, RenderLayer::gAlignTopAlways);
1119 void Frame::setStandardFont(const String& name)
1121 d->m_settings->setStdFontName(AtomicString(name));
1124 void Frame::setFixedFont(const String& name)
1126 d->m_settings->setFixedFontName(AtomicString(name));
1129 String Frame::selectedText() const
1131 return plainText(selection().toRange().get());
1134 bool Frame::hasSelection() const
1136 return d->m_selection.isCaretOrRange();
1139 SelectionController& Frame::selection() const
1141 return d->m_selection;
1144 TextGranularity Frame::selectionGranularity() const
1146 return d->m_selectionGranularity;
1149 void Frame::setSelectionGranularity(TextGranularity granularity) const
1151 d->m_selectionGranularity = granularity;
1154 SelectionController& Frame::dragCaret() const
1156 return d->m_page->dragCaret();
1159 const Selection& Frame::mark() const
1164 void Frame::setMark(const Selection& s)
1166 ASSERT(!s.base().node() || s.base().node()->document() == document());
1167 ASSERT(!s.extent().node() || s.extent().node()->document() == document());
1168 ASSERT(!s.start().node() || s.start().node()->document() == document());
1169 ASSERT(!s.end().node() || s.end().node()->document() == document());
1174 void Frame::setSelection(const SelectionController& s, bool closeTyping)
1177 TypingCommand::closeTyping(lastEditCommand());
1181 if (d->m_selection == s)
1184 ASSERT(!s.base().node() || s.base().node()->document() == document());
1185 ASSERT(!s.extent().node() || s.extent().node()->document() == document());
1186 ASSERT(!s.start().node() || s.start().node()->document() == document());
1187 ASSERT(!s.end().node() || s.end().node()->document() == document());
1189 clearCaretRectIfNeeded();
1191 SelectionController oldSelection = d->m_selection;
1195 setFocusNodeIfNeeded();
1197 selectionLayoutChanged();
1199 // Always clear the x position used for vertical arrow navigation.
1200 // It will be restored by the vertical arrow navigation code if necessary.
1201 d->m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation;
1203 notifyRendererOfSelectionChange(false);
1205 respondToChangedSelection(oldSelection, closeTyping);
1208 void Frame::notifyRendererOfSelectionChange(bool userTriggered)
1210 RenderObject* renderer = 0;
1211 if (d->m_selection.rootEditableElement())
1212 renderer = d->m_selection.rootEditableElement()->shadowAncestorNode()->renderer();
1214 // If the current selection is in a textfield or textarea, notify the renderer that the selection has changed
1215 if (renderer && (renderer->isTextArea() || renderer->isTextField()))
1216 static_cast<RenderTextControl*>(renderer)->selectionChanged(userTriggered);
1219 void Frame::setDragCaret(const SelectionController& dragCaret)
1221 d->m_page->setDragCaret(dragCaret);
1224 void Frame::invalidateSelection()
1226 clearCaretRectIfNeeded();
1227 d->m_selection.setNeedsLayout();
1228 selectionLayoutChanged();
1231 void Frame::setCaretVisible(bool flag)
1233 if (d->m_caretVisible == flag)
1235 clearCaretRectIfNeeded();
1237 setFocusNodeIfNeeded();
1238 d->m_caretVisible = flag;
1239 selectionLayoutChanged();
1243 void Frame::clearCaretRectIfNeeded()
1245 if (d->m_caretPaint) {
1246 d->m_caretPaint = false;
1247 d->m_selection.needsCaretRepaint();
1251 // Helper function that tells whether a particular node is an element that has an entire
1252 // Frame and FrameView, a <frame>, <iframe>, or <object>.
1253 static bool isFrameElement(const Node *n)
1257 RenderObject *renderer = n->renderer();
1258 if (!renderer || !renderer->isWidget())
1260 Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
1261 return widget && widget->isFrameView();
1264 void Frame::setFocusNodeIfNeeded()
1266 if (!document() || d->m_selection.isNone() || !d->m_isActive)
1269 Node* target = d->m_selection.rootEditableElement();
1271 RenderObject* renderer = target->renderer();
1273 // Walk up the render tree to search for a node to focus.
1274 // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields.
1276 // We don't want to set focus on a subframe when selecting in a parent frame,
1277 // so add the !isFrameElement check here. There's probably a better way to make this
1278 // work in the long term, but this is the safest fix at this time.
1279 if (target && target->isMouseFocusable() && !isFrameElement(target)) {
1280 document()->setFocusNode(target);
1283 renderer = renderer->parent();
1285 target = renderer->element();
1287 document()->setFocusNode(0);
1291 void Frame::selectionLayoutChanged()
1293 // kill any caret blink timer now running
1294 d->m_caretBlinkTimer.stop();
1296 // see if a new caret blink timer needs to be started
1297 if (d->m_caretVisible && d->m_caretBlinks &&
1298 d->m_selection.isCaret() && d->m_selection.start().node()->isContentEditable()) {
1299 d->m_caretBlinkTimer.startRepeating(caretBlinkFrequency);
1300 d->m_caretPaint = true;
1301 d->m_selection.needsCaretRepaint();
1305 d->m_doc->updateSelection();
1308 void Frame::setXPosForVerticalArrowNavigation(int x)
1310 d->m_xPosForVerticalArrowNavigation = x;
1313 int Frame::xPosForVerticalArrowNavigation() const
1315 return d->m_xPosForVerticalArrowNavigation;
1318 void Frame::caretBlinkTimerFired(Timer<Frame>*)
1320 // Might be better to turn the timer off during some of these circumstances
1321 // and assert rather then letting the timer fire and do nothing here.
1322 // Could do that in selectionLayoutChanged.
1324 if (!d->m_caretVisible)
1326 if (!d->m_caretBlinks)
1328 if (!d->m_selection.isCaret())
1330 bool caretPaint = d->m_caretPaint;
1331 if (d->m_bMousePressed && caretPaint)
1333 d->m_caretPaint = !caretPaint;
1334 d->m_selection.needsCaretRepaint();
1337 void Frame::paintCaret(GraphicsContext* p, const IntRect& rect) const
1339 if (d->m_caretPaint)
1340 d->m_selection.paintCaret(p, rect);
1343 void Frame::paintDragCaret(GraphicsContext* p, const IntRect& rect) const
1345 SelectionController& dragCaret = d->m_page->dragCaret();
1346 assert(dragCaret.selection().isCaret());
1347 if (dragCaret.selection().start().node()->document()->frame() == this)
1348 dragCaret.paintCaret(p, rect);
1351 void Frame::urlSelected(const DeprecatedString& url, const String& target)
1353 urlSelected(ResourceRequest(completeURL(url)), target);
1356 void Frame::urlSelected(const ResourceRequest& request, const String& _target)
1358 String target = _target;
1359 if (target.isEmpty() && d->m_doc)
1360 target = d->m_doc->baseTarget();
1362 const KURL& url = request.url();
1364 if (url.url().startsWith("javascript:", false)) {
1365 executeScript(0, KURL::decode_string(url.url().mid(11)), true);
1370 // ### ERROR HANDLING
1373 ResourceRequest requestCopy = request;
1374 requestCopy.frameName = target;
1376 if (d->m_bHTTPRefresh)
1377 d->m_bHTTPRefresh = false;
1379 if (!d->m_referrer.isEmpty())
1380 requestCopy.setReferrer(d->m_referrer);
1382 urlSelected(requestCopy);
1385 bool Frame::requestFrame(Element* ownerElement, const String& urlParam, const AtomicString& frameName)
1387 DeprecatedString _url = urlParam.deprecatedString();
1388 // Support for <frame src="javascript:string">
1391 if (_url.startsWith("javascript:", false)) {
1393 url = "about:blank";
1395 url = completeURL(_url);
1397 Frame* frame = tree()->child(frameName);
1399 ResourceRequest request(url);
1400 request.setReferrer(d->m_referrer);
1401 request.reload = (d->m_cachePolicy == CachePolicyReload) || (d->m_cachePolicy == CachePolicyRefresh);
1402 frame->openURLRequest(request);
1404 frame = loadSubframe(ownerElement, url, frameName, d->m_referrer);
1409 if (!scriptURL.isEmpty())
1410 frame->replaceContentsWithScriptResult(scriptURL);
1415 bool Frame::requestObject(RenderPart* renderer, const String& url, const AtomicString& frameName,
1416 const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
1420 completedURL = completeURL(url.deprecatedString());
1422 if (url.isEmpty() && mimeType.isEmpty())
1426 if (shouldUsePlugin(renderer->element(), completedURL, mimeType, renderer->hasFallbackContent(), useFallback))
1427 return loadPlugin(renderer, completedURL, mimeType, paramNames, paramValues, useFallback);
1429 ASSERT(renderer->node()->hasTagName(objectTag) || renderer->node()->hasTagName(embedTag));
1430 AtomicString uniqueFrameName = tree()->uniqueChildName(frameName);
1431 static_cast<HTMLPlugInElement*>(renderer->node())->setFrameName(uniqueFrameName);
1433 // FIXME: ok to always make a new one? when does the old frame get removed?
1434 return loadSubframe(static_cast<Element*>(renderer->node()), completedURL, uniqueFrameName, d->m_referrer);
1437 bool Frame::shouldUsePlugin(Node* element, const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback)
1439 useFallback = false;
1440 ObjectContentType objectType = objectContentType(url, mimeType);
1442 // if an object's content can't be handled and it has no fallback, let
1443 // it be handled as a plugin to show the broken plugin icon
1444 if (objectType == ObjectContentNone && hasFallback)
1447 return objectType == ObjectContentNone || objectType == ObjectContentPlugin;
1451 bool Frame::loadPlugin(RenderPart *renderer, const KURL& url, const String& mimeType,
1452 const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
1455 checkEmitLoadEvent();
1459 Element *pluginElement;
1460 if (renderer && renderer->node() && renderer->node()->isElementNode())
1461 pluginElement = static_cast<Element*>(renderer->node());
1465 Plugin* plugin = createPlugin(pluginElement, url, paramNames, paramValues, mimeType);
1467 checkEmitLoadEvent();
1470 d->m_plugins.append(plugin);
1472 if (renderer && plugin->view())
1473 renderer->setWidget(plugin->view());
1475 checkEmitLoadEvent();
1480 Frame* Frame::loadSubframe(Element* ownerElement, const KURL& url, const String& name, const String& referrer)
1482 Frame* frame = createFrame(url, name, ownerElement, referrer);
1484 checkEmitLoadEvent();
1488 frame->childBegin();
1490 if (ownerElement->renderer() && frame->view())
1491 static_cast<RenderWidget*>(ownerElement->renderer())->setWidget(frame->view());
1493 checkEmitLoadEvent();
1495 // In these cases, the synchronous load would have finished
1496 // before we could connect the signals, so make sure to send the
1497 // completed() signal for the child by hand
1498 // FIXME: In this case the Frame will have finished loading before
1499 // it's being added to the child list. It would be a good idea to
1500 // create the child first, then invoke the loader separately.
1501 if (url.isEmpty() || url == "about:blank") {
1502 frame->completed(false);
1503 frame->checkCompleted();
1509 void Frame::clearRecordedFormValues()
1511 d->m_formAboutToBeSubmitted = 0;
1512 d->m_formValuesAboutToBeSubmitted.clear();
1515 void Frame::recordFormValue(const String& name, const String& value, PassRefPtr<HTMLFormElement> element)
1517 d->m_formAboutToBeSubmitted = element;
1518 d->m_formValuesAboutToBeSubmitted.set(name, value);
1521 void Frame::submitFormAgain()
1523 FramePrivate::SubmitForm* form = d->m_submitForm;
1524 d->m_submitForm = 0;
1525 if (d->m_doc && !d->m_doc->parsing() && form)
1526 submitForm(form->submitAction, form->submitUrl, form->submitFormData,
1527 form->target, form->submitContentType, form->submitBoundary);
1531 void Frame::submitForm(const char *action, const String& url, const FormData& formData, const String& _target, const String& contentType, const String& boundary)
1533 KURL u = completeURL(url.deprecatedString());
1536 // ### ERROR HANDLING!
1539 DeprecatedString urlstring = u.url();
1540 if (urlstring.startsWith("javascript:", false)) {
1541 urlstring = KURL::decode_string(urlstring);
1542 d->m_executingJavaScriptFormAction = true;
1543 executeScript(0, urlstring.mid(11));
1544 d->m_executingJavaScriptFormAction = false;
1548 ResourceRequest request;
1550 if (!d->m_referrer.isEmpty())
1551 request.setReferrer(d->m_referrer);
1553 request.frameName = _target.isEmpty() ? d->m_doc->baseTarget() : _target ;
1555 // Handle mailto: forms
1556 if (u.protocol() == "mailto") {
1557 // 1) Check for attach= and strip it
1558 DeprecatedString q = u.query().mid(1);
1559 DeprecatedStringList nvps = DeprecatedStringList::split("&", q);
1560 bool triedToAttach = false;
1562 for (DeprecatedStringList::Iterator nvp = nvps.begin(); nvp != nvps.end(); ++nvp) {
1563 DeprecatedStringList pair = DeprecatedStringList::split("=", *nvp);
1564 if (pair.count() >= 2) {
1565 if (pair.first().lower() == "attach") {
1566 nvp = nvps.remove(nvp);
1567 triedToAttach = true;
1574 DeprecatedString bodyEnc;
1575 if (contentType.lower() == "multipart/form-data")
1576 // FIXME: is this correct? I suspect not
1577 bodyEnc = KURL::encode_string(formData.flattenToString());
1578 else if (contentType.lower() == "text/plain") {
1579 // Convention seems to be to decode, and s/&/\n/
1580 DeprecatedString tmpbody = formData.flattenToString();
1581 tmpbody.replace('&', '\n');
1582 tmpbody.replace('+', ' ');
1583 tmpbody = KURL::decode_string(tmpbody); // Decode the rest of it
1584 bodyEnc = KURL::encode_string(tmpbody); // Recode for the URL
1586 bodyEnc = KURL::encode_string(formData.flattenToString());
1588 nvps.append(String::sprintf("body=%s", bodyEnc.latin1()).deprecatedString());
1593 if (strcmp(action, "get") == 0) {
1594 if (u.protocol() != "mailto")
1595 u.setQuery(formData.flattenToString());
1596 request.setDoPost(false);
1598 request.postData = formData;
1599 request.setDoPost(true);
1601 // construct some user headers if necessary
1602 if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
1603 request.setContentType("Content-Type: application/x-www-form-urlencoded");
1604 else // contentType must be "multipart/form-data"
1605 request.setContentType("Content-Type: " + contentType + "; boundary=" + boundary);
1608 if (d->m_doc->parsing() || d->m_runningScripts > 0) {
1609 if (d->m_submitForm)
1611 d->m_submitForm = new FramePrivate::SubmitForm;
1612 d->m_submitForm->submitAction = action;
1613 d->m_submitForm->submitUrl = url;
1614 d->m_submitForm->submitFormData = formData;
1615 d->m_submitForm->target = _target;
1616 d->m_submitForm->submitContentType = contentType;
1617 d->m_submitForm->submitBoundary = boundary;
1620 submitForm(request);
1624 void Frame::parentCompleted()
1626 if (d->m_scheduledRedirection != noRedirectionScheduled && !d->m_redirectionTimer.isActive())
1627 startRedirectionTimer();
1630 void Frame::childCompleted(bool complete)
1632 if (complete && !tree()->parent())
1633 d->m_bPendingChildRedirection = true;
1637 int Frame::zoomFactor() const
1639 return d->m_zoomFactor;
1642 void Frame::setZoomFactor(int percent)
1644 if (d->m_zoomFactor == percent)
1647 d->m_zoomFactor = percent;
1650 d->m_doc->recalcStyle(Node::Force);
1652 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
1653 child->setZoomFactor(d->m_zoomFactor);
1655 if (d->m_doc && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout())
1659 void Frame::setJSStatusBarText(const String& text)
1661 d->m_kjsStatusBarText = text;
1662 setStatusBarText(d->m_kjsStatusBarText);
1665 void Frame::setJSDefaultStatusBarText(const String& text)
1667 d->m_kjsDefaultStatusBarText = text;
1668 setStatusBarText(d->m_kjsDefaultStatusBarText);
1671 String Frame::jsStatusBarText() const
1673 return d->m_kjsStatusBarText;
1676 String Frame::jsDefaultStatusBarText() const
1678 return d->m_kjsDefaultStatusBarText;
1681 DeprecatedString Frame::referrer() const
1683 return d->m_referrer;
1686 String Frame::lastModified() const
1688 return d->m_lastModified;
1691 void Frame::reparseConfiguration()
1693 setAutoloadImages(d->m_settings->autoLoadImages());
1695 d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled();
1696 d->m_bJavaEnabled = d->m_settings->isJavaEnabled();
1697 d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled();
1699 const KURL& userStyleSheetLocation = d->m_settings->userStyleSheetLocation();
1700 if (!userStyleSheetLocation.isEmpty())
1701 setUserStyleSheetLocation(userStyleSheetLocation);
1703 setUserStyleSheet(String());
1705 // FIXME: It's not entirely clear why the following is needed.
1706 // The document automatically does this as required when you set the style sheet.
1707 // But we had problems when this code was removed. Details are in
1708 // <http://bugzilla.opendarwin.org/show_bug.cgi?id=8079>.
1710 d->m_doc->updateStyleSelector();
1713 bool Frame::shouldDragAutoNode(Node *node, const IntPoint& point) const
1719 bool Frame::isPointInsideSelection(const IntPoint& point)
1721 // Treat a collapsed selection like no selection.
1722 if (!d->m_selection.isRange())
1724 if (!document()->renderer())
1727 RenderObject::NodeInfo nodeInfo(true, true);
1728 document()->renderer()->layer()->hitTest(nodeInfo, point);
1729 Node *innerNode = nodeInfo.innerNode();
1730 if (!innerNode || !innerNode->renderer())
1733 Position pos(innerNode->renderer()->positionForPoint(point).deepEquivalent());
1737 Node *n = d->m_selection.start().node();
1739 if (n == pos.node()) {
1740 if ((n == d->m_selection.start().node() && pos.offset() < d->m_selection.start().offset()) ||
1741 (n == d->m_selection.end().node() && pos.offset() > d->m_selection.end().offset())) {
1746 if (n == d->m_selection.end().node())
1748 n = n->traverseNextNode();
1754 void Frame::selectClosestWordFromMouseEvent(const PlatformMouseEvent& mouse, Node *innerNode)
1756 SelectionController selection;
1758 if (innerNode && innerNode->renderer() && mouseDownMayStartSelect() && innerNode->renderer()->shouldSelect()) {
1759 IntPoint vPoint = view()->viewportToContents(mouse.pos());
1760 VisiblePosition pos(innerNode->renderer()->positionForPoint(vPoint));
1761 if (pos.isNotNull()) {
1762 selection.moveTo(pos);
1763 selection.expandUsingGranularity(WordGranularity);
1767 if (selection.isRange()) {
1768 d->m_selectionGranularity = WordGranularity;
1769 d->m_beganSelectingText = true;
1772 if (shouldChangeSelection(selection))
1773 setSelection(selection);
1776 void Frame::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
1778 if (event.event().button() == LeftButton) {
1779 if (selection().isRange())
1780 // A double-click when range is already selected
1781 // should not change the selection. So, do not call
1782 // selectClosestWordFromMouseEvent, but do set
1783 // m_beganSelectingText to prevent handleMouseReleaseEvent
1784 // from setting caret selection.
1785 d->m_beganSelectingText = true;
1787 selectClosestWordFromMouseEvent(event.event(), event.targetNode());
1791 void Frame::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
1793 Node *innerNode = event.targetNode();
1795 if (event.event().button() == LeftButton && innerNode && innerNode->renderer() &&
1796 mouseDownMayStartSelect() && innerNode->renderer()->shouldSelect()) {
1797 SelectionController selection;
1798 IntPoint vPoint = view()->viewportToContents(event.event().pos());
1799 VisiblePosition pos(innerNode->renderer()->positionForPoint(vPoint));
1800 if (pos.isNotNull()) {
1801 selection.moveTo(pos);
1802 selection.expandUsingGranularity(ParagraphGranularity);
1804 if (selection.isRange()) {
1805 d->m_selectionGranularity = ParagraphGranularity;
1806 d->m_beganSelectingText = true;
1809 if (shouldChangeSelection(selection))
1810 setSelection(selection);
1814 void Frame::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
1816 Node *innerNode = event.targetNode();
1818 if (event.event().button() == LeftButton) {
1819 if (innerNode && innerNode->renderer() &&
1820 mouseDownMayStartSelect() && innerNode->renderer()->shouldSelect()) {
1821 SelectionController sel;
1823 // Extend the selection if the Shift key is down, unless the click is in a link.
1824 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
1826 // Don't restart the selection when the mouse is pressed on an
1827 // existing selection so we can allow for text dragging.
1828 IntPoint vPoint = view()->viewportToContents(event.event().pos());
1829 if (!extendSelection && isPointInsideSelection(vPoint))
1832 VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(vPoint));
1833 if (visiblePos.isNull())
1834 visiblePos = VisiblePosition(innerNode, innerNode->caretMinOffset(), DOWNSTREAM);
1835 Position pos = visiblePos.deepEquivalent();
1838 if (extendSelection && sel.isCaretOrRange()) {
1839 sel.clearModifyBias();
1841 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
1842 // was created right-to-left
1843 Position start = sel.start();
1844 short before = Range::compareBoundaryPoints(pos.node(), pos.offset(), start.node(), start.offset());
1846 sel.setBaseAndExtent(pos.node(), pos.offset(), sel.end().node(), sel.end().offset());
1848 sel.setBaseAndExtent(start.node(), start.offset(), pos.node(), pos.offset());
1850 if (d->m_selectionGranularity != CharacterGranularity)
1851 sel.expandUsingGranularity(d->m_selectionGranularity);
1852 d->m_beganSelectingText = true;
1854 sel = SelectionController(visiblePos);
1855 d->m_selectionGranularity = CharacterGranularity;
1858 if (shouldChangeSelection(sel))
1864 void Frame::handleMousePressEvent(const MouseEventWithHitTestResults& event)
1866 Node *innerNode = event.targetNode();
1868 d->m_mousePressNode = innerNode;
1869 d->m_dragStartPos = event.event().pos();
1871 if (event.event().button() == LeftButton || event.event().button() == MiddleButton) {
1872 d->m_bMousePressed = true;
1873 d->m_beganSelectingText = false;
1875 if (event.event().clickCount() == 2) {
1876 handleMousePressEventDoubleClick(event);
1879 if (event.event().clickCount() >= 3) {
1880 handleMousePressEventTripleClick(event);
1883 handleMousePressEventSingleClick(event);
1887 void Frame::handleMouseMoveEvent(const MouseEventWithHitTestResults& event)
1889 // Mouse not pressed. Do nothing.
1890 if (!d->m_bMousePressed)
1893 Node *innerNode = event.targetNode();
1895 if (event.event().button() != 0 || !innerNode || !innerNode->renderer() || !mouseDownMayStartSelect() || !innerNode->renderer()->shouldSelect())
1898 // handle making selection
1899 IntPoint vPoint = view()->viewportToContents(event.event().pos());
1900 VisiblePosition pos(innerNode->renderer()->positionForPoint(vPoint));
1902 // Don't modify the selection if we're not on a node.
1906 // Restart the selection if this is the first mouse move. This work is usually
1907 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
1908 SelectionController sel = selection();
1909 sel.clearModifyBias();
1911 if (!d->m_beganSelectingText) {
1912 d->m_beganSelectingText = true;
1917 if (d->m_selectionGranularity != CharacterGranularity)
1918 sel.expandUsingGranularity(d->m_selectionGranularity);
1920 if (shouldChangeSelection(sel))
1924 void Frame::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
1926 stopAutoscrollTimer();
1928 // Used to prevent mouseMoveEvent from initiating a drag before
1929 // the mouse is pressed again.
1930 d->m_bMousePressed = false;
1932 // Clear the selection if the mouse didn't move after the last mouse press.
1933 // We do this so when clicking on the selection, the selection goes away.
1934 // However, if we are editing, place the caret.
1935 if (mouseDownMayStartSelect() && !d->m_beganSelectingText
1936 && d->m_dragStartPos == event.event().pos()
1937 && d->m_selection.isRange()) {
1938 SelectionController selection;
1939 Node *node = event.targetNode();
1940 if (node && node->isContentEditable() && node->renderer()) {
1941 IntPoint vPoint = view()->viewportToContents(event.event().pos());
1942 VisiblePosition pos = node->renderer()->positionForPoint(vPoint);
1943 selection.moveTo(pos);
1945 if (shouldChangeSelection(selection))
1946 setSelection(selection);
1949 notifyRendererOfSelectionChange(true);
1951 selectFrameElementInParentIfFullySelected();
1954 void Frame::selectAll()
1959 Node* root = d->m_selection.isContentEditable() ? d->m_selection.rootEditableElement() : d->m_doc->documentElement();
1960 selectContentsOfNode(root);
1961 selectFrameElementInParentIfFullySelected();
1962 notifyRendererOfSelectionChange(true);
1965 bool Frame::selectContentsOfNode(Node* node)
1967 SelectionController sel = SelectionController(Selection::selectionFromContentsOfNode(node));
1968 if (shouldChangeSelection(sel)) {
1975 bool Frame::shouldChangeSelection(const SelectionController& newselection) const
1977 return shouldChangeSelection(d->m_selection, newselection, newselection.affinity(), false);
1980 bool Frame::shouldDeleteSelection(const SelectionController& newselection) const
1985 bool Frame::shouldBeginEditing(const Range *range) const
1990 bool Frame::shouldEndEditing(const Range *range) const
1995 bool Frame::isContentEditable() const
1999 return d->m_doc->inDesignMode();
2002 void Frame::textFieldDidBeginEditing(Element* input)
2006 void Frame::textFieldDidEndEditing(Element* input)
2010 void Frame::textDidChangeInTextField(Element* input)
2014 bool Frame::doTextFieldCommandFromEvent(Element* input, const PlatformKeyboardEvent* evt)
2019 void Frame::textWillBeDeletedInTextField(Element* input)
2023 void Frame::textDidChangeInTextArea(Element* input)
2027 bool Frame::isSelectionInPasswordField()
2029 Node* startNode = selection().start().node();
2031 startNode = startNode->shadowAncestorNode();
2032 return startNode && startNode->hasTagName(inputTag) && static_cast<HTMLInputElement*>(startNode)->inputType() == HTMLInputElement::PASSWORD;
2035 EditCommand* Frame::lastEditCommand()
2037 return d->m_lastEditCommand.get();
2040 static void dispatchEditableContentChangedEvents(const EditCommand& command)
2042 Element* startRoot = command.startingRootEditableElement();
2043 Element* endRoot = command.endingRootEditableElement();
2046 startRoot->dispatchEvent(new Event(khtmlEditableContentChangedEvent, false, false), ec, true);
2047 if (endRoot && endRoot != startRoot)
2048 endRoot->dispatchEvent(new Event(khtmlEditableContentChangedEvent, false, false), ec, true);
2051 void Frame::appliedEditing(PassRefPtr<EditCommand> cmd)
2053 dispatchEditableContentChangedEvents(*cmd);
2055 SelectionController sel(cmd->endingSelection());
2056 if (shouldChangeSelection(sel))
2057 setSelection(sel, false);
2059 // Now set the typing style from the command. Clear it when done.
2060 // This helps make the case work where you completely delete a piece
2061 // of styled text and then type a character immediately after.
2062 // That new character needs to take on the style of the just-deleted text.
2063 // FIXME: Improve typing style.
2064 // See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
2065 if (cmd->typingStyle()) {
2066 setTypingStyle(cmd->typingStyle());
2067 cmd->setTypingStyle(0);
2070 // Command will be equal to last edit command only in the case of typing
2071 if (d->m_lastEditCommand == cmd)
2072 assert(cmd->isTypingCommand());
2074 // Only register a new undo command if the command passed in is
2075 // different from the last command
2076 d->m_lastEditCommand = cmd.get();
2077 registerCommandForUndo(cmd);
2079 respondToChangedContents(sel);
2082 void Frame::unappliedEditing(PassRefPtr<EditCommand> cmd)
2084 dispatchEditableContentChangedEvents(*cmd);
2086 SelectionController sel(cmd->startingSelection());
2087 if (shouldChangeSelection(sel))
2088 setSelection(sel, true);
2090 d->m_lastEditCommand = 0;
2091 registerCommandForRedo(cmd);
2092 respondToChangedContents(sel);
2095 void Frame::reappliedEditing(PassRefPtr<EditCommand> cmd)
2097 dispatchEditableContentChangedEvents(*cmd);
2099 SelectionController sel(cmd->endingSelection());
2100 if (shouldChangeSelection(sel))
2101 setSelection(sel, true);
2103 d->m_lastEditCommand = 0;
2104 registerCommandForUndo(cmd);
2105 respondToChangedContents(sel);
2108 CSSMutableStyleDeclaration *Frame::typingStyle() const
2110 return d->m_typingStyle.get();
2113 void Frame::setTypingStyle(CSSMutableStyleDeclaration *style)
2115 d->m_typingStyle = style;
2118 void Frame::clearTypingStyle()
2120 d->m_typingStyle = 0;
2123 JSValue* Frame::executeScript(const String& filename, int baseLine, Node* n, const DeprecatedString& script)
2125 // FIXME: This is missing stuff that the other executeScript has.
2126 // --> d->m_runningScripts and submitFormAgain.
2128 KJSProxy *proxy = jScript();
2131 JSValue* ret = proxy->evaluate(filename, baseLine, script, n);
2132 Document::updateDocumentsRendering();
2136 Frame *Frame::opener()
2141 void Frame::setOpener(Frame* opener)
2144 d->m_opener->d->m_openedFrames.remove(this);
2146 opener->d->m_openedFrames.add(this);
2147 d->m_opener = opener;
2150 bool Frame::openedByJS()
2152 return d->m_openedByJS;
2155 void Frame::setOpenedByJS(bool _openedByJS)
2157 d->m_openedByJS = _openedByJS;
2160 bool Frame::tabsToLinks() const
2165 bool Frame::tabsToAllControls() const
2170 void Frame::copyToPasteboard()
2175 void Frame::cutToPasteboard()
2180 void Frame::pasteFromPasteboard()
2182 issuePasteCommand();
2185 void Frame::pasteAndMatchStyle()
2187 issuePasteAndMatchStyleCommand();
2190 bool Frame::mayCopy()
2192 return !isSelectionInPasswordField();
2195 void Frame::transpose()
2197 issueTransposeCommand();
2211 void Frame::computeAndSetTypingStyle(CSSStyleDeclaration *style, EditAction editingAction)
2213 if (!style || style->length() == 0) {
2218 // Calculate the current typing style.
2219 RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
2220 if (typingStyle()) {
2221 typingStyle()->merge(mutableStyle.get());
2222 mutableStyle = typingStyle();
2225 Node *node = VisiblePosition(selection().start(), selection().affinity()).deepEquivalent().node();
2226 CSSComputedStyleDeclaration computedStyle(node);
2227 computedStyle.diff(mutableStyle.get());
2229 // Handle block styles, substracting these from the typing style.
2230 RefPtr<CSSMutableStyleDeclaration> blockStyle = mutableStyle->copyBlockProperties();
2231 blockStyle->diff(mutableStyle.get());
2232 if (document() && blockStyle->length() > 0)
2233 applyCommand(new ApplyStyleCommand(document(), blockStyle.get(), editingAction));
2235 // Set the remaining style as the typing style.
2236 d->m_typingStyle = mutableStyle.release();
2239 void Frame::applyStyle(CSSStyleDeclaration *style, EditAction editingAction)
2241 switch (selection().state()) {
2242 case Selection::NONE:
2245 case Selection::CARET: {
2246 computeAndSetTypingStyle(style, editingAction);
2249 case Selection::RANGE:
2250 if (document() && style)
2251 applyCommand(new ApplyStyleCommand(document(), style, editingAction));
2256 void Frame::applyParagraphStyle(CSSStyleDeclaration *style, EditAction editingAction)
2258 switch (selection().state()) {
2259 case Selection::NONE:
2262 case Selection::CARET:
2263 case Selection::RANGE:
2264 if (document() && style)
2265 applyCommand(new ApplyStyleCommand(document(), style, editingAction, ApplyStyleCommand::ForceBlockProperties));
2270 static void updateState(CSSMutableStyleDeclaration *desiredStyle, CSSComputedStyleDeclaration *computedStyle, bool& atStart, Frame::TriState& state)
2272 DeprecatedValueListConstIterator<CSSProperty> end;
2273 for (DeprecatedValueListConstIterator<CSSProperty> it = desiredStyle->valuesIterator(); it != end; ++it) {
2274 int propertyID = (*it).id();
2275 String desiredProperty = desiredStyle->getPropertyValue(propertyID);
2276 String computedProperty = computedStyle->getPropertyValue(propertyID);
2277 Frame::TriState propertyState = equalIgnoringCase(desiredProperty, computedProperty)
2278 ? Frame::trueTriState : Frame::falseTriState;
2280 state = propertyState;
2282 } else if (state != propertyState) {
2283 state = Frame::mixedTriState;
2289 Frame::TriState Frame::selectionListState() const
2291 TriState state = falseTriState;
2293 if (!d->m_selection.isRange()) {
2294 Node* selectionNode = d->m_selection.selection().start().node();
2295 if (enclosingList(selectionNode))
2296 return trueTriState;
2298 //FIXME: Support ranges
2304 Frame::TriState Frame::selectionHasStyle(CSSStyleDeclaration *style) const
2306 bool atStart = true;
2307 TriState state = falseTriState;
2309 RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
2311 if (!d->m_selection.isRange()) {
2313 RefPtr<CSSComputedStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
2314 if (!selectionStyle)
2315 return falseTriState;
2316 updateState(mutableStyle.get(), selectionStyle.get(), atStart, state);
2318 ExceptionCode ec = 0;
2319 nodeToRemove->remove(ec);
2323 for (Node* node = d->m_selection.start().node(); node; node = node->traverseNextNode()) {
2324 RefPtr<CSSComputedStyleDeclaration> computedStyle = new CSSComputedStyleDeclaration(node);
2326 updateState(mutableStyle.get(), computedStyle.get(), atStart, state);
2327 if (state == mixedTriState)
2329 if (node == d->m_selection.end().node())
2337 bool Frame::selectionStartHasStyle(CSSStyleDeclaration *style) const
2340 RefPtr<CSSStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
2341 if (!selectionStyle)
2344 RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
2347 DeprecatedValueListConstIterator<CSSProperty> end;
2348 for (DeprecatedValueListConstIterator<CSSProperty> it = mutableStyle->valuesIterator(); it != end; ++it) {
2349 int propertyID = (*it).id();
2350 if (!equalIgnoringCase(mutableStyle->getPropertyValue(propertyID), selectionStyle->getPropertyValue(propertyID))) {
2357 ExceptionCode ec = 0;
2358 nodeToRemove->remove(ec);
2365 String Frame::selectionStartStylePropertyValue(int stylePropertyID) const
2368 RefPtr<CSSStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
2369 if (!selectionStyle)
2372 String value = selectionStyle->getPropertyValue(stylePropertyID);
2375 ExceptionCode ec = 0;
2376 nodeToRemove->remove(ec);
2383 CSSComputedStyleDeclaration *Frame::selectionComputedStyle(Node *&nodeToRemove) const
2390 if (d->m_selection.isNone())
2393 RefPtr<Range> range(d->m_selection.toRange());
2394 Position pos = range->editingStartPosition();
2396 Element *elem = pos.element();
2400 RefPtr<Element> styleElement = elem;
2401 ExceptionCode ec = 0;
2403 if (d->m_typingStyle) {
2404 styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec);
2407 styleElement->setAttribute(styleAttr, d->m_typingStyle->cssText().impl(), ec);
2410 styleElement->appendChild(document()->createEditingTextNode(""), ec);
2413 if (elem->renderer() && elem->renderer()->canHaveChildren()) {
2414 elem->appendChild(styleElement, ec);
2416 Node *parent = elem->parent();
2417 Node *next = elem->nextSibling();
2420 parent->insertBefore(styleElement, next, ec);
2422 parent->appendChild(styleElement, ec);
2427 nodeToRemove = styleElement.get();
2430 return new CSSComputedStyleDeclaration(styleElement);
2433 void Frame::applyEditingStyleToBodyElement() const
2438 RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body");
2439 unsigned len = list->length();
2440 for (unsigned i = 0; i < len; i++) {
2441 applyEditingStyleToElement(static_cast<Element*>(list->item(i)));
2445 void Frame::removeEditingStyleFromBodyElement() const
2450 RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body");
2451 unsigned len = list->length();
2452 for (unsigned i = 0; i < len; i++) {
2453 removeEditingStyleFromElement(static_cast<Element*>(list->item(i)));
2457 void Frame::applyEditingStyleToElement(Element* element) const
2462 CSSStyleDeclaration* style = element->style();
2465 ExceptionCode ec = 0;
2466 style->setProperty(CSS_PROP_WORD_WRAP, "break-word", false, ec);
2468 style->setProperty(CSS_PROP__WEBKIT_NBSP_MODE, "space", false, ec);
2470 style->setProperty(CSS_PROP__WEBKIT_LINE_BREAK, "after-white-space", false, ec);
2474 void Frame::removeEditingStyleFromElement(Element*) const
2478 bool Frame::isCharacterSmartReplaceExempt(const DeprecatedChar&, bool)
2485 static HashSet<Frame*> lifeSupportSet;
2488 void Frame::endAllLifeSupport()
2491 HashSet<Frame*> lifeSupportCopy = lifeSupportSet;
2492 HashSet<Frame*>::iterator end = lifeSupportCopy.end();
2493 for (HashSet<Frame*>::iterator it = lifeSupportCopy.begin(); it != end; ++it)
2494 (*it)->endLifeSupport();
2498 void Frame::keepAlive()
2500 if (d->m_lifeSupportTimer.isActive())
2504 lifeSupportSet.add(this);
2506 d->m_lifeSupportTimer.startOneShot(0);
2509 void Frame::endLifeSupport()
2511 if (!d->m_lifeSupportTimer.isActive())
2513 d->m_lifeSupportTimer.stop();
2515 lifeSupportSet.remove(this);
2520 void Frame::lifeSupportTimerFired(Timer<Frame>*)
2523 lifeSupportSet.remove(this);
2528 // Workaround for the fact that it's hard to delete a frame.
2529 // Call this after doing user-triggered selections to make it easy to delete the frame you entirely selected.
2530 // Can't do this implicitly as part of every setSelection call because in some contexts it might not be good
2531 // for the focus to move to another frame. So instead we call it from places where we are selecting with the
2532 // mouse or the keyboard after setting the selection.
2533 void Frame::selectFrameElementInParentIfFullySelected()
2535 // Find the parent frame; if there is none, then we have nothing to do.
2536 Frame *parent = tree()->parent();
2539 FrameView *parentView = parent->view();
2543 // Check if the selection contains the entire frame contents; if not, then there is nothing to do.
2544 if (!d->m_selection.isRange())
2546 if (!isStartOfDocument(VisiblePosition(d->m_selection.start(), d->m_selection.affinity())))
2548 if (!isEndOfDocument(VisiblePosition(d->m_selection.end(), d->m_selection.affinity())))
2551 // Get to the <iframe> or <frame> (or even <object>) element in the parent frame.
2552 Document *doc = document();
2555 Element *ownerElement = doc->ownerElement();
2558 Node *ownerElementParent = ownerElement->parentNode();
2559 if (!ownerElementParent)
2562 // This method's purpose is it to make it easier to select iframes (in order to delete them). Don't do anything if the iframe isn't deletable.
2563 if (!ownerElementParent->isContentEditable())
2566 // Create compute positions before and after the element.
2567 unsigned ownerElementNodeIndex = ownerElement->nodeIndex();
2568 VisiblePosition beforeOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex, SEL_DEFAULT_AFFINITY));
2569 VisiblePosition afterOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex + 1, VP_UPSTREAM_IF_POSSIBLE));
2571 // Focus on the parent frame, and then select from before this element to after.
2572 if (parent->shouldChangeSelection(SelectionController(beforeOwnerElement, afterOwnerElement))) {
2573 parentView->setFocus();
2574 parent->setSelection(SelectionController(beforeOwnerElement, afterOwnerElement));
2578 void Frame::handleFallbackContent()
2580 Element* owner = ownerElement();
2581 if (!owner || !owner->hasTagName(objectTag))
2583 static_cast<HTMLObjectElement*>(owner)->renderFallbackContent();
2586 void Frame::setSettings(Settings *settings)
2588 d->m_settings = settings;
2591 void Frame::provisionalLoadStarted()
2593 // we don't want to wait until we get an actual http response back
2594 // to cancel pending redirects, otherwise they might fire before
2596 cancelRedirection(true);
2599 bool Frame::userGestureHint()
2601 Frame *rootFrame = this;
2602 while (rootFrame->tree()->parent())
2603 rootFrame = rootFrame->tree()->parent();
2605 if (rootFrame->jScript())
2606 return rootFrame->jScript()->interpreter()->wasRunByUserGesture();
2608 return true; // If JavaScript is disabled, a user gesture must have initiated the navigation
2611 RenderObject *Frame::renderer() const
2613 Document *doc = document();
2614 return doc ? doc->renderer() : 0;
2617 Element* Frame::ownerElement()
2619 return d->m_ownerElement;
2622 RenderPart* Frame::ownerRenderer()
2624 Element* ownerElement = d->m_ownerElement;
2627 return static_cast<RenderPart*>(ownerElement->renderer());
2630 IntRect Frame::selectionRect() const
2632 RenderView *root = static_cast<RenderView*>(renderer());
2636 return root->selectionRect();
2639 // returns FloatRect because going through IntRect would truncate any floats
2640 FloatRect Frame::visibleSelectionRect() const
2645 return intersection(selectionRect(), d->m_view->visibleContentRect());
2648 bool Frame::isFrameSet() const
2650 Document* document = d->m_doc.get();
2651 if (!document || !document->isHTMLDocument())
2653 Node *body = static_cast<HTMLDocument*>(document)->body();
2654 return body && body->renderer() && body->hasTagName(framesetTag);
2657 bool Frame::openURL(const KURL& URL)
2659 ASSERT_NOT_REACHED();
2663 void Frame::didNotOpenURL(const KURL& URL)
2665 if (d->m_submittedFormURL == URL)
2666 d->m_submittedFormURL = KURL();
2669 // Scans logically forward from "start", including any child frames
2670 static HTMLFormElement *scanForForm(Node *start)
2673 for (n = start; n; n = n->traverseNextNode()) {
2674 if (n->hasTagName(formTag))
2675 return static_cast<HTMLFormElement*>(n);
2676 else if (n->isHTMLElement() && static_cast<HTMLElement*>(n)->isGenericFormElement())
2677 return static_cast<HTMLGenericFormElement*>(n)->form();
2678 else if (n->hasTagName(frameTag) || n->hasTagName(iframeTag)) {
2679 Node *childDoc = static_cast<HTMLFrameElement*>(n)->contentDocument();
2680 if (HTMLFormElement *frameResult = scanForForm(childDoc))
2687 // We look for either the form containing the current focus, or for one immediately after it
2688 HTMLFormElement *Frame::currentForm() const
2690 // start looking either at the active (first responder) node, or where the selection is
2691 Node *start = d->m_doc ? d->m_doc->focusNode() : 0;
2693 start = selection().start().node();
2695 // try walking up the node tree to find a form element
2697 for (n = start; n; n = n->parentNode()) {
2698 if (n->hasTagName(formTag))
2699 return static_cast<HTMLFormElement*>(n);
2700 else if (n->isHTMLElement()
2701 && static_cast<HTMLElement*>(n)->isGenericFormElement())
2702 return static_cast<HTMLGenericFormElement*>(n)->form();
2705 // try walking forward in the node tree to find a form element
2706 return start ? scanForForm(start) : 0;
2709 void Frame::setEncoding(const DeprecatedString& name, bool userChosen)
2711 if (!d->m_workingURL.isEmpty())
2712 receivedFirstData();
2713 d->m_encoding = name;
2714 d->m_haveEncoding = userChosen;
2717 void Frame::addData(const char *bytes, int length)
2719 ASSERT(d->m_workingURL.isEmpty());
2721 ASSERT(d->m_doc->parsing());
2722 write(bytes, length);
2725 // FIXME: should this go in SelectionController?
2726 void Frame::revealSelection()
2730 switch (selection().state()) {
2731 case Selection::NONE:
2734 case Selection::CARET:
2735 rect = selection().caretRect();
2738 case Selection::RANGE:
2739 rect = selectionRect();
2743 Position start = selection().start();
2744 Position end = selection().end();
2745 ASSERT(start.node());
2746 if (start.node() && start.node()->renderer()) {
2747 RenderLayer *layer = start.node()->renderer()->enclosingLayer();
2749 ASSERT(!end.node() || !end.node()->renderer()
2750 || (end.node()->renderer()->enclosingLayer() == layer));
2751 layer->scrollRectToVisible(rect);
2756 // FIXME: should this be here?
2757 bool Frame::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity)
2763 Node *node = document()->focusNode();
2765 node = d->m_mousePressNode.get();
2769 RenderObject *r = node->renderer();
2771 return r->scroll(direction, granularity);
2778 void Frame::handleAutoscroll(RenderLayer* layer)
2780 if (d->m_autoscrollTimer.isActive())
2782 d->m_autoscrollLayer = layer;
2783 startAutoscrollTimer();
2786 void Frame::autoscrollTimerFired(Timer<Frame>*)
2788 if (!d->m_bMousePressed){
2789 stopAutoscrollTimer();
2792 if (d->m_autoscrollLayer) {
2793 d->m_autoscrollLayer->autoscroll();
2797 RenderObject::NodeInfo Frame::nodeInfoAtPoint(const IntPoint& point, bool allowShadowContent)
2799 RenderObject::NodeInfo nodeInfo(true, true);
2800 renderer()->layer()->hitTest(nodeInfo, point);
2804 IntPoint widgetPoint(point);
2807 n = nodeInfo.innerNode();
2808 if (!n || !n->renderer() || !n->renderer()->isWidget())
2810 widget = static_cast<RenderWidget*>(n->renderer())->widget();
2811 if (!widget || !widget->isFrameView())
2813 Frame* frame = static_cast<HTMLFrameElement*>(n)->contentFrame();
2814 if (!frame || !frame->renderer())
2817 n->renderer()->absolutePosition(absX, absY, true);
2818 FrameView *view = static_cast<FrameView*>(widget);
2819 widgetPoint.setX(widgetPoint.x() - absX + view->contentsX());
2820 widgetPoint.setY(widgetPoint.y() - absY + view->contentsY());
2822 RenderObject::NodeInfo widgetNodeInfo(true, true);
2823 frame->renderer()->layer()->hitTest(widgetNodeInfo, widgetPoint);
2824 nodeInfo = widgetNodeInfo;
2827 if (!allowShadowContent) {
2828 Node* node = nodeInfo.innerNode();
2830 node = node->shadowAncestorNode();
2831 nodeInfo.setInnerNode(node);
2832 node = nodeInfo.innerNonSharedNode();
2834 node = node->shadowAncestorNode();
2835 nodeInfo.setInnerNonSharedNode(node);
2840 bool Frame::hasSelection()
2842 if (selection().isNone())
2845 // If a part has a selection, it should also have a document.
2851 void Frame::startAutoscrollTimer()
2853 d->m_autoscrollTimer.startRepeating(autoscrollInterval);
2856 void Frame::stopAutoscrollTimer()
2858 d->m_autoscrollLayer = 0;
2859 d->m_autoscrollTimer.stop();
2862 // FIXME: why is this here instead of on the FrameView?
2863 void Frame::paint(GraphicsContext* p, const IntRect& rect)
2867 if (!document() || document()->printing())
2868 fillWithRed = false; // Printing, don't fill with red (can't remember why).
2869 else if (document()->ownerElement())
2870 fillWithRed = false; // Subframe, don't fill with red.
2871 else if (view() && view()->isTransparent())
2872 fillWithRed = false; // Transparent, don't fill with red.
2873 else if (d->m_paintRestriction == PaintRestrictionSelectionOnly || d->m_paintRestriction == PaintRestrictionSelectionOnlyWhiteText)
2874 fillWithRed = false; // Selections are transparent, don't fill with red.
2875 else if (d->m_elementToDraw)
2876 fillWithRed = false; // Element images are transparent, don't fill with red.
2881 p->fillRect(rect, Color(0xFF, 0, 0));
2885 // d->m_elementToDraw is used to draw only one element
2886 RenderObject *eltRenderer = d->m_elementToDraw ? d->m_elementToDraw->renderer() : 0;
2887 if (d->m_paintRestriction == PaintRestrictionNone)
2888 renderer()->document()->invalidateRenderedRectsForMarkersInRect(rect);
2889 renderer()->layer()->paint(p, rect, d->m_paintRestriction, eltRenderer);
2892 // Regions may have changed as a result of the visibility/z-index of element changing.
2893 if (renderer()->document()->dashboardRegionsDirty())
2894 renderer()->view()->frameView()->updateDashboardRegions();
2897 LOG_ERROR("called Frame::paint with nil renderer");
2902 void Frame::adjustPageHeight(float *newBottom, float oldTop, float oldBottom, float bottomLimit)
2904 RenderView *root = static_cast<RenderView*>(document()->renderer());
2906 // Use a context with painting disabled.
2907 GraphicsContext context(0);
2908 root->setTruncatedAt((int)floorf(oldBottom));
2909 IntRect dirtyRect(0, (int)floorf(oldTop), root->docWidth(), (int)ceilf(oldBottom - oldTop));
2910 root->layer()->paint(&context, dirtyRect);
2911 *newBottom = root->bestTruncatedAt();
2912 if (*newBottom == 0)
2913 *newBottom = oldBottom;
2915 *newBottom = oldBottom;
2920 PausedTimeouts *Frame::pauseTimeouts()
2923 if (d->m_doc && d->m_doc->svgExtensions())
2924 d->m_doc->accessSVGExtensions()->pauseAnimations();
2927 if (d->m_doc && d->m_jscript) {
2928 if (Window* w = Window::retrieveWindow(this))
2929 return w->pauseTimeouts();
2934 void Frame::resumeTimeouts(PausedTimeouts* t)
2937 if (d->m_doc && d->m_doc->svgExtensions())
2938 d->m_doc->accessSVGExtensions()->unpauseAnimations();
2941 if (d->m_doc && d->m_jscript && d->m_bJScriptEnabled) {
2942 if (Window* w = Window::retrieveWindow(this))
2943 w->resumeTimeouts(t);
2947 bool Frame::canCachePage()
2949 // Only save page state if:
2950 // 1. We're not a frame or frameset.
2951 // 2. The page has no unload handler.
2952 // 3. The page has no password fields.
2953 // 4. The URL for the page is not https.
2954 // 5. The page has no applets.
2955 if (tree()->childCount() || d->m_plugins.size() ||
2957 d->m_url.protocol().startsWith("https") ||
2958 (d->m_doc && (d->m_doc->applets()->length() != 0 ||
2959 d->m_doc->hasWindowEventListener(unloadEvent) ||
2960 d->m_doc->hasPasswordField()))) {
2966 void Frame::saveWindowProperties(KJS::SavedProperties *windowProperties)
2968 Window *window = Window::retrieveWindow(this);
2970 window->saveProperties(*windowProperties);
2973 void Frame::saveLocationProperties(SavedProperties *locationProperties)
2975 Window *window = Window::retrieveWindow(this);
2978 Location *location = window->location();
2979 location->saveProperties(*locationProperties);
2983 void Frame::restoreWindowProperties(SavedProperties *windowProperties)
2985 Window *window = Window::retrieveWindow(this);
2987 window->restoreProperties(*windowProperties);
2990 void Frame::restoreLocationProperties(SavedProperties *locationProperties)
2992 Window *window = Window::retrieveWindow(this);
2995 Location *location = window->location();
2996 location->restoreProperties(*locationProperties);
3000 void Frame::saveInterpreterBuiltins(SavedBuiltins& interpreterBuiltins)
3003 jScript()->interpreter()->saveBuiltins(interpreterBuiltins);
3006 void Frame::restoreInterpreterBuiltins(const SavedBuiltins& interpreterBuiltins)
3009 jScript()->interpreter()->restoreBuiltins(interpreterBuiltins);
3012 Frame *Frame::frameForWidget(const Widget *widget)
3014 ASSERT_ARG(widget, widget);
3016 Node *node = nodeForWidget(widget);
3018 return frameForNode(node);
3020 // Assume all widgets are either form controls, or FrameViews.
3021 ASSERT(widget->isFrameView());
3022 return static_cast<const FrameView*>(widget)->frame();
3025 Frame *Frame::frameForNode(Node *node)
3027 ASSERT_ARG(node, node);
3028 return node->document()->frame();
3031 Node* Frame::nodeForWidget(const Widget* widget)
3033 ASSERT_ARG(widget, widget);
3034 WidgetClient* client = widget->client();
3037 return client->element(const_cast<Widget*>(widget));
3040 void Frame::clearDocumentFocus(Widget *widget)
3042 Node *node = nodeForWidget(widget);
3044 node->document()->setFocusNode(0);
3047 void Frame::updatePolicyBaseURL()
3049 if (tree()->parent() && tree()->parent()->document())
3050 setPolicyBaseURL(tree()->parent()->document()->policyBaseURL());
3052 setPolicyBaseURL(d->m_url.url());
3055 void Frame::setPolicyBaseURL(const String& s)
3058 document()->setPolicyBaseURL(s);
3059 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
3060 child->setPolicyBaseURL(s);
3063 void Frame::forceLayout()
3065 FrameView *v = d->m_view.get();
3068 // We cannot unschedule a pending relayout, since the force can be called with
3069 // a tiny rectangle from a drawRect update. By unscheduling we in effect
3070 // "validate" and stop the necessary full repaint from occurring. Basically any basic
3071 // append/remove DHTML is broken by this call. For now, I have removed the optimization
3072 // until we have a better invalidation stategy. -dwh
3073 //v->unscheduleRelayout();
3077 void Frame::forceLayoutWithPageWidthRange(float minPageWidth, float maxPageWidth)
3079 // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see
3080 // the state of things before and after the layout
3081 RenderView *root = static_cast<RenderView*>(document()->renderer());
3083 // This magic is basically copied from khtmlview::print
3084 int pageW = (int)ceilf(minPageWidth);
3085 root->setWidth(pageW);
3086 root->setNeedsLayoutAndMinMaxRecalc();
3089 // If we don't fit in the minimum page width, we'll lay out again. If we don't fit in the
3090 // maximum page width, we will lay out to the maximum page width and clip extra content.
3091 // FIXME: We are assuming a shrink-to-fit printing implementation. A cropping
3092 // implementation should not do this!
3093 int rightmostPos = root->rightmostPosition();
3094 if (rightmostPos > minPageWidth) {
3095 pageW = min(rightmostPos, (int)ceilf(maxPageWidth));
3096 root->setWidth(pageW);
3097 root->setNeedsLayoutAndMinMaxRecalc();
3103 void Frame::sendResizeEvent()
3105 if (Document* doc = document())
3106 doc->dispatchWindowEvent(EventNames::resizeEvent, false, false);
3109 void Frame::sendScrollEvent()
3111 FrameView *v = d->m_view.get();
3113 Document *doc = document();
3116 doc->dispatchHTMLEvent(scrollEvent, true, false);
3120 bool Frame::scrollbarsVisible()
3125 if (view()->hScrollBarMode() == ScrollBarAlwaysOff || view()->vScrollBarMode() == ScrollBarAlwaysOff)
3131 void Frame::addMetaData(const String& key, const String& value)
3133 d->m_metaData.set(key, value);
3136 // This does the same kind of work that Frame::openURL does, except it relies on the fact
3137 // that a higher level already checked that the URLs match and the scrolling is the right thing to do.
3138 void Frame::scrollToAnchor(const KURL& URL)
3145 // It's important to model this as a load that starts and immediately finishes.
3146 // Otherwise, the parent frame may think we never finished loading.
3147 d->m_bComplete = false;
3151 bool Frame::closeURL()
3153 saveDocumentState();
3155 clearUndoRedoOperations();
3159 bool Frame::canMouseDownStartSelect(Node* node)
3161 if (!node || !node->renderer())
3164 // Check to see if -webkit-user-select has been set to none
3165 if (!node->renderer()->canSelect())
3168 // Some controls and images can't start a select on a mouse down.
3169 for (RenderObject* curr = node->renderer(); curr; curr = curr->parent()) {
3170 if (curr->style()->userSelect() == SELECT_IGNORE)
3177 void Frame::handleMouseReleaseDoubleClickEvent(const MouseEventWithHitTestResults& event)
3179 passWidgetMouseDownEventToWidget(event, true);
3182 bool Frame::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event, bool isDoubleClick)
3184 // Figure out which view to send the event to.
3185 RenderObject *target = event.targetNode() ? event.targetNode()->renderer() : 0;
3189 Widget* widget = RenderLayer::gScrollBar;
3191 if (!target->isWidget())
3193 widget = static_cast<RenderWidget*>(target)->widget();
3196 // Doubleclick events don't exist in Cocoa. Since passWidgetMouseDownEventToWidget will
3197 // just pass _currentEvent down to the widget, we don't want to call it for events that
3198 // don't correspond to Cocoa events. The mousedown/ups will have already been passed on as
3199 // part of the pressed/released handling.
3201 return passMouseDownEventToWidget(widget);
3205 bool Frame::passWidgetMouseDownEventToWidget(RenderWidget *renderWidget)
3207 return passMouseDownEventToWidget(renderWidget->widget());
3210 void Frame::clearTimers(FrameView *view)
3213 view->unscheduleRelayout();
3214 if (view->frame()) {
3215 Document* document = view->frame()->document();
3216 if (document && document->renderer() && document->renderer()->layer())
3217 document->renderer()->layer()->suspendMarquees();
3222 void Frame::clearTimers()
3224 clearTimers(d->m_view.get());
3227 // FIXME: selection controller?
3228 void Frame::centerSelectionInVisibleArea() const
3232 switch (selection().state()) {
3233 case Selection::NONE:
3236 case Selection::CARET:
3237 rect = selection().caretRect();
3240 case Selection::RANGE:
3241 rect = selectionRect();
3245 Position start = selection().start();
3246 Position end = selection().end();
3247 ASSERT(start.node());
3248 if (start.node() && start.node()->renderer()) {
3249 RenderLayer *layer = start.node()->renderer()->enclosingLayer();
3251 ASSERT(!end.node() || !end.node()->renderer()
3252 || (end.node()->renderer()->enclosingLayer() == layer));
3253 layer->scrollRectToVisible(rect, RenderLayer::gAlignCenterAlways, RenderLayer::gAlignCenterAlways);
3258 RenderStyle *Frame::styleForSelectionStart(Node *&nodeToRemove) const
3264 if (d->m_selection.isNone())
3267 Position pos = VisiblePosition(d->m_selection.start(), d->m_selection.affinity()).deepEquivalent();
3268 if (!pos.inRenderedContent())
3270 Node *node = pos.node();
3274 if (!d->m_typingStyle)
3275 return node->renderer()->style();
3277 ExceptionCode ec = 0;
3278 RefPtr<Element> styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec);
3281 styleElement->setAttribute(styleAttr, d->m_typingStyle->cssText().impl(), ec);
3284 styleElement->appendChild(document()->createEditingTextNode(""), ec);
3287 node->parentNode()->appendChild(styleElement, ec);
3290 nodeToRemove = styleElement.get();
3291 return styleElement->renderer()->style();
3294 void Frame::setMediaType(const String& type)
3297 d->m_view->setMediaType(type);
3300 void Frame::setSelectionFromNone()
3302 // Put a caret inside the body if the entire frame is editable (either the
3303 // entire WebView is editable or designMode is on for this document).
3304 Document *doc = document();
3305 if (!doc || !selection().isNone() || !isContentEditable())
3308 Node* node = doc->documentElement();
3309 while (node && !node->hasTagName(bodyTag))
3310 node = node->traverseNextNode();
3312 setSelection(SelectionController(Position(node, 0), DOWNSTREAM));
3315 bool Frame::isActive() const
3317 return d->m_isActive;
3320 void Frame::setIsActive(bool flag)
3322 if (d->m_isActive == flag)
3325 d->m_isActive = flag;
3327 // This method does the job of updating the view based on whether the view is "active".
3328 // This involves three kinds of drawing updates:
3330 // 1. The background color used to draw behind selected content (active | inactive color)
3332 d->m_view->updateContents(enclosingIntRect(visibleSelectionRect()));
3334 // 2. Caret blinking (blinks | does not blink)
3336 setSelectionFromNone();
3337 setCaretVisible(flag);
3339 // 3. The drawing of a focus ring around links in web pages.
3340 Document *doc = document();
3342 Node *node = doc->focusNode();
3345 if (node->renderer() && node->renderer()->style()->hasAppearance())
3346 theme()->stateChanged(node->renderer(), FocusState);
3350 // 4. Changing the tint of controls from clear to aqua/graphite and vice versa. We
3351 // do a "fake" paint. When the theme gets a paint call, it can then do an invalidate. This is only
3352 // done if the theme supports control tinting.
3353 if (doc && d->m_view && theme()->supportsControlTints() && renderer()) {
3354 doc->updateLayout(); // Ensure layout is up to date.
3355 IntRect visibleRect(enclosingIntRect(d->m_view->visibleContentRect()));
3356 GraphicsContext context((PlatformGraphicsContext*)0);
3357 context.setUpdatingControlTints(true);
3358 paint(&context, visibleRect);
3361 // 5. Enable or disable secure keyboard entry
3362 if ((flag && !isSecureKeyboardEntry() && doc && doc->focusNode() && doc->focusNode()->hasTagName(inputTag) &&
3363 static_cast<HTMLInputElement*>(doc->focusNode())->inputType() == HTMLInputElement::PASSWORD) ||
3364 (!flag && isSecureKeyboardEntry()))
3365 setSecureKeyboardEntry(flag);
3368 void Frame::setWindowHasFocus(bool flag)
3370 if (d->m_windowHasFocus == flag)
3372 d->m_windowHasFocus = flag;
3374 if (Document *doc = document())
3375 doc->dispatchWindowEvent(flag ? focusEvent : blurEvent, false, false);
3378 bool Frame::inViewSourceMode() const
3380 return d->m_inViewSourceMode;
3383 void Frame::setInViewSourceMode(bool mode) const
3385 d->m_inViewSourceMode = mode;
3388 UChar Frame::backslashAsCurrencySymbol() const
3390 Document *doc = document();
3393 Decoder *decoder = doc->decoder();
3397 return decoder->encoding().backslashAsCurrencySymbol();
3400 bool Frame::markedTextUsesUnderlines() const
3402 return d->m_markedTextUsesUnderlines;
3405 DeprecatedValueList<MarkedTextUnderline> Frame::markedTextUnderlines() const
3407 return d->m_markedTextUnderlines;
3410 // Searches from the beginning of the document if nothing is selected.
3411 bool Frame::findString(const String& target, bool forward, bool caseFlag, bool wrapFlag)
3413 if (target.isEmpty())
3416 // Initially search from the start (if forward) or end (if backward) of the selection, and search to edge of document.
3417 RefPtr<Range> searchRange(rangeOfContents(document()));
3418 if (selection().start().node()) {
3420 setStart(searchRange.get(), VisiblePosition(selection().start(), selection().affinity()));
3422 setEnd(searchRange.get(), VisiblePosition(selection().end(), selection().affinity()));
3424 RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, forward, caseFlag));
3425 Selection sel = selection().selection();
3426 // If the found range is already selected, find again.
3427 // Build a selection with the found range to remove collapsed whitespace.
3428 // Compare ranges instead of selection objects to ignore the way that the current selection was made.
3429 if (!sel.isNone() && *Selection(resultRange.get()).toRange() == *sel.toRange()) {
3430 searchRange = rangeOfContents(document());
3432 setStart(searchRange.get(), VisiblePosition(sel.end(), sel.affinity()));
3434 setEnd(searchRange.get(), VisiblePosition(sel.start(), sel.affinity()));
3435 resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
3440 // If we didn't find anything and we're wrapping, search again in the entire document (this will
3441 // redundantly re-search the area already searched in some cases).
3442 if (resultRange->collapsed(exception) && wrapFlag) {
3443 searchRange = rangeOfContents(document());
3444 resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
3445 // We used to return false here if we ended up with the same range that we started with
3446 // (e.g., the selection was already the only instance of this text). But we decided that
3447 // this should be a success case instead, so we'll just fall through in that case.
3450 if (resultRange->collapsed(exception))
3453 setSelection(SelectionController(resultRange.get(), DOWNSTREAM));
3458 unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag)
3460 if (target.isEmpty())
3463 RefPtr<Range> searchRange(rangeOfContents(document()));
3466 unsigned matchCount = 0;
3468 RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, caseFlag));
3469 if (resultRange->collapsed(exception))
3472 // A non-collapsed result range can in some funky whitespace cases still not
3473 // advance the range's start position (4509328). Break to avoid infinite loop.
3474 VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
3475 if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
3479 document()->addMarker(resultRange.get(), DocumentMarker::TextMatch);
3481 setStart(searchRange.get(), newStart);
3484 // Do a "fake" paint in order to execute the code that computes the rendered rect for
3486 Document* doc = document();
3487 if (doc && d->m_view && renderer()) {
3488 doc->updateLayout(); // Ensure layout is up to date.
3489 IntRect visibleRect(enclosingIntRect(d->m_view->visibleContentRect()));
3490 GraphicsContext context((PlatformGraphicsContext*)0);
3491 context.setPaintingDisabled(true);
3492 paint(&context, visibleRect);
3498 bool Frame::markedTextMatchesAreHighlighted() const
3500 return d->m_highlightTextMatches;
3503 void Frame::setMarkedTextMatchesAreHighlighted(bool flag)
3505 if (flag == d->m_highlightTextMatches)
3508 d->m_highlightTextMatches = flag;
3509 document()->repaintMarkers(DocumentMarker::TextMatch);
3512 void Frame::prepareForUserAction()
3514 // Reset the multiple form submission protection code.
3515 // We'll let you submit the same form twice if you do two separate user actions.
3516 d->m_submittedFormURL = KURL();
3519 Node *Frame::mousePressNode()
3521 return d->m_mousePressNode.get();
3524 bool Frame::isComplete() const
3526 return d->m_bComplete;
3529 bool Frame::isLoadingMainResource() const
3531 return d->m_bLoadingMainResource;
3534 FrameTree* Frame::tree() const
3536 return &d->m_treeNode;
3539 DOMWindow* Frame::domWindow() const
3541 if (!d->m_domWindow)
3542 d->m_domWindow = new DOMWindow(const_cast<Frame*>(this));
3544 return d->m_domWindow.get();
3547 KURL Frame::url() const
3552 void Frame::startRedirectionTimer()
3554 d->m_redirectionTimer.startOneShot(d->m_delayRedirect);
3557 void Frame::stopRedirectionTimer()
3559 d->m_redirectionTimer.stop();
3562 void Frame::frameDetached()
3566 void Frame::updateBaseURLForEmptyDocument()
3568 Element* owner = ownerElement();
3569 // FIXME: Should embed be included?
3570 if (owner && (owner->hasTagName(iframeTag) || owner->hasTagName(objectTag) || owner->hasTagName(embedTag)))
3571 d->m_doc->setBaseURL(tree()->parent()->d->m_doc->baseURL());
3574 Page* Frame::page() const
3579 void Frame::pageDestroyed()
3583 // This will stop any JS timers
3584 if (d->m_jscript && d->m_jscript->haveInterpreter())
3585 if (Window* w = Window::retrieveWindow(this))
3586 w->disconnectFrame();
3589 void Frame::completed(bool complete)
3592 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
3593 child->parentCompleted();
3594 if (Frame* parent = tree()->parent())
3595 parent->childCompleted(complete);
3600 void Frame::setStatusBarText(const String&)
3604 void Frame::started()
3606 for (Frame* frame = this; frame; frame = frame->tree()->parent())
3607 frame->d->m_bComplete = false;
3610 void Frame::disconnectOwnerElement()
3612 if (d->m_ownerElement)
3613 d->m_page->decrementFrameCount();
3615 d->m_ownerElement = 0;
3618 String Frame::documentTypeString() const
3620 if (Document *doc = document())
3621 if (DocumentType *doctype = doc->realDocType())
3622 return doctype->toString();
3627 bool Frame::containsPlugins() const
3629 return d->m_plugins.size() != 0;
3632 bool Frame::prohibitsScrolling() const
3634 return d->m_prohibitsScrolling;
3637 void Frame::setProhibitsScrolling(const bool prohibit)
3639 d->m_prohibitsScrolling = prohibit;
3642 } // namespace WebCore