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