1 /* This file is part of the KDE project
3 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
4 * 1999 Lars Knoll <knoll@kde.org>
5 * 1999 Antti Koivisto <koivisto@kde.org>
6 * 2000 Simon Hausmann <hausmann@kde.org>
7 * 2000 Stefan Schimanski <1Stein@gmx.de>
8 * 2001 George Staikos <staikos@kde.org>
9 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
10 * Copyright (C) 2005 Alexey Proskuryakov <ap@nypop.com>
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public License
23 * along with this library; see the file COPYING.LIB. If not, write to
24 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 * Boston, MA 02111-1307, USA.
30 #include "FramePrivate.h"
32 #include "ApplyStyleCommand.h"
33 #include "CSSComputedStyleDeclaration.h"
34 #include "CSSProperty.h"
35 #include "CSSPropertyNames.h"
37 #include "CachedCSSStyleSheet.h"
38 #include "DOMImplementation.h"
39 #include "DOMWindow.h"
41 #include "DocLoader.h"
42 #include "DocumentType.h"
43 #include "EditingText.h"
45 #include "EventNames.h"
46 #include "FloatRect.h"
48 #include "GraphicsContext.h"
49 #include "HTMLFormElement.h"
50 #include "HTMLFrameElement.h"
51 #include "HTMLGenericFormElement.h"
52 #include "HTMLInputElement.h"
53 #include "HTMLNames.h"
54 #include "HTMLObjectElement.h"
55 #include "HTMLViewSourceDocument.h"
56 #include "ImageDocument.h"
57 #include "loader/icon/IconDatabase.h"
58 #include "loader/icon/IconLoader.h"
59 #include "MediaFeatureNames.h"
60 #include "MouseEventWithHitTestResults.h"
63 #include "PlatformScrollBar.h"
64 #include "PlugInInfoStore.h"
66 #include "PluginDocument.h"
67 #include "RenderListBox.h"
68 #include "RenderPart.h"
69 #include "RenderTextControl.h"
70 #include "RenderTheme.h"
71 #include "RenderView.h"
72 #include "SegmentedString.h"
73 #include "TextDocument.h"
74 #include "TextIterator.h"
75 #include "TypingCommand.h"
76 #include "XMLTokenizer.h"
77 #include "cssstyleselector.h"
78 #include "htmlediting.h"
79 #include "kjs_window.h"
81 #include "visible_units.h"
82 #include "xmlhttprequest.h"
84 #include <sys/types.h>
85 #include <wtf/Platform.h>
97 #include "XLinkNames.h"
99 #include "SVGDocument.h"
100 #include "SVGDocumentExtensions.h"
108 using KJS::PausedTimeouts;
109 using KJS::SavedProperties;
110 using KJS::SavedBuiltins;
116 using namespace EventNames;
117 using namespace HTMLNames;
119 const double caretBlinkFrequency = 0.5;
120 const double autoscrollInterval = 0.1;
122 class UserStyleSheetLoader : public CachedResourceClient {
124 UserStyleSheetLoader(Frame* frame, const String& url, DocLoader* dl)
126 , m_cachedSheet(Cache::requestCSSStyleSheet(dl, url, false, 0, ""))
128 m_cachedSheet->ref(this);
130 ~UserStyleSheetLoader()
132 m_cachedSheet->deref(this);
135 virtual void setCSSStyleSheet(const String& /*URL*/, const String& /*charset*/, const String& sheet)
137 m_frame->setUserStyleSheet(sheet);
140 CachedCSSStyleSheet* m_cachedSheet;
144 struct FrameCounter {
146 ~FrameCounter() { if (count != 0) fprintf(stderr, "LEAK: %d Frame\n", count); }
148 int FrameCounter::count = 0;
149 static FrameCounter frameCounter;
152 static inline Frame* parentFromOwnerElement(Element* ownerElement)
156 return ownerElement->document()->frame();
159 Frame::Frame(Page* page, Element* ownerElement)
160 : d(new FramePrivate(page, parentFromOwnerElement(ownerElement), this, ownerElement))
162 AtomicString::init();
166 QualifiedName::init();
167 MediaFeatureNames::init();
175 if (d->m_ownerElement)
176 d->m_page->incrementFrameCount();
178 // FIXME: Frames were originally created with a refcount of 1, leave this
179 // ref call here until we can straighten that out.
182 ++FrameCounter::count;
188 ASSERT(!d->m_lifeSupportTimer.isActive());
191 --FrameCounter::count;
196 if (d->m_jscript && d->m_jscript->haveInterpreter())
197 if (Window* w = Window::retrieveWindow(this)) {
198 w->disconnectFrame();
199 // Must clear the window pointer, otherwise we will not
200 // garbage-collect collect the window (inside the call to
205 disconnectOwnerElement();
208 d->m_domWindow->disconnectFrame();
211 HashSet<Frame*> openedBy = d->m_openedFrames;
212 HashSet<Frame*>::iterator end = openedBy.end();
213 for (HashSet<Frame*>::iterator it = openedBy.begin(); it != end; ++it)
218 d->m_view->m_frame = 0;
221 ASSERT(!d->m_lifeSupportTimer.isActive());
223 delete d->m_userStyleSheetLoader;
228 KURL Frame::iconURL()
230 // If this isn't a top level frame, return nothing
231 if (tree() && tree()->parent())
234 // If we have an iconURL from a Link element, return that
235 if (document() && !document()->iconURL().isEmpty())
236 return KURL(document()->iconURL().deprecatedString());
238 // Don't return a favicon iconURL unless we're http or https
239 if (d->m_url.protocol() != "http" && d->m_url.protocol() != "https")
243 url.setProtocol(d->m_url.protocol());
244 url.setHost(d->m_url.host());
245 url.setPath("/favicon.ico");
249 bool Frame::didOpenURL(const KURL& url)
251 if (d->m_scheduledRedirection == locationChangeScheduledDuringLoad) {
252 // A redirect was shceduled before the document was created. This can happen
253 // when one frame changes another frame's location.
259 // clear last edit command
260 d->m_lastEditCommand = 0;
264 d->m_bComplete = false;
265 d->m_bLoadingMainResource = true;
266 d->m_bLoadEventEmitted = false;
268 d->m_kjsStatusBarText = String();
269 d->m_kjsDefaultStatusBarText = String();
271 d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled();
272 d->m_bJavaEnabled = d->m_settings->isJavaEnabled();
273 d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled();
275 // 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
276 // data arrives) (Simon)
278 if (d->m_url.protocol().startsWith("http") && !d->m_url.host().isEmpty() && d->m_url.path().isEmpty())
279 d->m_url.setPath("/");
280 d->m_workingURL = d->m_url;
287 void Frame::didExplicitOpen()
289 d->m_bComplete = false;
290 d->m_bLoadEventEmitted = false;
292 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
293 // from a subsequent window.document.open / window.document.write call.
294 // Cancelling redirection here works for all cases because document.open
295 // implicitly precedes document.write.
297 d->m_url = d->m_doc->URL();
300 void Frame::stopLoading(bool sendUnload)
302 if (d->m_doc && d->m_doc->tokenizer())
303 d->m_doc->tokenizer()->stopParsing();
305 d->m_metaData.clear();
309 if (d->m_bLoadEventEmitted && !d->m_bUnloadEventEmitted) {
310 Node* currentFocusNode = d->m_doc->focusNode();
311 if (currentFocusNode)
312 currentFocusNode->aboutToUnload();
313 d->m_doc->dispatchWindowEvent(unloadEvent, false, false);
315 d->m_doc->updateRendering();
316 d->m_bUnloadEventEmitted = true;
320 if (d->m_doc && !d->m_doc->inPageCache())
321 d->m_doc->removeAllEventListenersFromAllNodes();
324 d->m_bComplete = true; // to avoid calling completed() in finishedParsing() (David)
325 d->m_bLoadingMainResource = false;
326 d->m_bLoadEventEmitted = true; // don't want that one either
327 d->m_cachePolicy = CachePolicyVerify; // Why here?
329 if (d->m_doc && d->m_doc->parsing()) {
331 d->m_doc->setParsing(false);
334 d->m_workingURL = KURL();
336 if (Document *doc = d->m_doc.get()) {
337 if (DocLoader *docLoader = doc->docLoader())
338 Cache::loader()->cancelRequests(docLoader);
339 XMLHttpRequest::cancelRequests(doc);
342 // tell all subframes to stop as well
343 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
344 child->stopLoading(sendUnload);
346 d->m_bPendingChildRedirection = false;
351 BrowserExtension *Frame::browserExtension() const
353 return d->m_extension;
356 FrameView* Frame::view() const
358 return d->m_view.get();
361 void Frame::setView(FrameView* view)
366 bool Frame::jScriptEnabled() const
368 return d->m_bJScriptEnabled;
371 KJSProxy *Frame::jScript()
373 if (!d->m_bJScriptEnabled)
377 d->m_jscript = new KJSProxy(this);
382 static bool getString(JSValue* result, String& string)
388 if (!result->getString(ustring))
394 void Frame::replaceContentsWithScriptResult(const KURL& url)
396 JSValue* ret = executeScript(0, KURL::decode_string(url.url().mid(strlen("javascript:"))));
398 if (getString(ret, scriptResult)) {
405 JSValue* Frame::executeScript(Node* n, const String& script, bool forceUserGesture)
407 KJSProxy *proxy = jScript();
412 d->m_runningScripts++;
413 // If forceUserGesture is true, then make the script interpreter
414 // treat it as if triggered by a user gesture even if there is no
415 // current DOM event being processed.
416 JSValue* ret = proxy->evaluate(forceUserGesture ? DeprecatedString::null : d->m_url.url(), 0, script, n);
417 d->m_runningScripts--;
419 if (!d->m_runningScripts)
422 Document::updateDocumentsRendering();
427 bool Frame::javaEnabled() const
429 return d->m_settings->isJavaEnabled();
432 bool Frame::pluginsEnabled() const
434 return d->m_bPluginsEnabled;
437 void Frame::setAutoloadImages(bool enable)
439 if (d->m_doc && d->m_doc->docLoader()->autoloadImages() == enable)
443 d->m_doc->docLoader()->setAutoloadImages(enable);
446 bool Frame::autoloadImages() const
449 return d->m_doc->docLoader()->autoloadImages();
454 void Frame::cancelAndClear()
464 void Frame::clear(bool clearWindowProperties)
468 d->m_bCleared = true;
469 d->m_mousePressNode = 0;
472 // FIXME: This is a temporary hack to work around a mismatch between WebCore and WebKit
473 // regarding frame lifetime. The proper solution is to move all frame management
474 // into WebCore, so frames can work the same way on all platforms.
475 for (Frame* descendant = tree()->firstChild(); descendant; descendant = descendant->tree()->traverseNext())
476 descendant->disconnectOwnerElement();
480 d->m_doc->cancelParsing();
484 // Moving past doc so that onUnload works.
485 if (clearWindowProperties && d->m_jscript)
486 d->m_jscript->clear();
491 // do not drop the document before the jscript and view are cleared, as some destructors
492 // might still try to access the document.
496 d->m_plugins.clear();
497 cleanupPluginObjects();
499 d->m_scheduledRedirection = noRedirectionScheduled;
500 d->m_delayRedirect = 0;
501 d->m_redirectURL = DeprecatedString::null;
502 d->m_redirectReferrer = String();
503 d->m_redirectLockHistory = true;
504 d->m_redirectUserGesture = false;
505 d->m_bHTTPRefresh = false;
506 d->m_bFirstData = true;
508 d->m_bMousePressed = false;
510 if (!d->m_haveEncoding)
511 d->m_encoding = String();
514 Document *Frame::document() const
517 return d->m_doc.get();
521 void Frame::setDocument(Document* newDoc)
532 void Frame::receivedFirstData()
534 begin(d->m_workingURL);
536 d->m_doc->docLoader()->setCachePolicy(d->m_cachePolicy);
537 d->m_workingURL = KURL();
539 // When the first data arrives, the metadata has just been made available
540 DeprecatedString qData;
542 // Support for http-refresh
543 qData = d->m_metaData.get("http-refresh").deprecatedString();
544 if (!qData.isEmpty()) {
546 int pos = qData.find(';');
548 pos = qData.find(',');
551 delay = qData.stripWhiteSpace().toDouble();
552 // We want a new history item if the refresh timeout > 1 second
553 scheduleRedirection(delay, d->m_url.url(), delay <= 1);
555 int end_pos = qData.length();
556 delay = qData.left(pos).stripWhiteSpace().toDouble();
557 while (qData[++pos] == ' ');
558 if (qData.find("url", pos, false) == pos) {
560 while (qData[pos] == ' ' || qData[pos] == '=')
562 if (qData[pos] == '"') {
564 int index = end_pos-1;
565 while (index > pos) {
566 if (qData[index] == '"')
574 // We want a new history item if the refresh timeout > 1 second
575 scheduleRedirection(delay, d->m_doc->completeURL(qData.mid(pos, end_pos)), delay <= 1);
577 d->m_bHTTPRefresh = true;
580 // Support for http last-modified
581 d->m_lastModified = d->m_metaData.get("modified");
584 void Frame::childBegin()
586 // We need to do this when the child is created so as to avoid the parent thining the child
587 // is complete before it has even started loading.
588 // FIXME: do we really still need this?
589 d->m_bComplete = false;
592 void Frame::setResourceRequest(const ResourceRequest& request)
594 d->m_request = request;
597 const ResourceRequest& Frame::resourceRequest() const
602 void Frame::begin(const KURL& url)
604 if (d->m_workingURL.isEmpty())
605 createEmptyDocument(); // Creates an empty document if we don't have one already
608 partClearedInBegin();
610 d->m_bCleared = false;
611 d->m_bComplete = false;
612 d->m_bLoadEventEmitted = false;
613 d->m_bLoadingMainResource = true;
616 ref.setUser(DeprecatedString());
617 ref.setPass(DeprecatedString());
618 ref.setRef(DeprecatedString());
619 d->m_referrer = ref.url();
623 // We don't need KDE chained URI handling or window caption setting
624 if (!d->m_url.isEmpty())
628 if (d->m_request.m_responseMIMEType == "image/svg+xml")
629 d->m_doc = DOMImplementation::instance()->createSVGDocument(d->m_view.get());
632 if (DOMImplementation::isXMLMIMEType(d->m_request.m_responseMIMEType))
633 d->m_doc = DOMImplementation::instance()->createDocument(d->m_view.get());
634 else if (DOMImplementation::isTextMIMEType(d->m_request.m_responseMIMEType))
635 d->m_doc = new TextDocument(DOMImplementation::instance(), d->m_view.get());
636 else if ((d->m_request.m_responseMIMEType == "application/pdf" || d->m_request.m_responseMIMEType == "text/pdf") && PlugInInfoStore::supportsMIMEType(d->m_request.m_responseMIMEType))
637 d->m_doc = new PluginDocument(DOMImplementation::instance(), d->m_view.get());
638 else if (Image::supportsType(d->m_request.m_responseMIMEType))
639 d->m_doc = new ImageDocument(DOMImplementation::instance(), d->m_view.get());
640 else if (PlugInInfoStore::supportsMIMEType(d->m_request.m_responseMIMEType))
641 d->m_doc = new PluginDocument(DOMImplementation::instance(), d->m_view.get());
642 else if (inViewSourceMode())
643 d->m_doc = new HTMLViewSourceDocument(DOMImplementation::instance(), d->m_view.get());
645 d->m_doc = DOMImplementation::instance()->createHTMLDocument(d->m_view.get());
647 if (!d->m_doc->attached())
649 d->m_doc->setURL(d->m_url.url());
650 // We prefer m_baseURL over d->m_url because d->m_url changes when we are
651 // about to load a new page.
652 d->m_doc->setBaseURL(baseurl.url());
654 d->m_doc->setDecoder(d->m_decoder.get());
656 updatePolicyBaseURL();
658 setAutoloadImages(d->m_settings->autoLoadImages());
659 const KURL& userStyleSheet = d->m_settings->userStyleSheetLocation();
661 if (!userStyleSheet.isEmpty())
662 setUserStyleSheetLocation(KURL(userStyleSheet));
664 restoreDocumentState();
666 d->m_doc->implicitOpen();
669 d->m_view->resizeContents(0, 0);
672 void Frame::write(const char* str, int len)
680 if (Tokenizer* t = d->m_doc->tokenizer()) {
681 if (t->wantsRawData()) {
682 t->writeRawData(str, len);
688 d->m_decoder = new Decoder(d->m_request.m_responseMIMEType, settings()->encoding());
689 if (!d->m_encoding.isNull())
690 d->m_decoder->setEncoding(d->m_encoding,
691 d->m_haveEncoding ? Decoder::UserChosenEncoding : Decoder::EncodingFromHTTPHeader);
693 d->m_doc->setDecoder(d->m_decoder.get());
696 String decoded = d->m_decoder->decode(str, len);
698 if (decoded.isEmpty())
701 if (d->m_bFirstData) {
702 d->m_bFirstData = false;
703 d->m_doc->determineParseMode(decoded);
704 if (d->m_decoder->encoding().usesVisualOrdering())
705 d->m_doc->setVisuallyOrdered();
706 d->m_doc->recalcStyle(Node::Force);
709 if (Tokenizer* t = d->m_doc->tokenizer()) {
710 ASSERT(!t->wantsRawData());
711 t->write(decoded, true);
715 void Frame::write(const String& str)
720 if (d->m_bFirstData) {
721 // determine the parse mode
722 d->m_doc->setParseMode(Document::Strict);
723 d->m_bFirstData = false;
725 Tokenizer* t = d->m_doc->tokenizer();
732 d->m_bLoadingMainResource = false;
736 void Frame::endIfNotLoading()
738 // http://bugzilla.opendarwin.org/show_bug.cgi?id=10854
739 // The frame's last ref may be remove and it be deleted by checkCompleted(),
740 // so we'll add a protective refcount
741 RefPtr<Frame> protector(this);
743 if (d->m_bLoadingMainResource)
746 // make sure nothing's left in there...
749 String decoded = d->m_decoder->flush();
750 if (d->m_bFirstData) {
751 d->m_bFirstData = false;
752 d->m_doc->determineParseMode(decoded);
756 d->m_doc->finishParsing();
758 // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but
759 // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
760 // become true. An example is when a subframe is a pure text doc, and that subframe is the
761 // last one to complete.
764 // FIXME - Right now, we kick off the icon loader when the frame is done receiving all its main resource.
765 // We could kick off the icon loader after we're done parsing the HEAD element, if that becomes convinient to find
768 // Don't load an icon if -
769 // 1) This is not the main frame
770 // 2) The database is disabled
771 // 3) We have no valid icon URL
772 // 4) We already have an unexpired icon
774 if (tree()->parent())
778 if (IconDatabase* sharedIconDatabase = IconDatabase::sharedIconDatabase()) {
779 if (!sharedIconDatabase->enabled())
782 String url(iconURL().url());
786 // If we already have an unexpired icon, we won't kick off a load but we *will* map the appropriate URLs to it
787 if (sharedIconDatabase->hasEntryForIconURL(url) && !isLoadTypeReload() && !sharedIconDatabase->isIconExpiredForIconURL(url)) {
788 commitIconURLToIconDatabase();
792 if (!d->m_iconLoader)
793 d->m_iconLoader = IconLoader::createForFrame(this);
794 d->m_iconLoader->startLoading();
798 void Frame::commitIconURLToIconDatabase()
800 KURL icon = iconURL();
802 IconDatabase* iconDatabase = IconDatabase::sharedIconDatabase();
803 ASSERT(iconDatabase);
804 iconDatabase->setIconURLForPageURL(icon.url(), this->url().url());
805 iconDatabase->setIconURLForPageURL(icon.url(), originalRequestURL().url());
810 // http://bugzilla.opendarwin.org/show_bug.cgi?id=10854
811 // The frame's last ref may be remove and it be deleted by checkCompleted(),
812 // so we'll add a protective refcount
813 RefPtr<Frame> protector(this);
816 if (d->m_doc->tokenizer())
817 d->m_doc->tokenizer()->stopParsing();
818 d->m_doc->finishParsing();
820 // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but
821 // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
822 // become true. An example is when a subframe is a pure text doc, and that subframe is the
823 // last one to complete.
826 d->m_iconLoader->stopLoading();
829 void Frame::gotoAnchor()
831 // If our URL has no ref, then we have no place we need to jump to.
832 if (!d->m_url.hasRef())
835 DeprecatedString ref = d->m_url.encodedHtmlRef();
836 if (!gotoAnchor(ref)) {
837 // Can't use htmlRef() here because it doesn't know which encoding to use to decode.
838 // Decoding here has to match encoding in completeURL, which means it has to use the
839 // page's encoding rather than UTF-8.
841 gotoAnchor(KURL::decode_string(ref, d->m_decoder->encoding()));
845 void Frame::finishedParsing()
847 RefPtr<Frame> protector(this);
851 return; // We are being destroyed by something checkCompleted called.
853 // check if the scrollbars are really needed for the content
854 // if not, remove them, relayout, and repaint
856 d->m_view->restoreScrollBar();
860 void Frame::loadDone()
866 void Frame::checkCompleted()
868 // Any frame that hasn't completed yet ?
869 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
870 if (!child->d->m_bComplete)
873 // Have we completed before?
877 // Are we still parsing?
878 if (d->m_doc && d->m_doc->parsing())
881 // Still waiting for images/scripts from the loader ?
883 if (d->m_doc && d->m_doc->docLoader())
884 requests = Cache::loader()->numRequests(d->m_doc->docLoader());
890 // Now do what should be done when we are really completed.
891 d->m_bComplete = true;
893 checkEmitLoadEvent(); // if we didn't do it before
895 if (d->m_scheduledRedirection != noRedirectionScheduled) {
896 // Do not start redirection for frames here! That action is
897 // deferred until the parent emits a completed signal.
898 if (!tree()->parent())
899 startRedirectionTimer();
903 completed(d->m_bPendingChildRedirection);
907 void Frame::checkEmitLoadEvent()
909 if (d->m_bLoadEventEmitted || !d->m_doc || d->m_doc->parsing())
912 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
913 if (!child->d->m_bComplete) // still got a frame running -> too early
916 // All frames completed -> set their domain to the frameset's domain
917 // This must only be done when loading the frameset initially (#22039),
918 // not when following a link in a frame (#44162).
920 String domain = d->m_doc->domain();
921 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
923 child->d->m_doc->setDomain(domain);
926 d->m_bLoadEventEmitted = true;
927 d->m_bUnloadEventEmitted = false;
929 d->m_doc->implicitClose();
932 const Settings *Frame::settings() const
934 return d->m_settings;
937 KURL Frame::baseURL() const
941 return d->m_doc->baseURL();
944 String Frame::baseTarget() const
948 return d->m_doc->baseTarget();
951 KURL Frame::completeURL(const DeprecatedString& url)
956 return KURL(d->m_doc->completeURL(url));
959 void Frame::scheduleRedirection(double delay, const DeprecatedString& url, bool doLockHistory)
961 if (delay < 0 || delay > INT_MAX / 1000)
963 if (d->m_scheduledRedirection == noRedirectionScheduled || delay <= d->m_delayRedirect)
965 d->m_scheduledRedirection = redirectionScheduled;
966 d->m_delayRedirect = delay;
967 d->m_redirectURL = url;
968 d->m_redirectReferrer = String();
969 d->m_redirectLockHistory = doLockHistory;
970 d->m_redirectUserGesture = false;
972 stopRedirectionTimer();
974 startRedirectionTimer();
978 void Frame::scheduleLocationChange(const DeprecatedString& url, const String& referrer, bool lockHistory, bool userGesture)
982 // If the URL we're going to navigate to is the same as the current one, except for the
983 // fragment part, we don't need to schedule the location change.
984 if (u.hasRef() && equalIgnoringRef(d->m_url, u)) {
985 changeLocation(url, referrer, lockHistory, userGesture);
989 // Handle a location change of a page with no document as a special case.
990 // This may happen when a frame changes the location of another frame.
991 d->m_scheduledRedirection = d->m_doc ? locationChangeScheduled : locationChangeScheduledDuringLoad;
993 // If a redirect was scheduled during a load, then stop the current load.
994 // Otherwise when the current load transitions from a provisional to a
995 // committed state, pending redirects may be cancelled.
996 if (d->m_scheduledRedirection == locationChangeScheduledDuringLoad) {
1000 d->m_delayRedirect = 0;
1001 d->m_redirectURL = url;
1002 d->m_redirectReferrer = referrer;
1003 d->m_redirectLockHistory = lockHistory;
1004 d->m_redirectUserGesture = userGesture;
1005 stopRedirectionTimer();
1007 startRedirectionTimer();
1010 void Frame::scheduleRefresh(bool userGesture)
1012 // Handle a location change of a page with no document as a special case.
1013 // This may happen when a frame requests a refresh of another frame.
1014 d->m_scheduledRedirection = d->m_doc ? locationChangeScheduled : locationChangeScheduledDuringLoad;
1016 // If a refresh was scheduled during a load, then stop the current load.
1017 // Otherwise when the current load transitions from a provisional to a
1018 // committed state, pending redirects may be cancelled.
1019 if (d->m_scheduledRedirection == locationChangeScheduledDuringLoad)
1022 d->m_delayRedirect = 0;
1023 d->m_redirectURL = url().url();
1024 d->m_redirectReferrer = referrer();
1025 d->m_redirectLockHistory = true;
1026 d->m_redirectUserGesture = userGesture;
1027 d->m_cachePolicy = CachePolicyRefresh;
1028 stopRedirectionTimer();
1030 startRedirectionTimer();
1033 bool Frame::isScheduledLocationChangePending() const
1035 switch (d->m_scheduledRedirection) {
1036 case noRedirectionScheduled:
1037 case redirectionScheduled:
1039 case historyNavigationScheduled:
1040 case locationChangeScheduled:
1041 case locationChangeScheduledDuringLoad:
1047 void Frame::scheduleHistoryNavigation(int steps)
1049 // navigation will always be allowed in the 0 steps case, which is OK because
1050 // that's supposed to force a reload.
1051 if (!canGoBackOrForward(steps)) {
1052 cancelRedirection();
1056 // If the URL we're going to navigate to is the same as the current one, except for the
1057 // fragment part, we don't need to schedule the navigation.
1058 if (d->m_extension) {
1059 KURL u = d->m_extension->historyURL(steps);
1061 if (equalIgnoringRef(d->m_url, u)) {
1062 d->m_extension->goBackOrForward(steps);
1067 d->m_scheduledRedirection = historyNavigationScheduled;
1068 d->m_delayRedirect = 0;
1069 d->m_redirectURL = DeprecatedString::null;
1070 d->m_redirectReferrer = String();
1071 d->m_scheduledHistoryNavigationSteps = steps;
1072 stopRedirectionTimer();
1074 startRedirectionTimer();
1077 void Frame::cancelRedirection(bool cancelWithLoadInProgress)
1080 d->m_cancelWithLoadInProgress = cancelWithLoadInProgress;
1081 d->m_scheduledRedirection = noRedirectionScheduled;
1082 stopRedirectionTimer();
1086 void Frame::changeLocation(const DeprecatedString& URL, const String& referrer, bool lockHistory, bool userGesture)
1088 if (URL.find("javascript:", 0, false) == 0) {
1089 String script = KURL::decode_string(URL.mid(11));
1090 JSValue* result = executeScript(0, script, userGesture);
1091 String scriptResult;
1092 if (getString(result, scriptResult)) {
1094 write(scriptResult);
1100 ResourceRequest request(completeURL(URL));
1101 request.setLockHistory(lockHistory);
1102 if (!referrer.isEmpty())
1103 request.setReferrer(referrer);
1105 request.reload = (d->m_cachePolicy == CachePolicyReload) || (d->m_cachePolicy == CachePolicyRefresh);
1107 urlSelected(request, "_self");
1110 void Frame::redirectionTimerFired(Timer<Frame>*)
1112 if (d->m_scheduledRedirection == historyNavigationScheduled) {
1113 d->m_scheduledRedirection = noRedirectionScheduled;
1115 // Special case for go(0) from a frame -> reload only the frame
1116 // go(i!=0) from a frame navigates into the history of the frame only,
1117 // in both IE and NS (but not in Mozilla).... we can't easily do that
1119 if (d->m_scheduledHistoryNavigationSteps == 0) // add && parent() to get only frames, but doesn't matter
1120 openURL(url()); /// ## need args.reload=true?
1122 if (d->m_extension) {
1123 d->m_extension->goBackOrForward(d->m_scheduledHistoryNavigationSteps);
1129 DeprecatedString URL = d->m_redirectURL;
1130 String referrer = d->m_redirectReferrer;
1131 bool lockHistory = d->m_redirectLockHistory;
1132 bool userGesture = d->m_redirectUserGesture;
1134 d->m_scheduledRedirection = noRedirectionScheduled;
1135 d->m_delayRedirect = 0;
1136 d->m_redirectURL = DeprecatedString::null;
1137 d->m_redirectReferrer = String();
1139 changeLocation(URL, referrer, lockHistory, userGesture);
1142 String Frame::encoding() const
1144 if (d->m_haveEncoding && !d->m_encoding.isEmpty())
1145 return d->m_encoding;
1146 if (d->m_decoder && d->m_decoder->encoding().isValid())
1147 return d->m_decoder->encoding().name();
1148 return settings()->encoding();
1151 void Frame::setUserStyleSheetLocation(const KURL& url)
1153 delete d->m_userStyleSheetLoader;
1154 d->m_userStyleSheetLoader = 0;
1155 if (d->m_doc && d->m_doc->docLoader())
1156 d->m_userStyleSheetLoader = new UserStyleSheetLoader(this, url.url(), d->m_doc->docLoader());
1159 void Frame::setUserStyleSheet(const String& styleSheet)
1161 delete d->m_userStyleSheetLoader;
1162 d->m_userStyleSheetLoader = 0;
1164 d->m_doc->setUserStyleSheet(styleSheet);
1167 bool Frame::gotoAnchor(const String& name)
1172 Node *n = d->m_doc->getElementById(AtomicString(name));
1174 n = d->m_doc->anchors()->namedItem(name, !d->m_doc->inCompatMode());
1176 d->m_doc->setCSSTarget(n); // Setting to null will clear the current target.
1178 // Implement the rule that "" and "top" both mean top of page as in other browsers.
1179 if (!n && !(name.isEmpty() || name.lower() == "top"))
1182 // We need to update the layout before scrolling, otherwise we could
1183 // really mess things up if an anchor scroll comes at a bad moment.
1185 d->m_doc->updateRendering();
1186 // Only do a layout if changes have occurred that make it necessary.
1187 if (d->m_view && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout()) {
1188 d->m_view->layout();
1192 // Scroll nested layers and frames to reveal the anchor.
1193 RenderObject *renderer;
1196 renderer = n->renderer();
1197 rect = n->getRect();
1199 // If there's no node, we should scroll to the top of the document.
1200 renderer = d->m_doc->renderer();
1205 // Align to the top and to the closest side (this matches other browsers).
1206 renderer->enclosingLayer()->scrollRectToVisible(rect, RenderLayer::gAlignToEdgeIfNeeded, RenderLayer::gAlignTopAlways);
1212 void Frame::setStandardFont(const String& name)
1214 d->m_settings->setStdFontName(AtomicString(name));
1217 void Frame::setFixedFont(const String& name)
1219 d->m_settings->setFixedFontName(AtomicString(name));
1222 String Frame::selectedText() const
1224 return plainText(selectionController()->toRange().get());
1227 bool Frame::hasSelection() const
1229 return selectionController()->isCaretOrRange();
1232 SelectionController* Frame::selectionController() const
1234 return &(d->m_selectionController);
1237 CommandByName* Frame::command() const
1239 return &(d->m_command);
1242 TextGranularity Frame::selectionGranularity() const
1244 return d->m_selectionGranularity;
1247 void Frame::setSelectionGranularity(TextGranularity granularity) const
1249 d->m_selectionGranularity = granularity;
1252 SelectionController* Frame::dragCaretController() const
1254 return d->m_page->dragCaretController();
1257 const Selection& Frame::mark() const
1262 void Frame::setMark(const Selection& s)
1264 ASSERT(!s.base().node() || s.base().node()->document() == document());
1265 ASSERT(!s.extent().node() || s.extent().node()->document() == document());
1266 ASSERT(!s.start().node() || s.start().node()->document() == document());
1267 ASSERT(!s.end().node() || s.end().node()->document() == document());
1272 void Frame::notifyRendererOfSelectionChange(bool userTriggered)
1274 RenderObject* renderer = 0;
1275 if (selectionController()->rootEditableElement())
1276 renderer = selectionController()->rootEditableElement()->shadowAncestorNode()->renderer();
1278 // If the current selection is in a textfield or textarea, notify the renderer that the selection has changed
1279 if (renderer && (renderer->isTextArea() || renderer->isTextField()))
1280 static_cast<RenderTextControl*>(renderer)->selectionChanged(userTriggered);
1283 void Frame::invalidateSelection()
1285 clearCaretRectIfNeeded();
1286 selectionController()->setNeedsLayout();
1287 selectionLayoutChanged();
1290 void Frame::setCaretVisible(bool flag)
1292 if (d->m_caretVisible == flag)
1294 clearCaretRectIfNeeded();
1296 setFocusNodeIfNeeded();
1297 d->m_caretVisible = flag;
1298 selectionLayoutChanged();
1302 void Frame::clearCaretRectIfNeeded()
1304 if (d->m_caretPaint) {
1305 d->m_caretPaint = false;
1306 selectionController()->needsCaretRepaint();
1310 // Helper function that tells whether a particular node is an element that has an entire
1311 // Frame and FrameView, a <frame>, <iframe>, or <object>.
1312 static bool isFrameElement(const Node *n)
1316 RenderObject *renderer = n->renderer();
1317 if (!renderer || !renderer->isWidget())
1319 Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
1320 return widget && widget->isFrameView();
1323 void Frame::setFocusNodeIfNeeded()
1325 if (!document() || selectionController()->isNone() || !d->m_isActive)
1328 Node* target = selectionController()->rootEditableElement();
1330 RenderObject* renderer = target->renderer();
1332 // Walk up the render tree to search for a node to focus.
1333 // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields.
1335 // We don't want to set focus on a subframe when selecting in a parent frame,
1336 // so add the !isFrameElement check here. There's probably a better way to make this
1337 // work in the long term, but this is the safest fix at this time.
1338 if (target && target->isMouseFocusable() && !isFrameElement(target)) {
1339 document()->setFocusNode(target);
1342 renderer = renderer->parent();
1344 target = renderer->element();
1346 document()->setFocusNode(0);
1350 void Frame::selectionLayoutChanged()
1352 // kill any caret blink timer now running
1353 d->m_caretBlinkTimer.stop();
1355 // see if a new caret blink timer needs to be started
1356 if (d->m_caretVisible && d->m_caretBlinks &&
1357 selectionController()->isCaret() && selectionController()->start().node()->isContentEditable()) {
1358 d->m_caretBlinkTimer.startRepeating(caretBlinkFrequency);
1359 d->m_caretPaint = true;
1360 selectionController()->needsCaretRepaint();
1364 d->m_doc->updateSelection();
1367 void Frame::setXPosForVerticalArrowNavigation(int x)
1369 d->m_xPosForVerticalArrowNavigation = x;
1372 int Frame::xPosForVerticalArrowNavigation() const
1374 return d->m_xPosForVerticalArrowNavigation;
1377 void Frame::caretBlinkTimerFired(Timer<Frame>*)
1379 // Might be better to turn the timer off during some of these circumstances
1380 // and assert rather then letting the timer fire and do nothing here.
1381 // Could do that in selectionLayoutChanged.
1383 if (!d->m_caretVisible)
1385 if (!d->m_caretBlinks)
1387 if (!selectionController()->isCaret())
1389 bool caretPaint = d->m_caretPaint;
1390 if (d->m_bMousePressed && caretPaint)
1392 d->m_caretPaint = !caretPaint;
1393 selectionController()->needsCaretRepaint();
1396 void Frame::paintCaret(GraphicsContext* p, const IntRect& rect) const
1398 if (d->m_caretPaint)
1399 selectionController()->paintCaret(p, rect);
1402 void Frame::paintDragCaret(GraphicsContext* p, const IntRect& rect) const
1404 SelectionController* dragCaretController = d->m_page->dragCaretController();
1405 assert(dragCaretController->selection().isCaret());
1406 if (dragCaretController->selection().start().node()->document()->frame() == this)
1407 dragCaretController->paintCaret(p, rect);
1410 void Frame::urlSelected(const DeprecatedString& url, const String& target)
1412 urlSelected(ResourceRequest(completeURL(url)), target);
1415 void Frame::urlSelected(const ResourceRequest& request, const String& _target)
1417 String target = _target;
1418 if (target.isEmpty() && d->m_doc)
1419 target = d->m_doc->baseTarget();
1421 const KURL& url = request.url();
1423 if (url.url().startsWith("javascript:", false)) {
1424 executeScript(0, KURL::decode_string(url.url().mid(11)), true);
1429 // ### ERROR HANDLING
1432 ResourceRequest requestCopy = request;
1433 requestCopy.frameName = target;
1435 if (d->m_bHTTPRefresh)
1436 d->m_bHTTPRefresh = false;
1438 if (!d->m_referrer.isEmpty())
1439 requestCopy.setReferrer(d->m_referrer);
1441 urlSelected(requestCopy);
1444 bool Frame::requestFrame(Element* ownerElement, const String& urlParam, const AtomicString& frameName)
1446 DeprecatedString _url = urlParam.deprecatedString();
1447 // Support for <frame src="javascript:string">
1450 if (_url.startsWith("javascript:", false)) {
1452 url = "about:blank";
1454 url = completeURL(_url);
1456 Frame* frame = tree()->child(frameName);
1458 ResourceRequest request(url);
1459 request.setReferrer(d->m_referrer);
1460 request.reload = (d->m_cachePolicy == CachePolicyReload) || (d->m_cachePolicy == CachePolicyRefresh);
1461 frame->openURLRequest(request);
1463 frame = loadSubframe(ownerElement, url, frameName, d->m_referrer);
1468 if (!scriptURL.isEmpty())
1469 frame->replaceContentsWithScriptResult(scriptURL);
1474 bool Frame::requestObject(RenderPart* renderer, const String& url, const AtomicString& frameName,
1475 const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
1479 completedURL = completeURL(url.deprecatedString());
1481 if (url.isEmpty() && mimeType.isEmpty())
1485 if (shouldUsePlugin(renderer->element(), completedURL, mimeType, renderer->hasFallbackContent(), useFallback))
1486 return loadPlugin(renderer, completedURL, mimeType, paramNames, paramValues, useFallback);
1488 ASSERT(renderer->node()->hasTagName(objectTag) || renderer->node()->hasTagName(embedTag));
1489 AtomicString uniqueFrameName = tree()->uniqueChildName(frameName);
1490 static_cast<HTMLPlugInElement*>(renderer->node())->setFrameName(uniqueFrameName);
1492 // FIXME: ok to always make a new one? when does the old frame get removed?
1493 return loadSubframe(static_cast<Element*>(renderer->node()), completedURL, uniqueFrameName, d->m_referrer);
1496 bool Frame::shouldUsePlugin(Node* element, const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback)
1498 useFallback = false;
1499 ObjectContentType objectType = objectContentType(url, mimeType);
1501 // if an object's content can't be handled and it has no fallback, let
1502 // it be handled as a plugin to show the broken plugin icon
1503 if (objectType == ObjectContentNone && hasFallback)
1506 return objectType == ObjectContentNone || objectType == ObjectContentPlugin;
1510 bool Frame::loadPlugin(RenderPart *renderer, const KURL& url, const String& mimeType,
1511 const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
1514 checkEmitLoadEvent();
1518 Element *pluginElement;
1519 if (renderer && renderer->node() && renderer->node()->isElementNode())
1520 pluginElement = static_cast<Element*>(renderer->node());
1524 Plugin* plugin = createPlugin(pluginElement, url, paramNames, paramValues, mimeType);
1526 checkEmitLoadEvent();
1529 d->m_plugins.append(plugin);
1531 if (renderer && plugin->view())
1532 renderer->setWidget(plugin->view());
1534 checkEmitLoadEvent();
1539 Frame* Frame::loadSubframe(Element* ownerElement, const KURL& url, const String& name, const String& referrer)
1541 Frame* frame = createFrame(url, name, ownerElement, referrer);
1543 checkEmitLoadEvent();
1547 frame->childBegin();
1549 if (ownerElement->renderer() && frame->view())
1550 static_cast<RenderWidget*>(ownerElement->renderer())->setWidget(frame->view());
1552 checkEmitLoadEvent();
1554 // In these cases, the synchronous load would have finished
1555 // before we could connect the signals, so make sure to send the
1556 // completed() signal for the child by hand
1557 // FIXME: In this case the Frame will have finished loading before
1558 // it's being added to the child list. It would be a good idea to
1559 // create the child first, then invoke the loader separately.
1560 if (url.isEmpty() || url == "about:blank") {
1561 frame->completed(false);
1562 frame->checkCompleted();
1568 void Frame::clearRecordedFormValues()
1570 d->m_formAboutToBeSubmitted = 0;
1571 d->m_formValuesAboutToBeSubmitted.clear();
1574 void Frame::recordFormValue(const String& name, const String& value, PassRefPtr<HTMLFormElement> element)
1576 d->m_formAboutToBeSubmitted = element;
1577 d->m_formValuesAboutToBeSubmitted.set(name, value);
1580 void Frame::submitFormAgain()
1582 FramePrivate::SubmitForm* form = d->m_submitForm;
1583 d->m_submitForm = 0;
1584 if (d->m_doc && !d->m_doc->parsing() && form)
1585 submitForm(form->submitAction, form->submitUrl, form->submitFormData,
1586 form->target, form->submitContentType, form->submitBoundary);
1590 void Frame::submitForm(const char *action, const String& url, const FormData& formData, const String& _target, const String& contentType, const String& boundary)
1592 KURL u = completeURL(url.deprecatedString());
1595 // ### ERROR HANDLING!
1598 DeprecatedString urlstring = u.url();
1599 if (urlstring.startsWith("javascript:", false)) {
1600 urlstring = KURL::decode_string(urlstring);
1601 d->m_executingJavaScriptFormAction = true;
1602 executeScript(0, urlstring.mid(11));
1603 d->m_executingJavaScriptFormAction = false;
1607 ResourceRequest request;
1609 if (!d->m_referrer.isEmpty())
1610 request.setReferrer(d->m_referrer);
1612 request.frameName = _target.isEmpty() ? d->m_doc->baseTarget() : _target ;
1614 // Handle mailto: forms
1615 if (u.protocol() == "mailto") {
1616 // 1) Check for attach= and strip it
1617 DeprecatedString q = u.query().mid(1);
1618 DeprecatedStringList nvps = DeprecatedStringList::split("&", q);
1619 bool triedToAttach = false;
1621 for (DeprecatedStringList::Iterator nvp = nvps.begin(); nvp != nvps.end(); ++nvp) {
1622 DeprecatedStringList pair = DeprecatedStringList::split("=", *nvp);
1623 if (pair.count() >= 2) {
1624 if (pair.first().lower() == "attach") {
1625 nvp = nvps.remove(nvp);
1626 triedToAttach = true;
1633 DeprecatedString bodyEnc;
1634 if (contentType.lower() == "multipart/form-data")
1635 // FIXME: is this correct? I suspect not
1636 bodyEnc = KURL::encode_string(formData.flattenToString().deprecatedString());
1637 else if (contentType.lower() == "text/plain") {
1638 // Convention seems to be to decode, and s/&/\n/
1639 DeprecatedString tmpbody = formData.flattenToString().deprecatedString();
1640 tmpbody.replace('&', '\n');
1641 tmpbody.replace('+', ' ');
1642 tmpbody = KURL::decode_string(tmpbody); // Decode the rest of it
1643 bodyEnc = KURL::encode_string(tmpbody); // Recode for the URL
1645 bodyEnc = KURL::encode_string(formData.flattenToString().deprecatedString());
1647 nvps.append(String::sprintf("body=%s", bodyEnc.latin1()).deprecatedString());
1652 if (strcmp(action, "get") == 0) {
1653 if (u.protocol() != "mailto")
1654 u.setQuery(formData.flattenToString().deprecatedString());
1655 request.setDoPost(false);
1657 request.postData = formData;
1658 request.setDoPost(true);
1660 // construct some user headers if necessary
1661 if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
1662 request.setContentType("Content-Type: application/x-www-form-urlencoded");
1663 else // contentType must be "multipart/form-data"
1664 request.setContentType("Content-Type: " + contentType + "; boundary=" + boundary);
1667 if (d->m_runningScripts > 0) {
1668 if (d->m_submitForm)
1670 d->m_submitForm = new FramePrivate::SubmitForm;
1671 d->m_submitForm->submitAction = action;
1672 d->m_submitForm->submitUrl = url;
1673 d->m_submitForm->submitFormData = formData;
1674 d->m_submitForm->target = _target;
1675 d->m_submitForm->submitContentType = contentType;
1676 d->m_submitForm->submitBoundary = boundary;
1679 submitForm(request);
1683 void Frame::parentCompleted()
1685 if (d->m_scheduledRedirection != noRedirectionScheduled && !d->m_redirectionTimer.isActive())
1686 startRedirectionTimer();
1689 void Frame::childCompleted(bool complete)
1691 if (complete && !tree()->parent())
1692 d->m_bPendingChildRedirection = true;
1696 int Frame::zoomFactor() const
1698 return d->m_zoomFactor;
1701 void Frame::setZoomFactor(int percent)
1703 if (d->m_zoomFactor == percent)
1706 d->m_zoomFactor = percent;
1709 d->m_doc->recalcStyle(Node::Force);
1711 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
1712 child->setZoomFactor(d->m_zoomFactor);
1714 if (d->m_doc && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout())
1718 void Frame::setJSStatusBarText(const String& text)
1720 d->m_kjsStatusBarText = text;
1721 setStatusBarText(d->m_kjsStatusBarText);
1724 void Frame::setJSDefaultStatusBarText(const String& text)
1726 d->m_kjsDefaultStatusBarText = text;
1727 setStatusBarText(d->m_kjsDefaultStatusBarText);
1730 String Frame::jsStatusBarText() const
1732 return d->m_kjsStatusBarText;
1735 String Frame::jsDefaultStatusBarText() const
1737 return d->m_kjsDefaultStatusBarText;
1740 String Frame::referrer() const
1742 return d->m_referrer;
1745 String Frame::lastModified() const
1747 return d->m_lastModified;
1750 void Frame::reparseConfiguration()
1752 setAutoloadImages(d->m_settings->autoLoadImages());
1754 d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled();
1755 d->m_bJavaEnabled = d->m_settings->isJavaEnabled();
1756 d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled();
1758 const KURL& userStyleSheetLocation = d->m_settings->userStyleSheetLocation();
1759 if (!userStyleSheetLocation.isEmpty())
1760 setUserStyleSheetLocation(userStyleSheetLocation);
1762 setUserStyleSheet(String());
1764 // FIXME: It's not entirely clear why the following is needed.
1765 // The document automatically does this as required when you set the style sheet.
1766 // But we had problems when this code was removed. Details are in
1767 // <http://bugzilla.opendarwin.org/show_bug.cgi?id=8079>.
1769 d->m_doc->updateStyleSelector();
1772 bool Frame::shouldDragAutoNode(Node *node, const IntPoint& point) const
1778 bool Frame::isPointInsideSelection(const IntPoint& point)
1780 // Treat a collapsed selection like no selection.
1781 if (!selectionController()->isRange())
1783 if (!document()->renderer())
1786 RenderObject::NodeInfo nodeInfo(true, true);
1787 document()->renderer()->layer()->hitTest(nodeInfo, point);
1788 Node *innerNode = nodeInfo.innerNode();
1789 if (!innerNode || !innerNode->renderer())
1792 Position pos(innerNode->renderer()->positionForPoint(point).deepEquivalent());
1796 Node *n = selectionController()->start().node();
1798 if (n == pos.node()) {
1799 if ((n == selectionController()->start().node() && pos.offset() < selectionController()->start().offset()) ||
1800 (n == selectionController()->end().node() && pos.offset() > selectionController()->end().offset())) {
1805 if (n == selectionController()->end().node())
1807 n = n->traverseNextNode();
1813 void Frame::selectClosestWordFromMouseEvent(const PlatformMouseEvent& mouse, Node *innerNode)
1815 Selection newSelection;
1817 if (innerNode && innerNode->renderer() && mouseDownMayStartSelect() && innerNode->renderer()->shouldSelect()) {
1818 IntPoint vPoint = view()->convertFromContainingWindow(mouse.pos());
1819 VisiblePosition pos(innerNode->renderer()->positionForPoint(vPoint));
1820 if (pos.isNotNull()) {
1821 newSelection = Selection(pos);
1822 newSelection.expandUsingGranularity(WordGranularity);
1826 if (newSelection.isRange()) {
1827 d->m_selectionGranularity = WordGranularity;
1828 d->m_beganSelectingText = true;
1831 if (shouldChangeSelection(newSelection))
1832 selectionController()->setSelection(newSelection);
1835 void Frame::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
1837 if (event.event().button() == LeftButton) {
1838 if (selectionController()->isRange())
1839 // A double-click when range is already selected
1840 // should not change the selection. So, do not call
1841 // selectClosestWordFromMouseEvent, but do set
1842 // m_beganSelectingText to prevent handleMouseReleaseEvent
1843 // from setting caret selection.
1844 d->m_beganSelectingText = true;
1846 selectClosestWordFromMouseEvent(event.event(), event.targetNode());
1850 void Frame::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
1852 Node *innerNode = event.targetNode();
1854 if (event.event().button() == LeftButton && innerNode && innerNode->renderer() &&
1855 mouseDownMayStartSelect() && innerNode->renderer()->shouldSelect()) {
1856 Selection newSelection;
1857 IntPoint vPoint = view()->convertFromContainingWindow(event.event().pos());
1858 VisiblePosition pos(innerNode->renderer()->positionForPoint(vPoint));
1859 if (pos.isNotNull()) {
1860 newSelection = Selection(pos);
1861 newSelection.expandUsingGranularity(ParagraphGranularity);
1863 if (newSelection.isRange()) {
1864 d->m_selectionGranularity = ParagraphGranularity;
1865 d->m_beganSelectingText = true;
1868 if (shouldChangeSelection(newSelection))
1869 selectionController()->setSelection(newSelection);
1873 void Frame::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
1875 Node *innerNode = event.targetNode();
1877 if (event.event().button() == LeftButton) {
1878 if (innerNode && innerNode->renderer() &&
1879 mouseDownMayStartSelect() && innerNode->renderer()->shouldSelect()) {
1881 // Extend the selection if the Shift key is down, unless the click is in a link.
1882 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
1884 // Don't restart the selection when the mouse is pressed on an
1885 // existing selection so we can allow for text dragging.
1886 IntPoint vPoint = view()->convertFromContainingWindow(event.event().pos());
1887 if (!extendSelection && isPointInsideSelection(vPoint))
1890 VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(vPoint));
1891 if (visiblePos.isNull())
1892 visiblePos = VisiblePosition(innerNode, innerNode->caretMinOffset(), DOWNSTREAM);
1893 Position pos = visiblePos.deepEquivalent();
1895 Selection newSelection = selectionController()->selection();
1896 if (extendSelection && newSelection.isCaretOrRange()) {
1897 selectionController()->clearModifyBias();
1899 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
1900 // was created right-to-left
1901 Position start = newSelection.start();
1902 Position end = newSelection.end();
1903 short before = Range::compareBoundaryPoints(pos.node(), pos.offset(), start.node(), start.offset());
1905 newSelection = Selection(pos, end);
1907 newSelection = Selection(start, pos);
1909 if (d->m_selectionGranularity != CharacterGranularity)
1910 newSelection.expandUsingGranularity(d->m_selectionGranularity);
1911 d->m_beganSelectingText = true;
1913 newSelection = Selection(visiblePos);
1914 d->m_selectionGranularity = CharacterGranularity;
1917 if (shouldChangeSelection(newSelection))
1918 selectionController()->setSelection(newSelection);
1923 void Frame::handleMousePressEvent(const MouseEventWithHitTestResults& event)
1925 Node *innerNode = event.targetNode();
1927 d->m_mousePressNode = innerNode;
1928 d->m_dragStartPos = event.event().pos();
1930 if (event.event().button() == LeftButton || event.event().button() == MiddleButton) {
1931 d->m_bMousePressed = true;
1932 d->m_beganSelectingText = false;
1934 if (event.event().clickCount() == 2) {
1935 handleMousePressEventDoubleClick(event);
1938 if (event.event().clickCount() >= 3) {
1939 handleMousePressEventTripleClick(event);
1942 handleMousePressEventSingleClick(event);
1946 void Frame::handleMouseMoveEvent(const MouseEventWithHitTestResults& event)
1948 // Mouse not pressed. Do nothing.
1949 if (!d->m_bMousePressed)
1952 Node *innerNode = event.targetNode();
1954 if (event.event().button() != 0 || !innerNode || !innerNode->renderer() || !mouseDownMayStartSelect() || !innerNode->renderer()->shouldSelect())
1957 // handle making selection
1959 IntPoint vPoint = view()->convertFromContainingWindow(event.event().pos());
1960 VisiblePosition pos(innerNode->renderer()->positionForPoint(vPoint));
1962 // Don't modify the selection if we're not on a node.
1966 // Restart the selection if this is the first mouse move. This work is usually
1967 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
1968 Selection newSelection = selectionController()->selection();
1969 selectionController()->clearModifyBias();
1971 if (!d->m_beganSelectingText) {
1972 d->m_beganSelectingText = true;
1973 newSelection = Selection(pos);
1976 newSelection.setExtent(pos);
1977 if (d->m_selectionGranularity != CharacterGranularity)
1978 newSelection.expandUsingGranularity(d->m_selectionGranularity);
1980 if (shouldChangeSelection(newSelection))
1981 selectionController()->setSelection(newSelection);
1984 void Frame::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
1986 stopAutoscrollTimer();
1988 // Used to prevent mouseMoveEvent from initiating a drag before
1989 // the mouse is pressed again.
1990 d->m_bMousePressed = false;
1992 // Clear the selection if the mouse didn't move after the last mouse press.
1993 // We do this so when clicking on the selection, the selection goes away.
1994 // However, if we are editing, place the caret.
1995 if (mouseDownMayStartSelect() && !d->m_beganSelectingText
1996 && d->m_dragStartPos == event.event().pos()
1997 && selectionController()->isRange()) {
1998 Selection newSelection;
1999 Node *node = event.targetNode();
2000 if (node && node->isContentEditable() && node->renderer()) {
2001 IntPoint vPoint = view()->convertFromContainingWindow(event.event().pos());
2002 VisiblePosition pos = node->renderer()->positionForPoint(vPoint);
2003 newSelection = Selection(pos);
2005 if (shouldChangeSelection(newSelection))
2006 selectionController()->setSelection(newSelection);
2009 notifyRendererOfSelectionChange(true);
2011 selectFrameElementInParentIfFullySelected();
2014 void Frame::selectAll()
2019 Node* root = selectionController()->isContentEditable() ? selectionController()->rootEditableElement() : d->m_doc->documentElement();
2020 selectContentsOfNode(root);
2021 selectFrameElementInParentIfFullySelected();
2022 notifyRendererOfSelectionChange(true);
2025 bool Frame::selectContentsOfNode(Node* node)
2027 Selection newSelection(Selection::selectionFromContentsOfNode(node));
2028 if (shouldChangeSelection(newSelection)) {
2029 selectionController()->setSelection(newSelection);
2035 bool Frame::shouldChangeSelection(const Selection& newSelection) const
2037 return shouldChangeSelection(selectionController()->selection(), newSelection, newSelection.affinity(), false);
2040 bool Frame::shouldDeleteSelection(const Selection& newSelection) const
2045 bool Frame::shouldBeginEditing(const Range *range) const
2050 bool Frame::shouldEndEditing(const Range *range) const
2055 bool Frame::isContentEditable() const
2059 return d->m_doc->inDesignMode();
2062 void Frame::textFieldDidBeginEditing(Element* input)
2066 void Frame::textFieldDidEndEditing(Element* input)
2070 void Frame::textDidChangeInTextField(Element* input)
2074 bool Frame::doTextFieldCommandFromEvent(Element* input, const PlatformKeyboardEvent* evt)
2079 void Frame::textWillBeDeletedInTextField(Element* input)
2083 void Frame::textDidChangeInTextArea(Element* input)
2087 bool Frame::isSelectionInPasswordField()
2089 Node* startNode = selectionController()->start().node();
2091 startNode = startNode->shadowAncestorNode();
2092 return startNode && startNode->hasTagName(inputTag) && static_cast<HTMLInputElement*>(startNode)->inputType() == HTMLInputElement::PASSWORD;
2095 EditCommand* Frame::lastEditCommand()
2097 return d->m_lastEditCommand.get();
2100 static void dispatchEditableContentChangedEvents(const EditCommand& command)
2102 Element* startRoot = command.startingRootEditableElement();
2103 Element* endRoot = command.endingRootEditableElement();
2106 startRoot->dispatchEvent(new Event(khtmlEditableContentChangedEvent, false, false), ec, true);
2107 if (endRoot && endRoot != startRoot)
2108 endRoot->dispatchEvent(new Event(khtmlEditableContentChangedEvent, false, false), ec, true);
2111 void Frame::appliedEditing(PassRefPtr<EditCommand> cmd)
2113 dispatchEditableContentChangedEvents(*cmd);
2115 Selection newSelection(cmd->endingSelection());
2116 if (shouldChangeSelection(newSelection))
2117 selectionController()->setSelection(newSelection, false);
2119 // Now set the typing style from the command. Clear it when done.
2120 // This helps make the case work where you completely delete a piece
2121 // of styled text and then type a character immediately after.
2122 // That new character needs to take on the style of the just-deleted text.
2123 // FIXME: Improve typing style.
2124 // See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
2125 if (cmd->typingStyle()) {
2126 setTypingStyle(cmd->typingStyle());
2127 cmd->setTypingStyle(0);
2130 // Command will be equal to last edit command only in the case of typing
2131 if (d->m_lastEditCommand == cmd)
2132 assert(cmd->isTypingCommand());
2134 // Only register a new undo command if the command passed in is
2135 // different from the last command
2136 d->m_lastEditCommand = cmd.get();
2137 registerCommandForUndo(cmd);
2139 respondToChangedContents(newSelection);
2142 void Frame::unappliedEditing(PassRefPtr<EditCommand> cmd)
2144 dispatchEditableContentChangedEvents(*cmd);
2146 Selection newSelection(cmd->startingSelection());
2147 if (shouldChangeSelection(newSelection))
2148 selectionController()->setSelection(newSelection, true);
2150 d->m_lastEditCommand = 0;
2151 registerCommandForRedo(cmd);
2152 respondToChangedContents(newSelection);
2155 void Frame::reappliedEditing(PassRefPtr<EditCommand> cmd)
2157 dispatchEditableContentChangedEvents(*cmd);
2159 Selection newSelection(cmd->endingSelection());
2160 if (shouldChangeSelection(newSelection))
2161 selectionController()->setSelection(newSelection, true);
2163 d->m_lastEditCommand = 0;
2164 registerCommandForUndo(cmd);
2165 respondToChangedContents(newSelection);
2168 CSSMutableStyleDeclaration *Frame::typingStyle() const
2170 return d->m_typingStyle.get();
2173 void Frame::setTypingStyle(CSSMutableStyleDeclaration *style)
2175 d->m_typingStyle = style;
2178 void Frame::clearTypingStyle()
2180 d->m_typingStyle = 0;
2183 JSValue* Frame::executeScript(const String& filename, int baseLine, Node* n, const String& script)
2185 // FIXME: This is missing stuff that the other executeScript has.
2186 // --> d->m_runningScripts and submitFormAgain.
2188 KJSProxy* proxy = jScript();
2191 JSValue* ret = proxy->evaluate(filename, baseLine, script, n);
2192 Document::updateDocumentsRendering();
2196 Frame *Frame::opener()
2201 void Frame::setOpener(Frame* opener)
2204 d->m_opener->d->m_openedFrames.remove(this);
2206 opener->d->m_openedFrames.add(this);
2207 d->m_opener = opener;
2210 bool Frame::openedByJS()
2212 return d->m_openedByJS;
2215 void Frame::setOpenedByJS(bool _openedByJS)
2217 d->m_openedByJS = _openedByJS;
2220 bool Frame::tabsToLinks() const
2225 bool Frame::tabsToAllControls() const
2230 void Frame::copyToPasteboard()
2235 void Frame::cutToPasteboard()
2240 void Frame::pasteFromPasteboard()
2242 issuePasteCommand();
2245 void Frame::pasteAndMatchStyle()
2247 issuePasteAndMatchStyleCommand();
2250 bool Frame::mayCopy()
2252 return !isSelectionInPasswordField();
2255 void Frame::transpose()
2257 issueTransposeCommand();
2271 void Frame::computeAndSetTypingStyle(CSSStyleDeclaration *style, EditAction editingAction)
2273 if (!style || style->length() == 0) {
2278 // Calculate the current typing style.
2279 RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
2280 if (typingStyle()) {
2281 typingStyle()->merge(mutableStyle.get());
2282 mutableStyle = typingStyle();
2285 Node *node = selectionController()->selection().visibleStart().deepEquivalent().node();
2286 CSSComputedStyleDeclaration computedStyle(node);
2287 computedStyle.diff(mutableStyle.get());
2289 // Handle block styles, substracting these from the typing style.
2290 RefPtr<CSSMutableStyleDeclaration> blockStyle = mutableStyle->copyBlockProperties();
2291 blockStyle->diff(mutableStyle.get());
2292 if (document() && blockStyle->length() > 0)
2293 applyCommand(new ApplyStyleCommand(document(), blockStyle.get(), editingAction));
2295 // Set the remaining style as the typing style.
2296 d->m_typingStyle = mutableStyle.release();
2299 void Frame::applyStyle(CSSStyleDeclaration *style, EditAction editingAction)
2301 switch (selectionController()->state()) {
2302 case Selection::NONE:
2305 case Selection::CARET: {
2306 computeAndSetTypingStyle(style, editingAction);
2309 case Selection::RANGE:
2310 if (document() && style)
2311 applyCommand(new ApplyStyleCommand(document(), style, editingAction));
2316 void Frame::applyParagraphStyle(CSSStyleDeclaration *style, EditAction editingAction)
2318 switch (selectionController()->state()) {
2319 case Selection::NONE:
2322 case Selection::CARET:
2323 case Selection::RANGE:
2324 if (document() && style)
2325 applyCommand(new ApplyStyleCommand(document(), style, editingAction, ApplyStyleCommand::ForceBlockProperties));
2330 static void updateState(CSSMutableStyleDeclaration *desiredStyle, CSSComputedStyleDeclaration *computedStyle, bool& atStart, Frame::TriState& state)
2332 DeprecatedValueListConstIterator<CSSProperty> end;
2333 for (DeprecatedValueListConstIterator<CSSProperty> it = desiredStyle->valuesIterator(); it != end; ++it) {
2334 int propertyID = (*it).id();
2335 String desiredProperty = desiredStyle->getPropertyValue(propertyID);
2336 String computedProperty = computedStyle->getPropertyValue(propertyID);
2337 Frame::TriState propertyState = equalIgnoringCase(desiredProperty, computedProperty)
2338 ? Frame::trueTriState : Frame::falseTriState;
2340 state = propertyState;
2342 } else if (state != propertyState) {
2343 state = Frame::mixedTriState;
2349 Frame::TriState Frame::selectionListState() const
2351 TriState state = falseTriState;
2353 if (!selectionController()->isRange()) {
2354 Node* selectionNode = selectionController()->selection().start().node();
2355 if (enclosingList(selectionNode))
2356 return trueTriState;
2358 //FIXME: Support ranges
2364 Frame::TriState Frame::selectionHasStyle(CSSStyleDeclaration *style) const
2366 bool atStart = true;
2367 TriState state = falseTriState;
2369 RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
2371 if (!selectionController()->isRange()) {
2373 RefPtr<CSSComputedStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
2374 if (!selectionStyle)
2375 return falseTriState;
2376 updateState(mutableStyle.get(), selectionStyle.get(), atStart, state);
2378 ExceptionCode ec = 0;
2379 nodeToRemove->remove(ec);
2383 for (Node* node = selectionController()->start().node(); node; node = node->traverseNextNode()) {
2384 RefPtr<CSSComputedStyleDeclaration> computedStyle = new CSSComputedStyleDeclaration(node);
2386 updateState(mutableStyle.get(), computedStyle.get(), atStart, state);
2387 if (state == mixedTriState)
2389 if (node == selectionController()->end().node())
2397 bool Frame::selectionStartHasStyle(CSSStyleDeclaration *style) const
2400 RefPtr<CSSStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
2401 if (!selectionStyle)
2404 RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
2407 DeprecatedValueListConstIterator<CSSProperty> end;
2408 for (DeprecatedValueListConstIterator<CSSProperty> it = mutableStyle->valuesIterator(); it != end; ++it) {
2409 int propertyID = (*it).id();
2410 if (!equalIgnoringCase(mutableStyle->getPropertyValue(propertyID), selectionStyle->getPropertyValue(propertyID))) {
2417 ExceptionCode ec = 0;
2418 nodeToRemove->remove(ec);
2425 String Frame::selectionStartStylePropertyValue(int stylePropertyID) const
2428 RefPtr<CSSStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
2429 if (!selectionStyle)
2432 String value = selectionStyle->getPropertyValue(stylePropertyID);
2435 ExceptionCode ec = 0;
2436 nodeToRemove->remove(ec);
2443 CSSComputedStyleDeclaration *Frame::selectionComputedStyle(Node *&nodeToRemove) const
2450 if (selectionController()->isNone())
2453 RefPtr<Range> range(selectionController()->toRange());
2454 Position pos = range->editingStartPosition();
2456 Element *elem = pos.element();
2460 RefPtr<Element> styleElement = elem;
2461 ExceptionCode ec = 0;
2463 if (d->m_typingStyle) {
2464 styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec);
2467 styleElement->setAttribute(styleAttr, d->m_typingStyle->cssText().impl(), ec);
2470 styleElement->appendChild(document()->createEditingTextNode(""), ec);
2473 if (elem->renderer() && elem->renderer()->canHaveChildren()) {
2474 elem->appendChild(styleElement, ec);
2476 Node *parent = elem->parent();
2477 Node *next = elem->nextSibling();
2480 parent->insertBefore(styleElement, next, ec);
2482 parent->appendChild(styleElement, ec);
2487 nodeToRemove = styleElement.get();
2490 return new CSSComputedStyleDeclaration(styleElement);
2493 void Frame::applyEditingStyleToBodyElement() const
2498 RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body");
2499 unsigned len = list->length();
2500 for (unsigned i = 0; i < len; i++) {
2501 applyEditingStyleToElement(static_cast<Element*>(list->item(i)));
2505 void Frame::removeEditingStyleFromBodyElement() const
2510 RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body");
2511 unsigned len = list->length();
2512 for (unsigned i = 0; i < len; i++) {
2513 removeEditingStyleFromElement(static_cast<Element*>(list->item(i)));
2517 void Frame::applyEditingStyleToElement(Element* element) const
2522 CSSStyleDeclaration* style = element->style();
2525 ExceptionCode ec = 0;
2526 style->setProperty(CSS_PROP_WORD_WRAP, "break-word", false, ec);
2528 style->setProperty(CSS_PROP__WEBKIT_NBSP_MODE, "space", false, ec);
2530 style->setProperty(CSS_PROP__WEBKIT_LINE_BREAK, "after-white-space", false, ec);
2534 void Frame::removeEditingStyleFromElement(Element*) const
2538 bool Frame::isCharacterSmartReplaceExempt(UChar, bool)
2545 static HashSet<Frame*> lifeSupportSet;
2548 void Frame::endAllLifeSupport()
2551 HashSet<Frame*> lifeSupportCopy = lifeSupportSet;
2552 HashSet<Frame*>::iterator end = lifeSupportCopy.end();
2553 for (HashSet<Frame*>::iterator it = lifeSupportCopy.begin(); it != end; ++it)
2554 (*it)->endLifeSupport();
2558 void Frame::keepAlive()
2560 if (d->m_lifeSupportTimer.isActive())
2564 lifeSupportSet.add(this);
2566 d->m_lifeSupportTimer.startOneShot(0);
2569 void Frame::endLifeSupport()
2571 if (!d->m_lifeSupportTimer.isActive())
2573 d->m_lifeSupportTimer.stop();
2575 lifeSupportSet.remove(this);
2580 void Frame::lifeSupportTimerFired(Timer<Frame>*)
2583 lifeSupportSet.remove(this);
2588 // Workaround for the fact that it's hard to delete a frame.
2589 // Call this after doing user-triggered selections to make it easy to delete the frame you entirely selected.
2590 // Can't do this implicitly as part of every setSelection call because in some contexts it might not be good
2591 // for the focus to move to another frame. So instead we call it from places where we are selecting with the
2592 // mouse or the keyboard after setting the selection.
2593 void Frame::selectFrameElementInParentIfFullySelected()
2595 // Find the parent frame; if there is none, then we have nothing to do.
2596 Frame *parent = tree()->parent();
2599 FrameView *parentView = parent->view();
2603 // Check if the selection contains the entire frame contents; if not, then there is nothing to do.
2604 if (!selectionController()->isRange())
2606 if (!isStartOfDocument(selectionController()->selection().visibleStart()))
2608 if (!isEndOfDocument(selectionController()->selection().visibleEnd()))
2611 // Get to the <iframe> or <frame> (or even <object>) element in the parent frame.
2612 Document *doc = document();
2615 Element *ownerElement = doc->ownerElement();
2618 Node *ownerElementParent = ownerElement->parentNode();
2619 if (!ownerElementParent)
2622 // 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.
2623 if (!ownerElementParent->isContentEditable())
2626 // Create compute positions before and after the element.
2627 unsigned ownerElementNodeIndex = ownerElement->nodeIndex();
2628 VisiblePosition beforeOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex, SEL_DEFAULT_AFFINITY));
2629 VisiblePosition afterOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex + 1, VP_UPSTREAM_IF_POSSIBLE));
2631 // Focus on the parent frame, and then select from before this element to after.
2632 Selection newSelection(beforeOwnerElement, afterOwnerElement);
2633 if (parent->shouldChangeSelection(newSelection)) {
2634 parentView->setFocus();
2635 parent->selectionController()->setSelection(newSelection);
2639 void Frame::handleFallbackContent()
2641 Element* owner = ownerElement();
2642 if (!owner || !owner->hasTagName(objectTag))
2644 static_cast<HTMLObjectElement*>(owner)->renderFallbackContent();
2647 void Frame::setSettings(Settings *settings)
2649 d->m_settings = settings;
2652 void Frame::provisionalLoadStarted()
2654 // we don't want to wait until we get an actual http response back
2655 // to cancel pending redirects, otherwise they might fire before
2657 cancelRedirection(true);
2660 bool Frame::userGestureHint()
2662 Frame *rootFrame = this;
2663 while (rootFrame->tree()->parent())
2664 rootFrame = rootFrame->tree()->parent();
2666 if (rootFrame->jScript())
2667 return rootFrame->jScript()->interpreter()->wasRunByUserGesture();
2669 return true; // If JavaScript is disabled, a user gesture must have initiated the navigation
2672 RenderObject *Frame::renderer() const
2674 Document *doc = document();
2675 return doc ? doc->renderer() : 0;
2678 Element* Frame::ownerElement()
2680 return d->m_ownerElement;
2683 RenderPart* Frame::ownerRenderer()
2685 Element* ownerElement = d->m_ownerElement;
2688 return static_cast<RenderPart*>(ownerElement->renderer());
2691 IntRect Frame::selectionRect() const
2693 RenderView *root = static_cast<RenderView*>(renderer());
2697 return root->selectionRect();
2700 // returns FloatRect because going through IntRect would truncate any floats
2701 FloatRect Frame::visibleSelectionRect() const
2706 return intersection(selectionRect(), d->m_view->visibleContentRect());
2709 bool Frame::isFrameSet() const
2711 Document* document = d->m_doc.get();
2712 if (!document || !document->isHTMLDocument())
2714 Node *body = static_cast<HTMLDocument*>(document)->body();
2715 return body && body->renderer() && body->hasTagName(framesetTag);
2718 bool Frame::openURL(const KURL& URL)
2720 ASSERT_NOT_REACHED();
2724 void Frame::didNotOpenURL(const KURL& URL)
2726 if (d->m_submittedFormURL == URL)
2727 d->m_submittedFormURL = KURL();
2730 // Scans logically forward from "start", including any child frames
2731 static HTMLFormElement *scanForForm(Node *start)
2734 for (n = start; n; n = n->traverseNextNode()) {
2735 if (n->hasTagName(formTag))
2736 return static_cast<HTMLFormElement*>(n);
2737 else if (n->isHTMLElement() && static_cast<HTMLElement*>(n)->isGenericFormElement())
2738 return static_cast<HTMLGenericFormElement*>(n)->form();
2739 else if (n->hasTagName(frameTag) || n->hasTagName(iframeTag)) {
2740 Node *childDoc = static_cast<HTMLFrameElement*>(n)->contentDocument();
2741 if (HTMLFormElement *frameResult = scanForForm(childDoc))
2748 // We look for either the form containing the current focus, or for one immediately after it
2749 HTMLFormElement *Frame::currentForm() const
2751 // start looking either at the active (first responder) node, or where the selection is
2752 Node *start = d->m_doc ? d->m_doc->focusNode() : 0;
2754 start = selectionController()->start().node();
2756 // try walking up the node tree to find a form element
2758 for (n = start; n; n = n->parentNode()) {
2759 if (n->hasTagName(formTag))
2760 return static_cast<HTMLFormElement*>(n);
2761 else if (n->isHTMLElement()
2762 && static_cast<HTMLElement*>(n)->isGenericFormElement())
2763 return static_cast<HTMLGenericFormElement*>(n)->form();
2766 // try walking forward in the node tree to find a form element
2767 return start ? scanForForm(start) : 0;
2770 void Frame::setEncoding(const String& name, bool userChosen)
2772 if (!d->m_workingURL.isEmpty())
2773 receivedFirstData();
2774 d->m_encoding = name;
2775 d->m_haveEncoding = userChosen;
2778 void Frame::addData(const char *bytes, int length)
2780 ASSERT(d->m_workingURL.isEmpty());
2782 ASSERT(d->m_doc->parsing());
2783 write(bytes, length);
2786 // FIXME: should this go in SelectionController?
2787 void Frame::revealSelection(const RenderLayer::ScrollAlignment& alignment) const
2791 switch (selectionController()->state()) {
2792 case Selection::NONE:
2795 case Selection::CARET:
2796 rect = selectionController()->caretRect();
2799 case Selection::RANGE:
2800 rect = selectionRect();
2804 Position start = selectionController()->start();
2805 Position end = selectionController()->end();
2807 ASSERT(start.node());
2808 if (start.node() && start.node()->renderer()) {
2809 RenderLayer *layer = start.node()->renderer()->enclosingLayer();
2811 ASSERT(!end.node() || !end.node()->renderer()
2812 || (end.node()->renderer()->enclosingLayer() == layer));
2813 layer->scrollRectToVisible(rect, alignment, alignment);
2818 void Frame::revealCaret(const RenderLayer::ScrollAlignment& alignment) const
2820 if (!hasSelection())
2823 Position extent = selectionController()->extent();
2824 if (extent.node() && extent.node()->renderer()) {
2825 IntRect extentRect = VisiblePosition(extent).caretRect();
2826 RenderLayer* layer = extent.node()->renderer()->enclosingLayer();
2828 layer->scrollRectToVisible(extentRect, alignment, alignment);
2832 // FIXME: should this be here?
2833 bool Frame::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity)
2839 Node *node = document()->focusNode();
2841 node = d->m_mousePressNode.get();
2845 RenderObject *r = node->renderer();
2846 if (r != 0 && !r->isListBox()) {
2847 return r->scroll(direction, granularity);
2854 void Frame::handleAutoscroll(RenderObject* renderer)
2856 if (d->m_autoscrollTimer.isActive())
2858 d->m_autoscrollRenderer = renderer;
2859 startAutoscrollTimer();
2862 void Frame::autoscrollTimerFired(Timer<Frame>*)
2864 if (!d->m_bMousePressed){
2865 stopAutoscrollTimer();
2868 if (d->m_autoscrollRenderer) {
2869 d->m_autoscrollRenderer->autoscroll();
2873 RenderObject::NodeInfo Frame::nodeInfoAtPoint(const IntPoint& point, bool allowShadowContent)
2875 RenderObject::NodeInfo nodeInfo(true, true);
2876 renderer()->layer()->hitTest(nodeInfo, point);
2880 IntPoint widgetPoint(point);
2883 n = nodeInfo.innerNode();
2884 if (!n || !n->renderer() || !n->renderer()->isWidget())
2886 widget = static_cast<RenderWidget*>(n->renderer())->widget();
2887 if (!widget || !widget->isFrameView())
2889 Frame* frame = static_cast<HTMLFrameElement*>(n)->contentFrame();
2890 if (!frame || !frame->renderer())
2893 n->renderer()->absolutePosition(absX, absY, true);
2894 FrameView *view = static_cast<FrameView*>(widget);
2895 widgetPoint.setX(widgetPoint.x() - absX + view->contentsX());
2896 widgetPoint.setY(widgetPoint.y() - absY + view->contentsY());
2898 RenderObject::NodeInfo widgetNodeInfo(true, true);
2899 frame->renderer()->layer()->hitTest(widgetNodeInfo, widgetPoint);
2900 nodeInfo = widgetNodeInfo;
2903 if (!allowShadowContent) {
2904 Node* node = nodeInfo.innerNode();
2906 node = node->shadowAncestorNode();
2907 nodeInfo.setInnerNode(node);
2908 node = nodeInfo.innerNonSharedNode();
2910 node = node->shadowAncestorNode();
2911 nodeInfo.setInnerNonSharedNode(node);
2916 bool Frame::hasSelection()
2918 if (selectionController()->isNone())
2921 // If a part has a selection, it should also have a document.
2927 void Frame::startAutoscrollTimer()
2929 d->m_autoscrollTimer.startRepeating(autoscrollInterval);
2932 void Frame::stopAutoscrollTimer()
2934 d->m_autoscrollRenderer = 0;
2935 d->m_autoscrollTimer.stop();
2938 // FIXME: why is this here instead of on the FrameView?
2939 void Frame::paint(GraphicsContext* p, const IntRect& rect)
2943 if (!document() || document()->printing())
2944 fillWithRed = false; // Printing, don't fill with red (can't remember why).
2945 else if (document()->ownerElement())
2946 fillWithRed = false; // Subframe, don't fill with red.
2947 else if (view() && view()->isTransparent())
2948 fillWithRed = false; // Transparent, don't fill with red.
2949 else if (d->m_paintRestriction == PaintRestrictionSelectionOnly || d->m_paintRestriction == PaintRestrictionSelectionOnlyWhiteText)
2950 fillWithRed = false; // Selections are transparent, don't fill with red.
2951 else if (d->m_elementToDraw)
2952 fillWithRed = false; // Element images are transparent, don't fill with red.
2957 p->fillRect(rect, Color(0xFF, 0, 0));
2961 // d->m_elementToDraw is used to draw only one element
2962 RenderObject *eltRenderer = d->m_elementToDraw ? d->m_elementToDraw->renderer() : 0;
2963 if (d->m_paintRestriction == PaintRestrictionNone)
2964 renderer()->document()->invalidateRenderedRectsForMarkersInRect(rect);
2965 renderer()->layer()->paint(p, rect, d->m_paintRestriction, eltRenderer);
2968 // Regions may have changed as a result of the visibility/z-index of element changing.
2969 if (renderer()->document()->dashboardRegionsDirty())
2970 renderer()->view()->frameView()->updateDashboardRegions();
2973 LOG_ERROR("called Frame::paint with nil renderer");
2978 void Frame::adjustPageHeight(float *newBottom, float oldTop, float oldBottom, float bottomLimit)
2980 RenderView *root = static_cast<RenderView*>(document()->renderer());
2982 // Use a context with painting disabled.
2983 GraphicsContext context(0);
2984 root->setTruncatedAt((int)floorf(oldBottom));
2985 IntRect dirtyRect(0, (int)floorf(oldTop), root->docWidth(), (int)ceilf(oldBottom - oldTop));
2986 root->layer()->paint(&context, dirtyRect);
2987 *newBottom = root->bestTruncatedAt();
2988 if (*newBottom == 0)
2989 *newBottom = oldBottom;
2991 *newBottom = oldBottom;
2996 PausedTimeouts *Frame::pauseTimeouts()
2999 if (d->m_doc && d->m_doc->svgExtensions())
3000 d->m_doc->accessSVGExtensions()->pauseAnimations();
3003 if (d->m_doc && d->m_jscript) {
3004 if (Window* w = Window::retrieveWindow(this))
3005 return w->pauseTimeouts();
3010 void Frame::resumeTimeouts(PausedTimeouts* t)
3013 if (d->m_doc && d->m_doc->svgExtensions())
3014 d->m_doc->accessSVGExtensions()->unpauseAnimations();
3017 if (d->m_doc && d->m_jscript && d->m_bJScriptEnabled) {
3018 if (Window* w = Window::retrieveWindow(this))
3019 w->resumeTimeouts(t);
3023 bool Frame::canCachePage()
3025 // Only save page state if:
3026 // 1. We're not a frame or frameset.
3027 // 2. The page has no unload handler.
3028 // 3. The page has no password fields.
3029 // 4. The URL for the page is not https.
3030 // 5. The page has no applets.
3031 if (tree()->childCount() || d->m_plugins.size() ||
3033 d->m_url.protocol().startsWith("https") ||
3034 (d->m_doc && (d->m_doc->applets()->length() != 0 ||
3035 d->m_doc->hasWindowEventListener(unloadEvent) ||
3036 d->m_doc->hasPasswordField()))) {
3042 void Frame::saveWindowProperties(KJS::SavedProperties *windowProperties)
3044 Window *window = Window::retrieveWindow(this);
3046 window->saveProperties(*windowProperties);
3049 void Frame::saveLocationProperties(SavedProperties *locationProperties)
3051 Window *window = Window::retrieveWindow(this);
3054 Location *location = window->location();
3055 location->saveProperties(*locationProperties);
3059 void Frame::restoreWindowProperties(SavedProperties *windowProperties)
3061 Window *window = Window::retrieveWindow(this);
3063 window->restoreProperties(*windowProperties);
3066 void Frame::restoreLocationProperties(SavedProperties *locationProperties)
3068 Window *window = Window::retrieveWindow(this);
3071 Location *location = window->location();
3072 location->restoreProperties(*locationProperties);
3076 void Frame::saveInterpreterBuiltins(SavedBuiltins& interpreterBuiltins)
3079 jScript()->interpreter()->saveBuiltins(interpreterBuiltins);
3082 void Frame::restoreInterpreterBuiltins(const SavedBuiltins& interpreterBuiltins)
3085 jScript()->interpreter()->restoreBuiltins(interpreterBuiltins);
3088 Frame *Frame::frameForWidget(const Widget *widget)
3090 ASSERT_ARG(widget, widget);
3092 Node *node = nodeForWidget(widget);
3094 return frameForNode(node);
3096 // Assume all widgets are either form controls, or FrameViews.
3097 ASSERT(widget->isFrameView());
3098 return static_cast<const FrameView*>(widget)->frame();
3101 Frame *Frame::frameForNode(Node *node)
3103 ASSERT_ARG(node, node);
3104 return node->document()->frame();
3107 Node* Frame::nodeForWidget(const Widget* widget)
3109 ASSERT_ARG(widget, widget);
3110 WidgetClient* client = widget->client();
3113 return client->element(const_cast<Widget*>(widget));
3116 void Frame::clearDocumentFocus(Widget *widget)
3118 Node *node = nodeForWidget(widget);
3120 node->document()->setFocusNode(0);
3123 void Frame::updatePolicyBaseURL()
3125 if (tree()->parent() && tree()->parent()->document())
3126 setPolicyBaseURL(tree()->parent()->document()->policyBaseURL());
3128 setPolicyBaseURL(d->m_url.url());
3131 void Frame::setPolicyBaseURL(const String& s)
3134 document()->setPolicyBaseURL(s);
3135 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
3136 child->setPolicyBaseURL(s);
3139 void Frame::forceLayout()
3141 FrameView *v = d->m_view.get();
3144 // We cannot unschedule a pending relayout, since the force can be called with
3145 // a tiny rectangle from a drawRect update. By unscheduling we in effect
3146 // "validate" and stop the necessary full repaint from occurring. Basically any basic
3147 // append/remove DHTML is broken by this call. For now, I have removed the optimization
3148 // until we have a better invalidation stategy. -dwh
3149 //v->unscheduleRelayout();
3153 void Frame::forceLayoutWithPageWidthRange(float minPageWidth, float maxPageWidth)
3155 // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see
3156 // the state of things before and after the layout
3157 RenderView *root = static_cast<RenderView*>(document()->renderer());
3159 // This magic is basically copied from khtmlview::print
3160 int pageW = (int)ceilf(minPageWidth);
3161 root->setWidth(pageW);
3162 root->setNeedsLayoutAndMinMaxRecalc();
3165 // If we don't fit in the minimum page width, we'll lay out again. If we don't fit in the
3166 // maximum page width, we will lay out to the maximum page width and clip extra content.
3167 // FIXME: We are assuming a shrink-to-fit printing implementation. A cropping
3168 // implementation should not do this!
3169 int rightmostPos = root->rightmostPosition();
3170 if (rightmostPos > minPageWidth) {
3171 pageW = min(rightmostPos, (int)ceilf(maxPageWidth));
3172 root->setWidth(pageW);
3173 root->setNeedsLayoutAndMinMaxRecalc();
3179 void Frame::sendResizeEvent()
3181 if (Document* doc = document())
3182 doc->dispatchWindowEvent(EventNames::resizeEvent, false, false);
3185 void Frame::sendScrollEvent()
3187 FrameView *v = d->m_view.get();
3189 Document *doc = document();
3192 doc->dispatchHTMLEvent(scrollEvent, true, false);
3196 bool Frame::scrollbarsVisible()
3201 if (view()->hScrollBarMode() == ScrollBarAlwaysOff || view()->vScrollBarMode() == ScrollBarAlwaysOff)
3207 void Frame::addMetaData(const String& key, const String& value)
3209 d->m_metaData.set(key, value);
3212 // This does the same kind of work that Frame::openURL does, except it relies on the fact
3213 // that a higher level already checked that the URLs match and the scrolling is the right thing to do.
3214 void Frame::scrollToAnchor(const KURL& URL)
3221 // It's important to model this as a load that starts and immediately finishes.
3222 // Otherwise, the parent frame may think we never finished loading.
3223 d->m_bComplete = false;
3227 bool Frame::closeURL()
3229 saveDocumentState();
3231 clearUndoRedoOperations();
3235 bool Frame::canMouseDownStartSelect(Node* node)
3237 if (!node || !node->renderer())
3240 // Check to see if -webkit-user-select has been set to none
3241 if (!node->renderer()->canSelect())
3244 // Some controls and images can't start a select on a mouse down.
3245 for (RenderObject* curr = node->renderer(); curr; curr = curr->parent()) {
3246 if (curr->style()->userSelect() == SELECT_IGNORE)
3253 void Frame::clearTimers(FrameView *view)
3256 view->unscheduleRelayout();
3257 if (view->frame()) {
3258 Document* document = view->frame()->document();
3259 if (document && document->renderer() && document->renderer()->layer())
3260 document->renderer()->layer()->suspendMarquees();
3265 void Frame::clearTimers()
3267 clearTimers(d->m_view.get());
3270 RenderStyle *Frame::styleForSelectionStart(Node *&nodeToRemove) const
3276 if (selectionController()->isNone())
3279 Position pos = selectionController()->selection().visibleStart().deepEquivalent();
3280 if (!pos.inRenderedContent())
3282 Node *node = pos.node();
3286 if (!d->m_typingStyle)
3287 return node->renderer()->style();
3289 ExceptionCode ec = 0;
3290 RefPtr<Element> styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec);
3293 styleElement->setAttribute(styleAttr, d->m_typingStyle->cssText().impl(), ec);
3296 styleElement->appendChild(document()->createEditingTextNode(""), ec);
3299 node->parentNode()->appendChild(styleElement, ec);
3302 nodeToRemove = styleElement.get();
3303 return styleElement->renderer()->style();
3306 void Frame::setMediaType(const String& type)
3309 d->m_view->setMediaType(type);
3312 void Frame::setSelectionFromNone()
3314 // Put a caret inside the body if the entire frame is editable (either the
3315 // entire WebView is editable or designMode is on for this document).
3316 Document *doc = document();
3317 if (!doc || !selectionController()->isNone() || !isContentEditable())
3320 Node* node = doc->documentElement();
3321 while (node && !node->hasTagName(bodyTag))
3322 node = node->traverseNextNode();
3324 selectionController()->setSelection(Selection(Position(node, 0), DOWNSTREAM));
3327 bool Frame::isActive() const
3329 return d->m_isActive;
3332 void Frame::setIsActive(bool flag)
3334 if (d->m_isActive == flag)
3337 d->m_isActive = flag;
3339 // This method does the job of updating the view based on whether the view is "active".
3340 // This involves three kinds of drawing updates:
3342 // 1. The background color used to draw behind selected content (active | inactive color)
3344 d->m_view->updateContents(enclosingIntRect(visibleSelectionRect()));
3346 // 2. Caret blinking (blinks | does not blink)
3348 setSelectionFromNone();
3349 setCaretVisible(flag);
3351 // 3. The drawing of a focus ring around links in web pages.
3352 Document *doc = document();
3354 Node *node = doc->focusNode();
3357 if (node->renderer() && node->renderer()->style()->hasAppearance())
3358 theme()->stateChanged(node->renderer(), FocusState);
3362 // 4. Changing the tint of controls from clear to aqua/graphite and vice versa. We
3363 // do a "fake" paint. When the theme gets a paint call, it can then do an invalidate. This is only
3364 // done if the theme supports control tinting.
3365 if (doc && d->m_view && theme()->supportsControlTints() && renderer()) {
3366 doc->updateLayout(); // Ensure layout is up to date.
3367 IntRect visibleRect(enclosingIntRect(d->m_view->visibleContentRect()));
3368 GraphicsContext context((PlatformGraphicsContext*)0);
3369 context.setUpdatingControlTints(true);
3370 paint(&context, visibleRect);
3373 // 5. Enable or disable secure keyboard entry
3374 if ((flag && !isSecureKeyboardEntry() && doc && doc->focusNode() && doc->focusNode()->hasTagName(inputTag) &&
3375 static_cast<HTMLInputElement*>(doc->focusNode())->inputType() == HTMLInputElement::PASSWORD) ||
3376 (!flag && isSecureKeyboardEntry()))
3377 setSecureKeyboardEntry(flag);
3380 void Frame::setWindowHasFocus(bool flag)
3382 if (d->m_windowHasFocus == flag)
3384 d->m_windowHasFocus = flag;
3386 if (Document *doc = document())
3387 doc->dispatchWindowEvent(flag ? focusEvent : blurEvent, false, false);
3390 bool Frame::inViewSourceMode() const
3392 return d->m_inViewSourceMode;
3395 void Frame::setInViewSourceMode(bool mode) const
3397 d->m_inViewSourceMode = mode;
3400 UChar Frame::backslashAsCurrencySymbol() const
3402 Document *doc = document();
3405 Decoder *decoder = doc->decoder();
3409 return decoder->encoding().backslashAsCurrencySymbol();
3412 bool Frame::markedTextUsesUnderlines() const
3414 return d->m_markedTextUsesUnderlines;
3417 const Vector<MarkedTextUnderline>& Frame::markedTextUnderlines() const
3419 return d->m_markedTextUnderlines;
3422 // Searches from the beginning of the document if nothing is selected.
3423 bool Frame::findString(const String& target, bool forward, bool caseFlag, bool wrapFlag)
3425 if (target.isEmpty())
3428 // Initially search from the start (if forward) or end (if backward) of the selection, and search to edge of document.
3429 RefPtr<Range> searchRange(rangeOfContents(document()));
3430 Selection selection(selectionController()->selection());
3431 if (!selection.isNone()) {
3433 setStart(searchRange.get(), selection.visibleStart());
3435 setEnd(searchRange.get(), selection.visibleEnd());
3437 RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, forward, caseFlag));
3438 // If the found range is already selected, find again.
3439 // Build a selection with the found range to remove collapsed whitespace.
3440 // Compare ranges instead of selection objects to ignore the way that the current selection was made.
3441 if (!selection.isNone() && *Selection(resultRange.get()).toRange() == *selection.toRange()) {
3442 searchRange = rangeOfContents(document());
3444 setStart(searchRange.get(), selection.visibleEnd());
3446 setEnd(searchRange.get(), selection.visibleStart());
3447 resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
3452 // If we didn't find anything and we're wrapping, search again in the entire document (this will
3453 // redundantly re-search the area already searched in some cases).
3454 if (resultRange->collapsed(exception) && wrapFlag) {
3455 searchRange = rangeOfContents(document());
3456 resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
3457 // We used to return false here if we ended up with the same range that we started with
3458 // (e.g., the selection was already the only instance of this text). But we decided that
3459 // this should be a success case instead, so we'll just fall through in that case.
3462 if (resultRange->collapsed(exception))
3465 selectionController()->setSelection(Selection(resultRange.get(), DOWNSTREAM));
3470 unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag, unsigned limit)
3472 if (target.isEmpty())
3475 RefPtr<Range> searchRange(rangeOfContents(document()));
3478 unsigned matchCount = 0;
3480 RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, caseFlag));
3481 if (resultRange->collapsed(exception))
3484 // A non-collapsed result range can in some funky whitespace cases still not
3485 // advance the range's start position (4509328). Break to avoid infinite loop.
3486 VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
3487 if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
3492 document()->addMarker(resultRange.get(), DocumentMarker::TextMatch);
3494 // Stop looking if we hit the specified limit. A limit of 0 means no limit.
3495 if (limit > 0 && matchCount >= limit)
3498 setStart(searchRange.get(), newStart);
3501 // Do a "fake" paint in order to execute the code that computes the rendered rect for
3503 Document* doc = document();
3504 if (doc && d->m_view && renderer()) {
3505 doc->updateLayout(); // Ensure layout is up to date.
3506 IntRect visibleRect(enclosingIntRect(d->m_view->visibleContentRect()));
3507 GraphicsContext context((PlatformGraphicsContext*)0);
3508 context.setPaintingDisabled(true);
3509 paint(&context, visibleRect);
3515 bool Frame::markedTextMatchesAreHighlighted() const
3517 return d->m_highlightTextMatches;
3520 void Frame::setMarkedTextMatchesAreHighlighted(bool flag)
3522 if (flag == d->m_highlightTextMatches)
3525 d->m_highlightTextMatches = flag;
3526 document()->repaintMarkers(DocumentMarker::TextMatch);
3529 void Frame::prepareForUserAction()
3531 // Reset the multiple form submission protection code.
3532 // We'll let you submit the same form twice if you do two separate user actions.
3533 d->m_submittedFormURL = KURL();
3536 Node *Frame::mousePressNode()
3538 return d->m_mousePressNode.get();
3541 bool Frame::isComplete() const
3543 return d->m_bComplete;
3546 bool Frame::isLoadingMainResource() const
3548 return d->m_bLoadingMainResource;
3551 FrameTree* Frame::tree() const
3553 return &d->m_treeNode;
3556 DOMWindow* Frame::domWindow() const
3558 if (!d->m_domWindow)
3559 d->m_domWindow = new DOMWindow(const_cast<Frame*>(this));
3561 return d->m_domWindow.get();
3564 KURL Frame::url() const
3569 void Frame::startRedirectionTimer()
3571 d->m_redirectionTimer.startOneShot(d->m_delayRedirect);
3574 void Frame::stopRedirectionTimer()
3576 d->m_redirectionTimer.stop();
3579 void Frame::frameDetached()
3583 void Frame::updateBaseURLForEmptyDocument()
3585 Element* owner = ownerElement();
3586 // FIXME: Should embed be included?
3587 if (owner && (owner->hasTagName(iframeTag) || owner->hasTagName(objectTag) || owner->hasTagName(embedTag)))
3588 d->m_doc->setBaseURL(tree()->parent()->d->m_doc->baseURL());
3591 Page* Frame::page() const
3596 void Frame::pageDestroyed()
3600 // This will stop any JS timers
3601 if (d->m_jscript && d->m_jscript->haveInterpreter())
3602 if (Window* w = Window::retrieveWindow(this))
3603 w->disconnectFrame();
3606 void Frame::completed(bool complete)
3609 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
3610 child->parentCompleted();
3611 if (Frame* parent = tree()->parent())
3612 parent->childCompleted(complete);
3617 void Frame::setStatusBarText(const String&)
3621 void Frame::started()
3623 for (Frame* frame = this; frame; frame = frame->tree()->parent())
3624 frame->d->m_bComplete = false;
3627 void Frame::disconnectOwnerElement()
3629 if (d->m_ownerElement && d->m_page)
3630 d->m_page->decrementFrameCount();
3632 d->m_ownerElement = 0;
3635 String Frame::documentTypeString() const
3637 if (Document *doc = document())
3638 if (DocumentType *doctype = doc->realDocType())
3639 return doctype->toString();
3644 bool Frame::containsPlugins() const
3646 return d->m_plugins.size() != 0;
3649 bool Frame::prohibitsScrolling() const
3651 return d->m_prohibitsScrolling;
3654 void Frame::setProhibitsScrolling(const bool prohibit)
3656 d->m_prohibitsScrolling = prohibit;
3659 } // namespace WebCore