WebCore:
[WebKit-https.git] / WebCore / page / Frame.cpp
1 /*
2  * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
3  *                     1999 Lars Knoll <knoll@kde.org>
4  *                     1999 Antti Koivisto <koivisto@kde.org>
5  *                     2000 Simon Hausmann <hausmann@kde.org>
6  *                     2000 Stefan Schimanski <1Stein@gmx.de>
7  *                     2001 George Staikos <staikos@kde.org>
8  * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
9  * Copyright (C) 2005 Alexey Proskuryakov <ap@nypop.com>
10  * Copyright (C) 2007 Trolltech ASA
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 "CSSComputedStyleDeclaration.h"
35 #include "CSSProperty.h"
36 #include "CSSPropertyNames.h"
37 #include "CachedCSSStyleSheet.h"
38 #include "DOMWindow.h"
39 #include "DocLoader.h"
40 #include "DocumentType.h"
41 #include "EditingText.h"
42 #include "EditorClient.h"
43 #include "EventNames.h"
44 #include "FocusController.h"
45 #include "FrameLoader.h"
46 #include "FrameView.h"
47 #include "GraphicsContext.h"
48 #include "HitTestResult.h"
49 #include "HTMLDocument.h"
50 #include "HTMLFormElement.h"
51 #include "HTMLFrameElementBase.h"
52 #include "HTMLGenericFormElement.h"
53 #include "HTMLNames.h"
54 #include "HTMLTableCellElement.h"
55 #include "Logging.h"
56 #include "MediaFeatureNames.h"
57 #include "NodeList.h"
58 #include "Page.h"
59 #include "RegularExpression.h"
60 #include "RenderPart.h"
61 #include "RenderTableCell.h"
62 #include "RenderTextControl.h"
63 #include "RenderTheme.h"
64 #include "RenderView.h"
65 #include "Settings.h"
66 #include "SystemTime.h"
67 #include "TextIterator.h"
68 #include "TextResourceDecoder.h"
69 #include "XMLNames.h"
70 #include "bindings/NP_jsobject.h"
71 #include "bindings/npruntime_impl.h"
72 #include "bindings/runtime_root.h"
73 #include "kjs_proxy.h"
74 #include "kjs_window.h"
75 #include "visible_units.h"
76
77 #if ENABLE(SVG)
78 #include "SVGNames.h"
79 #include "XLinkNames.h"
80 #endif
81
82 using namespace std;
83
84 using KJS::JSLock;
85 using KJS::Window;
86
87 namespace WebCore {
88
89 using namespace EventNames;
90 using namespace HTMLNames;
91
92 static const double caretBlinkFrequency = 0.5;
93
94 double Frame::s_currentPaintTimeStamp = 0;
95
96 class UserStyleSheetLoader : public CachedResourceClient {
97 public:
98     UserStyleSheetLoader(PassRefPtr<Document> document, const String& url)
99         : m_document(document)
100         , m_cachedSheet(m_document->docLoader()->requestUserCSSStyleSheet(url, ""))
101     {
102         m_document->addPendingSheet();
103         m_cachedSheet->ref(this);
104     }
105     ~UserStyleSheetLoader()
106     {
107         if (!m_cachedSheet->isLoaded())
108             m_document->removePendingSheet();        
109         m_cachedSheet->deref(this);
110     }
111 private:
112     virtual void setCSSStyleSheet(const String& /*URL*/, const String& /*charset*/, const String& sheet)
113     {
114         m_document->removePendingSheet();
115         if (Frame* frame = m_document->frame())
116             frame->setUserStyleSheet(sheet);
117     }
118     RefPtr<Document> m_document;
119     CachedCSSStyleSheet* m_cachedSheet;
120 };
121
122 #ifndef NDEBUG
123 WTFLogChannel LogWebCoreFrameLeaks =  { 0x00000000, "", WTFLogChannelOn };
124
125 struct FrameCounter { 
126     static int count; 
127     ~FrameCounter() 
128     { 
129         if (count)
130             LOG(WebCoreFrameLeaks, "LEAK: %d Frame\n", count);
131     }
132 };
133 int FrameCounter::count = 0;
134 static FrameCounter frameCounter;
135 #endif
136
137 static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement)
138 {
139     if (!ownerElement)
140         return 0;
141     return ownerElement->document()->frame();
142 }
143
144 Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient) 
145     : d(new FramePrivate(page, parentFromOwnerElement(ownerElement), this, ownerElement, frameLoaderClient))
146 {
147     AtomicString::init();
148     EventNames::init();
149     HTMLNames::init();
150     QualifiedName::init();
151     MediaFeatureNames::init();
152
153 #if ENABLE(SVG)
154     SVGNames::init();
155     XLinkNames::init();
156 #endif
157
158     XMLNames::init();
159
160     if (!ownerElement)
161         page->setMainFrame(this);
162     else {
163         // FIXME: Frames were originally created with a refcount of 1.
164         // Leave this ref call here until we can straighten that out.
165         ref();
166         page->incrementFrameCount();
167         ownerElement->m_contentFrame = this;
168     }
169
170 #ifndef NDEBUG
171     ++FrameCounter::count;
172 #endif
173 }
174
175 Frame::~Frame()
176 {
177     setView(0);
178     loader()->clearRecordedFormValues();
179
180 #if PLATFORM(MAC)
181     setBridge(0);
182 #endif
183     
184     loader()->cancelAndClear();
185     
186     // FIXME: We should not be doing all this work inside the destructor
187
188     ASSERT(!d->m_lifeSupportTimer.isActive());
189
190 #ifndef NDEBUG
191     --FrameCounter::count;
192 #endif
193
194     if (d->m_jscript && d->m_jscript->haveInterpreter())
195         static_cast<Window*>(d->m_jscript->interpreter()->globalObject())->disconnectFrame();
196
197     disconnectOwnerElement();
198     
199     if (d->m_domWindow)
200         d->m_domWindow->disconnectFrame();
201             
202     if (d->m_view) {
203         d->m_view->hide();
204         d->m_view->clearFrame();
205     }
206   
207     ASSERT(!d->m_lifeSupportTimer.isActive());
208
209     delete d->m_userStyleSheetLoader;
210     delete d;
211     d = 0;
212 }
213
214 void Frame::init()
215 {
216     d->m_loader->init();
217 }
218
219 FrameLoader* Frame::loader() const
220 {
221     return d->m_loader;
222 }
223
224 FrameView* Frame::view() const
225 {
226     return d->m_view.get();
227 }
228
229 void Frame::setView(FrameView* view)
230 {
231     // Detach the document now, so any onUnload handlers get run - if
232     // we wait until the view is destroyed, then things won't be
233     // hooked up enough for some JavaScript calls to work.
234     if (d->m_doc && view == 0) {
235         d->m_doc->detach();
236         if (d->m_view)
237             d->m_view->unscheduleRelayout();
238     }
239     eventHandler()->clear();
240
241     d->m_view = view;
242
243     // Only one form submission is allowed per view of a part.
244     // Since this part may be getting reused as a result of being
245     // pulled from the back/forward cache, reset this flag.
246     loader()->resetMultipleFormSubmissionProtection();
247 }
248
249 KJSProxy *Frame::scriptProxy()
250 {
251     Settings* settings = this->settings();
252     if (!settings || !settings->isJavaScriptEnabled())
253         return 0;
254
255     if (!d->m_jscript)
256         d->m_jscript = new KJSProxy(this);
257
258     return d->m_jscript;
259 }
260
261 Document *Frame::document() const
262 {
263     if (d)
264         return d->m_doc.get();
265     return 0;
266 }
267
268 void Frame::setDocument(PassRefPtr<Document> newDoc)
269 {
270     if (d->m_doc && d->m_doc->attached())
271         d->m_doc->detach();
272
273     d->m_doc = newDoc;
274     if (d->m_doc && d->m_isActive)
275         setUseSecureKeyboardEntry(d->m_doc->useSecureKeyboardEntryWhenActive());
276         
277     if (d->m_doc && !d->m_doc->attached())
278         d->m_doc->attach();
279 }
280
281 Settings* Frame::settings() const
282 {
283     return d->m_page ? d->m_page->settings() : 0;
284 }
285
286 void Frame::setUserStyleSheetLocation(const KURL& url)
287 {
288     delete d->m_userStyleSheetLoader;
289     d->m_userStyleSheetLoader = 0;
290     if (d->m_doc && d->m_doc->docLoader())
291         d->m_userStyleSheetLoader = new UserStyleSheetLoader(d->m_doc, url.url());
292 }
293
294 void Frame::setUserStyleSheet(const String& styleSheet)
295 {
296     delete d->m_userStyleSheetLoader;
297     d->m_userStyleSheetLoader = 0;
298     if (d->m_doc)
299         d->m_doc->setUserStyleSheet(styleSheet);
300 }
301
302 String Frame::selectedText() const
303 {
304     return plainText(selectionController()->toRange().get());
305 }
306
307 Range* Frame::markedTextRange() const
308 {
309     return d->m_markedTextRange.get();
310 }
311
312
313 IntRect Frame::firstRectForRange(Range* range) const
314 {
315     int extraWidthToEndOfLine = 0;
316     ExceptionCode ec = 0;
317     ASSERT(range->startContainer(ec));
318     ASSERT(range->endContainer(ec));
319     IntRect startCaretRect = range->startContainer(ec)->renderer()->caretRect(range->startOffset(ec), DOWNSTREAM, &extraWidthToEndOfLine);
320     ASSERT(!ec);
321     IntRect endCaretRect = range->endContainer(ec)->renderer()->caretRect(range->endOffset(ec), UPSTREAM);
322     ASSERT(!ec);
323     
324     if (startCaretRect.y() == endCaretRect.y()) {
325         // start and end are on the same line
326         return IntRect(min(startCaretRect.x(), endCaretRect.x()), 
327                        startCaretRect.y(), 
328                        abs(endCaretRect.x() - startCaretRect.x()),
329                        max(startCaretRect.height(), endCaretRect.height()));
330     }
331     
332     // start and end aren't on the same line, so go from start to the end of its line
333     return IntRect(startCaretRect.x(), 
334                    startCaretRect.y(),
335                    startCaretRect.width() + extraWidthToEndOfLine,
336                    startCaretRect.height());
337 }
338
339 void Frame::setMarkedTextRange(Range* range, Vector<MarkedTextUnderline>& markedRangeDecorations)
340 {
341     int exception = 0;
342     
343     ASSERT(!range || range->startContainer(exception) == range->endContainer(exception));
344     ASSERT(!range || range->collapsed(exception) || range->startContainer(exception)->isTextNode());
345     
346     d->m_markedTextUnderlines.clear();
347     if (markedRangeDecorations.size()) {
348         d->m_markedTextUsesUnderlines = true;
349         d->m_markedTextUnderlines = markedRangeDecorations;
350     } else 
351         d->m_markedTextUsesUnderlines = false;
352     
353     if (d->m_markedTextRange.get() && document() && d->m_markedTextRange->startContainer(exception)->renderer())
354         d->m_markedTextRange->startContainer(exception)->renderer()->repaint();
355     
356     if (range && range->collapsed(exception))
357         d->m_markedTextRange = 0;
358     else
359         d->m_markedTextRange = range;
360     
361     if (d->m_markedTextRange.get() && document() && d->m_markedTextRange->startContainer(exception)->renderer())
362         d->m_markedTextRange->startContainer(exception)->renderer()->repaint();    
363 }
364
365 void Frame::selectRangeInMarkedText(unsigned selOffset, unsigned selLength)
366 {
367     ExceptionCode ec = 0;
368     
369     RefPtr<Range> selectedRange = document()->createRange();
370     Range* markedTextRange = this->markedTextRange();
371     
372     ASSERT(markedTextRange->startContainer(ec) == markedTextRange->endContainer(ec));
373     ASSERT(!ec);
374     unsigned selectionStart = markedTextRange->startOffset(ec) + selOffset;
375     unsigned selectionEnd = selectionStart + selLength;
376     ASSERT(!ec);
377     
378     selectedRange->setStart(markedTextRange->startContainer(ec), selectionStart, ec);
379     ASSERT(!ec);
380     selectedRange->setEnd(markedTextRange->startContainer(ec), selectionEnd, ec);
381     ASSERT(!ec);
382     
383     selectionController()->setSelectedRange(selectedRange.get(), DOWNSTREAM, false, ec);
384 }
385
386 SelectionController* Frame::selectionController() const
387 {
388     return &d->m_selectionController;
389 }
390
391 Editor* Frame::editor() const
392 {
393     return &d->m_editor;
394 }
395
396 CommandByName* Frame::command() const
397 {
398     return &d->m_command;
399 }
400
401 TextGranularity Frame::selectionGranularity() const
402 {
403     return d->m_selectionGranularity;
404 }
405
406 void Frame::setSelectionGranularity(TextGranularity granularity) const
407 {
408     d->m_selectionGranularity = granularity;
409 }
410
411 SelectionController* Frame::dragCaretController() const
412 {
413     return d->m_page->dragCaretController();
414 }
415
416
417 // Either get cached regexp or build one that matches any of the labels.
418 // The regexp we build is of the form:  (STR1|STR2|STRN)
419 static RegularExpression *regExpForLabels(const Vector<String>& labels)
420 {
421     // REVIEW- version of this call in FrameMac.mm caches based on the NSArray ptrs being
422     // the same across calls.  We can't do that.
423
424     static RegularExpression wordRegExp = RegularExpression("\\w");
425     DeprecatedString pattern("(");
426     unsigned int numLabels = labels.size();
427     unsigned int i;
428     for (i = 0; i < numLabels; i++) {
429         DeprecatedString label = labels[i].deprecatedString();
430
431         bool startsWithWordChar = false;
432         bool endsWithWordChar = false;
433         if (label.length() != 0) {
434             startsWithWordChar = wordRegExp.search(label.at(0)) >= 0;
435             endsWithWordChar = wordRegExp.search(label.at(label.length() - 1)) >= 0;
436         }
437         
438         if (i != 0)
439             pattern.append("|");
440         // Search for word boundaries only if label starts/ends with "word characters".
441         // If we always searched for word boundaries, this wouldn't work for languages
442         // such as Japanese.
443         if (startsWithWordChar) {
444             pattern.append("\\b");
445         }
446         pattern.append(label);
447         if (endsWithWordChar) {
448             pattern.append("\\b");
449         }
450     }
451     pattern.append(")");
452     return new RegularExpression(pattern, false);
453 }
454
455 String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell)
456 {
457     RenderTableCell* cellRenderer = static_cast<RenderTableCell*>(cell->renderer());
458
459     if (cellRenderer && cellRenderer->isTableCell()) {
460         RenderTableCell* cellAboveRenderer = cellRenderer->table()->cellAbove(cellRenderer);
461
462         if (cellAboveRenderer) {
463             HTMLTableCellElement* aboveCell =
464                 static_cast<HTMLTableCellElement*>(cellAboveRenderer->element());
465
466             if (aboveCell) {
467                 // search within the above cell we found for a match
468                 for (Node* n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) {
469                     if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
470                         // For each text chunk, run the regexp
471                         DeprecatedString nodeString = n->nodeValue().deprecatedString();
472                         int pos = regExp->searchRev(nodeString);
473                         if (pos >= 0)
474                             return nodeString.mid(pos, regExp->matchedLength());
475                     }
476                 }
477             }
478         }
479     }
480     // Any reason in practice to search all cells in that are above cell?
481     return String();
482 }
483
484 String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element)
485 {
486     RegularExpression* regExp = regExpForLabels(labels);
487     // We stop searching after we've seen this many chars
488     const unsigned int charsSearchedThreshold = 500;
489     // This is the absolute max we search.  We allow a little more slop than
490     // charsSearchedThreshold, to make it more likely that we'll search whole nodes.
491     const unsigned int maxCharsSearched = 600;
492     // If the starting element is within a table, the cell that contains it
493     HTMLTableCellElement* startingTableCell = 0;
494     bool searchedCellAbove = false;
495
496     // walk backwards in the node tree, until another element, or form, or end of tree
497     int unsigned lengthSearched = 0;
498     Node* n;
499     for (n = element->traversePreviousNode();
500          n && lengthSearched < charsSearchedThreshold;
501          n = n->traversePreviousNode())
502     {
503         if (n->hasTagName(formTag)
504             || (n->isHTMLElement()
505                 && static_cast<HTMLElement*>(n)->isGenericFormElement()))
506         {
507             // We hit another form element or the start of the form - bail out
508             break;
509         } else if (n->hasTagName(tdTag) && !startingTableCell) {
510             startingTableCell = static_cast<HTMLTableCellElement*>(n);
511         } else if (n->hasTagName(trTag) && startingTableCell) {
512             String result = searchForLabelsAboveCell(regExp, startingTableCell);
513             if (!result.isEmpty())
514                 return result;
515             searchedCellAbove = true;
516         } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
517             // For each text chunk, run the regexp
518             DeprecatedString nodeString = n->nodeValue().deprecatedString();
519             // add 100 for slop, to make it more likely that we'll search whole nodes
520             if (lengthSearched + nodeString.length() > maxCharsSearched)
521                 nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
522             int pos = regExp->searchRev(nodeString);
523             if (pos >= 0)
524                 return nodeString.mid(pos, regExp->matchedLength());
525             else
526                 lengthSearched += nodeString.length();
527         }
528     }
529
530     // If we started in a cell, but bailed because we found the start of the form or the
531     // previous element, we still might need to search the row above us for a label.
532     if (startingTableCell && !searchedCellAbove) {
533          return searchForLabelsAboveCell(regExp, startingTableCell);
534     }
535     return String();
536 }
537
538 String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* element)
539 {
540     DeprecatedString name = element->getAttribute(nameAttr).deprecatedString();
541     // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
542     name.replace(RegularExpression("[[:digit:]]"), " ");
543     name.replace('_', ' ');
544     
545     RegularExpression* regExp = regExpForLabels(labels);
546     // Use the largest match we can find in the whole name string
547     int pos;
548     int length;
549     int bestPos = -1;
550     int bestLength = -1;
551     int start = 0;
552     do {
553         pos = regExp->search(name, start);
554         if (pos != -1) {
555             length = regExp->matchedLength();
556             if (length >= bestLength) {
557                 bestPos = pos;
558                 bestLength = length;
559             }
560             start = pos+1;
561         }
562     } while (pos != -1);
563
564     if (bestPos != -1)
565         return name.mid(bestPos, bestLength);
566     return String();
567 }
568
569 const Selection& Frame::mark() const
570 {
571     return d->m_mark;
572 }
573
574 void Frame::setMark(const Selection& s)
575 {
576     ASSERT(!s.base().node() || s.base().node()->document() == document());
577     ASSERT(!s.extent().node() || s.extent().node()->document() == document());
578     ASSERT(!s.start().node() || s.start().node()->document() == document());
579     ASSERT(!s.end().node() || s.end().node()->document() == document());
580
581     d->m_mark = s;
582 }
583
584 void Frame::notifyRendererOfSelectionChange(bool userTriggered)
585 {
586     RenderObject* renderer = 0;
587     if (selectionController()->rootEditableElement())
588         renderer = selectionController()->rootEditableElement()->shadowAncestorNode()->renderer();
589
590     // If the current selection is in a textfield or textarea, notify the renderer that the selection has changed
591     if (renderer && (renderer->isTextArea() || renderer->isTextField()))
592         static_cast<RenderTextControl*>(renderer)->selectionChanged(userTriggered);
593 }
594
595 void Frame::invalidateSelection()
596 {
597     selectionController()->setNeedsLayout();
598     selectionLayoutChanged();
599 }
600
601 void Frame::setCaretVisible(bool flag)
602 {
603     if (d->m_caretVisible == flag)
604         return;
605     clearCaretRectIfNeeded();
606     d->m_caretVisible = flag;
607     selectionLayoutChanged();
608 }
609
610 void Frame::clearCaretRectIfNeeded()
611 {
612     if (d->m_caretPaint) {
613         d->m_caretPaint = false;
614         selectionController()->invalidateCaretRect();
615     }
616 }
617
618 // Helper function that tells whether a particular node is an element that has an entire
619 // Frame and FrameView, a <frame>, <iframe>, or <object>.
620 static bool isFrameElement(const Node *n)
621 {
622     if (!n)
623         return false;
624     RenderObject *renderer = n->renderer();
625     if (!renderer || !renderer->isWidget())
626         return false;
627     Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
628     return widget && widget->isFrameView();
629 }
630
631 void Frame::setFocusedNodeIfNeeded()
632 {
633     if (!document() || selectionController()->isNone() || !d->m_isActive)
634         return;
635
636     Node* target = selectionController()->rootEditableElement();
637     if (target) {
638         RenderObject* renderer = target->renderer();
639
640         // Walk up the render tree to search for a node to focus.
641         // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields.
642         while (renderer) {
643             // We don't want to set focus on a subframe when selecting in a parent frame,
644             // so add the !isFrameElement check here. There's probably a better way to make this
645             // work in the long term, but this is the safest fix at this time.
646             if (target && target->isMouseFocusable() && !isFrameElement(target)) {
647                 page()->focusController()->setFocusedNode(target, this);
648                 return;
649             }
650             renderer = renderer->parent();
651             if (renderer)
652                 target = renderer->element();
653         }
654         document()->setFocusedNode(0);
655     }
656 }
657
658 void Frame::selectionLayoutChanged()
659 {
660     bool caretRectChanged = selectionController()->recomputeCaretRect();
661
662     bool shouldBlink = d->m_caretVisible
663         && selectionController()->isCaret() && selectionController()->isContentEditable();
664
665     // If the caret moved, stop the blink timer so we can restart with a
666     // black caret in the new location.
667     if (caretRectChanged || !shouldBlink)
668         d->m_caretBlinkTimer.stop();
669
670     // Start blinking with a black caret. Be sure not to restart if we're
671     // already blinking in the right location.
672     if (shouldBlink && !d->m_caretBlinkTimer.isActive()) {
673         d->m_caretBlinkTimer.startRepeating(caretBlinkFrequency);
674         if (!d->m_caretPaint) {
675             d->m_caretPaint = true;
676             selectionController()->invalidateCaretRect();
677         }
678     }
679
680     if (d->m_doc)
681         d->m_doc->updateSelection();
682 }
683
684 void Frame::caretBlinkTimerFired(Timer<Frame>*)
685 {
686     ASSERT(d->m_caretVisible);
687     ASSERT(selectionController()->isCaret());
688     bool caretPaint = d->m_caretPaint;
689     if (selectionController()->isCaretBlinkingSuspended() && caretPaint)
690         return;
691     d->m_caretPaint = !caretPaint;
692     selectionController()->invalidateCaretRect();
693 }
694
695 void Frame::paintCaret(GraphicsContext* p, const IntRect& rect) const
696 {
697     if (d->m_caretPaint && d->m_caretVisible)
698         selectionController()->paintCaret(p, rect);
699 }
700
701 void Frame::paintDragCaret(GraphicsContext* p, const IntRect& rect) const
702 {
703     SelectionController* dragCaretController = d->m_page->dragCaretController();
704     ASSERT(dragCaretController->selection().isCaret());
705     if (dragCaretController->selection().start().node()->document()->frame() == this)
706         dragCaretController->paintCaret(p, rect);
707 }
708
709 int Frame::zoomFactor() const
710 {
711   return d->m_zoomFactor;
712 }
713
714 void Frame::setZoomFactor(int percent)
715 {  
716   if (d->m_zoomFactor == percent)
717       return;
718
719   d->m_zoomFactor = percent;
720   if (d->m_doc) {
721 #if ENABLE(SVG)
722     if (d->m_doc->isSVGDocument()) {
723          if (d->m_doc->renderer())
724              d->m_doc->renderer()->repaint();
725          return;
726     }
727 #endif
728       d->m_doc->recalcStyle(Node::Force);
729   }
730
731   for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
732       child->setZoomFactor(d->m_zoomFactor);
733
734   if (d->m_doc && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout())
735       view()->layout();
736 }
737
738 void Frame::setPrinting(bool printing, float minPageWidth, float maxPageWidth, bool adjustViewSize)
739 {
740     if (!d->m_doc)
741         return;
742
743     d->m_doc->setPrinting(printing);
744     view()->setMediaType(printing ? "print" : "screen");
745     d->m_doc->updateStyleSelector();
746     forceLayoutWithPageWidthRange(minPageWidth, maxPageWidth, adjustViewSize);
747
748     for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
749         child->setPrinting(printing, minPageWidth, maxPageWidth, adjustViewSize);
750 }
751
752 void Frame::setJSStatusBarText(const String& text)
753 {
754     d->m_kjsStatusBarText = text;
755     if (d->m_page)
756         d->m_page->chrome()->setStatusbarText(this, d->m_kjsStatusBarText);
757 }
758
759 void Frame::setJSDefaultStatusBarText(const String& text)
760 {
761     d->m_kjsDefaultStatusBarText = text;
762     if (d->m_page)
763         d->m_page->chrome()->setStatusbarText(this, d->m_kjsDefaultStatusBarText);
764 }
765
766 String Frame::jsStatusBarText() const
767 {
768     return d->m_kjsStatusBarText;
769 }
770
771 String Frame::jsDefaultStatusBarText() const
772 {
773    return d->m_kjsDefaultStatusBarText;
774 }
775
776 void Frame::reparseConfiguration()
777 {
778     if (d->m_doc)
779         d->m_doc->docLoader()->setAutoLoadImages(d->m_page && d->m_page->settings()->loadsImagesAutomatically());
780         
781     const KURL userStyleSheetLocation = d->m_page ? d->m_page->settings()->userStyleSheetLocation() : KURL();
782     if (!userStyleSheetLocation.isEmpty())
783         setUserStyleSheetLocation(userStyleSheetLocation);
784     else
785         setUserStyleSheet(String());
786
787     // FIXME: It's not entirely clear why the following is needed.
788     // The document automatically does this as required when you set the style sheet.
789     // But we had problems when this code was removed. Details are in
790     // <http://bugs.webkit.org/show_bug.cgi?id=8079>.
791     if (d->m_doc)
792         d->m_doc->updateStyleSelector();
793 }
794
795 bool Frame::shouldChangeSelection(const Selection& newSelection) const
796 {
797     return shouldChangeSelection(selectionController()->selection(), newSelection, newSelection.affinity(), false);
798 }
799
800 bool Frame::shouldChangeSelection(const Selection& oldSelection, const Selection& newSelection, EAffinity affinity, bool stillSelecting) const
801 {
802     return editor()->client()->shouldChangeSelectedRange(oldSelection.toRange().get(), newSelection.toRange().get(),
803                                                          affinity, stillSelecting);
804 }
805
806 bool Frame::shouldDeleteSelection(const Selection& selection) const
807 {
808     return editor()->client()->shouldDeleteRange(selection.toRange().get());
809 }
810
811 bool Frame::isContentEditable() const 
812 {
813     if (d->m_editor.clientIsEditable())
814         return true;
815     if (!d->m_doc)
816         return false;
817     return d->m_doc->inDesignMode();
818 }
819
820 #if !PLATFORM(MAC)
821
822 void Frame::setUseSecureKeyboardEntry(bool)
823 {
824 }
825
826 #endif
827
828 void Frame::updateSecureKeyboardEntryIfActive()
829 {
830     if (d->m_isActive)
831         setUseSecureKeyboardEntry(d->m_doc->useSecureKeyboardEntryWhenActive());
832 }
833
834 CSSMutableStyleDeclaration *Frame::typingStyle() const
835 {
836     return d->m_typingStyle.get();
837 }
838
839 void Frame::setTypingStyle(CSSMutableStyleDeclaration *style)
840 {
841     d->m_typingStyle = style;
842 }
843
844 void Frame::clearTypingStyle()
845 {
846     d->m_typingStyle = 0;
847 }
848
849 void Frame::transpose()
850 {
851     issueTransposeCommand();
852 }
853
854 void Frame::computeAndSetTypingStyle(CSSStyleDeclaration *style, EditAction editingAction)
855 {
856     if (!style || style->length() == 0) {
857         clearTypingStyle();
858         return;
859     }
860
861     // Calculate the current typing style.
862     RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
863     if (typingStyle()) {
864         typingStyle()->merge(mutableStyle.get());
865         mutableStyle = typingStyle();
866     }
867
868     Node *node = selectionController()->selection().visibleStart().deepEquivalent().node();
869     CSSComputedStyleDeclaration computedStyle(node);
870     computedStyle.diff(mutableStyle.get());
871     
872     // Handle block styles, substracting these from the typing style.
873     RefPtr<CSSMutableStyleDeclaration> blockStyle = mutableStyle->copyBlockProperties();
874     blockStyle->diff(mutableStyle.get());
875     if (document() && blockStyle->length() > 0)
876         applyCommand(new ApplyStyleCommand(document(), blockStyle.get(), editingAction));
877     
878     // Set the remaining style as the typing style.
879     d->m_typingStyle = mutableStyle.release();
880 }
881
882 static void updateState(CSSMutableStyleDeclaration *desiredStyle, CSSComputedStyleDeclaration *computedStyle, bool& atStart, Frame::TriState& state)
883 {
884     DeprecatedValueListConstIterator<CSSProperty> end;
885     for (DeprecatedValueListConstIterator<CSSProperty> it = desiredStyle->valuesIterator(); it != end; ++it) {
886         int propertyID = (*it).id();
887         String desiredProperty = desiredStyle->getPropertyValue(propertyID);
888         String computedProperty = computedStyle->getPropertyValue(propertyID);
889         Frame::TriState propertyState = equalIgnoringCase(desiredProperty, computedProperty)
890             ? Frame::trueTriState : Frame::falseTriState;
891         if (atStart) {
892             state = propertyState;
893             atStart = false;
894         } else if (state != propertyState) {
895             state = Frame::mixedTriState;
896             break;
897         }
898     }
899 }
900
901 Frame::TriState Frame::selectionHasStyle(CSSStyleDeclaration *style) const
902 {
903     bool atStart = true;
904     TriState state = falseTriState;
905
906     RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
907
908     if (!selectionController()->isRange()) {
909         Node* nodeToRemove;
910         RefPtr<CSSComputedStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
911         if (!selectionStyle)
912             return falseTriState;
913         updateState(mutableStyle.get(), selectionStyle.get(), atStart, state);
914         if (nodeToRemove) {
915             ExceptionCode ec = 0;
916             nodeToRemove->remove(ec);
917             ASSERT(ec == 0);
918         }
919     } else {
920         for (Node* node = selectionController()->start().node(); node; node = node->traverseNextNode()) {
921             RefPtr<CSSComputedStyleDeclaration> computedStyle = new CSSComputedStyleDeclaration(node);
922             if (computedStyle)
923                 updateState(mutableStyle.get(), computedStyle.get(), atStart, state);
924             if (state == mixedTriState)
925                 break;
926             if (node == selectionController()->end().node())
927                 break;
928         }
929     }
930
931     return state;
932 }
933
934 String Frame::selectionStartStylePropertyValue(int stylePropertyID) const
935 {
936     Node *nodeToRemove;
937     RefPtr<CSSStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove);
938     if (!selectionStyle)
939         return String();
940
941     String value = selectionStyle->getPropertyValue(stylePropertyID);
942
943     if (nodeToRemove) {
944         ExceptionCode ec = 0;
945         nodeToRemove->remove(ec);
946         ASSERT(ec == 0);
947     }
948
949     return value;
950 }
951
952 CSSComputedStyleDeclaration *Frame::selectionComputedStyle(Node *&nodeToRemove) const
953 {
954     nodeToRemove = 0;
955
956     if (!document())
957         return 0;
958
959     if (selectionController()->isNone())
960         return 0;
961
962     RefPtr<Range> range(selectionController()->toRange());
963     Position pos = range->editingStartPosition();
964
965     Element *elem = pos.element();
966     if (!elem)
967         return 0;
968     
969     RefPtr<Element> styleElement = elem;
970     ExceptionCode ec = 0;
971
972     if (d->m_typingStyle) {
973         styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec);
974         ASSERT(ec == 0);
975
976         styleElement->setAttribute(styleAttr, d->m_typingStyle->cssText().impl(), ec);
977         ASSERT(ec == 0);
978         
979         styleElement->appendChild(document()->createEditingTextNode(""), ec);
980         ASSERT(ec == 0);
981
982         if (elem->renderer() && elem->renderer()->canHaveChildren()) {
983             elem->appendChild(styleElement, ec);
984         } else {
985             Node *parent = elem->parent();
986             Node *next = elem->nextSibling();
987
988             if (next) {
989                 parent->insertBefore(styleElement, next, ec);
990             } else {
991                 parent->appendChild(styleElement, ec);
992             }
993         }
994         ASSERT(ec == 0);
995
996         nodeToRemove = styleElement.get();
997     }
998
999     return new CSSComputedStyleDeclaration(styleElement);
1000 }
1001
1002 void Frame::textFieldDidBeginEditing(Element* e)
1003 {
1004     if (editor()->client())
1005         editor()->client()->textFieldDidBeginEditing(e);
1006 }
1007
1008 void Frame::textFieldDidEndEditing(Element* e)
1009 {
1010     if (editor()->client())
1011         editor()->client()->textFieldDidEndEditing(e);
1012 }
1013
1014 void Frame::textDidChangeInTextField(Element* e)
1015 {
1016     if (editor()->client())
1017         editor()->client()->textDidChangeInTextField(e);
1018 }
1019
1020 bool Frame::doTextFieldCommandFromEvent(Element* e, KeyboardEvent* ke)
1021 {
1022     if (editor()->client())
1023         return editor()->client()->doTextFieldCommandFromEvent(e, ke);
1024
1025     return false;
1026 }
1027
1028 void Frame::textWillBeDeletedInTextField(Element* input)
1029 {
1030     if (editor()->client())
1031         editor()->client()->textWillBeDeletedInTextField(input);
1032 }
1033
1034 void Frame::textDidChangeInTextArea(Element* e)
1035 {
1036     if (editor()->client())
1037         editor()->client()->textDidChangeInTextArea(e);
1038 }
1039
1040 void Frame::applyEditingStyleToBodyElement() const
1041 {
1042     if (!d->m_doc)
1043         return;
1044         
1045     RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body");
1046     unsigned len = list->length();
1047     for (unsigned i = 0; i < len; i++) {
1048         applyEditingStyleToElement(static_cast<Element*>(list->item(i)));    
1049     }
1050 }
1051
1052 void Frame::removeEditingStyleFromBodyElement() const
1053 {
1054     if (!d->m_doc)
1055         return;
1056         
1057     RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body");
1058     unsigned len = list->length();
1059     for (unsigned i = 0; i < len; i++) {
1060         removeEditingStyleFromElement(static_cast<Element*>(list->item(i)));    
1061     }
1062 }
1063
1064 void Frame::applyEditingStyleToElement(Element* element) const
1065 {
1066     if (!element)
1067         return;
1068
1069     CSSStyleDeclaration* style = element->style();
1070     ASSERT(style);
1071
1072     ExceptionCode ec = 0;
1073     style->setProperty(CSS_PROP_WORD_WRAP, "break-word", false, ec);
1074     ASSERT(ec == 0);
1075     style->setProperty(CSS_PROP__WEBKIT_NBSP_MODE, "space", false, ec);
1076     ASSERT(ec == 0);
1077     style->setProperty(CSS_PROP__WEBKIT_LINE_BREAK, "after-white-space", false, ec);
1078     ASSERT(ec == 0);
1079 }
1080
1081 void Frame::removeEditingStyleFromElement(Element*) const
1082 {
1083 }
1084
1085 #ifndef NDEBUG
1086 static HashSet<Frame*>& keepAliveSet()
1087 {
1088     static HashSet<Frame*> staticKeepAliveSet;
1089     return staticKeepAliveSet;
1090 }
1091 #endif
1092
1093 void Frame::keepAlive()
1094 {
1095     if (d->m_lifeSupportTimer.isActive())
1096         return;
1097 #ifndef NDEBUG
1098     keepAliveSet().add(this);
1099 #endif
1100     ref();
1101     d->m_lifeSupportTimer.startOneShot(0);
1102 }
1103
1104 #ifndef NDEBUG
1105 void Frame::cancelAllKeepAlive()
1106 {
1107     HashSet<Frame*>::iterator end = keepAliveSet().end();
1108     for (HashSet<Frame*>::iterator it = keepAliveSet().begin(); it != end; ++it) {
1109         Frame* frame = *it;
1110         frame->d->m_lifeSupportTimer.stop();
1111         frame->deref();
1112     }
1113     keepAliveSet().clear();
1114 }
1115 #endif
1116
1117 void Frame::lifeSupportTimerFired(Timer<Frame>*)
1118 {
1119 #ifndef NDEBUG
1120     keepAliveSet().remove(this);
1121 #endif
1122     deref();
1123 }
1124
1125 KJS::Bindings::RootObject* Frame::bindingRootObject()
1126 {
1127     Settings* settings = this->settings();
1128     if (!settings || !settings->isJavaScriptEnabled())
1129         return 0;
1130
1131     if (!d->m_bindingRootObject) {
1132         JSLock lock;
1133         d->m_bindingRootObject = KJS::Bindings::RootObject::create(0, scriptProxy()->interpreter());
1134     }
1135     return d->m_bindingRootObject.get();
1136 }
1137
1138 PassRefPtr<KJS::Bindings::RootObject> Frame::createRootObject(void* nativeHandle, PassRefPtr<KJS::Interpreter> interpreter)
1139 {
1140     RootObjectMap::iterator it = d->m_rootObjects.find(nativeHandle);
1141     if (it != d->m_rootObjects.end())
1142         return it->second;
1143     
1144     RefPtr<KJS::Bindings::RootObject> rootObject = KJS::Bindings::RootObject::create(nativeHandle, interpreter);
1145     
1146     d->m_rootObjects.set(nativeHandle, rootObject);
1147     return rootObject.release();
1148 }
1149
1150 #if USE(NPOBJECT)
1151 NPObject* Frame::windowScriptNPObject()
1152 {
1153     if (!d->m_windowScriptNPObject) {
1154         Settings* settings = this->settings();
1155         if (settings && settings->isJavaScriptEnabled()) {
1156             // JavaScript is enabled, so there is a JavaScript window object.  Return an NPObject bound to the window
1157             // object.
1158             KJS::JSObject* win = KJS::Window::retrieveWindow(this);
1159             ASSERT(win);
1160             KJS::Bindings::RootObject* root = bindingRootObject();
1161             d->m_windowScriptNPObject = _NPN_CreateScriptObject(0, win, root, root);
1162         } else {
1163             // JavaScript is not enabled, so we cannot bind the NPObject to the JavaScript window object.
1164             // Instead, we create an NPObject of a different class, one which is not bound to a JavaScript object.
1165             d->m_windowScriptNPObject = _NPN_CreateNoScriptObject();
1166         }
1167     }
1168
1169     return d->m_windowScriptNPObject;
1170 }
1171 #endif
1172     
1173 void Frame::clearScriptProxy()
1174 {
1175     if (d->m_jscript)
1176         d->m_jscript->clear();
1177 }
1178
1179 void Frame::clearDOMWindow()
1180 {
1181     if (d->m_domWindow)
1182         d->m_domWindow->clear();
1183 }
1184
1185 void Frame::cleanupScriptObjectsForPlugin(void* nativeHandle)
1186 {
1187     RootObjectMap::iterator it = d->m_rootObjects.find(nativeHandle);
1188     
1189     if (it == d->m_rootObjects.end())
1190         return;
1191     
1192     it->second->invalidate();
1193     d->m_rootObjects.remove(it);
1194 }
1195     
1196 void Frame::cleanupScriptObjects()
1197 {
1198     cleanupPlatformScriptObjects();
1199     JSLock lock;
1200
1201     RootObjectMap::const_iterator end = d->m_rootObjects.end();
1202     for (RootObjectMap::const_iterator it = d->m_rootObjects.begin(); it != end; ++it)
1203         it->second->invalidate();
1204
1205     d->m_rootObjects.clear();
1206
1207     if (d->m_bindingRootObject) {
1208         d->m_bindingRootObject->invalidate();
1209         d->m_bindingRootObject = 0;
1210     }
1211
1212 #if USE(NPOBJECT)
1213     if (d->m_windowScriptNPObject) {
1214         // Call _NPN_DeallocateObject() instead of _NPN_ReleaseObject() so that we don't leak if a plugin fails to release the window
1215         // script object properly.
1216         // This shouldn't cause any problems for plugins since they should have already been stopped and destroyed at this point.
1217         _NPN_DeallocateObject(d->m_windowScriptNPObject);
1218         d->m_windowScriptNPObject = 0;
1219     }
1220 #endif
1221 }
1222
1223 RenderObject *Frame::renderer() const
1224 {
1225     Document *doc = document();
1226     return doc ? doc->renderer() : 0;
1227 }
1228
1229 HTMLFrameOwnerElement* Frame::ownerElement() const
1230 {
1231     return d->m_ownerElement;
1232 }
1233
1234 RenderPart* Frame::ownerRenderer()
1235 {
1236     HTMLFrameOwnerElement* ownerElement = d->m_ownerElement;
1237     if (!ownerElement)
1238         return 0;
1239     return static_cast<RenderPart*>(ownerElement->renderer());
1240 }
1241
1242 // returns FloatRect because going through IntRect would truncate any floats
1243 FloatRect Frame::selectionRect(bool clipToVisibleContent) const
1244 {
1245     RenderView *root = static_cast<RenderView*>(renderer());
1246     if (!root)
1247         return IntRect();
1248     
1249     IntRect selectionRect = root->selectionRect(clipToVisibleContent);
1250     return clipToVisibleContent ? intersection(selectionRect, d->m_view->visibleContentRect()) : selectionRect;
1251 }
1252
1253 void Frame::selectionTextRects(Vector<FloatRect>& rects, bool clipToVisibleContent) const
1254 {
1255     RenderView *root = static_cast<RenderView*>(renderer());
1256     if (!root)
1257         return;
1258
1259     RefPtr<Range> selectedRange = selectionController()->toRange();
1260
1261     Vector<IntRect> intRects;
1262     selectedRange->addLineBoxRects(intRects, true);
1263
1264     unsigned size = intRects.size();
1265     FloatRect visibleContentRect = d->m_view->visibleContentRect();
1266     for (unsigned i = 0; i < size; ++i)
1267         if (clipToVisibleContent)
1268             rects.append(intersection(intRects[i], visibleContentRect));
1269         else
1270             rects.append(intRects[i]);
1271 }
1272
1273
1274 bool Frame::isFrameSet() const
1275 {
1276     Document* document = d->m_doc.get();
1277     if (!document || !document->isHTMLDocument())
1278         return false;
1279     Node *body = static_cast<HTMLDocument*>(document)->body();
1280     return body && body->renderer() && body->hasTagName(framesetTag);
1281 }
1282
1283 // Scans logically forward from "start", including any child frames
1284 static HTMLFormElement *scanForForm(Node *start)
1285 {
1286     Node *n;
1287     for (n = start; n; n = n->traverseNextNode()) {
1288         if (n->hasTagName(formTag))
1289             return static_cast<HTMLFormElement*>(n);
1290         else if (n->isHTMLElement() && static_cast<HTMLElement*>(n)->isGenericFormElement())
1291             return static_cast<HTMLGenericFormElement*>(n)->form();
1292         else if (n->hasTagName(frameTag) || n->hasTagName(iframeTag)) {
1293             Node *childDoc = static_cast<HTMLFrameElementBase*>(n)->contentDocument();
1294             if (HTMLFormElement *frameResult = scanForForm(childDoc))
1295                 return frameResult;
1296         }
1297     }
1298     return 0;
1299 }
1300
1301 // We look for either the form containing the current focus, or for one immediately after it
1302 HTMLFormElement *Frame::currentForm() const
1303 {
1304     // start looking either at the active (first responder) node, or where the selection is
1305     Node *start = d->m_doc ? d->m_doc->focusedNode() : 0;
1306     if (!start)
1307         start = selectionController()->start().node();
1308     
1309     // try walking up the node tree to find a form element
1310     Node *n;
1311     for (n = start; n; n = n->parentNode()) {
1312         if (n->hasTagName(formTag))
1313             return static_cast<HTMLFormElement*>(n);
1314         else if (n->isHTMLElement()
1315                    && static_cast<HTMLElement*>(n)->isGenericFormElement())
1316             return static_cast<HTMLGenericFormElement*>(n)->form();
1317     }
1318     
1319     // try walking forward in the node tree to find a form element
1320     return start ? scanForForm(start) : 0;
1321 }
1322
1323 // FIXME: should this go in SelectionController?
1324 void Frame::revealSelection(const RenderLayer::ScrollAlignment& alignment) const
1325 {
1326     IntRect rect;
1327     
1328     switch (selectionController()->state()) {
1329         case Selection::NONE:
1330             return;
1331             
1332         case Selection::CARET:
1333             rect = selectionController()->caretRect();
1334             break;
1335             
1336         case Selection::RANGE:
1337             rect = enclosingIntRect(selectionRect(false));
1338             break;
1339     }
1340
1341     Position start = selectionController()->start();
1342
1343     ASSERT(start.node());
1344     if (start.node() && start.node()->renderer()) {
1345         // FIXME: This code only handles scrolling the startContainer's layer, but
1346         // the selection rect could intersect more than just that. 
1347         // See <rdar://problem/4799899>.
1348         if (RenderLayer *layer = start.node()->renderer()->enclosingLayer())
1349             layer->scrollRectToVisible(rect, alignment, alignment);
1350     }
1351 }
1352
1353 void Frame::revealCaret(const RenderLayer::ScrollAlignment& alignment) const
1354 {
1355     if (selectionController()->isNone())
1356         return;
1357
1358     Position extent = selectionController()->extent();
1359     if (extent.node() && extent.node()->renderer()) {
1360         IntRect extentRect = VisiblePosition(extent).caretRect();
1361         RenderLayer* layer = extent.node()->renderer()->enclosingLayer();
1362         if (layer)
1363             layer->scrollRectToVisible(extentRect, alignment, alignment);
1364     }
1365 }
1366
1367 // FIXME: why is this here instead of on the FrameView?
1368 void Frame::paint(GraphicsContext* p, const IntRect& rect)
1369 {
1370 #ifndef NDEBUG
1371     bool fillWithRed;
1372     if (!document() || document()->printing())
1373         fillWithRed = false; // Printing, don't fill with red (can't remember why).
1374     else if (document()->ownerElement())
1375         fillWithRed = false; // Subframe, don't fill with red.
1376     else if (view() && view()->isTransparent())
1377         fillWithRed = false; // Transparent, don't fill with red.
1378     else if (d->m_paintRestriction == PaintRestrictionSelectionOnly || d->m_paintRestriction == PaintRestrictionSelectionOnlyBlackText)
1379         fillWithRed = false; // Selections are transparent, don't fill with red.
1380     else if (d->m_elementToDraw)
1381         fillWithRed = false; // Element images are transparent, don't fill with red.
1382     else
1383         fillWithRed = true;
1384     
1385     if (fillWithRed)
1386         p->fillRect(rect, Color(0xFF, 0, 0));
1387 #endif
1388
1389     bool isTopLevelPainter = !s_currentPaintTimeStamp;
1390     if (isTopLevelPainter)
1391         s_currentPaintTimeStamp = currentTime();
1392     
1393     if (renderer()) {
1394         ASSERT(d->m_view && !d->m_view->needsLayout());
1395         ASSERT(!d->m_isPainting);
1396         
1397         d->m_isPainting = true;
1398         
1399         // d->m_elementToDraw is used to draw only one element
1400         RenderObject *eltRenderer = d->m_elementToDraw ? d->m_elementToDraw->renderer() : 0;
1401         if (d->m_paintRestriction == PaintRestrictionNone)
1402             renderer()->document()->invalidateRenderedRectsForMarkersInRect(rect);
1403         renderer()->layer()->paint(p, rect, d->m_paintRestriction, eltRenderer);
1404         
1405         d->m_isPainting = false;
1406
1407         // Regions may have changed as a result of the visibility/z-index of element changing.
1408         if (renderer()->document()->dashboardRegionsDirty())
1409             renderer()->view()->frameView()->updateDashboardRegions();
1410     } else
1411         LOG_ERROR("called Frame::paint with nil renderer");
1412         
1413     if (isTopLevelPainter)
1414         s_currentPaintTimeStamp = 0;
1415 }
1416
1417 void Frame::setPaintRestriction(PaintRestriction pr)
1418 {
1419     d->m_paintRestriction = pr;
1420 }
1421     
1422 bool Frame::isPainting() const
1423 {
1424     return d->m_isPainting;
1425 }
1426
1427 void Frame::adjustPageHeight(float *newBottom, float oldTop, float oldBottom, float bottomLimit)
1428 {
1429     RenderView *root = static_cast<RenderView*>(document()->renderer());
1430     if (root) {
1431         // Use a context with painting disabled.
1432         GraphicsContext context((PlatformGraphicsContext*)0);
1433         root->setTruncatedAt((int)floorf(oldBottom));
1434         IntRect dirtyRect(0, (int)floorf(oldTop), root->docWidth(), (int)ceilf(oldBottom - oldTop));
1435         root->layer()->paint(&context, dirtyRect);
1436         *newBottom = root->bestTruncatedAt();
1437         if (*newBottom == 0)
1438             *newBottom = oldBottom;
1439     } else
1440         *newBottom = oldBottom;
1441 }
1442
1443 Frame* Frame::frameForWidget(const Widget* widget)
1444 {
1445     ASSERT_ARG(widget, widget);
1446
1447     if (RenderWidget* renderer = RenderWidget::find(widget))
1448         if (Node* node = renderer->node())
1449             return node->document()->frame();
1450
1451     // Assume all widgets are either a FrameView or owned by a RenderWidget.
1452     // FIXME: That assumption is not right for scroll bars!
1453     ASSERT(widget->isFrameView());
1454     return static_cast<const FrameView*>(widget)->frame();
1455 }
1456
1457 void Frame::forceLayout(bool allowSubtree)
1458 {
1459     FrameView *v = d->m_view.get();
1460     if (v) {
1461         v->layout(allowSubtree);
1462         // We cannot unschedule a pending relayout, since the force can be called with
1463         // a tiny rectangle from a drawRect update.  By unscheduling we in effect
1464         // "validate" and stop the necessary full repaint from occurring.  Basically any basic
1465         // append/remove DHTML is broken by this call.  For now, I have removed the optimization
1466         // until we have a better invalidation stategy. -dwh
1467         //v->unscheduleRelayout();
1468     }
1469 }
1470
1471 void Frame::forceLayoutWithPageWidthRange(float minPageWidth, float maxPageWidth, bool adjustViewSize)
1472 {
1473     // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see
1474     // the state of things before and after the layout
1475     RenderView *root = static_cast<RenderView*>(document()->renderer());
1476     if (root) {
1477         // This magic is basically copied from khtmlview::print
1478         int pageW = (int)ceilf(minPageWidth);
1479         root->setWidth(pageW);
1480         root->setNeedsLayoutAndPrefWidthsRecalc();
1481         forceLayout();
1482         
1483         // If we don't fit in the minimum page width, we'll lay out again. If we don't fit in the
1484         // maximum page width, we will lay out to the maximum page width and clip extra content.
1485         // FIXME: We are assuming a shrink-to-fit printing implementation.  A cropping
1486         // implementation should not do this!
1487         int rightmostPos = root->rightmostPosition();
1488         if (rightmostPos > minPageWidth) {
1489             pageW = min(rightmostPos, (int)ceilf(maxPageWidth));
1490             root->setWidth(pageW);
1491             root->setNeedsLayoutAndPrefWidthsRecalc();
1492             forceLayout();
1493         }
1494     }
1495
1496     if (adjustViewSize && view())
1497         view()->adjustViewSize();
1498 }
1499
1500 void Frame::sendResizeEvent()
1501 {
1502     if (Document* doc = document())
1503         doc->dispatchWindowEvent(EventNames::resizeEvent, false, false);
1504 }
1505
1506 void Frame::sendScrollEvent()
1507 {
1508     FrameView* v = d->m_view.get();
1509     if (!v)
1510         return;
1511     v->setWasScrolledByUser(true);
1512     Document* doc = document();
1513     if (!doc)
1514         return;
1515     doc->dispatchHTMLEvent(scrollEvent, true, false);
1516 }
1517
1518 void Frame::clearTimers(FrameView *view)
1519 {
1520     if (view) {
1521         view->unscheduleRelayout();
1522         if (view->frame()) {
1523             Document* document = view->frame()->document();
1524             if (document && document->renderer() && document->renderer()->hasLayer())
1525                 document->renderer()->layer()->suspendMarquees();
1526         }
1527     }
1528 }
1529
1530 void Frame::clearTimers()
1531 {
1532     clearTimers(d->m_view.get());
1533 }
1534
1535 RenderStyle *Frame::styleForSelectionStart(Node *&nodeToRemove) const
1536 {
1537     nodeToRemove = 0;
1538     
1539     if (!document())
1540         return 0;
1541     if (selectionController()->isNone())
1542         return 0;
1543     
1544     Position pos = selectionController()->selection().visibleStart().deepEquivalent();
1545     if (!pos.isCandidate())
1546         return 0;
1547     Node *node = pos.node();
1548     if (!node)
1549         return 0;
1550     
1551     if (!d->m_typingStyle)
1552         return node->renderer()->style();
1553     
1554     ExceptionCode ec = 0;
1555     RefPtr<Element> styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec);
1556     ASSERT(ec == 0);
1557     
1558     String styleText = d->m_typingStyle->cssText() + " display: inline";
1559     styleElement->setAttribute(styleAttr, styleText.impl(), ec);
1560     ASSERT(ec == 0);
1561     
1562     styleElement->appendChild(document()->createEditingTextNode(""), ec);
1563     ASSERT(ec == 0);
1564     
1565     node->parentNode()->appendChild(styleElement, ec);
1566     ASSERT(ec == 0);
1567     
1568     nodeToRemove = styleElement.get();    
1569     return styleElement->renderer() ? styleElement->renderer()->style() : 0;
1570 }
1571
1572 void Frame::setSelectionFromNone()
1573 {
1574     // Put a caret inside the body if the entire frame is editable (either the 
1575     // entire WebView is editable or designMode is on for this document).
1576     Document *doc = document();
1577     if (!doc || !selectionController()->isNone() || !isContentEditable())
1578         return;
1579         
1580     Node* node = doc->documentElement();
1581     while (node && !node->hasTagName(bodyTag))
1582         node = node->traverseNextNode();
1583     if (node)
1584         selectionController()->setSelection(Selection(Position(node, 0), DOWNSTREAM));
1585 }
1586
1587 bool Frame::isActive() const
1588 {
1589     return d->m_isActive;
1590 }
1591
1592 void Frame::setIsActive(bool flag)
1593 {
1594     if (d->m_isActive == flag)
1595         return;
1596     d->m_isActive = flag;
1597
1598     // Because RenderObject::selectionBackgroundColor() and
1599     // RenderObject::selectionForegroundColor() check if the frame is active,
1600     // we have to update places those colors were painted.
1601     if (d->m_view)
1602         d->m_view->updateContents(enclosingIntRect(selectionRect()));
1603
1604     // Caret appears in the active frame.
1605     if (flag)
1606         setSelectionFromNone();
1607     setCaretVisible(flag);
1608
1609     // Because CSSStyleSelector::checkOneSelector() and
1610     // RenderTheme::isFocused() check if the frame is active, we have to
1611     // update style and theme state that depended on those.
1612     if (d->m_doc) {
1613         if (Node* node = d->m_doc->focusedNode()) {
1614             node->setChanged();
1615             if (RenderObject* renderer = node->renderer())
1616                 if (renderer && renderer->style()->hasAppearance())
1617                     theme()->stateChanged(renderer, FocusState);
1618         }
1619     }
1620
1621     // Secure keyboard entry is set by the active frame.
1622     if (d->m_doc->useSecureKeyboardEntryWhenActive())
1623         setUseSecureKeyboardEntry(flag);
1624 }
1625
1626 void Frame::setWindowHasFocus(bool flag)
1627 {
1628     if (d->m_windowHasFocus == flag)
1629         return;
1630     d->m_windowHasFocus = flag;
1631     
1632     if (Document *doc = document())
1633         doc->dispatchWindowEvent(flag ? focusEvent : blurEvent, false, false);
1634 }
1635
1636 bool Frame::inViewSourceMode() const
1637 {
1638     return d->m_inViewSourceMode;
1639 }
1640
1641 void Frame::setInViewSourceMode(bool mode) const
1642 {
1643     d->m_inViewSourceMode = mode;
1644 }
1645   
1646 UChar Frame::backslashAsCurrencySymbol() const
1647 {
1648     Document *doc = document();
1649     if (!doc)
1650         return '\\';
1651     TextResourceDecoder *decoder = doc->decoder();
1652     if (!decoder)
1653         return '\\';
1654
1655     return decoder->encoding().backslashAsCurrencySymbol();
1656 }
1657
1658 bool Frame::markedTextUsesUnderlines() const
1659 {
1660     return d->m_markedTextUsesUnderlines;
1661 }
1662
1663 const Vector<MarkedTextUnderline>& Frame::markedTextUnderlines() const
1664 {
1665     return d->m_markedTextUnderlines;
1666 }
1667
1668 static bool isInShadowTree(Node* node)
1669 {
1670     for (Node* n = node; n; n = n->parentNode())
1671         if (n->isShadowNode())
1672             return true;
1673     return false;
1674 }
1675
1676 // Searches from the beginning of the document if nothing is selected.
1677 bool Frame::findString(const String& target, bool forward, bool caseFlag, bool wrapFlag, bool startInSelection)
1678 {
1679     if (target.isEmpty() || !document())
1680         return false;
1681     
1682     // Start from an edge of the selection, if there's a selection that's not in shadow content. Which edge
1683     // is used depends on whether we're searching forward or backward, and whether startInSelection is set.
1684     RefPtr<Range> searchRange(rangeOfContents(document()));
1685     Selection selection(selectionController()->selection());
1686     Node* selectionBaseNode = selection.base().node();
1687     
1688     // FIXME 3099526: We don't search in the shadow trees (e.g. text fields and textareas), though we'd like to
1689     // someday. If we don't explicitly skip them here, we'll miss hits in the regular content.
1690     bool selectionIsInMainContent = selectionBaseNode && !isInShadowTree(selectionBaseNode);
1691
1692     if (selectionIsInMainContent) {
1693         if (forward)
1694             setStart(searchRange.get(), startInSelection ? selection.visibleStart() : selection.visibleEnd());
1695         else
1696             setEnd(searchRange.get(), startInSelection ? selection.visibleEnd() : selection.visibleStart());
1697     }
1698     RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, forward, caseFlag));
1699     // If we started in the selection and the found range exactly matches the existing selection, find again.
1700     // Build a selection with the found range to remove collapsed whitespace.
1701     // Compare ranges instead of selection objects to ignore the way that the current selection was made.
1702     if (startInSelection && selectionIsInMainContent && *Selection(resultRange.get()).toRange() == *selection.toRange()) {
1703         searchRange = rangeOfContents(document());
1704         if (forward)
1705             setStart(searchRange.get(), selection.visibleEnd());
1706         else
1707             setEnd(searchRange.get(), selection.visibleStart());
1708         resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
1709     }
1710     
1711     int exception = 0;
1712     
1713     // If we didn't find anything and we're wrapping, search again in the entire document (this will
1714     // redundantly re-search the area already searched in some cases).
1715     if (resultRange->collapsed(exception) && wrapFlag) {
1716         searchRange = rangeOfContents(document());
1717         resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
1718         // We used to return false here if we ended up with the same range that we started with
1719         // (e.g., the selection was already the only instance of this text). But we decided that
1720         // this should be a success case instead, so we'll just fall through in that case.
1721     }
1722
1723     if (resultRange->collapsed(exception))
1724         return false;
1725
1726     selectionController()->setSelection(Selection(resultRange.get(), DOWNSTREAM));
1727     revealSelection();
1728     return true;
1729 }
1730
1731 unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag, unsigned limit)
1732 {
1733     if (target.isEmpty() || !document())
1734         return 0;
1735     
1736     RefPtr<Range> searchRange(rangeOfContents(document()));
1737     
1738     int exception = 0;
1739     unsigned matchCount = 0;
1740     do {
1741         RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, caseFlag));
1742         if (resultRange->collapsed(exception))
1743             break;
1744         
1745         // A non-collapsed result range can in some funky whitespace cases still not
1746         // advance the range's start position (4509328). Break to avoid infinite loop.
1747         VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
1748         if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
1749             break;
1750
1751         ++matchCount;
1752         
1753         document()->addMarker(resultRange.get(), DocumentMarker::TextMatch);        
1754         
1755         // Stop looking if we hit the specified limit. A limit of 0 means no limit.
1756         if (limit > 0 && matchCount >= limit)
1757             break;
1758         
1759         setStart(searchRange.get(), newStart);
1760     } while (true);
1761     
1762     // Do a "fake" paint in order to execute the code that computes the rendered rect for 
1763     // each text match.
1764     Document* doc = document();
1765     if (doc && d->m_view && renderer()) {
1766         doc->updateLayout(); // Ensure layout is up to date.
1767         IntRect visibleRect(enclosingIntRect(d->m_view->visibleContentRect()));
1768         GraphicsContext context((PlatformGraphicsContext*)0);
1769         context.setPaintingDisabled(true);
1770         paint(&context, visibleRect);
1771     }
1772     
1773     return matchCount;
1774 }
1775
1776 bool Frame::markedTextMatchesAreHighlighted() const
1777 {
1778     return d->m_highlightTextMatches;
1779 }
1780
1781 void Frame::setMarkedTextMatchesAreHighlighted(bool flag)
1782 {
1783     if (flag == d->m_highlightTextMatches || !document())
1784         return;
1785     
1786     d->m_highlightTextMatches = flag;
1787     document()->repaintMarkers(DocumentMarker::TextMatch);
1788 }
1789
1790 FrameTree* Frame::tree() const
1791 {
1792     return &d->m_treeNode;
1793 }
1794
1795 DOMWindow* Frame::domWindow() const
1796 {
1797     if (!d->m_domWindow)
1798         d->m_domWindow = new DOMWindow(const_cast<Frame*>(this));
1799
1800     return d->m_domWindow.get();
1801 }
1802
1803 Page* Frame::page() const
1804 {
1805     return d->m_page;
1806 }
1807
1808 EventHandler* Frame::eventHandler() const
1809 {
1810     return &d->m_eventHandler;
1811 }
1812
1813 void Frame::pageDestroyed()
1814 {
1815     if (Frame* parent = tree()->parent())
1816         parent->loader()->checkLoadComplete();
1817
1818     if (d->m_page && d->m_page->focusController()->focusedFrame() == this)
1819         d->m_page->focusController()->setFocusedFrame(0);
1820
1821     // This will stop any JS timers
1822     if (d->m_jscript && d->m_jscript->haveInterpreter())
1823         if (Window* w = Window::retrieveWindow(this))
1824             w->disconnectFrame();
1825
1826     d->m_page = 0;
1827 }
1828
1829 void Frame::disconnectOwnerElement()
1830 {
1831     if (d->m_ownerElement) {
1832         d->m_ownerElement->m_contentFrame = 0;
1833         if (d->m_page)
1834             d->m_page->decrementFrameCount();
1835     }
1836     d->m_ownerElement = 0;
1837 }
1838
1839 String Frame::documentTypeString() const
1840 {
1841     if (Document *doc = document())
1842         if (DocumentType *doctype = doc->realDocType())
1843             return doctype->toString();
1844
1845     return String();
1846 }
1847
1848 bool Frame::prohibitsScrolling() const
1849 {
1850     return d->m_prohibitsScrolling;
1851 }
1852
1853 void Frame::setProhibitsScrolling(bool prohibit)
1854 {
1855     d->m_prohibitsScrolling = prohibit;
1856 }
1857
1858 void Frame::focusWindow()
1859 {
1860     if (!page())
1861         return;
1862
1863     // If we're a top level window, bring the window to the front.
1864     if (!tree()->parent())
1865         page()->chrome()->focus();
1866
1867     eventHandler()->focusDocumentView();
1868 }
1869
1870 void Frame::unfocusWindow()
1871 {
1872     if (!page())
1873         return;
1874     
1875     // If we're a top level window, deactivate the window.
1876     if (!tree()->parent())
1877         page()->chrome()->unfocus();
1878 }
1879
1880 bool Frame::shouldClose()
1881 {
1882     Chrome* chrome = page() ? page()->chrome() : 0;
1883     if (!chrome || !chrome->canRunBeforeUnloadConfirmPanel())
1884         return true;
1885
1886     RefPtr<Document> doc = document();
1887     if (!doc)
1888         return true;
1889     HTMLElement* body = doc->body();
1890     if (!body)
1891         return true;
1892
1893     RefPtr<BeforeUnloadEvent> beforeUnloadEvent = new BeforeUnloadEvent;
1894     beforeUnloadEvent->setTarget(doc);
1895     doc->handleWindowEvent(beforeUnloadEvent.get(), false);
1896
1897     if (!beforeUnloadEvent->defaultPrevented() && doc)
1898         doc->defaultEventHandler(beforeUnloadEvent.get());
1899     if (beforeUnloadEvent->result().isNull())
1900         return true;
1901
1902     String text = beforeUnloadEvent->result();
1903     text.replace('\\', backslashAsCurrencySymbol());
1904
1905     return chrome->runBeforeUnloadConfirmPanel(text, this);
1906 }
1907
1908 void Frame::scheduleClose()
1909 {
1910     if (!shouldClose())
1911         return;
1912
1913     Chrome* chrome = page() ? page()->chrome() : 0;
1914     if (chrome)
1915         chrome->closeWindowSoon();
1916 }
1917
1918 void Frame::respondToChangedSelection(const Selection& oldSelection, bool closeTyping)
1919 {
1920     if (document()) {
1921         bool isContinuousSpellCheckingEnabled = editor()->isContinuousSpellCheckingEnabled();
1922         bool isContinuousGrammarCheckingEnabled = isContinuousSpellCheckingEnabled && editor()->isGrammarCheckingEnabled();
1923         if (isContinuousSpellCheckingEnabled) {
1924             Selection newAdjacentWords;
1925             Selection newSelectedSentence;
1926             if (selectionController()->selection().isContentEditable()) {
1927                 VisiblePosition newStart(selectionController()->selection().visibleStart());
1928                 newAdjacentWords = Selection(startOfWord(newStart, LeftWordIfOnBoundary), endOfWord(newStart, RightWordIfOnBoundary));
1929                 if (isContinuousGrammarCheckingEnabled)
1930                     newSelectedSentence = Selection(startOfSentence(newStart), endOfSentence(newStart));
1931             }
1932
1933             // When typing we check spelling elsewhere, so don't redo it here.
1934             // If this is a change in selection resulting from a delete operation,
1935             // oldSelection may no longer be in the document.
1936             if (closeTyping && oldSelection.isContentEditable() && oldSelection.start().node() && oldSelection.start().node()->inDocument()) {
1937                 VisiblePosition oldStart(oldSelection.visibleStart());
1938                 Selection oldAdjacentWords = Selection(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary));   
1939                 if (oldAdjacentWords != newAdjacentWords) {
1940                     editor()->markMisspellings(oldAdjacentWords);
1941                     if (isContinuousGrammarCheckingEnabled) {
1942                         Selection oldSelectedSentence = Selection(startOfSentence(oldStart), endOfSentence(oldStart));   
1943                         if (oldSelectedSentence != newSelectedSentence)
1944                             editor()->markBadGrammar(oldSelectedSentence);
1945                     }
1946                 }
1947             }
1948
1949             // This only erases markers that are in the first unit (word or sentence) of the selection.
1950             // Perhaps peculiar, but it matches AppKit.
1951             if (RefPtr<Range> wordRange = newAdjacentWords.toRange())
1952                 document()->removeMarkers(wordRange.get(), DocumentMarker::Spelling);
1953             if (RefPtr<Range> sentenceRange = newSelectedSentence.toRange())
1954                 document()->removeMarkers(sentenceRange.get(), DocumentMarker::Grammar);
1955         }
1956
1957         // When continuous spell checking is off, existing markers disappear after the selection changes.
1958         if (!isContinuousSpellCheckingEnabled)
1959             document()->removeMarkers(DocumentMarker::Spelling);
1960         if (!isContinuousGrammarCheckingEnabled)
1961             document()->removeMarkers(DocumentMarker::Grammar);
1962     }
1963
1964     editor()->respondToChangedSelection(oldSelection);
1965 }
1966
1967 VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint)
1968 {
1969     HitTestResult result = eventHandler()->hitTestResultAtPoint(framePoint, true);
1970     Node* node = result.innerNode();
1971     if (!node)
1972         return VisiblePosition();
1973     RenderObject* renderer = node->renderer();
1974     if (!renderer)
1975         return VisiblePosition();
1976     VisiblePosition visiblePos = renderer->positionForCoordinates(result.localPoint().x(), result.localPoint().y());
1977     if (visiblePos.isNull())
1978         visiblePos = VisiblePosition(Position(node, 0));
1979     return visiblePos;
1980 }
1981     
1982 Document* Frame::documentAtPoint(const IntPoint& point)
1983 {  
1984     if (!view()) 
1985         return 0;
1986     
1987     IntPoint pt = view()->windowToContents(point);
1988     HitTestResult result = HitTestResult(pt);
1989     
1990     if (renderer())
1991         result = eventHandler()->hitTestResultAtPoint(pt, false);
1992     return result.innerNode() ? result.innerNode()->document() : 0;
1993 }
1994     
1995 FramePrivate::FramePrivate(Page* page, Frame* parent, Frame* thisFrame, HTMLFrameOwnerElement* ownerElement,
1996                            FrameLoaderClient* frameLoaderClient)
1997     : m_page(page)
1998     , m_treeNode(thisFrame, parent)
1999     , m_ownerElement(ownerElement)
2000     , m_jscript(0)
2001     , m_zoomFactor(parent ? parent->d->m_zoomFactor : 100)
2002     , m_selectionController(thisFrame)
2003     , m_caretBlinkTimer(thisFrame, &Frame::caretBlinkTimerFired)
2004     , m_editor(thisFrame)
2005     , m_command(thisFrame)
2006     , m_eventHandler(thisFrame)
2007     , m_caretVisible(false)
2008     , m_caretPaint(true)
2009     , m_isActive(false)
2010     , m_isPainting(false)
2011     , m_lifeSupportTimer(thisFrame, &Frame::lifeSupportTimerFired)
2012     , m_loader(new FrameLoader(thisFrame, frameLoaderClient))
2013     , m_userStyleSheetLoader(0)
2014     , m_paintRestriction(PaintRestrictionNone)
2015     , m_markedTextUsesUnderlines(false)
2016     , m_highlightTextMatches(false)
2017     , m_windowHasFocus(false)
2018     , m_inViewSourceMode(false)
2019     , frameCount(0)
2020     , m_prohibitsScrolling(false)
2021     , m_windowScriptNPObject(0)
2022 #if PLATFORM(MAC)
2023     , m_windowScriptObject(nil)
2024     , m_bridge(nil)
2025 #endif
2026 {
2027 }
2028
2029 FramePrivate::~FramePrivate()
2030 {
2031     delete m_jscript;
2032     delete m_loader;
2033 }
2034
2035 } // namespace WebCore