2006-12-18 Ada Chan <adachan@apple.com>
[WebKit-https.git] / WebCore / page / Frame.cpp
1 /* This file is part of the KDE project
2  *
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>
11  *
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.
16  *
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.
21  *
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.
26  */
27
28 #include "config.h"
29 #include "Frame.h"
30 #include "FramePrivate.h"
31
32 #include "ApplyStyleCommand.h"
33 #include "BeforeUnloadEvent.h"
34 #include "Chrome.h"
35 #include "CSSComputedStyleDeclaration.h"
36 #include "CSSProperty.h"
37 #include "CSSPropertyNames.h"
38 #include "Cache.h"
39 #include "CachedCSSStyleSheet.h"
40 #include "DOMWindow.h"
41 #include "DocLoader.h"
42 #include "DocumentType.h"
43 #include "EditingText.h"
44 #include "Event.h"
45 #include "EventNames.h"
46 #include "FloatRect.h"
47 #include "Frame.h"
48 #include "FrameLoadRequest.h"
49 #include "FrameLoader.h"
50 #include "FrameView.h"
51 #include "GraphicsContext.h"
52 #include "HTMLFormElement.h"
53 #include "HTMLFrameElementBase.h"
54 #include "HTMLGenericFormElement.h"
55 #include "HTMLInputElement.h"
56 #include "HTMLNames.h"
57 #include "HTMLObjectElement.h"
58 #include "HitTestRequest.h"
59 #include "HitTestResult.h"
60 #include "IconDatabase.h"
61 #include "IconLoader.h"
62 #include "ImageDocument.h"
63 #include "IndentOutdentCommand.h"
64 #include "MediaFeatureNames.h"
65 #include "MouseEventWithHitTestResults.h"
66 #include "NodeList.h"
67 #include "Page.h"
68 #include "PlatformScrollBar.h"
69 #include "RenderListBox.h"
70 #include "RenderObject.h"
71 #include "RenderPart.h"
72 #include "RenderTextControl.h"
73 #include "RenderTheme.h"
74 #include "RenderView.h"
75 #include "SegmentedString.h"
76 #include "TextIterator.h"
77 #include "TextResourceDecoder.h"
78 #include "TypingCommand.h"
79 #include "XMLTokenizer.h"
80 #include "cssstyleselector.h"
81 #include "htmlediting.h"
82 #include "kjs_proxy.h"
83 #include "kjs_window.h"
84 #include "markup.h"
85 #include "visible_units.h"
86 #include "xmlhttprequest.h"
87 #include <math.h>
88 #include <sys/types.h>
89 #include <wtf/Platform.h>
90
91 #if PLATFORM(MAC)
92 #include "FrameMac.h"
93 #endif
94
95 #if !PLATFORM(WIN_OS)
96 #include <unistd.h>
97 #endif
98
99 #ifdef SVG_SUPPORT
100 #include "SVGNames.h"
101 #include "XLinkNames.h"
102 #include "XMLNames.h"
103 #include "SVGDocument.h"
104 #include "SVGDocumentExtensions.h"
105 #endif
106
107 using namespace std;
108
109 using KJS::JSLock;
110 using KJS::JSValue;
111 using KJS::Location;
112 using KJS::PausedTimeouts;
113 using KJS::SavedProperties;
114 using KJS::SavedBuiltins;
115 using KJS::UString;
116 using KJS::Window;
117
118 namespace WebCore {
119
120 using namespace EventNames;
121 using namespace HTMLNames;
122
123 const double caretBlinkFrequency = 0.5;
124
125 class UserStyleSheetLoader : public CachedResourceClient {
126 public:
127     UserStyleSheetLoader(Frame* frame, const String& url, DocLoader* docLoader)
128         : m_frame(frame)
129         , m_cachedSheet(docLoader->requestCSSStyleSheet(url, ""))
130     {
131         m_cachedSheet->ref(this);
132     }
133     ~UserStyleSheetLoader()
134     {
135         m_cachedSheet->deref(this);
136     }
137 private:
138     virtual void setCSSStyleSheet(const String& /*URL*/, const String& /*charset*/, const String& sheet)
139     {
140         m_frame->setUserStyleSheet(sheet);
141     }
142     Frame* m_frame;
143     CachedCSSStyleSheet* m_cachedSheet;
144 };
145
146 #ifndef NDEBUG
147 struct FrameCounter { 
148     static int count; 
149     ~FrameCounter() { if (count != 0) fprintf(stderr, "LEAK: %d Frame\n", count); }
150 };
151 int FrameCounter::count = 0;
152 static FrameCounter frameCounter;
153 #endif
154
155 static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement)
156 {
157     if (!ownerElement)
158         return 0;
159     return ownerElement->document()->frame();
160 }
161
162 Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient) 
163     : d(new FramePrivate(page, parentFromOwnerElement(ownerElement), this, ownerElement, frameLoaderClient))
164 {
165     AtomicString::init();
166     EventNames::init();
167     HTMLNames::init();
168     QualifiedName::init();
169     MediaFeatureNames::init();
170
171 #ifdef SVG_SUPPORT
172     SVGNames::init();
173     XLinkNames::init();
174     XMLNames::init();
175 #endif
176
177     if (!ownerElement)
178         page->setMainFrame(this);
179     else {
180         // FIXME: Frames were originally created with a refcount of 1.
181         // Leave this ref call here until we can straighten that out.
182         ref();
183         page->incrementFrameCount();
184         ownerElement->m_contentFrame = this;
185     }
186
187 #ifndef NDEBUG
188     ++FrameCounter::count;
189 #endif
190 }
191
192 Frame::~Frame()
193 {
194     // FIXME: We should not be doing all this work inside the destructor
195
196     ASSERT(!d->m_lifeSupportTimer.isActive());
197
198 #ifndef NDEBUG
199     --FrameCounter::count;
200 #endif
201
202     if (d->m_jscript && d->m_jscript->haveInterpreter())
203         if (Window* w = Window::retrieveWindow(this)) {
204             w->disconnectFrame();
205             // Must clear the window pointer, otherwise we will not
206             // garbage-collect collect the window (inside the call to
207             // delete d below).
208             w = 0;
209         }
210
211     disconnectOwnerElement();
212     
213     if (d->m_domWindow)
214         d->m_domWindow->disconnectFrame();
215             
216     if (d->m_view) {
217         d->m_view->hide();
218         d->m_view->m_frame = 0;
219     }
220   
221     ASSERT(!d->m_lifeSupportTimer.isActive());
222
223     delete d->m_userStyleSheetLoader;
224     delete d;
225     d = 0;
226 }
227
228 FrameLoader* Frame::loader() const
229 {
230     return d->m_loader;
231 }
232
233 FrameView* Frame::view() const
234 {
235     return d->m_view.get();
236 }
237
238 void Frame::setView(FrameView* view)
239 {
240     // Detach the document now, so any onUnload handlers get run - if
241     // we wait until the view is destroyed, then things won't be
242     // hooked up enough for some JavaScript calls to work.
243     if (d->m_doc && view == 0)
244         d->m_doc->detach();
245
246     d->m_view = view;
247
248 #ifdef MULTIPLE_FORM_SUBMISSION_PROTECTION
249     // Only one form submission is allowed per view of a part.
250     // Since this part may be getting reused as a result of being
251     // pulled from the back/forward cache, reset this flag.
252     loader()->resetMultipleFormSubmissionProtection();
253 #endif
254 }
255
256 bool Frame::javaScriptEnabled() const
257 {
258     return d->m_bJScriptEnabled;
259 }
260
261 KJSProxy *Frame::scriptProxy()
262 {
263     if (!d->m_bJScriptEnabled)
264         return 0;
265
266     if (!d->m_jscript)
267         d->m_jscript = new KJSProxy(this);
268
269     return d->m_jscript;
270 }
271
272 bool Frame::javaEnabled() const
273 {
274     return d->m_settings->isJavaEnabled();
275 }
276
277 bool Frame::pluginsEnabled() const
278 {
279     return d->m_bPluginsEnabled;
280 }
281
282 Document *Frame::document() const
283 {
284     if (d)
285         return d->m_doc.get();
286     return 0;
287 }
288
289 void Frame::setDocument(Document* newDoc)
290 {
291     if (d) {
292         if (d->m_doc)
293             d->m_doc->detach();
294         d->m_doc = newDoc;
295         if (newDoc)
296             newDoc->attach();
297     }
298 }
299
300 const Settings *Frame::settings() const
301 {
302   return d->m_settings;
303 }
304
305 void Frame::setUserStyleSheetLocation(const KURL& url)
306 {
307     delete d->m_userStyleSheetLoader;
308     d->m_userStyleSheetLoader = 0;
309     if (d->m_doc && d->m_doc->docLoader())
310         d->m_userStyleSheetLoader = new UserStyleSheetLoader(this, url.url(), d->m_doc->docLoader());
311 }
312
313 void Frame::setUserStyleSheet(const String& styleSheet)
314 {
315     delete d->m_userStyleSheetLoader;
316     d->m_userStyleSheetLoader = 0;
317     if (d->m_doc)
318         d->m_doc->setUserStyleSheet(styleSheet);
319 }
320
321 void Frame::setStandardFont(const String& name)
322 {
323     d->m_settings->setStdFontName(AtomicString(name));
324 }
325
326 void Frame::setFixedFont(const String& name)
327 {
328     d->m_settings->setFixedFontName(AtomicString(name));
329 }
330
331 String Frame::selectedText() const
332 {
333     return plainText(selectionController()->toRange().get());
334 }
335
336 SelectionController* Frame::selectionController() const
337 {
338     return &d->m_selectionController;
339 }
340
341 Editor* Frame::editor() const
342 {
343     return &d->m_editor;
344 }
345
346 CommandByName* Frame::command() const
347 {
348     return &d->m_command;
349 }
350
351 TextGranularity Frame::selectionGranularity() const
352 {
353     return d->m_selectionGranularity;
354 }
355
356 void Frame::setSelectionGranularity(TextGranularity granularity) const
357 {
358     d->m_selectionGranularity = granularity;
359 }
360
361 SelectionController* Frame::dragCaretController() const
362 {
363     return d->m_page->dragCaretController();
364 }
365
366 const Selection& Frame::mark() const
367 {
368     return d->m_mark;
369 }
370
371 void Frame::setMark(const Selection& s)
372 {
373     ASSERT(!s.base().node() || s.base().node()->document() == document());
374     ASSERT(!s.extent().node() || s.extent().node()->document() == document());
375     ASSERT(!s.start().node() || s.start().node()->document() == document());
376     ASSERT(!s.end().node() || s.end().node()->document() == document());
377
378     d->m_mark = s;
379 }
380
381 void Frame::notifyRendererOfSelectionChange(bool userTriggered)
382 {
383     RenderObject* renderer = 0;
384     if (selectionController()->rootEditableElement())
385         renderer = selectionController()->rootEditableElement()->shadowAncestorNode()->renderer();
386
387     // If the current selection is in a textfield or textarea, notify the renderer that the selection has changed
388     if (renderer && (renderer->isTextArea() || renderer->isTextField()))
389         static_cast<RenderTextControl*>(renderer)->selectionChanged(userTriggered);
390 }
391
392 void Frame::invalidateSelection()
393 {
394     selectionController()->setNeedsLayout();
395     selectionLayoutChanged();
396 }
397
398 void Frame::setCaretVisible(bool flag)
399 {
400     if (d->m_caretVisible == flag)
401         return;
402     clearCaretRectIfNeeded();
403     if (flag)
404         setFocusedNodeIfNeeded();
405     d->m_caretVisible = flag;
406     selectionLayoutChanged();
407 }
408
409
410 void Frame::clearCaretRectIfNeeded()
411 {
412     if (d->m_caretPaint) {
413         d->m_caretPaint = false;
414         selectionController()->invalidateCaretRect();
415     }        
416 }
417
418 // Helper function that tells whether a particular node is an element that has an entire
419 // Frame and FrameView, a <frame>, <iframe>, or <object>.
420 static bool isFrameElement(const Node *n)
421 {
422     if (!n)
423         return false;
424     RenderObject *renderer = n->renderer();
425     if (!renderer || !renderer->isWidget())
426         return false;
427     Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
428     return widget && widget->isFrameView();
429 }
430
431 void Frame::setFocusedNodeIfNeeded()
432 {
433     if (!document() || selectionController()->isNone() || !d->m_isActive)
434         return;
435
436     Node* target = selectionController()->rootEditableElement();
437     if (target) {
438         RenderObject* renderer = target->renderer();
439
440         // Walk up the render tree to search for a node to focus.
441         // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields.
442         while (renderer) {
443             // We don't want to set focus on a subframe when selecting in a parent frame,
444             // so add the !isFrameElement check here. There's probably a better way to make this
445             // work in the long term, but this is the safest fix at this time.
446             if (target && target->isMouseFocusable() && !isFrameElement(target)) {
447                 document()->setFocusedNode(target);
448                 return;
449             }
450             renderer = renderer->parent();
451             if (renderer)
452                 target = renderer->element();
453         }
454         document()->setFocusedNode(0);
455     }
456 }
457
458 void Frame::selectionLayoutChanged()
459 {
460     bool caretRectChanged = selectionController()->recomputeCaretRect();
461
462     bool shouldBlink = d->m_caretVisible
463         && selectionController()->isCaret() && selectionController()->isContentEditable();
464
465     // If the caret moved, stop the blink timer so we can restart with a
466     // black caret in the new location.
467     if (caretRectChanged || !shouldBlink)
468         d->m_caretBlinkTimer.stop();
469
470     // Start blinking with a black caret. Be sure not to restart if we're
471     // already blinking in the right location.
472     if (shouldBlink && !d->m_caretBlinkTimer.isActive()) {
473         d->m_caretBlinkTimer.startRepeating(caretBlinkFrequency);
474         d->m_caretPaint = true;
475     }
476
477     if (d->m_doc)
478         d->m_doc->updateSelection();
479 }
480
481 void Frame::setXPosForVerticalArrowNavigation(int x)
482 {
483     d->m_xPosForVerticalArrowNavigation = x;
484 }
485
486 int Frame::xPosForVerticalArrowNavigation() const
487 {
488     return d->m_xPosForVerticalArrowNavigation;
489 }
490
491 void Frame::caretBlinkTimerFired(Timer<Frame>*)
492 {
493     ASSERT(d->m_caretVisible);
494     ASSERT(selectionController()->isCaret());
495     bool caretPaint = d->m_caretPaint;
496     if (selectionController()->isCaretBlinkingSuspended() && caretPaint)
497         return;
498     d->m_caretPaint = !caretPaint;
499     selectionController()->invalidateCaretRect();
500 }
501
502 void Frame::paintCaret(GraphicsContext* p, const IntRect& rect) const
503 {
504     if (d->m_caretPaint && d->m_caretVisible)
505         selectionController()->paintCaret(p, rect);
506 }
507
508 void Frame::paintDragCaret(GraphicsContext* p, const IntRect& rect) const
509 {
510     SelectionController* dragCaretController = d->m_page->dragCaretController();
511     assert(dragCaretController->selection().isCaret());
512     if (dragCaretController->selection().start().node()->document()->frame() == this)
513         dragCaretController->paintCaret(p, rect);
514 }
515
516 int Frame::zoomFactor() const
517 {
518   return d->m_zoomFactor;
519 }
520
521 void Frame::setZoomFactor(int percent)
522 {  
523   if (d->m_zoomFactor == percent)
524       return;
525
526   d->m_zoomFactor = percent;
527
528   if (d->m_doc)
529       d->m_doc->recalcStyle(Node::Force);
530
531   for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
532       child->setZoomFactor(d->m_zoomFactor);
533
534   if (d->m_doc && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout())
535       view()->layout();
536 }
537
538 void Frame::setJSStatusBarText(const String& text)
539 {
540     d->m_kjsStatusBarText = text;
541     setStatusBarText(d->m_kjsStatusBarText);
542 }
543
544 void Frame::setJSDefaultStatusBarText(const String& text)
545 {
546     d->m_kjsDefaultStatusBarText = text;
547     setStatusBarText(d->m_kjsDefaultStatusBarText);
548 }
549
550 String Frame::jsStatusBarText() const
551 {
552     return d->m_kjsStatusBarText;
553 }
554
555 String Frame::jsDefaultStatusBarText() const
556 {
557    return d->m_kjsDefaultStatusBarText;
558 }
559
560 void Frame::reparseConfiguration()
561 {
562     if (d->m_doc)
563         d->m_doc->docLoader()->setAutoLoadImages(d->m_settings->autoLoadImages());
564         
565     d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled();
566     d->m_bJavaEnabled = d->m_settings->isJavaEnabled();
567     d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled();
568
569     const KURL& userStyleSheetLocation = d->m_settings->userStyleSheetLocation();
570     if (!userStyleSheetLocation.isEmpty())
571         setUserStyleSheetLocation(userStyleSheetLocation);
572     else
573         setUserStyleSheet(String());
574
575     // FIXME: It's not entirely clear why the following is needed.
576     // The document automatically does this as required when you set the style sheet.
577     // But we had problems when this code was removed. Details are in
578     // <http://bugs.webkit.org/show_bug.cgi?id=8079>.
579     if (d->m_doc)
580         d->m_doc->updateStyleSelector();
581 }
582
583 bool Frame::shouldChangeSelection(const Selection& newSelection) const
584 {
585     return shouldChangeSelection(selectionController()->selection(), newSelection, newSelection.affinity(), false);
586 }
587
588 bool Frame::shouldDeleteSelection(const Selection& newSelection) const
589 {
590     return true;
591 }
592
593 bool Frame::isContentEditable() const 
594 {
595     if (!d->m_doc)
596         return false;
597     return d->m_doc->inDesignMode();
598 }
599
600 void Frame::textFieldDidBeginEditing(Element* input)
601 {
602 }
603
604 void Frame::textFieldDidEndEditing(Element* input)
605 {
606 }
607
608 void Frame::textDidChangeInTextField(Element* input)
609 {
610 }
611
612 bool Frame::doTextFieldCommandFromEvent(Element*, KeyboardEvent*)
613 {
614     return false;
615 }
616
617 void Frame::textWillBeDeletedInTextField(Element* input)
618 {
619 }
620
621 void Frame::textDidChangeInTextArea(Element* input)
622 {
623 }
624
625 CSSMutableStyleDeclaration *Frame::typingStyle() const
626 {
627     return d->m_typingStyle.get();
628 }
629
630 void Frame::setTypingStyle(CSSMutableStyleDeclaration *style)
631 {
632     d->m_typingStyle = style;
633 }
634
635 void Frame::clearTypingStyle()
636 {
637     d->m_typingStyle = 0;
638 }
639
640 void Frame::copyToPasteboard()
641 {
642     issueCopyCommand();
643 }
644
645 void Frame::cutToPasteboard()
646 {
647     issueCutCommand();
648 }
649
650 void Frame::pasteFromPasteboard()
651 {
652     issuePasteCommand();
653 }
654
655 void Frame::pasteAndMatchStyle()
656 {
657     issuePasteAndMatchStyleCommand();
658 }
659
660 void Frame::transpose()
661 {
662     issueTransposeCommand();
663 }
664
665 void Frame::computeAndSetTypingStyle(CSSStyleDeclaration *style, EditAction editingAction)
666 {
667     if (!style || style->length() == 0) {
668         clearTypingStyle();
669         return;
670     }
671
672     // Calculate the current typing style.
673     RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
674     if (typingStyle()) {
675         typingStyle()->merge(mutableStyle.get());
676         mutableStyle = typingStyle();
677     }
678
679     Node *node = selectionController()->selection().visibleStart().deepEquivalent().node();
680     CSSComputedStyleDeclaration computedStyle(node);
681     computedStyle.diff(mutableStyle.get());
682     
683     // Handle block styles, substracting these from the typing style.
684     RefPtr<CSSMutableStyleDeclaration> blockStyle = mutableStyle->copyBlockProperties();
685     blockStyle->diff(mutableStyle.get());
686     if (document() && blockStyle->length() > 0)
687         applyCommand(new ApplyStyleCommand(document(), blockStyle.get(), editingAction));
688     
689     // Set the remaining style as the typing style.
690     d->m_typingStyle = mutableStyle.release();
691 }
692
693 static void updateState(CSSMutableStyleDeclaration *desiredStyle, CSSComputedStyleDeclaration *computedStyle, bool& atStart, Frame::TriState& state)
694 {
695     DeprecatedValueListConstIterator<CSSProperty> end;
696     for (DeprecatedValueListConstIterator<CSSProperty> it = desiredStyle->valuesIterator(); it != end; ++it) {
697         int propertyID = (*it).id();
698         String desiredProperty = desiredStyle->getPropertyValue(propertyID);
699         String computedProperty = computedStyle->getPropertyValue(propertyID);
700         Frame::TriState propertyState = equalIgnoringCase(desiredProperty, computedProperty)
701             ? Frame::trueTriState : Frame::falseTriState;
702         if (atStart) {
703             state = propertyState;
704             atStart = false;
705         } else if (state != propertyState) {
706             state = Frame::mixedTriState;
707             break;
708         }
709     }
710 }
711
712 Frame::TriState Frame::selectionHasStyle(CSSStyleDeclaration *style) const
713 {
714     bool atStart = true;
715     TriState state = falseTriState;
716
717     RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
718
719     if (!selectionController()->isRange()) {
720         Node* nodeToRemove;
721         RefPtr<CSSComputedStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
722         if (!selectionStyle)
723             return falseTriState;
724         updateState(mutableStyle.get(), selectionStyle.get(), atStart, state);
725         if (nodeToRemove) {
726             ExceptionCode ec = 0;
727             nodeToRemove->remove(ec);
728             assert(ec == 0);
729         }
730     } else {
731         for (Node* node = selectionController()->start().node(); node; node = node->traverseNextNode()) {
732             RefPtr<CSSComputedStyleDeclaration> computedStyle = new CSSComputedStyleDeclaration(node);
733             if (computedStyle)
734                 updateState(mutableStyle.get(), computedStyle.get(), atStart, state);
735             if (state == mixedTriState)
736                 break;
737             if (node == selectionController()->end().node())
738                 break;
739         }
740     }
741
742     return state;
743 }
744
745 String Frame::selectionStartStylePropertyValue(int stylePropertyID) const
746 {
747     Node *nodeToRemove;
748     RefPtr<CSSStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
749     if (!selectionStyle)
750         return String();
751
752     String value = selectionStyle->getPropertyValue(stylePropertyID);
753
754     if (nodeToRemove) {
755         ExceptionCode ec = 0;
756         nodeToRemove->remove(ec);
757         assert(ec == 0);
758     }
759
760     return value;
761 }
762
763 CSSComputedStyleDeclaration *Frame::selectionComputedStyle(Node *&nodeToRemove) const
764 {
765     nodeToRemove = 0;
766
767     if (!document())
768         return 0;
769
770     if (selectionController()->isNone())
771         return 0;
772
773     RefPtr<Range> range(selectionController()->toRange());
774     Position pos = range->editingStartPosition();
775
776     Element *elem = pos.element();
777     if (!elem)
778         return 0;
779     
780     RefPtr<Element> styleElement = elem;
781     ExceptionCode ec = 0;
782
783     if (d->m_typingStyle) {
784         styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec);
785         assert(ec == 0);
786
787         styleElement->setAttribute(styleAttr, d->m_typingStyle->cssText().impl(), ec);
788         assert(ec == 0);
789         
790         styleElement->appendChild(document()->createEditingTextNode(""), ec);
791         assert(ec == 0);
792
793         if (elem->renderer() && elem->renderer()->canHaveChildren()) {
794             elem->appendChild(styleElement, ec);
795         } else {
796             Node *parent = elem->parent();
797             Node *next = elem->nextSibling();
798
799             if (next) {
800                 parent->insertBefore(styleElement, next, ec);
801             } else {
802                 parent->appendChild(styleElement, ec);
803             }
804         }
805         assert(ec == 0);
806
807         nodeToRemove = styleElement.get();
808     }
809
810     return new CSSComputedStyleDeclaration(styleElement);
811 }
812
813 void Frame::applyEditingStyleToBodyElement() const
814 {
815     if (!d->m_doc)
816         return;
817         
818     RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body");
819     unsigned len = list->length();
820     for (unsigned i = 0; i < len; i++) {
821         applyEditingStyleToElement(static_cast<Element*>(list->item(i)));    
822     }
823 }
824
825 void Frame::removeEditingStyleFromBodyElement() const
826 {
827     if (!d->m_doc)
828         return;
829         
830     RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body");
831     unsigned len = list->length();
832     for (unsigned i = 0; i < len; i++) {
833         removeEditingStyleFromElement(static_cast<Element*>(list->item(i)));    
834     }
835 }
836
837 void Frame::applyEditingStyleToElement(Element* element) const
838 {
839     if (!element)
840         return;
841
842     CSSStyleDeclaration* style = element->style();
843     ASSERT(style);
844
845     ExceptionCode ec = 0;
846     style->setProperty(CSS_PROP_WORD_WRAP, "break-word", false, ec);
847     ASSERT(ec == 0);
848     style->setProperty(CSS_PROP__WEBKIT_NBSP_MODE, "space", false, ec);
849     ASSERT(ec == 0);
850     style->setProperty(CSS_PROP__WEBKIT_LINE_BREAK, "after-white-space", false, ec);
851     ASSERT(ec == 0);
852 }
853
854 void Frame::removeEditingStyleFromElement(Element*) const
855 {
856 }
857
858 bool Frame::isCharacterSmartReplaceExempt(UChar, bool)
859 {
860     // no smart replace
861     return true;
862 }
863
864 #ifndef NDEBUG
865 static HashSet<Frame*> lifeSupportSet;
866 #endif
867
868 void Frame::endAllLifeSupport()
869 {
870 #ifndef NDEBUG
871     HashSet<Frame*> lifeSupportCopy = lifeSupportSet;
872     HashSet<Frame*>::iterator end = lifeSupportCopy.end();
873     for (HashSet<Frame*>::iterator it = lifeSupportCopy.begin(); it != end; ++it)
874         (*it)->endLifeSupport();
875 #endif
876 }
877
878 void Frame::keepAlive()
879 {
880     if (d->m_lifeSupportTimer.isActive())
881         return;
882     ref();
883 #ifndef NDEBUG
884     lifeSupportSet.add(this);
885 #endif
886     d->m_lifeSupportTimer.startOneShot(0);
887 }
888
889 void Frame::endLifeSupport()
890 {
891     if (!d->m_lifeSupportTimer.isActive())
892         return;
893     d->m_lifeSupportTimer.stop();
894 #ifndef NDEBUG
895     lifeSupportSet.remove(this);
896 #endif
897     deref();
898 }
899
900 void Frame::lifeSupportTimerFired(Timer<Frame>*)
901 {
902 #ifndef NDEBUG
903     lifeSupportSet.remove(this);
904 #endif
905     deref();
906 }
907
908 void Frame::setSettings(Settings *settings)
909 {
910     d->m_settings = settings;
911 }
912
913 RenderObject *Frame::renderer() const
914 {
915     Document *doc = document();
916     return doc ? doc->renderer() : 0;
917 }
918
919 HTMLFrameOwnerElement* Frame::ownerElement() const
920 {
921     return d->m_ownerElement;
922 }
923
924 RenderPart* Frame::ownerRenderer()
925 {
926     HTMLFrameOwnerElement* ownerElement = d->m_ownerElement;
927     if (!ownerElement)
928         return 0;
929     return static_cast<RenderPart*>(ownerElement->renderer());
930 }
931
932 IntRect Frame::selectionRect() const
933 {
934     RenderView *root = static_cast<RenderView*>(renderer());
935     if (!root)
936         return IntRect();
937
938     return root->selectionRect();
939 }
940
941 // returns FloatRect because going through IntRect would truncate any floats
942 FloatRect Frame::visibleSelectionRect() const
943 {
944     if (!d->m_view)
945         return FloatRect();
946     
947     return intersection(selectionRect(), d->m_view->visibleContentRect());
948 }
949
950 bool Frame::isFrameSet() const
951 {
952     Document* document = d->m_doc.get();
953     if (!document || !document->isHTMLDocument())
954         return false;
955     Node *body = static_cast<HTMLDocument*>(document)->body();
956     return body && body->renderer() && body->hasTagName(framesetTag);
957 }
958
959 // Scans logically forward from "start", including any child frames
960 static HTMLFormElement *scanForForm(Node *start)
961 {
962     Node *n;
963     for (n = start; n; n = n->traverseNextNode()) {
964         if (n->hasTagName(formTag))
965             return static_cast<HTMLFormElement*>(n);
966         else if (n->isHTMLElement() && static_cast<HTMLElement*>(n)->isGenericFormElement())
967             return static_cast<HTMLGenericFormElement*>(n)->form();
968         else if (n->hasTagName(frameTag) || n->hasTagName(iframeTag)) {
969             Node *childDoc = static_cast<HTMLFrameElementBase*>(n)->contentDocument();
970             if (HTMLFormElement *frameResult = scanForForm(childDoc))
971                 return frameResult;
972         }
973     }
974     return 0;
975 }
976
977 // We look for either the form containing the current focus, or for one immediately after it
978 HTMLFormElement *Frame::currentForm() const
979 {
980     // start looking either at the active (first responder) node, or where the selection is
981     Node *start = d->m_doc ? d->m_doc->focusedNode() : 0;
982     if (!start)
983         start = selectionController()->start().node();
984     
985     // try walking up the node tree to find a form element
986     Node *n;
987     for (n = start; n; n = n->parentNode()) {
988         if (n->hasTagName(formTag))
989             return static_cast<HTMLFormElement*>(n);
990         else if (n->isHTMLElement()
991                    && static_cast<HTMLElement*>(n)->isGenericFormElement())
992             return static_cast<HTMLGenericFormElement*>(n)->form();
993     }
994     
995     // try walking forward in the node tree to find a form element
996     return start ? scanForForm(start) : 0;
997 }
998
999 // FIXME: should this go in SelectionController?
1000 void Frame::revealSelection(const RenderLayer::ScrollAlignment& alignment) const
1001 {
1002     IntRect rect;
1003     
1004     switch (selectionController()->state()) {
1005         case Selection::NONE:
1006             return;
1007             
1008         case Selection::CARET:
1009             rect = selectionController()->caretRect();
1010             break;
1011             
1012         case Selection::RANGE:
1013             rect = selectionRect();
1014             break;
1015     }
1016
1017     Position start = selectionController()->start();
1018
1019     ASSERT(start.node());
1020     if (start.node() && start.node()->renderer()) {
1021         // FIXME: This code only handles scrolling the startContainer's layer, but
1022         // the selection rect could intersect more than just that. 
1023         // See <rdar://problem/4799899>.
1024         if (RenderLayer *layer = start.node()->renderer()->enclosingLayer())
1025             layer->scrollRectToVisible(rect, alignment, alignment);
1026     }
1027 }
1028
1029 void Frame::revealCaret(const RenderLayer::ScrollAlignment& alignment) const
1030 {
1031     if (selectionController()->isNone())
1032         return;
1033
1034     Position extent = selectionController()->extent();
1035     if (extent.node() && extent.node()->renderer()) {
1036         IntRect extentRect = VisiblePosition(extent).caretRect();
1037         RenderLayer* layer = extent.node()->renderer()->enclosingLayer();
1038         if (layer)
1039             layer->scrollRectToVisible(extentRect, alignment, alignment);
1040     }
1041 }
1042
1043 // FIXME: why is this here instead of on the FrameView?
1044 void Frame::paint(GraphicsContext* p, const IntRect& rect)
1045 {
1046 #ifndef NDEBUG
1047     bool fillWithRed;
1048     if (!document() || document()->printing())
1049         fillWithRed = false; // Printing, don't fill with red (can't remember why).
1050     else if (document()->ownerElement())
1051         fillWithRed = false; // Subframe, don't fill with red.
1052     else if (view() && view()->isTransparent())
1053         fillWithRed = false; // Transparent, don't fill with red.
1054     else if (d->m_paintRestriction == PaintRestrictionSelectionOnly || d->m_paintRestriction == PaintRestrictionSelectionOnlyWhiteText)
1055         fillWithRed = false; // Selections are transparent, don't fill with red.
1056     else if (d->m_elementToDraw)
1057         fillWithRed = false; // Element images are transparent, don't fill with red.
1058     else
1059         fillWithRed = true;
1060     
1061     if (fillWithRed)
1062         p->fillRect(rect, Color(0xFF, 0, 0));
1063 #endif
1064     
1065     if (renderer()) {
1066         // d->m_elementToDraw is used to draw only one element
1067         RenderObject *eltRenderer = d->m_elementToDraw ? d->m_elementToDraw->renderer() : 0;
1068         if (d->m_paintRestriction == PaintRestrictionNone)
1069             renderer()->document()->invalidateRenderedRectsForMarkersInRect(rect);
1070         renderer()->layer()->paint(p, rect, d->m_paintRestriction, eltRenderer);
1071
1072 #if PLATFORM(MAC)
1073         // Regions may have changed as a result of the visibility/z-index of element changing.
1074         if (renderer()->document()->dashboardRegionsDirty())
1075             renderer()->view()->frameView()->updateDashboardRegions();
1076 #endif
1077     } else
1078         LOG_ERROR("called Frame::paint with nil renderer");
1079 }
1080
1081 #if PLATFORM(CG)
1082
1083 void Frame::adjustPageHeight(float *newBottom, float oldTop, float oldBottom, float bottomLimit)
1084 {
1085     RenderView *root = static_cast<RenderView*>(document()->renderer());
1086     if (root) {
1087         // Use a context with painting disabled.
1088         GraphicsContext context((PlatformGraphicsContext*)0);
1089         root->setTruncatedAt((int)floorf(oldBottom));
1090         IntRect dirtyRect(0, (int)floorf(oldTop), root->docWidth(), (int)ceilf(oldBottom - oldTop));
1091         root->layer()->paint(&context, dirtyRect);
1092         *newBottom = root->bestTruncatedAt();
1093         if (*newBottom == 0)
1094             *newBottom = oldBottom;
1095     } else
1096         *newBottom = oldBottom;
1097 }
1098
1099 #endif
1100
1101 Frame* Frame::frameForWidget(const Widget* widget)
1102 {
1103     ASSERT_ARG(widget, widget);
1104     
1105     if (WidgetClient* client = widget->client()) {
1106         if (Element* element = client->element(const_cast<Widget*>(widget)))
1107             return element->document()->frame();
1108     }
1109     
1110     // Assume all widgets are either form controls, or FrameViews.
1111     ASSERT(widget->isFrameView());
1112     return static_cast<const FrameView*>(widget)->frame();
1113 }
1114
1115 void Frame::forceLayout()
1116 {
1117     FrameView *v = d->m_view.get();
1118     if (v) {
1119         v->layout(false);
1120         // We cannot unschedule a pending relayout, since the force can be called with
1121         // a tiny rectangle from a drawRect update.  By unscheduling we in effect
1122         // "validate" and stop the necessary full repaint from occurring.  Basically any basic
1123         // append/remove DHTML is broken by this call.  For now, I have removed the optimization
1124         // until we have a better invalidation stategy. -dwh
1125         //v->unscheduleRelayout();
1126     }
1127 }
1128
1129 void Frame::forceLayoutWithPageWidthRange(float minPageWidth, float maxPageWidth)
1130 {
1131     // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see
1132     // the state of things before and after the layout
1133     RenderView *root = static_cast<RenderView*>(document()->renderer());
1134     if (root) {
1135         // This magic is basically copied from khtmlview::print
1136         int pageW = (int)ceilf(minPageWidth);
1137         root->setWidth(pageW);
1138         root->setNeedsLayoutAndMinMaxRecalc();
1139         forceLayout();
1140         
1141         // If we don't fit in the minimum page width, we'll lay out again. If we don't fit in the
1142         // maximum page width, we will lay out to the maximum page width and clip extra content.
1143         // FIXME: We are assuming a shrink-to-fit printing implementation.  A cropping
1144         // implementation should not do this!
1145         int rightmostPos = root->rightmostPosition();
1146         if (rightmostPos > minPageWidth) {
1147             pageW = min(rightmostPos, (int)ceilf(maxPageWidth));
1148             root->setWidth(pageW);
1149             root->setNeedsLayoutAndMinMaxRecalc();
1150             forceLayout();
1151         }
1152     }
1153 }
1154
1155 void Frame::sendResizeEvent()
1156 {
1157     if (Document* doc = document())
1158         doc->dispatchWindowEvent(EventNames::resizeEvent, false, false);
1159 }
1160
1161 void Frame::sendScrollEvent()
1162 {
1163     FrameView *v = d->m_view.get();
1164     if (v) {
1165         Document *doc = document();
1166         if (!doc)
1167             return;
1168         doc->dispatchHTMLEvent(scrollEvent, true, false);
1169     }
1170 }
1171
1172 void Frame::clearTimers(FrameView *view)
1173 {
1174     if (view) {
1175         view->unscheduleRelayout();
1176         if (view->frame()) {
1177             Document* document = view->frame()->document();
1178             if (document && document->renderer() && document->renderer()->layer())
1179                 document->renderer()->layer()->suspendMarquees();
1180         }
1181     }
1182 }
1183
1184 void Frame::clearTimers()
1185 {
1186     clearTimers(d->m_view.get());
1187 }
1188
1189 RenderStyle *Frame::styleForSelectionStart(Node *&nodeToRemove) const
1190 {
1191     nodeToRemove = 0;
1192     
1193     if (!document())
1194         return 0;
1195     if (selectionController()->isNone())
1196         return 0;
1197     
1198     Position pos = selectionController()->selection().visibleStart().deepEquivalent();
1199     if (!pos.isCandidate())
1200         return 0;
1201     Node *node = pos.node();
1202     if (!node)
1203         return 0;
1204     
1205     if (!d->m_typingStyle)
1206         return node->renderer()->style();
1207     
1208     ExceptionCode ec = 0;
1209     RefPtr<Element> styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec);
1210     ASSERT(ec == 0);
1211     
1212     styleElement->setAttribute(styleAttr, d->m_typingStyle->cssText().impl(), ec);
1213     ASSERT(ec == 0);
1214     
1215     styleElement->appendChild(document()->createEditingTextNode(""), ec);
1216     ASSERT(ec == 0);
1217     
1218     node->parentNode()->appendChild(styleElement, ec);
1219     ASSERT(ec == 0);
1220     
1221     nodeToRemove = styleElement.get();    
1222     return styleElement->renderer()->style();
1223 }
1224
1225 void Frame::setSelectionFromNone()
1226 {
1227     // Put a caret inside the body if the entire frame is editable (either the 
1228     // entire WebView is editable or designMode is on for this document).
1229     Document *doc = document();
1230     if (!doc || !selectionController()->isNone() || !isContentEditable())
1231         return;
1232         
1233     Node* node = doc->documentElement();
1234     while (node && !node->hasTagName(bodyTag))
1235         node = node->traverseNextNode();
1236     if (node)
1237         selectionController()->setSelection(Selection(Position(node, 0), DOWNSTREAM));
1238 }
1239
1240 bool Frame::isActive() const
1241 {
1242     return d->m_isActive;
1243 }
1244
1245 void Frame::setIsActive(bool flag)
1246 {
1247     if (d->m_isActive == flag)
1248         return;
1249     
1250     d->m_isActive = flag;
1251
1252     // This method does the job of updating the view based on whether the view is "active".
1253     // This involves three kinds of drawing updates:
1254
1255     // 1. The background color used to draw behind selected content (active | inactive color)
1256     if (d->m_view)
1257         d->m_view->updateContents(enclosingIntRect(visibleSelectionRect()));
1258
1259     // 2. Caret blinking (blinks | does not blink)
1260     if (flag)
1261         setSelectionFromNone();
1262     setCaretVisible(flag);
1263     
1264     // 3. The drawing of a focus ring around links in web pages.
1265     Document *doc = document();
1266     if (doc) {
1267         Node *node = doc->focusedNode();
1268         if (node) {
1269             node->setChanged();
1270             if (node->renderer() && node->renderer()->style()->hasAppearance())
1271                 theme()->stateChanged(node->renderer(), FocusState);
1272         }
1273     }
1274     
1275     // 4. Changing the tint of controls from clear to aqua/graphite and vice versa.  We
1276     // do a "fake" paint.  When the theme gets a paint call, it can then do an invalidate.  This is only
1277     // done if the theme supports control tinting.
1278     if (doc && d->m_view && theme()->supportsControlTints() && renderer()) {
1279         doc->updateLayout(); // Ensure layout is up to date.
1280         IntRect visibleRect(enclosingIntRect(d->m_view->visibleContentRect()));
1281         GraphicsContext context((PlatformGraphicsContext*)0);
1282         context.setUpdatingControlTints(true);
1283         paint(&context, visibleRect);
1284     }
1285    
1286     // 5. Enable or disable secure keyboard entry
1287     if ((flag && !isSecureKeyboardEntry() && doc && doc->focusedNode() && doc->focusedNode()->hasTagName(inputTag) && 
1288             static_cast<HTMLInputElement*>(doc->focusedNode())->inputType() == HTMLInputElement::PASSWORD) ||
1289         (!flag && isSecureKeyboardEntry()))
1290             setSecureKeyboardEntry(flag);
1291 }
1292
1293 void Frame::setWindowHasFocus(bool flag)
1294 {
1295     if (d->m_windowHasFocus == flag)
1296         return;
1297     d->m_windowHasFocus = flag;
1298     
1299     if (Document *doc = document())
1300         doc->dispatchWindowEvent(flag ? focusEvent : blurEvent, false, false);
1301 }
1302
1303 bool Frame::inViewSourceMode() const
1304 {
1305     return d->m_inViewSourceMode;
1306 }
1307
1308 void Frame::setInViewSourceMode(bool mode) const
1309 {
1310     d->m_inViewSourceMode = mode;
1311 }
1312   
1313 UChar Frame::backslashAsCurrencySymbol() const
1314 {
1315     Document *doc = document();
1316     if (!doc)
1317         return '\\';
1318     TextResourceDecoder *decoder = doc->decoder();
1319     if (!decoder)
1320         return '\\';
1321
1322     return decoder->encoding().backslashAsCurrencySymbol();
1323 }
1324
1325 bool Frame::markedTextUsesUnderlines() const
1326 {
1327     return d->m_markedTextUsesUnderlines;
1328 }
1329
1330 const Vector<MarkedTextUnderline>& Frame::markedTextUnderlines() const
1331 {
1332     return d->m_markedTextUnderlines;
1333 }
1334
1335 // Searches from the beginning of the document if nothing is selected.
1336 bool Frame::findString(const String& target, bool forward, bool caseFlag, bool wrapFlag)
1337 {
1338     if (target.isEmpty())
1339         return false;
1340     
1341     // Initially search from the start (if forward) or end (if backward) of the selection, and search to edge of document.
1342     RefPtr<Range> searchRange(rangeOfContents(document()));
1343     Selection selection(selectionController()->selection());
1344     if (!selection.isNone()) {
1345         if (forward)
1346             setStart(searchRange.get(), selection.visibleStart());
1347         else
1348             setEnd(searchRange.get(), selection.visibleEnd());
1349     }
1350     RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, forward, caseFlag));
1351     // If the found range is already selected, find again.
1352     // Build a selection with the found range to remove collapsed whitespace.
1353     // Compare ranges instead of selection objects to ignore the way that the current selection was made.
1354     if (!selection.isNone() && *Selection(resultRange.get()).toRange() == *selection.toRange()) {
1355         searchRange = rangeOfContents(document());
1356         if (forward)
1357             setStart(searchRange.get(), selection.visibleEnd());
1358         else
1359             setEnd(searchRange.get(), selection.visibleStart());
1360         resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
1361     }
1362     
1363     int exception = 0;
1364     
1365     // If we didn't find anything and we're wrapping, search again in the entire document (this will
1366     // redundantly re-search the area already searched in some cases).
1367     if (resultRange->collapsed(exception) && wrapFlag) {
1368         searchRange = rangeOfContents(document());
1369         resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
1370         // We used to return false here if we ended up with the same range that we started with
1371         // (e.g., the selection was already the only instance of this text). But we decided that
1372         // this should be a success case instead, so we'll just fall through in that case.
1373     }
1374
1375     if (resultRange->collapsed(exception))
1376         return false;
1377
1378     selectionController()->setSelection(Selection(resultRange.get(), DOWNSTREAM));
1379     revealSelection();
1380     return true;
1381 }
1382
1383 unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag, unsigned limit)
1384 {
1385     if (target.isEmpty())
1386         return 0;
1387     
1388     RefPtr<Range> searchRange(rangeOfContents(document()));
1389     
1390     int exception = 0;
1391     unsigned matchCount = 0;
1392     do {
1393         RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, caseFlag));
1394         if (resultRange->collapsed(exception))
1395             break;
1396         
1397         // A non-collapsed result range can in some funky whitespace cases still not
1398         // advance the range's start position (4509328). Break to avoid infinite loop.
1399         VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
1400         if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
1401             break;
1402
1403         ++matchCount;
1404         
1405         document()->addMarker(resultRange.get(), DocumentMarker::TextMatch);        
1406         
1407         // Stop looking if we hit the specified limit. A limit of 0 means no limit.
1408         if (limit > 0 && matchCount >= limit)
1409             break;
1410         
1411         setStart(searchRange.get(), newStart);
1412     } while (true);
1413     
1414     // Do a "fake" paint in order to execute the code that computes the rendered rect for 
1415     // each text match.
1416     Document* doc = document();
1417     if (doc && d->m_view && renderer()) {
1418         doc->updateLayout(); // Ensure layout is up to date.
1419         IntRect visibleRect(enclosingIntRect(d->m_view->visibleContentRect()));
1420         GraphicsContext context((PlatformGraphicsContext*)0);
1421         context.setPaintingDisabled(true);
1422         paint(&context, visibleRect);
1423     }
1424     
1425     return matchCount;
1426 }
1427
1428 bool Frame::markedTextMatchesAreHighlighted() const
1429 {
1430     return d->m_highlightTextMatches;
1431 }
1432
1433 void Frame::setMarkedTextMatchesAreHighlighted(bool flag)
1434 {
1435     if (flag == d->m_highlightTextMatches)
1436         return;
1437     
1438     d->m_highlightTextMatches = flag;
1439     document()->repaintMarkers(DocumentMarker::TextMatch);
1440 }
1441
1442 FrameTree* Frame::tree() const
1443 {
1444     return &d->m_treeNode;
1445 }
1446
1447 DOMWindow* Frame::domWindow() const
1448 {
1449     if (!d->m_domWindow)
1450         d->m_domWindow = new DOMWindow(const_cast<Frame*>(this));
1451
1452     return d->m_domWindow.get();
1453 }
1454
1455 Page* Frame::page() const
1456 {
1457     return d->m_page;
1458 }
1459
1460 EventHandler* Frame::eventHandler() const
1461 {
1462     return &d->m_eventHandler;
1463 }
1464
1465 void Frame::pageDestroyed()
1466 {
1467     d->m_page = 0;
1468
1469     // This will stop any JS timers
1470     if (d->m_jscript && d->m_jscript->haveInterpreter())
1471         if (Window* w = Window::retrieveWindow(this))
1472             w->disconnectFrame();
1473 }
1474
1475 void Frame::setStatusBarText(const String&)
1476 {
1477 }
1478
1479 void Frame::disconnectOwnerElement()
1480 {
1481     if (d->m_ownerElement) {
1482         d->m_ownerElement->m_contentFrame = 0;
1483         if (d->m_page)
1484             d->m_page->decrementFrameCount();
1485     }
1486     d->m_ownerElement = 0;
1487 }
1488
1489 String Frame::documentTypeString() const
1490 {
1491     if (Document *doc = document())
1492         if (DocumentType *doctype = doc->realDocType())
1493             return doctype->toString();
1494
1495     return String();
1496 }
1497
1498 bool Frame::prohibitsScrolling() const
1499 {
1500     return d->m_prohibitsScrolling;
1501 }
1502
1503 void Frame::setProhibitsScrolling(bool prohibit)
1504 {
1505     d->m_prohibitsScrolling = prohibit;
1506 }
1507
1508 bool Frame::shouldClose()
1509 {
1510     Chrome* chrome = page() ? page()->chrome() : 0;
1511     if (!chrome || !chrome->canRunBeforeUnloadConfirmPanel())
1512         return true;
1513
1514     RefPtr<Document> doc = document();
1515     if (!doc)
1516         return true;
1517     HTMLElement* body = doc->body();
1518     if (!body)
1519         return true;
1520
1521     RefPtr<BeforeUnloadEvent> beforeUnloadEvent = new BeforeUnloadEvent;
1522     beforeUnloadEvent->setTarget(doc);
1523     doc->handleWindowEvent(beforeUnloadEvent.get(), false);
1524
1525     if (!beforeUnloadEvent->defaultPrevented() && doc)
1526         doc->defaultEventHandler(beforeUnloadEvent.get());
1527     if (beforeUnloadEvent->result().isNull())
1528         return true;
1529
1530     String text = beforeUnloadEvent->result();
1531     text.replace('\\', backslashAsCurrencySymbol());
1532
1533     return chrome->runBeforeUnloadConfirmPanel(text, this);
1534 }
1535
1536 void Frame::scheduleClose()
1537 {
1538     if (!shouldClose())
1539         return;
1540
1541     Chrome* chrome = page() ? page()->chrome() : 0;
1542     if (chrome)
1543         chrome->closeWindowSoon();
1544 }
1545
1546 FramePrivate::FramePrivate(Page* page, Frame* parent, Frame* thisFrame, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient)
1547     : m_page(page)
1548     , m_treeNode(thisFrame, parent)
1549     , m_ownerElement(ownerElement)
1550     , m_jscript(0)
1551     , m_bJScriptEnabled(true)
1552     , m_bJavaEnabled(true)
1553     , m_bPluginsEnabled(true)
1554     , m_settings(0)
1555     , m_zoomFactor(parent ? parent->d->m_zoomFactor : 100)
1556     , m_selectionController(thisFrame)
1557     , m_caretBlinkTimer(thisFrame, &Frame::caretBlinkTimerFired)
1558     , m_editor(thisFrame)
1559     , m_command(thisFrame)
1560     , m_eventHandler(thisFrame)
1561     , m_caretVisible(false)
1562     , m_caretPaint(true)
1563     , m_isActive(false)
1564     , m_lifeSupportTimer(thisFrame, &Frame::lifeSupportTimerFired)
1565     , m_loader(new FrameLoader(thisFrame, frameLoaderClient))
1566     , m_userStyleSheetLoader(0)
1567     , m_paintRestriction(PaintRestrictionNone)
1568     , m_markedTextUsesUnderlines(false)
1569     , m_highlightTextMatches(false)
1570     , m_windowHasFocus(false)
1571     , m_inViewSourceMode(false)
1572     , frameCount(0)
1573     , m_prohibitsScrolling(false)
1574 {
1575 }
1576
1577 FramePrivate::~FramePrivate()
1578 {
1579     delete m_jscript;
1580     delete m_loader;
1581 }
1582
1583 } // namespace WebCore