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 "FrameLoadRequest.h"
49 #include "GraphicsContext.h"
50 #include "HTMLFormElement.h"
51 #include "HTMLFrameElement.h"
52 #include "HTMLGenericFormElement.h"
53 #include "HTMLInputElement.h"
54 #include "HTMLNames.h"
55 #include "HTMLObjectElement.h"
56 #include "HTMLViewSourceDocument.h"
57 #include "ImageDocument.h"
58 #include "IndentOutdentCommand.h"
59 #include "loader/icon/IconDatabase.h"
60 #include "loader/icon/IconLoader.h"
61 #include "MediaFeatureNames.h"
62 #include "MouseEventWithHitTestResults.h"
65 #include "PlatformScrollBar.h"
66 #include "PlugInInfoStore.h"
68 #include "PluginDocument.h"
69 #include "RenderListBox.h"
70 #include "RenderPart.h"
71 #include "RenderTextControl.h"
72 #include "RenderTheme.h"
73 #include "RenderView.h"
74 #include "SegmentedString.h"
75 #include "TextDocument.h"
76 #include "TextIterator.h"
77 #include "TypingCommand.h"
78 #include "XMLTokenizer.h"
79 #include "cssstyleselector.h"
80 #include "htmlediting.h"
81 #include "kjs_window.h"
83 #include "visible_units.h"
84 #include "xmlhttprequest.h"
86 #include <sys/types.h>
87 #include <wtf/Platform.h>
99 #include "XLinkNames.h"
100 #include "XMLNames.h"
101 #include "SVGDocument.h"
102 #include "SVGDocumentExtensions.h"
110 using KJS::PausedTimeouts;
111 using KJS::SavedProperties;
112 using KJS::SavedBuiltins;
118 using namespace EventNames;
119 using namespace HTMLNames;
121 const double caretBlinkFrequency = 0.5;
122 const double autoscrollInterval = 0.1;
124 class UserStyleSheetLoader : public CachedResourceClient {
126 UserStyleSheetLoader(Frame* frame, const String& url, DocLoader* docLoader)
128 , m_cachedSheet(docLoader->requestCSSStyleSheet(url, ""))
130 m_cachedSheet->ref(this);
132 ~UserStyleSheetLoader()
134 m_cachedSheet->deref(this);
137 virtual void setCSSStyleSheet(const String& /*URL*/, const String& /*charset*/, const String& sheet)
139 m_frame->setUserStyleSheet(sheet);
142 CachedCSSStyleSheet* m_cachedSheet;
146 struct FrameCounter {
148 ~FrameCounter() { if (count != 0) fprintf(stderr, "LEAK: %d Frame\n", count); }
150 int FrameCounter::count = 0;
151 static FrameCounter frameCounter;
154 static inline Frame* parentFromOwnerElement(Element* ownerElement)
158 return ownerElement->document()->frame();
161 Frame::Frame(Page* page, Element* ownerElement)
162 : d(new FramePrivate(page, parentFromOwnerElement(ownerElement), this, ownerElement))
164 AtomicString::init();
167 QualifiedName::init();
168 MediaFeatureNames::init();
176 if (d->m_ownerElement)
177 d->m_page->incrementFrameCount();
179 // FIXME: Frames were originally created with a refcount of 1, leave this
180 // ref call here until we can straighten that out.
183 ++FrameCounter::count;
189 // FIXME: We should not be doing all this work inside the destructor
191 ASSERT(!d->m_lifeSupportTimer.isActive());
194 --FrameCounter::count;
197 if (d->m_jscript && d->m_jscript->haveInterpreter())
198 if (Window* w = Window::retrieveWindow(this)) {
199 w->disconnectFrame();
200 // Must clear the window pointer, otherwise we will not
201 // garbage-collect collect the window (inside the call to
206 disconnectOwnerElement();
209 d->m_domWindow->disconnectFrame();
212 HashSet<Frame*> openedBy = d->m_openedFrames;
213 HashSet<Frame*>::iterator end = openedBy.end();
214 for (HashSet<Frame*>::iterator it = openedBy.begin(); it != end; ++it)
219 d->m_view->m_frame = 0;
222 ASSERT(!d->m_lifeSupportTimer.isActive());
224 delete d->m_userStyleSheetLoader;
229 KURL Frame::iconURL()
231 // If this isn't a top level frame, return nothing
232 if (tree() && tree()->parent())
235 // If we have an iconURL from a Link element, return that
236 if (document() && !document()->iconURL().isEmpty())
237 return KURL(document()->iconURL().deprecatedString());
239 // Don't return a favicon iconURL unless we're http or https
240 if (d->m_url.protocol() != "http" && d->m_url.protocol() != "https")
244 url.setProtocol(d->m_url.protocol());
245 url.setHost(d->m_url.host());
246 url.setPath("/favicon.ico");
250 bool Frame::didOpenURL(const KURL& url)
252 if (d->m_scheduledRedirection == locationChangeScheduledDuringLoad) {
253 // A redirect was shceduled before the document was created. This can happen
254 // when one frame changes another frame's location.
260 // clear last edit command
261 d->m_lastEditCommand = 0;
265 d->m_bComplete = false;
266 d->m_bLoadingMainResource = true;
267 d->m_bLoadEventEmitted = false;
269 d->m_kjsStatusBarText = String();
270 d->m_kjsDefaultStatusBarText = String();
272 d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled();
273 d->m_bJavaEnabled = d->m_settings->isJavaEnabled();
274 d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled();
276 // 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
277 // data arrives) (Simon)
279 if (d->m_url.protocol().startsWith("http") && !d->m_url.host().isEmpty() && d->m_url.path().isEmpty())
280 d->m_url.setPath("/");
281 d->m_workingURL = d->m_url;
288 void Frame::didExplicitOpen()
290 d->m_bComplete = false;
291 d->m_bLoadEventEmitted = false;
293 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
294 // from a subsequent window.document.open / window.document.write call.
295 // Cancelling redirection here works for all cases because document.open
296 // implicitly precedes document.write.
298 d->m_url = d->m_doc->URL();
301 void Frame::stopLoading(bool sendUnload)
303 if (d->m_doc && d->m_doc->tokenizer())
304 d->m_doc->tokenizer()->stopParsing();
306 d->m_metaData.clear();
310 if (d->m_bLoadEventEmitted && !d->m_bUnloadEventEmitted) {
311 Node* currentFocusNode = d->m_doc->focusNode();
312 if (currentFocusNode)
313 currentFocusNode->aboutToUnload();
314 d->m_doc->dispatchWindowEvent(unloadEvent, false, false);
316 d->m_doc->updateRendering();
317 d->m_bUnloadEventEmitted = true;
321 if (d->m_doc && !d->m_doc->inPageCache())
322 d->m_doc->removeAllEventListenersFromAllNodes();
325 d->m_bComplete = true; // to avoid calling completed() in finishedParsing() (David)
326 d->m_bLoadingMainResource = false;
327 d->m_bLoadEventEmitted = true; // don't want that one either
328 d->m_cachePolicy = CachePolicyVerify; // Why here?
330 if (d->m_doc && d->m_doc->parsing()) {
332 d->m_doc->setParsing(false);
335 d->m_workingURL = KURL();
337 if (Document *doc = d->m_doc.get()) {
338 if (DocLoader *docLoader = doc->docLoader())
339 cache()->loader()->cancelRequests(docLoader);
340 XMLHttpRequest::cancelRequests(doc);
343 // tell all subframes to stop as well
344 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
345 child->stopLoading(sendUnload);
347 d->m_bPendingChildRedirection = false;
352 BrowserExtension *Frame::browserExtension() const
354 return d->m_extension;
357 FrameView* Frame::view() const
359 return d->m_view.get();
362 void Frame::setView(FrameView* view)
364 // Detach the document now, so any onUnload handlers get run - if
365 // we wait until the view is destroyed, then things won't be
366 // hooked up enough for some JavaScript calls to work.
367 if (d->m_doc && view == 0)
373 bool Frame::jScriptEnabled() const
375 return d->m_bJScriptEnabled;
378 KJSProxy *Frame::jScript()
380 if (!d->m_bJScriptEnabled)
384 d->m_jscript = new KJSProxy(this);
389 static bool getString(JSValue* result, String& string)
395 if (!result->getString(ustring))
401 void Frame::replaceContentsWithScriptResult(const KURL& url)
403 JSValue* ret = executeScript(0, KURL::decode_string(url.url().mid(strlen("javascript:"))));
405 if (getString(ret, scriptResult)) {
412 JSValue* Frame::executeScript(Node* n, const String& script, bool forceUserGesture)
414 KJSProxy *proxy = jScript();
419 d->m_runningScripts++;
420 // If forceUserGesture is true, then make the script interpreter
421 // treat it as if triggered by a user gesture even if there is no
422 // current DOM event being processed.
423 JSValue* ret = proxy->evaluate(forceUserGesture ? DeprecatedString::null : d->m_url.url(), 0, script, n);
424 d->m_runningScripts--;
426 if (!d->m_runningScripts)
429 Document::updateDocumentsRendering();
434 bool Frame::javaEnabled() const
436 return d->m_settings->isJavaEnabled();
439 bool Frame::pluginsEnabled() const
441 return d->m_bPluginsEnabled;
444 void Frame::setAutoLoadImages(bool enable)
446 if (d->m_doc && d->m_doc->docLoader()->autoLoadImages() == enable)
450 d->m_doc->docLoader()->setAutoLoadImages(enable);
453 bool Frame::autoLoadImages() const
456 return d->m_doc->docLoader()->autoLoadImages();
461 void Frame::cancelAndClear()
471 void Frame::clear(bool clearWindowProperties)
475 d->m_bCleared = true;
476 d->m_mousePressNode = 0;
479 // FIXME: This is a temporary hack to work around a mismatch between WebCore and WebKit
480 // regarding frame lifetime. The proper solution is to move all frame management
481 // into WebCore, so frames can work the same way on all platforms.
486 d->m_doc->cancelParsing();
490 // Moving past doc so that onUnload works.
491 if (clearWindowProperties && d->m_jscript)
492 d->m_jscript->clear();
497 // do not drop the document before the jscript and view are cleared, as some destructors
498 // might still try to access the document.
502 d->m_plugins.clear();
503 cleanupPluginObjects();
505 d->m_scheduledRedirection = noRedirectionScheduled;
506 d->m_delayRedirect = 0;
507 d->m_redirectURL = DeprecatedString::null;
508 d->m_redirectReferrer = String();
509 d->m_redirectLockHistory = true;
510 d->m_redirectUserGesture = false;
511 d->m_bHTTPRefresh = false;
512 d->m_bFirstData = true;
514 d->m_bMousePressed = false;
516 if (!d->m_haveEncoding)
517 d->m_encoding = String();
520 Document *Frame::document() const
523 return d->m_doc.get();
527 void Frame::setDocument(Document* newDoc)
538 void Frame::receivedFirstData()
540 begin(d->m_workingURL);
542 d->m_doc->docLoader()->setCachePolicy(d->m_cachePolicy);
543 d->m_workingURL = KURL();
545 // When the first data arrives, the metadata has just been made available
546 DeprecatedString qData;
548 // Support for http-refresh
549 qData = d->m_metaData.get("http-refresh").deprecatedString();
550 if (!qData.isEmpty()) {
552 int pos = qData.find(';');
554 pos = qData.find(',');
557 delay = qData.stripWhiteSpace().toDouble();
558 // We want a new history item if the refresh timeout > 1 second
559 scheduleRedirection(delay, d->m_url.url(), delay <= 1);
561 int end_pos = qData.length();
562 delay = qData.left(pos).stripWhiteSpace().toDouble();
563 while (qData[++pos] == ' ');
564 if (qData.find("url", pos, false) == pos) {
566 while (qData[pos] == ' ' || qData[pos] == '=')
568 if (qData[pos] == '"') {
570 int index = end_pos-1;
571 while (index > pos) {
572 if (qData[index] == '"')
580 // We want a new history item if the refresh timeout > 1 second
581 scheduleRedirection(delay, d->m_doc->completeURL(qData.mid(pos, end_pos)), delay <= 1);
583 d->m_bHTTPRefresh = true;
586 // Support for http last-modified
587 d->m_lastModified = d->m_metaData.get("modified");
590 void Frame::childBegin()
592 // We need to do this when the child is created so as to avoid the parent thining the child
593 // is complete before it has even started loading.
594 // FIXME: do we really still need this?
595 d->m_bComplete = false;
598 void Frame::setResponseMIMEType(const String& contentType)
600 d->m_responseMIMEType = contentType;
603 const String& Frame::responseMIMEType() const
605 return d->m_responseMIMEType;
608 void Frame::begin(const KURL& url)
610 if (d->m_workingURL.isEmpty())
611 createEmptyDocument(); // Creates an empty document if we don't have one already
614 partClearedInBegin();
616 d->m_bCleared = false;
617 d->m_bComplete = false;
618 d->m_bLoadEventEmitted = false;
619 d->m_bLoadingMainResource = true;
622 ref.setUser(DeprecatedString());
623 ref.setPass(DeprecatedString());
624 ref.setRef(DeprecatedString());
625 d->m_referrer = ref.url();
629 // We don't need KDE chained URI handling or window caption setting
630 if (!d->m_url.isEmpty())
634 if (d->m_responseMIMEType == "image/svg+xml")
635 d->m_doc = DOMImplementation::instance()->createSVGDocument(d->m_view.get());
638 if (DOMImplementation::isXMLMIMEType(d->m_responseMIMEType))
639 d->m_doc = DOMImplementation::instance()->createDocument(d->m_view.get());
640 else if (DOMImplementation::isTextMIMEType(d->m_responseMIMEType))
641 d->m_doc = new TextDocument(DOMImplementation::instance(), d->m_view.get());
642 else if ((d->m_responseMIMEType == "application/pdf" || d->m_responseMIMEType == "text/pdf") && PlugInInfoStore::supportsMIMEType(d->m_responseMIMEType))
643 d->m_doc = new PluginDocument(DOMImplementation::instance(), d->m_view.get());
644 else if (Image::supportsType(d->m_responseMIMEType))
645 d->m_doc = new ImageDocument(DOMImplementation::instance(), d->m_view.get());
646 else if (PlugInInfoStore::supportsMIMEType(d->m_responseMIMEType))
647 d->m_doc = new PluginDocument(DOMImplementation::instance(), d->m_view.get());
648 else if (inViewSourceMode())
649 d->m_doc = new HTMLViewSourceDocument(DOMImplementation::instance(), d->m_view.get());
651 d->m_doc = DOMImplementation::instance()->createHTMLDocument(d->m_view.get());
653 if (!d->m_doc->attached())
655 d->m_doc->setURL(d->m_url.url());
656 // We prefer m_baseURL over d->m_url because d->m_url changes when we are
657 // about to load a new page.
658 d->m_doc->setBaseURL(baseurl.url());
660 d->m_doc->setDecoder(d->m_decoder.get());
662 updatePolicyBaseURL();
664 setAutoLoadImages(d->m_settings->autoLoadImages());
665 const KURL& userStyleSheet = d->m_settings->userStyleSheetLocation();
667 if (!userStyleSheet.isEmpty())
668 setUserStyleSheetLocation(KURL(userStyleSheet));
670 restoreDocumentState();
672 d->m_doc->implicitOpen();
675 d->m_view->resizeContents(0, 0);
678 void Frame::write(const char* str, int len)
686 if (Tokenizer* t = d->m_doc->tokenizer()) {
687 if (t->wantsRawData()) {
688 t->writeRawData(str, len);
694 d->m_decoder = new Decoder(d->m_responseMIMEType, settings()->encoding());
695 if (!d->m_encoding.isNull())
696 d->m_decoder->setEncoding(d->m_encoding,
697 d->m_haveEncoding ? Decoder::UserChosenEncoding : Decoder::EncodingFromHTTPHeader);
699 d->m_doc->setDecoder(d->m_decoder.get());
702 String decoded = d->m_decoder->decode(str, len);
704 if (decoded.isEmpty())
707 if (d->m_bFirstData) {
708 d->m_bFirstData = false;
709 d->m_doc->determineParseMode(decoded);
710 if (d->m_decoder->encoding().usesVisualOrdering())
711 d->m_doc->setVisuallyOrdered();
712 d->m_doc->recalcStyle(Node::Force);
715 if (Tokenizer* t = d->m_doc->tokenizer()) {
716 ASSERT(!t->wantsRawData());
717 t->write(decoded, true);
721 void Frame::write(const String& str)
726 if (d->m_bFirstData) {
727 // determine the parse mode
728 d->m_doc->setParseMode(Document::Strict);
729 d->m_bFirstData = false;
731 Tokenizer* t = d->m_doc->tokenizer();
738 d->m_bLoadingMainResource = false;
742 void Frame::endIfNotLoading()
744 // http://bugzilla.opendarwin.org/show_bug.cgi?id=10854
745 // The frame's last ref may be remove and it be deleted by checkCompleted(),
746 // so we'll add a protective refcount
747 RefPtr<Frame> protector(this);
749 if (d->m_bLoadingMainResource)
752 // make sure nothing's left in there...
755 String decoded = d->m_decoder->flush();
756 if (d->m_bFirstData) {
757 d->m_bFirstData = false;
758 d->m_doc->determineParseMode(decoded);
762 d->m_doc->finishParsing();
764 // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but
765 // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
766 // become true. An example is when a subframe is a pure text doc, and that subframe is the
767 // last one to complete.
770 // FIXME - Right now, we kick off the icon loader when the frame is done receiving all its main resource.
771 // We could kick off the icon loader after we're done parsing the HEAD element, if that becomes convinient to find
774 // Don't load an icon if -
775 // 1) This is not the main frame
776 // 2) The database is disabled
777 // 3) We have no valid icon URL
778 // 4) We already have an unexpired icon
780 if (tree()->parent())
784 if (IconDatabase* sharedIconDatabase = IconDatabase::sharedIconDatabase()) {
785 if (!sharedIconDatabase->enabled())
788 String url(iconURL().url());
792 // If we already have an unexpired icon, we won't kick off a load but we *will* map the appropriate URLs to it
793 if (sharedIconDatabase->hasEntryForIconURL(url) && !isLoadTypeReload() && !sharedIconDatabase->isIconExpiredForIconURL(url)) {
794 commitIconURLToIconDatabase();
798 if (!d->m_iconLoader)
799 d->m_iconLoader = IconLoader::createForFrame(this);
800 d->m_iconLoader->startLoading();
804 void Frame::commitIconURLToIconDatabase()
806 KURL icon = iconURL();
808 IconDatabase* iconDatabase = IconDatabase::sharedIconDatabase();
809 ASSERT(iconDatabase);
810 iconDatabase->setIconURLForPageURL(icon.url(), this->url().url());
811 iconDatabase->setIconURLForPageURL(icon.url(), originalRequestURL().url());
816 // http://bugzilla.opendarwin.org/show_bug.cgi?id=10854
817 // The frame's last ref may be remove and it be deleted by checkCompleted(),
818 // so we'll add a protective refcount
819 RefPtr<Frame> protector(this);
822 if (d->m_doc->tokenizer())
823 d->m_doc->tokenizer()->stopParsing();
824 d->m_doc->finishParsing();
826 // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but
827 // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
828 // become true. An example is when a subframe is a pure text doc, and that subframe is the
829 // last one to complete.
832 d->m_iconLoader->stopLoading();
835 void Frame::gotoAnchor()
837 // If our URL has no ref, then we have no place we need to jump to.
838 if (!d->m_url.hasRef())
841 DeprecatedString ref = d->m_url.encodedHtmlRef();
842 if (!gotoAnchor(ref)) {
843 // Can't use htmlRef() here because it doesn't know which encoding to use to decode.
844 // Decoding here has to match encoding in completeURL, which means it has to use the
845 // page's encoding rather than UTF-8.
847 gotoAnchor(KURL::decode_string(ref, d->m_decoder->encoding()));
851 void Frame::finishedParsing()
853 // This method can be called from our destructor, in which case we shouldn't protect ourselves
854 // because doing so will cause us to re-enter our destructor when protector goes out of scope.
855 RefPtr<Frame> protector = refCount() > 0 ? this : 0;
859 return; // We are being destroyed by something checkCompleted called.
861 // check if the scrollbars are really needed for the content
862 // if not, remove them, relayout, and repaint
864 d->m_view->restoreScrollbar();
868 void Frame::loadDone()
874 void Frame::checkCompleted()
876 // Any frame that hasn't completed yet ?
877 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
878 if (!child->d->m_bComplete)
881 // Have we completed before?
885 // Are we still parsing?
886 if (d->m_doc && d->m_doc->parsing())
889 // Still waiting for images/scripts from the loader ?
891 if (d->m_doc && d->m_doc->docLoader())
892 requests = cache()->loader()->numRequests(d->m_doc->docLoader());
898 // Now do what should be done when we are really completed.
899 d->m_bComplete = true;
901 checkEmitLoadEvent(); // if we didn't do it before
903 if (d->m_scheduledRedirection != noRedirectionScheduled) {
904 // Do not start redirection for frames here! That action is
905 // deferred until the parent emits a completed signal.
906 if (!tree()->parent())
907 startRedirectionTimer();
911 completed(d->m_bPendingChildRedirection);
915 void Frame::checkEmitLoadEvent()
917 if (d->m_bLoadEventEmitted || !d->m_doc || d->m_doc->parsing())
920 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
921 if (!child->d->m_bComplete) // still got a frame running -> too early
924 // All frames completed -> set their domain to the frameset's domain
925 // This must only be done when loading the frameset initially (#22039),
926 // not when following a link in a frame (#44162).
928 String domain = d->m_doc->domain();
929 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
931 child->d->m_doc->setDomain(domain);
934 d->m_bLoadEventEmitted = true;
935 d->m_bUnloadEventEmitted = false;
937 d->m_doc->implicitClose();
940 const Settings *Frame::settings() const
942 return d->m_settings;
945 KURL Frame::baseURL() const
949 return d->m_doc->baseURL();
952 String Frame::baseTarget() const
956 return d->m_doc->baseTarget();
959 KURL Frame::completeURL(const DeprecatedString& url)
964 return KURL(d->m_doc->completeURL(url));
967 void Frame::scheduleRedirection(double delay, const DeprecatedString& url, bool doLockHistory)
969 if (delay < 0 || delay > INT_MAX / 1000)
971 if (d->m_scheduledRedirection == noRedirectionScheduled || delay <= d->m_delayRedirect)
973 d->m_scheduledRedirection = redirectionScheduled;
974 d->m_delayRedirect = delay;
975 d->m_redirectURL = url;
976 d->m_redirectReferrer = String();
977 d->m_redirectLockHistory = doLockHistory;
978 d->m_redirectUserGesture = false;
980 stopRedirectionTimer();
982 startRedirectionTimer();
986 void Frame::scheduleLocationChange(const DeprecatedString& url, const String& referrer, bool lockHistory, bool userGesture)
990 // If the URL we're going to navigate to is the same as the current one, except for the
991 // fragment part, we don't need to schedule the location change.
992 if (u.hasRef() && equalIgnoringRef(d->m_url, u)) {
993 changeLocation(url, referrer, lockHistory, userGesture);
997 // Handle a location change of a page with no document as a special case.
998 // This may happen when a frame changes the location of another frame.
999 d->m_scheduledRedirection = d->m_doc ? locationChangeScheduled : locationChangeScheduledDuringLoad;
1001 // If a redirect was scheduled during a load, then stop the current load.
1002 // Otherwise when the current load transitions from a provisional to a
1003 // committed state, pending redirects may be cancelled.
1004 if (d->m_scheduledRedirection == locationChangeScheduledDuringLoad) {
1008 d->m_delayRedirect = 0;
1009 d->m_redirectURL = url;
1010 d->m_redirectReferrer = referrer;
1011 d->m_redirectLockHistory = lockHistory;
1012 d->m_redirectUserGesture = userGesture;
1013 stopRedirectionTimer();
1015 startRedirectionTimer();
1018 void Frame::scheduleRefresh(bool userGesture)
1020 // Handle a location change of a page with no document as a special case.
1021 // This may happen when a frame requests a refresh of another frame.
1022 d->m_scheduledRedirection = d->m_doc ? locationChangeScheduled : locationChangeScheduledDuringLoad;
1024 // If a refresh was scheduled during a load, then stop the current load.
1025 // Otherwise when the current load transitions from a provisional to a
1026 // committed state, pending redirects may be cancelled.
1027 if (d->m_scheduledRedirection == locationChangeScheduledDuringLoad)
1030 d->m_delayRedirect = 0;
1031 d->m_redirectURL = url().url();
1032 d->m_redirectReferrer = referrer();
1033 d->m_redirectLockHistory = true;
1034 d->m_redirectUserGesture = userGesture;
1035 d->m_cachePolicy = CachePolicyRefresh;
1036 stopRedirectionTimer();
1038 startRedirectionTimer();
1041 bool Frame::isScheduledLocationChangePending() const
1043 switch (d->m_scheduledRedirection) {
1044 case noRedirectionScheduled:
1045 case redirectionScheduled:
1047 case historyNavigationScheduled:
1048 case locationChangeScheduled:
1049 case locationChangeScheduledDuringLoad:
1055 void Frame::scheduleHistoryNavigation(int steps)
1057 // navigation will always be allowed in the 0 steps case, which is OK because
1058 // that's supposed to force a reload.
1059 if (!canGoBackOrForward(steps)) {
1060 cancelRedirection();
1064 // If the URL we're going to navigate to is the same as the current one, except for the
1065 // fragment part, we don't need to schedule the navigation.
1066 if (d->m_extension) {
1067 KURL u = d->m_extension->historyURL(steps);
1069 if (equalIgnoringRef(d->m_url, u)) {
1070 d->m_extension->goBackOrForward(steps);
1075 d->m_scheduledRedirection = historyNavigationScheduled;
1076 d->m_delayRedirect = 0;
1077 d->m_redirectURL = DeprecatedString::null;
1078 d->m_redirectReferrer = String();
1079 d->m_scheduledHistoryNavigationSteps = steps;
1080 stopRedirectionTimer();
1082 startRedirectionTimer();
1085 void Frame::cancelRedirection(bool cancelWithLoadInProgress)
1088 d->m_cancelWithLoadInProgress = cancelWithLoadInProgress;
1089 d->m_scheduledRedirection = noRedirectionScheduled;
1090 stopRedirectionTimer();
1094 void Frame::changeLocation(const DeprecatedString& URL, const String& referrer, bool lockHistory, bool userGesture)
1096 if (URL.find("javascript:", 0, false) == 0) {
1097 String script = KURL::decode_string(URL.mid(11));
1098 JSValue* result = executeScript(0, script, userGesture);
1099 String scriptResult;
1100 if (getString(result, scriptResult)) {
1102 write(scriptResult);
1108 ResourceRequestCachePolicy policy = (d->m_cachePolicy == CachePolicyReload) || (d->m_cachePolicy == CachePolicyRefresh) ? ReloadIgnoringCacheData : UseProtocolCachePolicy;
1109 ResourceRequest request(completeURL(URL), referrer, policy);
1111 urlSelected(request, "_self", 0, lockHistory);
1114 void Frame::redirectionTimerFired(Timer<Frame>*)
1116 if (d->m_scheduledRedirection == historyNavigationScheduled) {
1117 d->m_scheduledRedirection = noRedirectionScheduled;
1119 // Special case for go(0) from a frame -> reload only the frame
1120 // go(i!=0) from a frame navigates into the history of the frame only,
1121 // in both IE and NS (but not in Mozilla).... we can't easily do that
1123 if (d->m_scheduledHistoryNavigationSteps == 0) // add && parent() to get only frames, but doesn't matter
1124 openURL(url()); /// ## need args.reload=true?
1126 if (d->m_extension) {
1127 d->m_extension->goBackOrForward(d->m_scheduledHistoryNavigationSteps);
1133 DeprecatedString URL = d->m_redirectURL;
1134 String referrer = d->m_redirectReferrer;
1135 bool lockHistory = d->m_redirectLockHistory;
1136 bool userGesture = d->m_redirectUserGesture;
1138 d->m_scheduledRedirection = noRedirectionScheduled;
1139 d->m_delayRedirect = 0;
1140 d->m_redirectURL = DeprecatedString::null;
1141 d->m_redirectReferrer = String();
1143 changeLocation(URL, referrer, lockHistory, userGesture);
1146 String Frame::encoding() const
1148 if (d->m_haveEncoding && !d->m_encoding.isEmpty())
1149 return d->m_encoding;
1150 if (d->m_decoder && d->m_decoder->encoding().isValid())
1151 return d->m_decoder->encoding().name();
1152 return settings()->encoding();
1155 void Frame::setUserStyleSheetLocation(const KURL& url)
1157 delete d->m_userStyleSheetLoader;
1158 d->m_userStyleSheetLoader = 0;
1159 if (d->m_doc && d->m_doc->docLoader())
1160 d->m_userStyleSheetLoader = new UserStyleSheetLoader(this, url.url(), d->m_doc->docLoader());
1163 void Frame::setUserStyleSheet(const String& styleSheet)
1165 delete d->m_userStyleSheetLoader;
1166 d->m_userStyleSheetLoader = 0;
1168 d->m_doc->setUserStyleSheet(styleSheet);
1171 bool Frame::gotoAnchor(const String& name)
1176 Node *n = d->m_doc->getElementById(AtomicString(name));
1178 n = d->m_doc->anchors()->namedItem(name, !d->m_doc->inCompatMode());
1180 d->m_doc->setCSSTarget(n); // Setting to null will clear the current target.
1182 // Implement the rule that "" and "top" both mean top of page as in other browsers.
1183 if (!n && !(name.isEmpty() || name.lower() == "top"))
1186 // We need to update the layout before scrolling, otherwise we could
1187 // really mess things up if an anchor scroll comes at a bad moment.
1189 d->m_doc->updateRendering();
1190 // Only do a layout if changes have occurred that make it necessary.
1191 if (d->m_view && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout()) {
1192 d->m_view->layout();
1196 // Scroll nested layers and frames to reveal the anchor.
1197 RenderObject *renderer;
1200 renderer = n->renderer();
1201 rect = n->getRect();
1203 // If there's no node, we should scroll to the top of the document.
1204 renderer = d->m_doc->renderer();
1209 // Align to the top and to the closest side (this matches other browsers).
1210 renderer->enclosingLayer()->scrollRectToVisible(rect, RenderLayer::gAlignToEdgeIfNeeded, RenderLayer::gAlignTopAlways);
1216 void Frame::setStandardFont(const String& name)
1218 d->m_settings->setStdFontName(AtomicString(name));
1221 void Frame::setFixedFont(const String& name)
1223 d->m_settings->setFixedFontName(AtomicString(name));
1226 String Frame::selectedText() const
1228 return plainText(selectionController()->toRange().get());
1231 bool Frame::hasSelection() const
1233 return selectionController()->isCaretOrRange();
1236 SelectionController* Frame::selectionController() const
1238 return &(d->m_selectionController);
1241 CommandByName* Frame::command() const
1243 return &(d->m_command);
1246 TextGranularity Frame::selectionGranularity() const
1248 return d->m_selectionGranularity;
1251 void Frame::setSelectionGranularity(TextGranularity granularity) const
1253 d->m_selectionGranularity = granularity;
1256 SelectionController* Frame::dragCaretController() const
1258 return d->m_page->dragCaretController();
1261 const Selection& Frame::mark() const
1266 void Frame::setMark(const Selection& s)
1268 ASSERT(!s.base().node() || s.base().node()->document() == document());
1269 ASSERT(!s.extent().node() || s.extent().node()->document() == document());
1270 ASSERT(!s.start().node() || s.start().node()->document() == document());
1271 ASSERT(!s.end().node() || s.end().node()->document() == document());
1276 void Frame::notifyRendererOfSelectionChange(bool userTriggered)
1278 RenderObject* renderer = 0;
1279 if (selectionController()->rootEditableElement())
1280 renderer = selectionController()->rootEditableElement()->shadowAncestorNode()->renderer();
1282 // If the current selection is in a textfield or textarea, notify the renderer that the selection has changed
1283 if (renderer && (renderer->isTextArea() || renderer->isTextField()))
1284 static_cast<RenderTextControl*>(renderer)->selectionChanged(userTriggered);
1287 void Frame::invalidateSelection()
1289 selectionController()->setNeedsLayout();
1290 selectionLayoutChanged();
1293 void Frame::setCaretVisible(bool flag)
1295 if (d->m_caretVisible == flag)
1297 clearCaretRectIfNeeded();
1299 setFocusNodeIfNeeded();
1300 d->m_caretVisible = flag;
1301 selectionLayoutChanged();
1305 void Frame::clearCaretRectIfNeeded()
1307 if (d->m_caretPaint) {
1308 d->m_caretPaint = false;
1309 selectionController()->invalidateCaretRect();
1313 // Helper function that tells whether a particular node is an element that has an entire
1314 // Frame and FrameView, a <frame>, <iframe>, or <object>.
1315 static bool isFrameElement(const Node *n)
1319 RenderObject *renderer = n->renderer();
1320 if (!renderer || !renderer->isWidget())
1322 Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
1323 return widget && widget->isFrameView();
1326 void Frame::setFocusNodeIfNeeded()
1328 if (!document() || selectionController()->isNone() || !d->m_isActive)
1331 Node* target = selectionController()->rootEditableElement();
1333 RenderObject* renderer = target->renderer();
1335 // Walk up the render tree to search for a node to focus.
1336 // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields.
1338 // We don't want to set focus on a subframe when selecting in a parent frame,
1339 // so add the !isFrameElement check here. There's probably a better way to make this
1340 // work in the long term, but this is the safest fix at this time.
1341 if (target && target->isMouseFocusable() && !isFrameElement(target)) {
1342 document()->setFocusNode(target);
1345 renderer = renderer->parent();
1347 target = renderer->element();
1349 document()->setFocusNode(0);
1353 void Frame::selectionLayoutChanged()
1355 bool caretRectChanged = selectionController()->recomputeCaretRect();
1357 bool shouldBlink = d->m_caretVisible
1358 && selectionController()->isCaret() && selectionController()->isContentEditable();
1360 // If the caret moved, stop the blink timer so we can restart with a
1361 // black caret in the new location.
1362 if (caretRectChanged || !shouldBlink)
1363 d->m_caretBlinkTimer.stop();
1365 // Start blinking with a black caret. Be sure not to restart if we're
1366 // already blinking in the right location.
1367 if (shouldBlink && !d->m_caretBlinkTimer.isActive()) {
1368 d->m_caretBlinkTimer.startRepeating(caretBlinkFrequency);
1369 d->m_caretPaint = true;
1373 d->m_doc->updateSelection();
1376 void Frame::setXPosForVerticalArrowNavigation(int x)
1378 d->m_xPosForVerticalArrowNavigation = x;
1381 int Frame::xPosForVerticalArrowNavigation() const
1383 return d->m_xPosForVerticalArrowNavigation;
1386 void Frame::caretBlinkTimerFired(Timer<Frame>*)
1388 ASSERT(d->m_caretVisible);
1389 ASSERT(selectionController()->isCaret());
1390 bool caretPaint = d->m_caretPaint;
1391 if (d->m_bMousePressed && caretPaint)
1393 d->m_caretPaint = !caretPaint;
1394 selectionController()->invalidateCaretRect();
1397 void Frame::paintCaret(GraphicsContext* p, const IntRect& rect) const
1399 if (d->m_caretPaint && d->m_caretVisible)
1400 selectionController()->paintCaret(p, rect);
1403 void Frame::paintDragCaret(GraphicsContext* p, const IntRect& rect) const
1405 SelectionController* dragCaretController = d->m_page->dragCaretController();
1406 assert(dragCaretController->selection().isCaret());
1407 if (dragCaretController->selection().start().node()->document()->frame() == this)
1408 dragCaretController->paintCaret(p, rect);
1411 void Frame::urlSelected(const DeprecatedString& url, const String& target, const Event* triggeringEvent)
1413 urlSelected(ResourceRequest(completeURL(url)), target, triggeringEvent);
1416 void Frame::urlSelected(const ResourceRequest& request, const String& _target, const Event* triggeringEvent, bool lockHistory)
1418 String target = _target;
1419 if (target.isEmpty() && d->m_doc)
1420 target = d->m_doc->baseTarget();
1422 const KURL& url = request.url();
1424 if (url.url().startsWith("javascript:", false)) {
1425 executeScript(0, KURL::decode_string(url.url().mid(11)), true);
1430 // ### ERROR HANDLING
1433 FrameLoadRequest frameRequest;
1434 frameRequest.m_request = request;
1435 frameRequest.m_frameName = target;
1437 if (d->m_bHTTPRefresh)
1438 d->m_bHTTPRefresh = false;
1440 if (frameRequest.m_request.httpReferrer().isEmpty())
1441 frameRequest.m_request.setHTTPReferrer(d->m_referrer);
1443 urlSelected(frameRequest, triggeringEvent);
1446 bool Frame::requestFrame(Element* ownerElement, const String& urlParam, const AtomicString& frameName)
1448 DeprecatedString _url = urlParam.deprecatedString();
1449 // Support for <frame src="javascript:string">
1452 if (_url.startsWith("javascript:", false)) {
1454 url = "about:blank";
1456 url = completeURL(_url);
1458 Frame* frame = tree()->child(frameName);
1460 ResourceRequestCachePolicy policy = (d->m_cachePolicy == CachePolicyReload) || (d->m_cachePolicy == CachePolicyRefresh) ? ReloadIgnoringCacheData : UseProtocolCachePolicy;
1461 ResourceRequest request(url, d->m_referrer, policy);
1462 FrameLoadRequest frameRequest;
1463 frameRequest.m_request = request;
1464 frame->openURLRequest(frameRequest);
1466 frame = loadSubframe(ownerElement, url, frameName, d->m_referrer);
1471 if (!scriptURL.isEmpty())
1472 frame->replaceContentsWithScriptResult(scriptURL);
1477 bool Frame::requestObject(RenderPart* renderer, const String& url, const AtomicString& frameName,
1478 const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
1482 completedURL = completeURL(url.deprecatedString());
1484 if (url.isEmpty() && mimeType.isEmpty())
1488 if (shouldUsePlugin(renderer->element(), completedURL, mimeType, renderer->hasFallbackContent(), useFallback))
1489 return loadPlugin(renderer, completedURL, mimeType, paramNames, paramValues, useFallback);
1491 ASSERT(renderer->node()->hasTagName(objectTag) || renderer->node()->hasTagName(embedTag));
1492 AtomicString uniqueFrameName = tree()->uniqueChildName(frameName);
1493 static_cast<HTMLPlugInElement*>(renderer->node())->setFrameName(uniqueFrameName);
1495 // FIXME: ok to always make a new one? when does the old frame get removed?
1496 return loadSubframe(static_cast<Element*>(renderer->node()), completedURL, uniqueFrameName, d->m_referrer);
1499 bool Frame::shouldUsePlugin(Node* element, const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback)
1501 useFallback = false;
1502 ObjectContentType objectType = objectContentType(url, mimeType);
1504 // if an object's content can't be handled and it has no fallback, let
1505 // it be handled as a plugin to show the broken plugin icon
1506 if (objectType == ObjectContentNone && hasFallback)
1509 return objectType == ObjectContentNone || objectType == ObjectContentPlugin;
1513 bool Frame::loadPlugin(RenderPart *renderer, const KURL& url, const String& mimeType,
1514 const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
1517 checkEmitLoadEvent();
1521 Element *pluginElement;
1522 if (renderer && renderer->node() && renderer->node()->isElementNode())
1523 pluginElement = static_cast<Element*>(renderer->node());
1527 Plugin* plugin = createPlugin(pluginElement, url, paramNames, paramValues, mimeType);
1529 checkEmitLoadEvent();
1532 d->m_plugins.append(plugin);
1534 if (renderer && plugin->view())
1535 renderer->setWidget(plugin->view());
1537 checkEmitLoadEvent();
1542 Frame* Frame::loadSubframe(Element* ownerElement, const KURL& url, const String& name, const String& referrer)
1544 Frame* frame = createFrame(url, name, ownerElement, referrer);
1546 checkEmitLoadEvent();
1550 frame->childBegin();
1552 if (ownerElement->renderer() && frame->view())
1553 static_cast<RenderWidget*>(ownerElement->renderer())->setWidget(frame->view());
1555 checkEmitLoadEvent();
1557 // In these cases, the synchronous load would have finished
1558 // before we could connect the signals, so make sure to send the
1559 // completed() signal for the child by hand
1560 // FIXME: In this case the Frame will have finished loading before
1561 // it's being added to the child list. It would be a good idea to
1562 // create the child first, then invoke the loader separately.
1563 if (url.isEmpty() || url == "about:blank") {
1564 frame->completed(false);
1565 frame->checkCompleted();
1571 void Frame::clearRecordedFormValues()
1573 d->m_formAboutToBeSubmitted = 0;
1574 d->m_formValuesAboutToBeSubmitted.clear();
1577 void Frame::recordFormValue(const String& name, const String& value, PassRefPtr<HTMLFormElement> element)
1579 d->m_formAboutToBeSubmitted = element;
1580 d->m_formValuesAboutToBeSubmitted.set(name, value);
1583 void Frame::submitFormAgain()
1585 FramePrivate::SubmitForm* form = d->m_submitForm;
1586 d->m_submitForm = 0;
1587 if (d->m_doc && !d->m_doc->parsing() && form)
1588 submitForm(form->submitAction, form->submitUrl, form->submitFormData,
1589 form->target, form->submitContentType, form->submitBoundary);
1593 void Frame::submitForm(const char *action, const String& url, const FormData& formData, const String& _target, const String& contentType, const String& boundary)
1595 KURL u = completeURL(url.deprecatedString());
1598 // ### ERROR HANDLING!
1601 DeprecatedString urlstring = u.url();
1602 if (urlstring.startsWith("javascript:", false)) {
1603 urlstring = KURL::decode_string(urlstring);
1604 d->m_executingJavaScriptFormAction = true;
1605 executeScript(0, urlstring.mid(11));
1606 d->m_executingJavaScriptFormAction = false;
1610 FrameLoadRequest frameRequest;
1612 if (!d->m_referrer.isEmpty())
1613 frameRequest.m_request.setHTTPReferrer(d->m_referrer);
1615 frameRequest.m_frameName = _target.isEmpty() ? d->m_doc->baseTarget() : _target ;
1617 // Handle mailto: forms
1618 if (u.protocol() == "mailto") {
1620 DeprecatedString bodyEnc;
1621 if (contentType.lower() == "multipart/form-data")
1622 // FIXME: is this correct? I suspect not
1623 bodyEnc = KURL::encode_string(formData.flattenToString().deprecatedString());
1624 else if (contentType.lower() == "text/plain") {
1625 // Convention seems to be to decode, and s/&/\n/
1626 DeprecatedString tmpbody = formData.flattenToString().deprecatedString();
1627 tmpbody.replace('&', '\n');
1628 tmpbody.replace('+', ' ');
1629 tmpbody = KURL::decode_string(tmpbody); // Decode the rest of it
1630 bodyEnc = KURL::encode_string(tmpbody); // Recode for the URL
1632 bodyEnc = KURL::encode_string(formData.flattenToString().deprecatedString());
1634 DeprecatedString query = u.query();
1635 if (!query.isEmpty())
1637 query += "body=" + bodyEnc;
1642 if (strcmp(action, "get") == 0) {
1643 if (u.protocol() != "mailto")
1644 u.setQuery(formData.flattenToString().deprecatedString());
1646 frameRequest.m_request.setHTTPBody(formData);
1647 frameRequest.m_request.setHTTPMethod("POST");
1649 // construct some user headers if necessary
1650 if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
1651 frameRequest.m_request.setHTTPContentType(contentType);
1652 else // contentType must be "multipart/form-data"
1653 frameRequest.m_request.setHTTPContentType(contentType + "; boundary=" + boundary);
1656 if (d->m_runningScripts > 0) {
1657 if (d->m_submitForm)
1659 d->m_submitForm = new FramePrivate::SubmitForm;
1660 d->m_submitForm->submitAction = action;
1661 d->m_submitForm->submitUrl = url;
1662 d->m_submitForm->submitFormData = formData;
1663 d->m_submitForm->target = _target;
1664 d->m_submitForm->submitContentType = contentType;
1665 d->m_submitForm->submitBoundary = boundary;
1667 frameRequest.m_request.setURL(u);
1668 submitForm(frameRequest);
1672 void Frame::parentCompleted()
1674 if (d->m_scheduledRedirection != noRedirectionScheduled && !d->m_redirectionTimer.isActive())
1675 startRedirectionTimer();
1678 void Frame::childCompleted(bool complete)
1680 if (complete && !tree()->parent())
1681 d->m_bPendingChildRedirection = true;
1685 int Frame::zoomFactor() const
1687 return d->m_zoomFactor;
1690 void Frame::setZoomFactor(int percent)
1692 if (d->m_zoomFactor == percent)
1695 d->m_zoomFactor = percent;
1698 d->m_doc->recalcStyle(Node::Force);
1700 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
1701 child->setZoomFactor(d->m_zoomFactor);
1703 if (d->m_doc && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout())
1707 void Frame::setJSStatusBarText(const String& text)
1709 d->m_kjsStatusBarText = text;
1710 setStatusBarText(d->m_kjsStatusBarText);
1713 void Frame::setJSDefaultStatusBarText(const String& text)
1715 d->m_kjsDefaultStatusBarText = text;
1716 setStatusBarText(d->m_kjsDefaultStatusBarText);
1719 String Frame::jsStatusBarText() const
1721 return d->m_kjsStatusBarText;
1724 String Frame::jsDefaultStatusBarText() const
1726 return d->m_kjsDefaultStatusBarText;
1729 String Frame::referrer() const
1731 return d->m_referrer;
1734 String Frame::lastModified() const
1736 return d->m_lastModified;
1739 void Frame::reparseConfiguration()
1741 setAutoLoadImages(d->m_settings->autoLoadImages());
1743 d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled();
1744 d->m_bJavaEnabled = d->m_settings->isJavaEnabled();
1745 d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled();
1747 const KURL& userStyleSheetLocation = d->m_settings->userStyleSheetLocation();
1748 if (!userStyleSheetLocation.isEmpty())
1749 setUserStyleSheetLocation(userStyleSheetLocation);
1751 setUserStyleSheet(String());
1753 // FIXME: It's not entirely clear why the following is needed.
1754 // The document automatically does this as required when you set the style sheet.
1755 // But we had problems when this code was removed. Details are in
1756 // <http://bugzilla.opendarwin.org/show_bug.cgi?id=8079>.
1758 d->m_doc->updateStyleSelector();
1761 bool Frame::shouldDragAutoNode(Node *node, const IntPoint& point) const
1767 bool Frame::isPointInsideSelection(const IntPoint& point)
1769 // Treat a collapsed selection like no selection.
1770 if (!selectionController()->isRange())
1772 if (!document()->renderer())
1775 RenderObject::NodeInfo nodeInfo(true, true);
1776 document()->renderer()->layer()->hitTest(nodeInfo, point);
1777 Node *innerNode = nodeInfo.innerNode();
1778 if (!innerNode || !innerNode->renderer())
1781 Position pos(innerNode->renderer()->positionForPoint(point).deepEquivalent());
1785 Node *n = selectionController()->start().node();
1787 if (n == pos.node()) {
1788 if ((n == selectionController()->start().node() && pos.offset() < selectionController()->start().offset()) ||
1789 (n == selectionController()->end().node() && pos.offset() > selectionController()->end().offset())) {
1794 if (n == selectionController()->end().node())
1796 n = n->traverseNextNode();
1802 void Frame::selectClosestWordFromMouseEvent(const PlatformMouseEvent& mouse, Node *innerNode)
1804 Selection newSelection;
1806 if (innerNode && innerNode->renderer() && mouseDownMayStartSelect() && innerNode->renderer()->shouldSelect()) {
1807 IntPoint vPoint = view()->windowToContents(mouse.pos());
1808 VisiblePosition pos(innerNode->renderer()->positionForPoint(vPoint));
1809 if (pos.isNotNull()) {
1810 newSelection = Selection(pos);
1811 newSelection.expandUsingGranularity(WordGranularity);
1815 if (newSelection.isRange()) {
1816 d->m_selectionGranularity = WordGranularity;
1817 d->m_beganSelectingText = true;
1820 if (shouldChangeSelection(newSelection))
1821 selectionController()->setSelection(newSelection);
1824 void Frame::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
1826 if (event.event().button() == LeftButton) {
1827 if (selectionController()->isRange())
1828 // A double-click when range is already selected
1829 // should not change the selection. So, do not call
1830 // selectClosestWordFromMouseEvent, but do set
1831 // m_beganSelectingText to prevent handleMouseReleaseEvent
1832 // from setting caret selection.
1833 d->m_beganSelectingText = true;
1835 selectClosestWordFromMouseEvent(event.event(), event.targetNode());
1839 void Frame::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
1841 Node *innerNode = event.targetNode();
1843 if (event.event().button() == LeftButton && innerNode && innerNode->renderer() &&
1844 mouseDownMayStartSelect() && innerNode->renderer()->shouldSelect()) {
1845 Selection newSelection;
1846 IntPoint vPoint = view()->windowToContents(event.event().pos());
1847 VisiblePosition pos(innerNode->renderer()->positionForPoint(vPoint));
1848 if (pos.isNotNull()) {
1849 newSelection = Selection(pos);
1850 newSelection.expandUsingGranularity(ParagraphGranularity);
1852 if (newSelection.isRange()) {
1853 d->m_selectionGranularity = ParagraphGranularity;
1854 d->m_beganSelectingText = true;
1857 if (shouldChangeSelection(newSelection))
1858 selectionController()->setSelection(newSelection);
1862 void Frame::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
1864 Node *innerNode = event.targetNode();
1866 if (event.event().button() == LeftButton) {
1867 if (innerNode && innerNode->renderer() &&
1868 mouseDownMayStartSelect() && innerNode->renderer()->shouldSelect()) {
1870 // Extend the selection if the Shift key is down, unless the click is in a link.
1871 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
1873 // Don't restart the selection when the mouse is pressed on an
1874 // existing selection so we can allow for text dragging.
1875 IntPoint vPoint = view()->windowToContents(event.event().pos());
1876 if (!extendSelection && isPointInsideSelection(vPoint))
1879 VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(vPoint));
1880 if (visiblePos.isNull())
1881 visiblePos = VisiblePosition(innerNode, innerNode->caretMinOffset(), DOWNSTREAM);
1882 Position pos = visiblePos.deepEquivalent();
1884 Selection newSelection = selectionController()->selection();
1885 if (extendSelection && newSelection.isCaretOrRange()) {
1886 selectionController()->clearModifyBias();
1888 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
1889 // was created right-to-left
1890 Position start = newSelection.start();
1891 Position end = newSelection.end();
1892 short before = Range::compareBoundaryPoints(pos.node(), pos.offset(), start.node(), start.offset());
1894 newSelection = Selection(pos, end);
1896 newSelection = Selection(start, pos);
1898 if (d->m_selectionGranularity != CharacterGranularity)
1899 newSelection.expandUsingGranularity(d->m_selectionGranularity);
1900 d->m_beganSelectingText = true;
1902 newSelection = Selection(visiblePos);
1903 d->m_selectionGranularity = CharacterGranularity;
1906 if (shouldChangeSelection(newSelection))
1907 selectionController()->setSelection(newSelection);
1912 void Frame::handleMousePressEvent(const MouseEventWithHitTestResults& event)
1914 Node *innerNode = event.targetNode();
1916 d->m_mousePressNode = innerNode;
1917 d->m_dragStartPos = event.event().pos();
1919 if (event.event().button() == LeftButton || event.event().button() == MiddleButton) {
1920 d->m_bMousePressed = true;
1921 d->m_beganSelectingText = false;
1923 if (event.event().clickCount() == 2) {
1924 handleMousePressEventDoubleClick(event);
1927 if (event.event().clickCount() >= 3) {
1928 handleMousePressEventTripleClick(event);
1931 handleMousePressEventSingleClick(event);
1934 setMouseDownMayStartAutoscroll(mouseDownMayStartSelect() ||
1935 (d->m_mousePressNode && d->m_mousePressNode->renderer() && d->m_mousePressNode->renderer()->shouldAutoscroll()));
1938 void Frame::handleMouseMoveEvent(const MouseEventWithHitTestResults& event)
1940 // Mouse not pressed. Do nothing.
1941 if (!d->m_bMousePressed)
1944 Node *innerNode = event.targetNode();
1946 if (event.event().button() != 0 || !innerNode || !innerNode->renderer())
1949 ASSERT(mouseDownMayStartSelect() || mouseDownMayStartAutoscroll());
1951 setMouseDownMayStartDrag(false);
1952 view()->invalidateClick();
1954 if (mouseDownMayStartAutoscroll()) {
1955 // If the selection is contained in a layer that can scroll, that layer should handle the autoscroll
1956 // Otherwise, let the bridge handle it so the view can scroll itself.
1957 RenderObject* renderer = innerNode->renderer();
1958 while (renderer && !renderer->shouldAutoscroll())
1959 renderer = renderer->parent();
1961 handleAutoscroll(renderer);
1964 if (mouseDownMayStartSelect() && innerNode->renderer()->shouldSelect()) {
1965 // handle making selection
1966 IntPoint vPoint = view()->windowToContents(event.event().pos());
1967 VisiblePosition pos(innerNode->renderer()->positionForPoint(vPoint));
1969 updateSelectionForMouseDragOverPosition(pos);
1974 void Frame::updateSelectionForMouseDragOverPosition(const VisiblePosition& pos)
1976 // Don't modify the selection if we're not on a node.
1980 // Restart the selection if this is the first mouse move. This work is usually
1981 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
1982 Selection newSelection = selectionController()->selection();
1983 selectionController()->clearModifyBias();
1985 if (!d->m_beganSelectingText) {
1986 d->m_beganSelectingText = true;
1987 newSelection = Selection(pos);
1990 newSelection.setExtent(pos);
1991 if (d->m_selectionGranularity != CharacterGranularity)
1992 newSelection.expandUsingGranularity(d->m_selectionGranularity);
1994 if (shouldChangeSelection(newSelection))
1995 selectionController()->setSelection(newSelection);
1998 void Frame::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
2000 stopAutoscrollTimer();
2002 // Used to prevent mouseMoveEvent from initiating a drag before
2003 // the mouse is pressed again.
2004 d->m_bMousePressed = false;
2006 // Clear the selection if the mouse didn't move after the last mouse press.
2007 // We do this so when clicking on the selection, the selection goes away.
2008 // However, if we are editing, place the caret.
2009 if (mouseDownMayStartSelect() && !d->m_beganSelectingText
2010 && d->m_dragStartPos == event.event().pos()
2011 && selectionController()->isRange()) {
2012 Selection newSelection;
2013 Node *node = event.targetNode();
2014 if (node && node->isContentEditable() && node->renderer()) {
2015 IntPoint vPoint = view()->windowToContents(event.event().pos());
2016 VisiblePosition pos = node->renderer()->positionForPoint(vPoint);
2017 newSelection = Selection(pos);
2019 if (shouldChangeSelection(newSelection))
2020 selectionController()->setSelection(newSelection);
2023 notifyRendererOfSelectionChange(true);
2025 selectFrameElementInParentIfFullySelected();
2028 void Frame::selectAll()
2033 Node* root = selectionController()->isContentEditable() ? selectionController()->rootEditableElement() : d->m_doc->documentElement();
2034 selectContentsOfNode(root);
2035 selectFrameElementInParentIfFullySelected();
2036 notifyRendererOfSelectionChange(true);
2039 bool Frame::selectContentsOfNode(Node* node)
2041 Selection newSelection(Selection::selectionFromContentsOfNode(node));
2042 if (shouldChangeSelection(newSelection)) {
2043 selectionController()->setSelection(newSelection);
2049 bool Frame::shouldChangeSelection(const Selection& newSelection) const
2051 return shouldChangeSelection(selectionController()->selection(), newSelection, newSelection.affinity(), false);
2054 bool Frame::shouldDeleteSelection(const Selection& newSelection) const
2059 bool Frame::shouldBeginEditing(const Range *range) const
2064 bool Frame::shouldEndEditing(const Range *range) const
2069 bool Frame::isContentEditable() const
2073 return d->m_doc->inDesignMode();
2076 void Frame::textFieldDidBeginEditing(Element* input)
2080 void Frame::textFieldDidEndEditing(Element* input)
2084 void Frame::textDidChangeInTextField(Element* input)
2088 bool Frame::doTextFieldCommandFromEvent(Element* input, const PlatformKeyboardEvent* evt)
2093 void Frame::textWillBeDeletedInTextField(Element* input)
2097 void Frame::textDidChangeInTextArea(Element* input)
2101 bool Frame::isSelectionInPasswordField()
2103 Node* startNode = selectionController()->start().node();
2105 startNode = startNode->shadowAncestorNode();
2106 return startNode && startNode->hasTagName(inputTag) && static_cast<HTMLInputElement*>(startNode)->inputType() == HTMLInputElement::PASSWORD;
2109 EditCommand* Frame::lastEditCommand()
2111 return d->m_lastEditCommand.get();
2114 static void dispatchEditableContentChangedEvents(const EditCommand& command)
2116 Element* startRoot = command.startingRootEditableElement();
2117 Element* endRoot = command.endingRootEditableElement();
2120 startRoot->dispatchEvent(new Event(khtmlEditableContentChangedEvent, false, false), ec, true);
2121 if (endRoot && endRoot != startRoot)
2122 endRoot->dispatchEvent(new Event(khtmlEditableContentChangedEvent, false, false), ec, true);
2125 void Frame::appliedEditing(PassRefPtr<EditCommand> cmd)
2127 dispatchEditableContentChangedEvents(*cmd);
2129 Selection newSelection(cmd->endingSelection());
2130 if (shouldChangeSelection(newSelection))
2131 selectionController()->setSelection(newSelection, false);
2133 // Now set the typing style from the command. Clear it when done.
2134 // This helps make the case work where you completely delete a piece
2135 // of styled text and then type a character immediately after.
2136 // That new character needs to take on the style of the just-deleted text.
2137 // FIXME: Improve typing style.
2138 // See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
2139 if (cmd->typingStyle()) {
2140 setTypingStyle(cmd->typingStyle());
2141 cmd->setTypingStyle(0);
2144 // Command will be equal to last edit command only in the case of typing
2145 if (d->m_lastEditCommand == cmd)
2146 assert(cmd->isTypingCommand());
2148 // Only register a new undo command if the command passed in is
2149 // different from the last command
2150 d->m_lastEditCommand = cmd.get();
2151 registerCommandForUndo(cmd);
2153 respondToChangedContents(newSelection);
2156 void Frame::unappliedEditing(PassRefPtr<EditCommand> cmd)
2158 dispatchEditableContentChangedEvents(*cmd);
2160 Selection newSelection(cmd->startingSelection());
2161 if (shouldChangeSelection(newSelection))
2162 selectionController()->setSelection(newSelection, true);
2164 d->m_lastEditCommand = 0;
2165 registerCommandForRedo(cmd);
2166 respondToChangedContents(newSelection);
2169 void Frame::reappliedEditing(PassRefPtr<EditCommand> cmd)
2171 dispatchEditableContentChangedEvents(*cmd);
2173 Selection newSelection(cmd->endingSelection());
2174 if (shouldChangeSelection(newSelection))
2175 selectionController()->setSelection(newSelection, true);
2177 d->m_lastEditCommand = 0;
2178 registerCommandForUndo(cmd);
2179 respondToChangedContents(newSelection);
2182 CSSMutableStyleDeclaration *Frame::typingStyle() const
2184 return d->m_typingStyle.get();
2187 void Frame::setTypingStyle(CSSMutableStyleDeclaration *style)
2189 d->m_typingStyle = style;
2192 void Frame::clearTypingStyle()
2194 d->m_typingStyle = 0;
2197 JSValue* Frame::executeScript(const String& filename, int baseLine, Node* n, const String& script)
2199 // FIXME: This is missing stuff that the other executeScript has.
2200 // --> d->m_runningScripts and submitFormAgain.
2202 KJSProxy* proxy = jScript();
2205 JSValue* ret = proxy->evaluate(filename, baseLine, script, n);
2206 Document::updateDocumentsRendering();
2210 Frame *Frame::opener()
2215 void Frame::setOpener(Frame* opener)
2218 d->m_opener->d->m_openedFrames.remove(this);
2220 opener->d->m_openedFrames.add(this);
2221 d->m_opener = opener;
2224 bool Frame::openedByJS()
2226 return d->m_openedByJS;
2229 void Frame::setOpenedByJS(bool _openedByJS)
2231 d->m_openedByJS = _openedByJS;
2234 bool Frame::tabsToLinks() const
2239 bool Frame::tabsToAllControls() const
2244 void Frame::copyToPasteboard()
2249 void Frame::cutToPasteboard()
2254 void Frame::pasteFromPasteboard()
2256 issuePasteCommand();
2259 void Frame::pasteAndMatchStyle()
2261 issuePasteAndMatchStyleCommand();
2264 bool Frame::mayCopy()
2266 return !isSelectionInPasswordField();
2269 void Frame::transpose()
2271 issueTransposeCommand();
2285 void Frame::computeAndSetTypingStyle(CSSStyleDeclaration *style, EditAction editingAction)
2287 if (!style || style->length() == 0) {
2292 // Calculate the current typing style.
2293 RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
2294 if (typingStyle()) {
2295 typingStyle()->merge(mutableStyle.get());
2296 mutableStyle = typingStyle();
2299 Node *node = selectionController()->selection().visibleStart().deepEquivalent().node();
2300 CSSComputedStyleDeclaration computedStyle(node);
2301 computedStyle.diff(mutableStyle.get());
2303 // Handle block styles, substracting these from the typing style.
2304 RefPtr<CSSMutableStyleDeclaration> blockStyle = mutableStyle->copyBlockProperties();
2305 blockStyle->diff(mutableStyle.get());
2306 if (document() && blockStyle->length() > 0)
2307 applyCommand(new ApplyStyleCommand(document(), blockStyle.get(), editingAction));
2309 // Set the remaining style as the typing style.
2310 d->m_typingStyle = mutableStyle.release();
2313 void Frame::applyStyle(CSSStyleDeclaration *style, EditAction editingAction)
2315 switch (selectionController()->state()) {
2316 case Selection::NONE:
2319 case Selection::CARET: {
2320 computeAndSetTypingStyle(style, editingAction);
2323 case Selection::RANGE:
2324 if (document() && style)
2325 applyCommand(new ApplyStyleCommand(document(), style, editingAction));
2330 void Frame::applyParagraphStyle(CSSStyleDeclaration *style, EditAction editingAction)
2332 switch (selectionController()->state()) {
2333 case Selection::NONE:
2336 case Selection::CARET:
2337 case Selection::RANGE:
2338 if (document() && style)
2339 applyCommand(new ApplyStyleCommand(document(), style, editingAction, ApplyStyleCommand::ForceBlockProperties));
2344 void Frame::indent()
2346 applyCommand(new IndentOutdentCommand(document(), IndentOutdentCommand::Indent));
2349 void Frame::outdent()
2351 applyCommand(new IndentOutdentCommand(document(), IndentOutdentCommand::Outdent));
2354 static void updateState(CSSMutableStyleDeclaration *desiredStyle, CSSComputedStyleDeclaration *computedStyle, bool& atStart, Frame::TriState& state)
2356 DeprecatedValueListConstIterator<CSSProperty> end;
2357 for (DeprecatedValueListConstIterator<CSSProperty> it = desiredStyle->valuesIterator(); it != end; ++it) {
2358 int propertyID = (*it).id();
2359 String desiredProperty = desiredStyle->getPropertyValue(propertyID);
2360 String computedProperty = computedStyle->getPropertyValue(propertyID);
2361 Frame::TriState propertyState = equalIgnoringCase(desiredProperty, computedProperty)
2362 ? Frame::trueTriState : Frame::falseTriState;
2364 state = propertyState;
2366 } else if (state != propertyState) {
2367 state = Frame::mixedTriState;
2373 Frame::TriState Frame::selectionListState() const
2375 TriState state = falseTriState;
2377 if (!selectionController()->isRange()) {
2378 Node* selectionNode = selectionController()->selection().start().node();
2379 if (enclosingList(selectionNode))
2380 return trueTriState;
2382 //FIXME: Support ranges
2388 Frame::TriState Frame::selectionHasStyle(CSSStyleDeclaration *style) const
2390 bool atStart = true;
2391 TriState state = falseTriState;
2393 RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
2395 if (!selectionController()->isRange()) {
2397 RefPtr<CSSComputedStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
2398 if (!selectionStyle)
2399 return falseTriState;
2400 updateState(mutableStyle.get(), selectionStyle.get(), atStart, state);
2402 ExceptionCode ec = 0;
2403 nodeToRemove->remove(ec);
2407 for (Node* node = selectionController()->start().node(); node; node = node->traverseNextNode()) {
2408 RefPtr<CSSComputedStyleDeclaration> computedStyle = new CSSComputedStyleDeclaration(node);
2410 updateState(mutableStyle.get(), computedStyle.get(), atStart, state);
2411 if (state == mixedTriState)
2413 if (node == selectionController()->end().node())
2421 bool Frame::selectionStartHasStyle(CSSStyleDeclaration *style) const
2424 RefPtr<CSSStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
2425 if (!selectionStyle)
2428 RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
2431 DeprecatedValueListConstIterator<CSSProperty> end;
2432 for (DeprecatedValueListConstIterator<CSSProperty> it = mutableStyle->valuesIterator(); it != end; ++it) {
2433 int propertyID = (*it).id();
2434 if (!equalIgnoringCase(mutableStyle->getPropertyValue(propertyID), selectionStyle->getPropertyValue(propertyID))) {
2441 ExceptionCode ec = 0;
2442 nodeToRemove->remove(ec);
2449 String Frame::selectionStartStylePropertyValue(int stylePropertyID) const
2452 RefPtr<CSSStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
2453 if (!selectionStyle)
2456 String value = selectionStyle->getPropertyValue(stylePropertyID);
2459 ExceptionCode ec = 0;
2460 nodeToRemove->remove(ec);
2467 CSSComputedStyleDeclaration *Frame::selectionComputedStyle(Node *&nodeToRemove) const
2474 if (selectionController()->isNone())
2477 RefPtr<Range> range(selectionController()->toRange());
2478 Position pos = range->editingStartPosition();
2480 Element *elem = pos.element();
2484 RefPtr<Element> styleElement = elem;
2485 ExceptionCode ec = 0;
2487 if (d->m_typingStyle) {
2488 styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec);
2491 styleElement->setAttribute(styleAttr, d->m_typingStyle->cssText().impl(), ec);
2494 styleElement->appendChild(document()->createEditingTextNode(""), ec);
2497 if (elem->renderer() && elem->renderer()->canHaveChildren()) {
2498 elem->appendChild(styleElement, ec);
2500 Node *parent = elem->parent();
2501 Node *next = elem->nextSibling();
2504 parent->insertBefore(styleElement, next, ec);
2506 parent->appendChild(styleElement, ec);
2511 nodeToRemove = styleElement.get();
2514 return new CSSComputedStyleDeclaration(styleElement);
2517 void Frame::applyEditingStyleToBodyElement() const
2522 RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body");
2523 unsigned len = list->length();
2524 for (unsigned i = 0; i < len; i++) {
2525 applyEditingStyleToElement(static_cast<Element*>(list->item(i)));
2529 void Frame::removeEditingStyleFromBodyElement() const
2534 RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body");
2535 unsigned len = list->length();
2536 for (unsigned i = 0; i < len; i++) {
2537 removeEditingStyleFromElement(static_cast<Element*>(list->item(i)));
2541 void Frame::applyEditingStyleToElement(Element* element) const
2546 CSSStyleDeclaration* style = element->style();
2549 ExceptionCode ec = 0;
2550 style->setProperty(CSS_PROP_WORD_WRAP, "break-word", false, ec);
2552 style->setProperty(CSS_PROP__WEBKIT_NBSP_MODE, "space", false, ec);
2554 style->setProperty(CSS_PROP__WEBKIT_LINE_BREAK, "after-white-space", false, ec);
2558 void Frame::removeEditingStyleFromElement(Element*) const
2562 bool Frame::isCharacterSmartReplaceExempt(UChar, bool)
2569 static HashSet<Frame*> lifeSupportSet;
2572 void Frame::endAllLifeSupport()
2575 HashSet<Frame*> lifeSupportCopy = lifeSupportSet;
2576 HashSet<Frame*>::iterator end = lifeSupportCopy.end();
2577 for (HashSet<Frame*>::iterator it = lifeSupportCopy.begin(); it != end; ++it)
2578 (*it)->endLifeSupport();
2582 void Frame::keepAlive()
2584 if (d->m_lifeSupportTimer.isActive())
2588 lifeSupportSet.add(this);
2590 d->m_lifeSupportTimer.startOneShot(0);
2593 void Frame::endLifeSupport()
2595 if (!d->m_lifeSupportTimer.isActive())
2597 d->m_lifeSupportTimer.stop();
2599 lifeSupportSet.remove(this);
2604 void Frame::lifeSupportTimerFired(Timer<Frame>*)
2607 lifeSupportSet.remove(this);
2612 // Workaround for the fact that it's hard to delete a frame.
2613 // Call this after doing user-triggered selections to make it easy to delete the frame you entirely selected.
2614 // Can't do this implicitly as part of every setSelection call because in some contexts it might not be good
2615 // for the focus to move to another frame. So instead we call it from places where we are selecting with the
2616 // mouse or the keyboard after setting the selection.
2617 void Frame::selectFrameElementInParentIfFullySelected()
2619 // Find the parent frame; if there is none, then we have nothing to do.
2620 Frame *parent = tree()->parent();
2623 FrameView *parentView = parent->view();
2627 // Check if the selection contains the entire frame contents; if not, then there is nothing to do.
2628 if (!selectionController()->isRange())
2630 if (!isStartOfDocument(selectionController()->selection().visibleStart()))
2632 if (!isEndOfDocument(selectionController()->selection().visibleEnd()))
2635 // Get to the <iframe> or <frame> (or even <object>) element in the parent frame.
2636 Document *doc = document();
2639 Element *ownerElement = doc->ownerElement();
2642 Node *ownerElementParent = ownerElement->parentNode();
2643 if (!ownerElementParent)
2646 // 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.
2647 if (!ownerElementParent->isContentEditable())
2650 // Create compute positions before and after the element.
2651 unsigned ownerElementNodeIndex = ownerElement->nodeIndex();
2652 VisiblePosition beforeOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex, SEL_DEFAULT_AFFINITY));
2653 VisiblePosition afterOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex + 1, VP_UPSTREAM_IF_POSSIBLE));
2655 // Focus on the parent frame, and then select from before this element to after.
2656 Selection newSelection(beforeOwnerElement, afterOwnerElement);
2657 if (parent->shouldChangeSelection(newSelection)) {
2658 parentView->setFocus();
2659 parent->selectionController()->setSelection(newSelection);
2663 bool Frame::mouseDownMayStartAutoscroll() const
2665 return d->m_mouseDownMayStartAutoscroll;
2668 void Frame::setMouseDownMayStartAutoscroll(bool b)
2670 d->m_mouseDownMayStartAutoscroll = b;
2673 bool Frame::mouseDownMayStartDrag() const
2675 return d->m_mouseDownMayStartDrag;
2678 void Frame::setMouseDownMayStartDrag(bool b)
2680 d->m_mouseDownMayStartDrag = b;
2683 void Frame::handleFallbackContent()
2685 Element* owner = ownerElement();
2686 if (!owner || !owner->hasTagName(objectTag))
2688 static_cast<HTMLObjectElement*>(owner)->renderFallbackContent();
2691 void Frame::setSettings(Settings *settings)
2693 d->m_settings = settings;
2696 void Frame::provisionalLoadStarted()
2698 // we don't want to wait until we get an actual http response back
2699 // to cancel pending redirects, otherwise they might fire before
2701 cancelRedirection(true);
2704 bool Frame::userGestureHint()
2706 Frame *rootFrame = this;
2707 while (rootFrame->tree()->parent())
2708 rootFrame = rootFrame->tree()->parent();
2710 if (rootFrame->jScript())
2711 return rootFrame->jScript()->interpreter()->wasRunByUserGesture();
2713 return true; // If JavaScript is disabled, a user gesture must have initiated the navigation
2716 RenderObject *Frame::renderer() const
2718 Document *doc = document();
2719 return doc ? doc->renderer() : 0;
2722 Element* Frame::ownerElement()
2724 return d->m_ownerElement;
2727 RenderPart* Frame::ownerRenderer()
2729 Element* ownerElement = d->m_ownerElement;
2732 return static_cast<RenderPart*>(ownerElement->renderer());
2735 IntRect Frame::selectionRect() const
2737 RenderView *root = static_cast<RenderView*>(renderer());
2741 return root->selectionRect();
2744 // returns FloatRect because going through IntRect would truncate any floats
2745 FloatRect Frame::visibleSelectionRect() const
2750 return intersection(selectionRect(), d->m_view->visibleContentRect());
2753 bool Frame::isFrameSet() const
2755 Document* document = d->m_doc.get();
2756 if (!document || !document->isHTMLDocument())
2758 Node *body = static_cast<HTMLDocument*>(document)->body();
2759 return body && body->renderer() && body->hasTagName(framesetTag);
2762 bool Frame::openURL(const KURL& URL)
2764 ASSERT_NOT_REACHED();
2768 void Frame::didNotOpenURL(const KURL& URL)
2770 if (d->m_submittedFormURL == URL)
2771 d->m_submittedFormURL = KURL();
2774 // Scans logically forward from "start", including any child frames
2775 static HTMLFormElement *scanForForm(Node *start)
2778 for (n = start; n; n = n->traverseNextNode()) {
2779 if (n->hasTagName(formTag))
2780 return static_cast<HTMLFormElement*>(n);
2781 else if (n->isHTMLElement() && static_cast<HTMLElement*>(n)->isGenericFormElement())
2782 return static_cast<HTMLGenericFormElement*>(n)->form();
2783 else if (n->hasTagName(frameTag) || n->hasTagName(iframeTag)) {
2784 Node *childDoc = static_cast<HTMLFrameElement*>(n)->contentDocument();
2785 if (HTMLFormElement *frameResult = scanForForm(childDoc))
2792 // We look for either the form containing the current focus, or for one immediately after it
2793 HTMLFormElement *Frame::currentForm() const
2795 // start looking either at the active (first responder) node, or where the selection is
2796 Node *start = d->m_doc ? d->m_doc->focusNode() : 0;
2798 start = selectionController()->start().node();
2800 // try walking up the node tree to find a form element
2802 for (n = start; n; n = n->parentNode()) {
2803 if (n->hasTagName(formTag))
2804 return static_cast<HTMLFormElement*>(n);
2805 else if (n->isHTMLElement()
2806 && static_cast<HTMLElement*>(n)->isGenericFormElement())
2807 return static_cast<HTMLGenericFormElement*>(n)->form();
2810 // try walking forward in the node tree to find a form element
2811 return start ? scanForForm(start) : 0;
2814 void Frame::setEncoding(const String& name, bool userChosen)
2816 if (!d->m_workingURL.isEmpty())
2817 receivedFirstData();
2818 d->m_encoding = name;
2819 d->m_haveEncoding = userChosen;
2822 void Frame::addData(const char *bytes, int length)
2824 ASSERT(d->m_workingURL.isEmpty());
2826 ASSERT(d->m_doc->parsing());
2827 write(bytes, length);
2830 // FIXME: should this go in SelectionController?
2831 void Frame::revealSelection(const RenderLayer::ScrollAlignment& alignment) const
2835 switch (selectionController()->state()) {
2836 case Selection::NONE:
2839 case Selection::CARET:
2840 rect = selectionController()->caretRect();
2843 case Selection::RANGE:
2844 rect = selectionRect();
2848 Position start = selectionController()->start();
2849 Position end = selectionController()->end();
2851 ASSERT(start.node());
2852 if (start.node() && start.node()->renderer()) {
2853 RenderLayer *layer = start.node()->renderer()->enclosingLayer();
2855 ASSERT(!end.node() || !end.node()->renderer()
2856 || (end.node()->renderer()->enclosingLayer() == layer));
2857 layer->scrollRectToVisible(rect, alignment, alignment);
2862 void Frame::revealCaret(const RenderLayer::ScrollAlignment& alignment) const
2864 if (!hasSelection())
2867 Position extent = selectionController()->extent();
2868 if (extent.node() && extent.node()->renderer()) {
2869 IntRect extentRect = VisiblePosition(extent).caretRect();
2870 RenderLayer* layer = extent.node()->renderer()->enclosingLayer();
2872 layer->scrollRectToVisible(extentRect, alignment, alignment);
2876 // FIXME: should this be here?
2877 bool Frame::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity)
2883 Node *node = document()->focusNode();
2885 node = d->m_mousePressNode.get();
2889 RenderObject *r = node->renderer();
2890 if (r != 0 && !r->isListBox()) {
2891 return r->scroll(direction, granularity);
2898 void Frame::handleAutoscroll(RenderObject* renderer)
2900 if (d->m_autoscrollTimer.isActive())
2902 setAutoscrollRenderer(renderer);
2903 startAutoscrollTimer();
2906 void Frame::autoscrollTimerFired(Timer<Frame>*)
2908 if (!d->m_bMousePressed){
2909 stopAutoscrollTimer();
2912 if (RenderObject* r = autoscrollRenderer())
2916 RenderObject* Frame::autoscrollRenderer() const
2918 return d->m_autoscrollRenderer;
2921 void Frame::setAutoscrollRenderer(RenderObject* renderer)
2923 d->m_autoscrollRenderer = renderer;
2926 RenderObject::NodeInfo Frame::nodeInfoAtPoint(const IntPoint& point, bool allowShadowContent)
2928 RenderObject::NodeInfo nodeInfo(true, true);
2929 renderer()->layer()->hitTest(nodeInfo, point);
2933 IntPoint widgetPoint(point);
2936 n = nodeInfo.innerNode();
2937 if (!n || !n->renderer() || !n->renderer()->isWidget())
2939 widget = static_cast<RenderWidget*>(n->renderer())->widget();
2940 if (!widget || !widget->isFrameView())
2942 Frame* frame = static_cast<HTMLFrameElement*>(n)->contentFrame();
2943 if (!frame || !frame->renderer())
2946 n->renderer()->absolutePosition(absX, absY, true);
2947 FrameView *view = static_cast<FrameView*>(widget);
2948 widgetPoint.setX(widgetPoint.x() - absX + view->contentsX());
2949 widgetPoint.setY(widgetPoint.y() - absY + view->contentsY());
2951 RenderObject::NodeInfo widgetNodeInfo(true, true);
2952 frame->renderer()->layer()->hitTest(widgetNodeInfo, widgetPoint);
2953 nodeInfo = widgetNodeInfo;
2956 if (!allowShadowContent) {
2957 Node* node = nodeInfo.innerNode();
2959 node = node->shadowAncestorNode();
2960 nodeInfo.setInnerNode(node);
2961 node = nodeInfo.innerNonSharedNode();
2963 node = node->shadowAncestorNode();
2964 nodeInfo.setInnerNonSharedNode(node);
2969 bool Frame::hasSelection()
2971 if (selectionController()->isNone())
2974 // If a part has a selection, it should also have a document.
2980 void Frame::startAutoscrollTimer()
2982 d->m_autoscrollTimer.startRepeating(autoscrollInterval);
2985 void Frame::stopAutoscrollTimer()
2987 setAutoscrollRenderer(0);
2988 d->m_autoscrollTimer.stop();
2991 // FIXME: why is this here instead of on the FrameView?
2992 void Frame::paint(GraphicsContext* p, const IntRect& rect)
2996 if (!document() || document()->printing())
2997 fillWithRed = false; // Printing, don't fill with red (can't remember why).
2998 else if (document()->ownerElement())
2999 fillWithRed = false; // Subframe, don't fill with red.
3000 else if (view() && view()->isTransparent())
3001 fillWithRed = false; // Transparent, don't fill with red.
3002 else if (d->m_paintRestriction == PaintRestrictionSelectionOnly || d->m_paintRestriction == PaintRestrictionSelectionOnlyWhiteText)
3003 fillWithRed = false; // Selections are transparent, don't fill with red.
3004 else if (d->m_elementToDraw)
3005 fillWithRed = false; // Element images are transparent, don't fill with red.
3010 p->fillRect(rect, Color(0xFF, 0, 0));
3014 // d->m_elementToDraw is used to draw only one element
3015 RenderObject *eltRenderer = d->m_elementToDraw ? d->m_elementToDraw->renderer() : 0;
3016 if (d->m_paintRestriction == PaintRestrictionNone)
3017 renderer()->document()->invalidateRenderedRectsForMarkersInRect(rect);
3018 renderer()->layer()->paint(p, rect, d->m_paintRestriction, eltRenderer);
3021 // Regions may have changed as a result of the visibility/z-index of element changing.
3022 if (renderer()->document()->dashboardRegionsDirty())
3023 renderer()->view()->frameView()->updateDashboardRegions();
3026 LOG_ERROR("called Frame::paint with nil renderer");
3031 void Frame::adjustPageHeight(float *newBottom, float oldTop, float oldBottom, float bottomLimit)
3033 RenderView *root = static_cast<RenderView*>(document()->renderer());
3035 // Use a context with painting disabled.
3036 GraphicsContext context(0);
3037 root->setTruncatedAt((int)floorf(oldBottom));
3038 IntRect dirtyRect(0, (int)floorf(oldTop), root->docWidth(), (int)ceilf(oldBottom - oldTop));
3039 root->layer()->paint(&context, dirtyRect);
3040 *newBottom = root->bestTruncatedAt();
3041 if (*newBottom == 0)
3042 *newBottom = oldBottom;
3044 *newBottom = oldBottom;
3049 PausedTimeouts *Frame::pauseTimeouts()
3052 if (d->m_doc && d->m_doc->svgExtensions())
3053 d->m_doc->accessSVGExtensions()->pauseAnimations();
3056 if (d->m_doc && d->m_jscript) {
3057 if (Window* w = Window::retrieveWindow(this))
3058 return w->pauseTimeouts();
3063 void Frame::resumeTimeouts(PausedTimeouts* t)
3066 if (d->m_doc && d->m_doc->svgExtensions())
3067 d->m_doc->accessSVGExtensions()->unpauseAnimations();
3070 if (d->m_doc && d->m_jscript && d->m_bJScriptEnabled) {
3071 if (Window* w = Window::retrieveWindow(this))
3072 w->resumeTimeouts(t);
3076 bool Frame::canCachePage()
3078 // Only save page state if:
3079 // 1. We're not a frame or frameset.
3080 // 2. The page has no unload handler.
3081 // 3. The page has no password fields.
3082 // 4. The URL for the page is not https.
3083 // 5. The page has no applets.
3084 if (tree()->childCount() || d->m_plugins.size() ||
3086 d->m_url.protocol().startsWith("https") ||
3087 (d->m_doc && (d->m_doc->applets()->length() != 0 ||
3088 d->m_doc->hasWindowEventListener(unloadEvent) ||
3089 d->m_doc->hasPasswordField()))) {
3095 void Frame::saveWindowProperties(KJS::SavedProperties *windowProperties)
3097 Window *window = Window::retrieveWindow(this);
3099 window->saveProperties(*windowProperties);
3102 void Frame::saveLocationProperties(SavedProperties *locationProperties)
3104 Window *window = Window::retrieveWindow(this);
3107 Location *location = window->location();
3108 location->saveProperties(*locationProperties);
3112 void Frame::restoreWindowProperties(SavedProperties *windowProperties)
3114 Window *window = Window::retrieveWindow(this);
3116 window->restoreProperties(*windowProperties);
3119 void Frame::restoreLocationProperties(SavedProperties *locationProperties)
3121 Window *window = Window::retrieveWindow(this);
3124 Location *location = window->location();
3125 location->restoreProperties(*locationProperties);
3129 void Frame::saveInterpreterBuiltins(SavedBuiltins& interpreterBuiltins)
3132 jScript()->interpreter()->saveBuiltins(interpreterBuiltins);
3135 void Frame::restoreInterpreterBuiltins(const SavedBuiltins& interpreterBuiltins)
3138 jScript()->interpreter()->restoreBuiltins(interpreterBuiltins);
3141 Frame *Frame::frameForWidget(const Widget *widget)
3143 ASSERT_ARG(widget, widget);
3145 Node *node = nodeForWidget(widget);
3147 return frameForNode(node);
3149 // Assume all widgets are either form controls, or FrameViews.
3150 ASSERT(widget->isFrameView());
3151 return static_cast<const FrameView*>(widget)->frame();
3154 Frame *Frame::frameForNode(Node *node)
3156 ASSERT_ARG(node, node);
3157 return node->document()->frame();
3160 Node* Frame::nodeForWidget(const Widget* widget)
3162 ASSERT_ARG(widget, widget);
3163 WidgetClient* client = widget->client();
3166 return client->element(const_cast<Widget*>(widget));
3169 void Frame::clearDocumentFocus(Widget *widget)
3171 Node *node = nodeForWidget(widget);
3173 node->document()->setFocusNode(0);
3176 void Frame::updatePolicyBaseURL()
3178 if (tree()->parent() && tree()->parent()->document())
3179 setPolicyBaseURL(tree()->parent()->document()->policyBaseURL());
3181 setPolicyBaseURL(d->m_url.url());
3184 void Frame::setPolicyBaseURL(const String& s)
3187 document()->setPolicyBaseURL(s);
3188 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
3189 child->setPolicyBaseURL(s);
3192 void Frame::forceLayout()
3194 FrameView *v = d->m_view.get();
3197 // We cannot unschedule a pending relayout, since the force can be called with
3198 // a tiny rectangle from a drawRect update. By unscheduling we in effect
3199 // "validate" and stop the necessary full repaint from occurring. Basically any basic
3200 // append/remove DHTML is broken by this call. For now, I have removed the optimization
3201 // until we have a better invalidation stategy. -dwh
3202 //v->unscheduleRelayout();
3206 void Frame::forceLayoutWithPageWidthRange(float minPageWidth, float maxPageWidth)
3208 // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see
3209 // the state of things before and after the layout
3210 RenderView *root = static_cast<RenderView*>(document()->renderer());
3212 // This magic is basically copied from khtmlview::print
3213 int pageW = (int)ceilf(minPageWidth);
3214 root->setWidth(pageW);
3215 root->setNeedsLayoutAndMinMaxRecalc();
3218 // If we don't fit in the minimum page width, we'll lay out again. If we don't fit in the
3219 // maximum page width, we will lay out to the maximum page width and clip extra content.
3220 // FIXME: We are assuming a shrink-to-fit printing implementation. A cropping
3221 // implementation should not do this!
3222 int rightmostPos = root->rightmostPosition();
3223 if (rightmostPos > minPageWidth) {
3224 pageW = min(rightmostPos, (int)ceilf(maxPageWidth));
3225 root->setWidth(pageW);
3226 root->setNeedsLayoutAndMinMaxRecalc();
3232 void Frame::sendResizeEvent()
3234 if (Document* doc = document())
3235 doc->dispatchWindowEvent(EventNames::resizeEvent, false, false);
3238 void Frame::sendScrollEvent()
3240 FrameView *v = d->m_view.get();
3242 Document *doc = document();
3245 doc->dispatchHTMLEvent(scrollEvent, true, false);
3249 bool Frame::scrollbarsVisible()
3254 if (view()->hScrollbarMode() == ScrollbarAlwaysOff || view()->vScrollbarMode() == ScrollbarAlwaysOff)
3260 void Frame::addMetaData(const String& key, const String& value)
3262 d->m_metaData.set(key, value);
3265 // This does the same kind of work that Frame::openURL does, except it relies on the fact
3266 // that a higher level already checked that the URLs match and the scrolling is the right thing to do.
3267 void Frame::scrollToAnchor(const KURL& URL)
3274 // It's important to model this as a load that starts and immediately finishes.
3275 // Otherwise, the parent frame may think we never finished loading.
3276 d->m_bComplete = false;
3280 bool Frame::closeURL()
3282 saveDocumentState();
3284 clearUndoRedoOperations();
3288 bool Frame::canMouseDownStartSelect(Node* node)
3290 if (!node || !node->renderer())
3293 // Check to see if -webkit-user-select has been set to none
3294 if (!node->renderer()->canSelect())
3297 // Some controls and images can't start a select on a mouse down.
3298 for (RenderObject* curr = node->renderer(); curr; curr = curr->parent()) {
3299 if (curr->style()->userSelect() == SELECT_IGNORE)
3306 void Frame::clearTimers(FrameView *view)
3309 view->unscheduleRelayout();
3310 if (view->frame()) {
3311 Document* document = view->frame()->document();
3312 if (document && document->renderer() && document->renderer()->layer())
3313 document->renderer()->layer()->suspendMarquees();
3318 void Frame::clearTimers()
3320 clearTimers(d->m_view.get());
3323 RenderStyle *Frame::styleForSelectionStart(Node *&nodeToRemove) const
3329 if (selectionController()->isNone())
3332 Position pos = selectionController()->selection().visibleStart().deepEquivalent();
3333 if (!pos.inRenderedContent())
3335 Node *node = pos.node();
3339 if (!d->m_typingStyle)
3340 return node->renderer()->style();
3342 ExceptionCode ec = 0;
3343 RefPtr<Element> styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec);
3346 styleElement->setAttribute(styleAttr, d->m_typingStyle->cssText().impl(), ec);
3349 styleElement->appendChild(document()->createEditingTextNode(""), ec);
3352 node->parentNode()->appendChild(styleElement, ec);
3355 nodeToRemove = styleElement.get();
3356 return styleElement->renderer()->style();
3359 void Frame::setMediaType(const String& type)
3362 d->m_view->setMediaType(type);
3365 void Frame::setSelectionFromNone()
3367 // Put a caret inside the body if the entire frame is editable (either the
3368 // entire WebView is editable or designMode is on for this document).
3369 Document *doc = document();
3370 if (!doc || !selectionController()->isNone() || !isContentEditable())
3373 Node* node = doc->documentElement();
3374 while (node && !node->hasTagName(bodyTag))
3375 node = node->traverseNextNode();
3377 selectionController()->setSelection(Selection(Position(node, 0), DOWNSTREAM));
3380 bool Frame::isActive() const
3382 return d->m_isActive;
3385 void Frame::setIsActive(bool flag)
3387 if (d->m_isActive == flag)
3390 d->m_isActive = flag;
3392 // This method does the job of updating the view based on whether the view is "active".
3393 // This involves three kinds of drawing updates:
3395 // 1. The background color used to draw behind selected content (active | inactive color)
3397 d->m_view->updateContents(enclosingIntRect(visibleSelectionRect()));
3399 // 2. Caret blinking (blinks | does not blink)
3401 setSelectionFromNone();
3402 setCaretVisible(flag);
3404 // 3. The drawing of a focus ring around links in web pages.
3405 Document *doc = document();
3407 Node *node = doc->focusNode();
3410 if (node->renderer() && node->renderer()->style()->hasAppearance())
3411 theme()->stateChanged(node->renderer(), FocusState);
3415 // 4. Changing the tint of controls from clear to aqua/graphite and vice versa. We
3416 // do a "fake" paint. When the theme gets a paint call, it can then do an invalidate. This is only
3417 // done if the theme supports control tinting.
3418 if (doc && d->m_view && theme()->supportsControlTints() && renderer()) {
3419 doc->updateLayout(); // Ensure layout is up to date.
3420 IntRect visibleRect(enclosingIntRect(d->m_view->visibleContentRect()));
3421 GraphicsContext context((PlatformGraphicsContext*)0);
3422 context.setUpdatingControlTints(true);
3423 paint(&context, visibleRect);
3426 // 5. Enable or disable secure keyboard entry
3427 if ((flag && !isSecureKeyboardEntry() && doc && doc->focusNode() && doc->focusNode()->hasTagName(inputTag) &&
3428 static_cast<HTMLInputElement*>(doc->focusNode())->inputType() == HTMLInputElement::PASSWORD) ||
3429 (!flag && isSecureKeyboardEntry()))
3430 setSecureKeyboardEntry(flag);
3433 void Frame::setWindowHasFocus(bool flag)
3435 if (d->m_windowHasFocus == flag)
3437 d->m_windowHasFocus = flag;
3439 if (Document *doc = document())
3440 doc->dispatchWindowEvent(flag ? focusEvent : blurEvent, false, false);
3443 bool Frame::inViewSourceMode() const
3445 return d->m_inViewSourceMode;
3448 void Frame::setInViewSourceMode(bool mode) const
3450 d->m_inViewSourceMode = mode;
3453 UChar Frame::backslashAsCurrencySymbol() const
3455 Document *doc = document();
3458 Decoder *decoder = doc->decoder();
3462 return decoder->encoding().backslashAsCurrencySymbol();
3465 bool Frame::markedTextUsesUnderlines() const
3467 return d->m_markedTextUsesUnderlines;
3470 const Vector<MarkedTextUnderline>& Frame::markedTextUnderlines() const
3472 return d->m_markedTextUnderlines;
3475 // Searches from the beginning of the document if nothing is selected.
3476 bool Frame::findString(const String& target, bool forward, bool caseFlag, bool wrapFlag)
3478 if (target.isEmpty())
3481 // Initially search from the start (if forward) or end (if backward) of the selection, and search to edge of document.
3482 RefPtr<Range> searchRange(rangeOfContents(document()));
3483 Selection selection(selectionController()->selection());
3484 if (!selection.isNone()) {
3486 setStart(searchRange.get(), selection.visibleStart());
3488 setEnd(searchRange.get(), selection.visibleEnd());
3490 RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, forward, caseFlag));
3491 // If the found range is already selected, find again.
3492 // Build a selection with the found range to remove collapsed whitespace.
3493 // Compare ranges instead of selection objects to ignore the way that the current selection was made.
3494 if (!selection.isNone() && *Selection(resultRange.get()).toRange() == *selection.toRange()) {
3495 searchRange = rangeOfContents(document());
3497 setStart(searchRange.get(), selection.visibleEnd());
3499 setEnd(searchRange.get(), selection.visibleStart());
3500 resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
3505 // If we didn't find anything and we're wrapping, search again in the entire document (this will
3506 // redundantly re-search the area already searched in some cases).
3507 if (resultRange->collapsed(exception) && wrapFlag) {
3508 searchRange = rangeOfContents(document());
3509 resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
3510 // We used to return false here if we ended up with the same range that we started with
3511 // (e.g., the selection was already the only instance of this text). But we decided that
3512 // this should be a success case instead, so we'll just fall through in that case.
3515 if (resultRange->collapsed(exception))
3518 selectionController()->setSelection(Selection(resultRange.get(), DOWNSTREAM));
3523 unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag, unsigned limit)
3525 if (target.isEmpty())
3528 RefPtr<Range> searchRange(rangeOfContents(document()));
3531 unsigned matchCount = 0;
3533 RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, caseFlag));
3534 if (resultRange->collapsed(exception))
3537 // A non-collapsed result range can in some funky whitespace cases still not
3538 // advance the range's start position (4509328). Break to avoid infinite loop.
3539 VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
3540 if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
3545 document()->addMarker(resultRange.get(), DocumentMarker::TextMatch);
3547 // Stop looking if we hit the specified limit. A limit of 0 means no limit.
3548 if (limit > 0 && matchCount >= limit)
3551 setStart(searchRange.get(), newStart);
3554 // Do a "fake" paint in order to execute the code that computes the rendered rect for
3556 Document* doc = document();
3557 if (doc && d->m_view && renderer()) {
3558 doc->updateLayout(); // Ensure layout is up to date.
3559 IntRect visibleRect(enclosingIntRect(d->m_view->visibleContentRect()));
3560 GraphicsContext context((PlatformGraphicsContext*)0);
3561 context.setPaintingDisabled(true);
3562 paint(&context, visibleRect);
3568 bool Frame::markedTextMatchesAreHighlighted() const
3570 return d->m_highlightTextMatches;
3573 void Frame::setMarkedTextMatchesAreHighlighted(bool flag)
3575 if (flag == d->m_highlightTextMatches)
3578 d->m_highlightTextMatches = flag;
3579 document()->repaintMarkers(DocumentMarker::TextMatch);
3582 void Frame::prepareForUserAction()
3584 // Reset the multiple form submission protection code.
3585 // We'll let you submit the same form twice if you do two separate user actions.
3586 d->m_submittedFormURL = KURL();
3589 Node *Frame::mousePressNode()
3591 return d->m_mousePressNode.get();
3594 bool Frame::isComplete() const
3596 return d->m_bComplete;
3599 bool Frame::isLoadingMainResource() const
3601 return d->m_bLoadingMainResource;
3604 FrameTree* Frame::tree() const
3606 return &d->m_treeNode;
3609 DOMWindow* Frame::domWindow() const
3611 if (!d->m_domWindow)
3612 d->m_domWindow = new DOMWindow(const_cast<Frame*>(this));
3614 return d->m_domWindow.get();
3617 KURL Frame::url() const
3622 void Frame::startRedirectionTimer()
3624 d->m_redirectionTimer.startOneShot(d->m_delayRedirect);
3627 void Frame::stopRedirectionTimer()
3629 d->m_redirectionTimer.stop();
3632 void Frame::frameDetached()
3636 void Frame::detachChildren()
3638 // FIXME: is it really necessary to do this in reverse order any more?
3639 while (Frame* child = tree()->lastChild())
3640 tree()->removeChild(child);
3643 void Frame::updateBaseURLForEmptyDocument()
3645 Element* owner = ownerElement();
3646 // FIXME: Should embed be included?
3647 if (owner && (owner->hasTagName(iframeTag) || owner->hasTagName(objectTag) || owner->hasTagName(embedTag)))
3648 d->m_doc->setBaseURL(tree()->parent()->d->m_doc->baseURL());
3651 Page* Frame::page() const
3656 void Frame::pageDestroyed()
3660 // This will stop any JS timers
3661 if (d->m_jscript && d->m_jscript->haveInterpreter())
3662 if (Window* w = Window::retrieveWindow(this))
3663 w->disconnectFrame();
3666 void Frame::completed(bool complete)
3669 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
3670 child->parentCompleted();
3671 if (Frame* parent = tree()->parent())
3672 parent->childCompleted(complete);
3677 void Frame::setStatusBarText(const String&)
3681 void Frame::started()
3683 for (Frame* frame = this; frame; frame = frame->tree()->parent())
3684 frame->d->m_bComplete = false;
3687 void Frame::disconnectOwnerElement()
3689 if (d->m_ownerElement && d->m_page)
3690 d->m_page->decrementFrameCount();
3692 d->m_ownerElement = 0;
3695 String Frame::documentTypeString() const
3697 if (Document *doc = document())
3698 if (DocumentType *doctype = doc->realDocType())
3699 return doctype->toString();
3704 bool Frame::containsPlugins() const
3706 return d->m_plugins.size() != 0;
3709 bool Frame::prohibitsScrolling() const
3711 return d->m_prohibitsScrolling;
3714 void Frame::setProhibitsScrolling(const bool prohibit)
3716 d->m_prohibitsScrolling = prohibit;
3719 } // namespace WebCore