• 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