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