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