WebKitTools:
[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     styleElement->setAttribute(styleAttr, d->m_typingStyle->cssText().impl(), ec);
1559     ASSERT(ec == 0);
1560     
1561     styleElement->appendChild(document()->createEditingTextNode(""), ec);
1562     ASSERT(ec == 0);
1563     
1564     node->parentNode()->appendChild(styleElement, ec);
1565     ASSERT(ec == 0);
1566     
1567     nodeToRemove = styleElement.get();    
1568     return styleElement->renderer()->style();
1569 }
1570
1571 void Frame::setSelectionFromNone()
1572 {
1573     // Put a caret inside the body if the entire frame is editable (either the 
1574     // entire WebView is editable or designMode is on for this document).
1575     Document *doc = document();
1576     if (!doc || !selectionController()->isNone() || !isContentEditable())
1577         return;
1578         
1579     Node* node = doc->documentElement();
1580     while (node && !node->hasTagName(bodyTag))
1581         node = node->traverseNextNode();
1582     if (node)
1583         selectionController()->setSelection(Selection(Position(node, 0), DOWNSTREAM));
1584 }
1585
1586 bool Frame::isActive() const
1587 {
1588     return d->m_isActive;
1589 }
1590
1591 void Frame::setIsActive(bool flag)
1592 {
1593     if (d->m_isActive == flag)
1594         return;
1595     d->m_isActive = flag;
1596
1597     // Because RenderObject::selectionBackgroundColor() and
1598     // RenderObject::selectionForegroundColor() check if the frame is active,
1599     // we have to update places those colors were painted.
1600     if (d->m_view)
1601         d->m_view->updateContents(enclosingIntRect(selectionRect()));
1602
1603     // Caret appears in the active frame.
1604     if (flag)
1605         setSelectionFromNone();
1606     setCaretVisible(flag);
1607
1608     // Because CSSStyleSelector::checkOneSelector() and
1609     // RenderTheme::isFocused() check if the frame is active, we have to
1610     // update style and theme state that depended on those.
1611     if (d->m_doc) {
1612         if (Node* node = d->m_doc->focusedNode()) {
1613             node->setChanged();
1614             if (RenderObject* renderer = node->renderer())
1615                 if (renderer && renderer->style()->hasAppearance())
1616                     theme()->stateChanged(renderer, FocusState);
1617         }
1618     }
1619
1620     // Secure keyboard entry is set by the active frame.
1621     if (d->m_doc->useSecureKeyboardEntryWhenActive())
1622         setUseSecureKeyboardEntry(flag);
1623 }
1624
1625 void Frame::setWindowHasFocus(bool flag)
1626 {
1627     if (d->m_windowHasFocus == flag)
1628         return;
1629     d->m_windowHasFocus = flag;
1630     
1631     if (Document *doc = document())
1632         doc->dispatchWindowEvent(flag ? focusEvent : blurEvent, false, false);
1633 }
1634
1635 bool Frame::inViewSourceMode() const
1636 {
1637     return d->m_inViewSourceMode;
1638 }
1639
1640 void Frame::setInViewSourceMode(bool mode) const
1641 {
1642     d->m_inViewSourceMode = mode;
1643 }
1644   
1645 UChar Frame::backslashAsCurrencySymbol() const
1646 {
1647     Document *doc = document();
1648     if (!doc)
1649         return '\\';
1650     TextResourceDecoder *decoder = doc->decoder();
1651     if (!decoder)
1652         return '\\';
1653
1654     return decoder->encoding().backslashAsCurrencySymbol();
1655 }
1656
1657 bool Frame::markedTextUsesUnderlines() const
1658 {
1659     return d->m_markedTextUsesUnderlines;
1660 }
1661
1662 const Vector<MarkedTextUnderline>& Frame::markedTextUnderlines() const
1663 {
1664     return d->m_markedTextUnderlines;
1665 }
1666
1667 static bool isInShadowTree(Node* node)
1668 {
1669     for (Node* n = node; n; n = n->parentNode())
1670         if (n->isShadowNode())
1671             return true;
1672     return false;
1673 }
1674
1675 // Searches from the beginning of the document if nothing is selected.
1676 bool Frame::findString(const String& target, bool forward, bool caseFlag, bool wrapFlag, bool startInSelection)
1677 {
1678     if (target.isEmpty() || !document())
1679         return false;
1680     
1681     // Start from an edge of the selection, if there's a selection that's not in shadow content. Which edge
1682     // is used depends on whether we're searching forward or backward, and whether startInSelection is set.
1683     RefPtr<Range> searchRange(rangeOfContents(document()));
1684     Selection selection(selectionController()->selection());
1685     Node* selectionBaseNode = selection.base().node();
1686     
1687     // FIXME 3099526: We don't search in the shadow trees (e.g. text fields and textareas), though we'd like to
1688     // someday. If we don't explicitly skip them here, we'll miss hits in the regular content.
1689     bool selectionIsInMainContent = selectionBaseNode && !isInShadowTree(selectionBaseNode);
1690
1691     if (selectionIsInMainContent) {
1692         if (forward)
1693             setStart(searchRange.get(), startInSelection ? selection.visibleStart() : selection.visibleEnd());
1694         else
1695             setEnd(searchRange.get(), startInSelection ? selection.visibleEnd() : selection.visibleStart());
1696     }
1697     RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, forward, caseFlag));
1698     // If we started in the selection and the found range exactly matches the existing selection, find again.
1699     // Build a selection with the found range to remove collapsed whitespace.
1700     // Compare ranges instead of selection objects to ignore the way that the current selection was made.
1701     if (startInSelection && selectionIsInMainContent && *Selection(resultRange.get()).toRange() == *selection.toRange()) {
1702         searchRange = rangeOfContents(document());
1703         if (forward)
1704             setStart(searchRange.get(), selection.visibleEnd());
1705         else
1706             setEnd(searchRange.get(), selection.visibleStart());
1707         resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
1708     }
1709     
1710     int exception = 0;
1711     
1712     // If we didn't find anything and we're wrapping, search again in the entire document (this will
1713     // redundantly re-search the area already searched in some cases).
1714     if (resultRange->collapsed(exception) && wrapFlag) {
1715         searchRange = rangeOfContents(document());
1716         resultRange = findPlainText(searchRange.get(), target, forward, caseFlag);
1717         // We used to return false here if we ended up with the same range that we started with
1718         // (e.g., the selection was already the only instance of this text). But we decided that
1719         // this should be a success case instead, so we'll just fall through in that case.
1720     }
1721
1722     if (resultRange->collapsed(exception))
1723         return false;
1724
1725     selectionController()->setSelection(Selection(resultRange.get(), DOWNSTREAM));
1726     revealSelection();
1727     return true;
1728 }
1729
1730 unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag, unsigned limit)
1731 {
1732     if (target.isEmpty() || !document())
1733         return 0;
1734     
1735     RefPtr<Range> searchRange(rangeOfContents(document()));
1736     
1737     int exception = 0;
1738     unsigned matchCount = 0;
1739     do {
1740         RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, caseFlag));
1741         if (resultRange->collapsed(exception))
1742             break;
1743         
1744         // A non-collapsed result range can in some funky whitespace cases still not
1745         // advance the range's start position (4509328). Break to avoid infinite loop.
1746         VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
1747         if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
1748             break;
1749
1750         ++matchCount;
1751         
1752         document()->addMarker(resultRange.get(), DocumentMarker::TextMatch);        
1753         
1754         // Stop looking if we hit the specified limit. A limit of 0 means no limit.
1755         if (limit > 0 && matchCount >= limit)
1756             break;
1757         
1758         setStart(searchRange.get(), newStart);
1759     } while (true);
1760     
1761     // Do a "fake" paint in order to execute the code that computes the rendered rect for 
1762     // each text match.
1763     Document* doc = document();
1764     if (doc && d->m_view && renderer()) {
1765         doc->updateLayout(); // Ensure layout is up to date.
1766         IntRect visibleRect(enclosingIntRect(d->m_view->visibleContentRect()));
1767         GraphicsContext context((PlatformGraphicsContext*)0);
1768         context.setPaintingDisabled(true);
1769         paint(&context, visibleRect);
1770     }
1771     
1772     return matchCount;
1773 }
1774
1775 bool Frame::markedTextMatchesAreHighlighted() const
1776 {
1777     return d->m_highlightTextMatches;
1778 }
1779
1780 void Frame::setMarkedTextMatchesAreHighlighted(bool flag)
1781 {
1782     if (flag == d->m_highlightTextMatches || !document())
1783         return;
1784     
1785     d->m_highlightTextMatches = flag;
1786     document()->repaintMarkers(DocumentMarker::TextMatch);
1787 }
1788
1789 FrameTree* Frame::tree() const
1790 {
1791     return &d->m_treeNode;
1792 }
1793
1794 DOMWindow* Frame::domWindow() const
1795 {
1796     if (!d->m_domWindow)
1797         d->m_domWindow = new DOMWindow(const_cast<Frame*>(this));
1798
1799     return d->m_domWindow.get();
1800 }
1801
1802 Page* Frame::page() const
1803 {
1804     return d->m_page;
1805 }
1806
1807 EventHandler* Frame::eventHandler() const
1808 {
1809     return &d->m_eventHandler;
1810 }
1811
1812 void Frame::pageDestroyed()
1813 {
1814     if (Frame* parent = tree()->parent())
1815         parent->loader()->checkLoadComplete();
1816
1817     if (d->m_page && d->m_page->focusController()->focusedFrame() == this)
1818         d->m_page->focusController()->setFocusedFrame(0);
1819
1820     // This will stop any JS timers
1821     if (d->m_jscript && d->m_jscript->haveInterpreter())
1822         if (Window* w = Window::retrieveWindow(this))
1823             w->disconnectFrame();
1824
1825     d->m_page = 0;
1826 }
1827
1828 void Frame::disconnectOwnerElement()
1829 {
1830     if (d->m_ownerElement) {
1831         d->m_ownerElement->m_contentFrame = 0;
1832         if (d->m_page)
1833             d->m_page->decrementFrameCount();
1834     }
1835     d->m_ownerElement = 0;
1836 }
1837
1838 String Frame::documentTypeString() const
1839 {
1840     if (Document *doc = document())
1841         if (DocumentType *doctype = doc->realDocType())
1842             return doctype->toString();
1843
1844     return String();
1845 }
1846
1847 bool Frame::prohibitsScrolling() const
1848 {
1849     return d->m_prohibitsScrolling;
1850 }
1851
1852 void Frame::setProhibitsScrolling(bool prohibit)
1853 {
1854     d->m_prohibitsScrolling = prohibit;
1855 }
1856
1857 void Frame::focusWindow()
1858 {
1859     if (!page())
1860         return;
1861
1862     // If we're a top level window, bring the window to the front.
1863     if (!tree()->parent())
1864         page()->chrome()->focus();
1865
1866     eventHandler()->focusDocumentView();
1867 }
1868
1869 void Frame::unfocusWindow()
1870 {
1871     if (!page())
1872         return;
1873     
1874     // If we're a top level window, deactivate the window.
1875     if (!tree()->parent())
1876         page()->chrome()->unfocus();
1877 }
1878
1879 bool Frame::shouldClose()
1880 {
1881     Chrome* chrome = page() ? page()->chrome() : 0;
1882     if (!chrome || !chrome->canRunBeforeUnloadConfirmPanel())
1883         return true;
1884
1885     RefPtr<Document> doc = document();
1886     if (!doc)
1887         return true;
1888     HTMLElement* body = doc->body();
1889     if (!body)
1890         return true;
1891
1892     RefPtr<BeforeUnloadEvent> beforeUnloadEvent = new BeforeUnloadEvent;
1893     beforeUnloadEvent->setTarget(doc);
1894     doc->handleWindowEvent(beforeUnloadEvent.get(), false);
1895
1896     if (!beforeUnloadEvent->defaultPrevented() && doc)
1897         doc->defaultEventHandler(beforeUnloadEvent.get());
1898     if (beforeUnloadEvent->result().isNull())
1899         return true;
1900
1901     String text = beforeUnloadEvent->result();
1902     text.replace('\\', backslashAsCurrencySymbol());
1903
1904     return chrome->runBeforeUnloadConfirmPanel(text, this);
1905 }
1906
1907 void Frame::scheduleClose()
1908 {
1909     if (!shouldClose())
1910         return;
1911
1912     Chrome* chrome = page() ? page()->chrome() : 0;
1913     if (chrome)
1914         chrome->closeWindowSoon();
1915 }
1916
1917 void Frame::respondToChangedSelection(const Selection& oldSelection, bool closeTyping)
1918 {
1919     if (document()) {
1920         bool isContinuousSpellCheckingEnabled = editor()->isContinuousSpellCheckingEnabled();
1921         bool isContinuousGrammarCheckingEnabled = isContinuousSpellCheckingEnabled && editor()->isGrammarCheckingEnabled();
1922         if (isContinuousSpellCheckingEnabled) {
1923             Selection newAdjacentWords;
1924             Selection newSelectedSentence;
1925             if (selectionController()->selection().isContentEditable()) {
1926                 VisiblePosition newStart(selectionController()->selection().visibleStart());
1927                 newAdjacentWords = Selection(startOfWord(newStart, LeftWordIfOnBoundary), endOfWord(newStart, RightWordIfOnBoundary));
1928                 if (isContinuousGrammarCheckingEnabled)
1929                     newSelectedSentence = Selection(startOfSentence(newStart), endOfSentence(newStart));
1930             }
1931
1932             // When typing we check spelling elsewhere, so don't redo it here.
1933             // If this is a change in selection resulting from a delete operation,
1934             // oldSelection may no longer be in the document.
1935             if (closeTyping && oldSelection.isContentEditable() && oldSelection.start().node() && oldSelection.start().node()->inDocument()) {
1936                 VisiblePosition oldStart(oldSelection.visibleStart());
1937                 Selection oldAdjacentWords = Selection(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary));   
1938                 if (oldAdjacentWords != newAdjacentWords) {
1939                     editor()->markMisspellings(oldAdjacentWords);
1940                     if (isContinuousGrammarCheckingEnabled) {
1941                         Selection oldSelectedSentence = Selection(startOfSentence(oldStart), endOfSentence(oldStart));   
1942                         if (oldSelectedSentence != newSelectedSentence)
1943                             editor()->markBadGrammar(oldSelectedSentence);
1944                     }
1945                 }
1946             }
1947
1948             // This only erases markers that are in the first unit (word or sentence) of the selection.
1949             // Perhaps peculiar, but it matches AppKit.
1950             if (RefPtr<Range> wordRange = newAdjacentWords.toRange())
1951                 document()->removeMarkers(wordRange.get(), DocumentMarker::Spelling);
1952             if (RefPtr<Range> sentenceRange = newSelectedSentence.toRange())
1953                 document()->removeMarkers(sentenceRange.get(), DocumentMarker::Grammar);
1954         }
1955
1956         // When continuous spell checking is off, existing markers disappear after the selection changes.
1957         if (!isContinuousSpellCheckingEnabled)
1958             document()->removeMarkers(DocumentMarker::Spelling);
1959         if (!isContinuousGrammarCheckingEnabled)
1960             document()->removeMarkers(DocumentMarker::Grammar);
1961     }
1962
1963     editor()->respondToChangedSelection(oldSelection);
1964 }
1965
1966 VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint)
1967 {
1968     HitTestResult result = eventHandler()->hitTestResultAtPoint(framePoint, true);
1969     Node* node = result.innerNode();
1970     if (!node)
1971         return VisiblePosition();
1972     RenderObject* renderer = node->renderer();
1973     if (!renderer)
1974         return VisiblePosition();
1975     VisiblePosition visiblePos = renderer->positionForCoordinates(result.localPoint().x(), result.localPoint().y());
1976     if (visiblePos.isNull())
1977         visiblePos = VisiblePosition(Position(node, 0));
1978     return visiblePos;
1979 }
1980     
1981 Document* Frame::documentAtPoint(const IntPoint& point)
1982 {  
1983     if (!view()) 
1984         return 0;
1985     
1986     IntPoint pt = view()->windowToContents(point);
1987     HitTestResult result = HitTestResult(pt);
1988     
1989     if (renderer())
1990         result = eventHandler()->hitTestResultAtPoint(pt, false);
1991     return result.innerNode() ? result.innerNode()->document() : 0;
1992 }
1993     
1994 FramePrivate::FramePrivate(Page* page, Frame* parent, Frame* thisFrame, HTMLFrameOwnerElement* ownerElement,
1995                            FrameLoaderClient* frameLoaderClient)
1996     : m_page(page)
1997     , m_treeNode(thisFrame, parent)
1998     , m_ownerElement(ownerElement)
1999     , m_jscript(0)
2000     , m_zoomFactor(parent ? parent->d->m_zoomFactor : 100)
2001     , m_selectionController(thisFrame)
2002     , m_caretBlinkTimer(thisFrame, &Frame::caretBlinkTimerFired)
2003     , m_editor(thisFrame)
2004     , m_command(thisFrame)
2005     , m_eventHandler(thisFrame)
2006     , m_caretVisible(false)
2007     , m_caretPaint(true)
2008     , m_isActive(false)
2009     , m_isPainting(false)
2010     , m_lifeSupportTimer(thisFrame, &Frame::lifeSupportTimerFired)
2011     , m_loader(new FrameLoader(thisFrame, frameLoaderClient))
2012     , m_userStyleSheetLoader(0)
2013     , m_paintRestriction(PaintRestrictionNone)
2014     , m_markedTextUsesUnderlines(false)
2015     , m_highlightTextMatches(false)
2016     , m_windowHasFocus(false)
2017     , m_inViewSourceMode(false)
2018     , frameCount(0)
2019     , m_prohibitsScrolling(false)
2020     , m_windowScriptNPObject(0)
2021 #if PLATFORM(MAC)
2022     , m_windowScriptObject(nil)
2023     , m_bridge(nil)
2024 #endif
2025 {
2026 }
2027
2028 FramePrivate::~FramePrivate()
2029 {
2030     delete m_jscript;
2031     delete m_loader;
2032 }
2033
2034 } // namespace WebCore