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