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