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