1 /* 2 * Copyright (C) 1998, 1999 Torben Weis <weis (at) kde.org> 3 * 1999 Lars Knoll <knoll (at) kde.org> 4 * 1999 Antti Koivisto <koivisto (at) kde.org> 5 * 2000 Simon Hausmann <hausmann (at) kde.org> 6 * 2000 Stefan Schimanski <1Stein (at) gmx.de> 7 * 2001 George Staikos <staikos (at) kde.org> 8 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. 9 * Copyright (C) 2005 Alexey Proskuryakov <ap (at) nypop.com> 10 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 11 * Copyright (C) 2008 Eric Seidel <eric (at) 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 29 #include "config.h" 30 #include "Frame.h" 31 32 #include "ApplyStyleCommand.h" 33 #include "CSSComputedStyleDeclaration.h" 34 #include "CSSMutableStyleDeclaration.h" 35 #include "CSSProperty.h" 36 #include "CSSPropertyNames.h" 37 #include "CachedCSSStyleSheet.h" 38 #include "Chrome.h" 39 #include "ChromeClient.h" 40 #include "DOMWindow.h" 41 #include "CachedResourceLoader.h" 42 #include "DocumentType.h" 43 #include "EditingText.h" 44 #include "EditorClient.h" 45 #include "EventNames.h" 46 #include "FloatQuad.h" 47 #include "FocusController.h" 48 #include "FrameLoader.h" 49 #include "FrameLoaderClient.h" 50 #include "FrameView.h" 51 #include "GraphicsContext.h" 52 #include "GraphicsLayer.h" 53 #include "HTMLDocument.h" 54 #include "HTMLFormControlElement.h" 55 #include "HTMLFormElement.h" 56 #include "HTMLFrameElementBase.h" 57 #include "HTMLNames.h" 58 #include "HTMLTableCellElement.h" 59 #include "HitTestResult.h" 60 #include "Logging.h" 61 #include "MediaFeatureNames.h" 62 #include "Navigator.h" 63 #include "NodeList.h" 64 #include "Page.h" 65 #include "PageGroup.h" 66 #include "RegularExpression.h" 67 #include "RenderLayer.h" 68 #include "RenderPart.h" 69 #include "RenderTableCell.h" 70 #include "RenderTextControl.h" 71 #include "RenderTheme.h" 72 #include "RenderView.h" 73 #include "ScriptController.h" 74 #include "ScriptSourceCode.h" 75 #include "ScriptValue.h" 76 #include "Settings.h" 77 #include "TextIterator.h" 78 #include "TextResourceDecoder.h" 79 #include "UserContentURLPattern.h" 80 #include "UserTypingGestureIndicator.h" 81 #include "XMLNSNames.h" 82 #include "XMLNames.h" 83 #include "htmlediting.h" 84 #include "markup.h" 85 #include "npruntime_impl.h" 86 #include "visible_units.h" 87 #include <wtf/RefCountedLeakCounter.h> 88 #include <wtf/StdLibExtras.h> 89 90 #if USE(ACCELERATED_COMPOSITING) 91 #include "RenderLayerCompositor.h" 92 #endif 93 94 #if USE(JSC) 95 #include "JSDOMWindowShell.h" 96 #include "runtime_root.h" 97 #endif 98 99 #include "MathMLNames.h" 100 #include "SVGNames.h" 101 #include "XLinkNames.h" 102 103 #if ENABLE(SVG) 104 #include "SVGDocument.h" 105 #include "SVGDocumentExtensions.h" 106 #endif 107 108 #if ENABLE(TILED_BACKING_STORE) 109 #include "TiledBackingStore.h" 110 #endif 111 112 #if ENABLE(WML) 113 #include "WMLNames.h" 114 #endif 115 116 #if PLATFORM(ANDROID) 117 #include "WebViewCore.h" 118 #endif 119 120 using namespace std; 121 122 namespace WebCore { 123 124 using namespace HTMLNames; 125 126 #ifndef NDEBUG 127 static WTF::RefCountedLeakCounter frameCounter("Frame"); 128 #endif 129 130 static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement) 131 { 132 if (!ownerElement) 133 return 0; 134 return ownerElement->document()->frame(); 135 } 136 137 static inline float parentPageZoomFactor(Frame* frame) 138 { 139 Frame* parent = frame->tree()->parent(); 140 if (!parent) 141 return 1; 142 return parent->pageZoomFactor(); 143 } 144 145 static inline float parentTextZoomFactor(Frame* frame) 146 { 147 Frame* parent = frame->tree()->parent(); 148 if (!parent) 149 return 1; 150 return parent->textZoomFactor(); 151 } 152 153 inline Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient) 154 : m_page(page) 155 , m_treeNode(this, parentFromOwnerElement(ownerElement)) 156 , m_loader(this, frameLoaderClient) 157 , m_navigationScheduler(this) 158 , m_ownerElement(ownerElement) 159 , m_script(this) 160 , m_editor(this) 161 , m_selectionController(this) 162 , m_eventHandler(this) 163 , m_animationController(this) 164 , m_lifeSupportTimer(this, &Frame::lifeSupportTimerFired) 165 , m_pageZoomFactor(parentPageZoomFactor(this)) 166 , m_textZoomFactor(parentTextZoomFactor(this)) 167 , m_pageScaleFactor(1) 168 #if ENABLE(ORIENTATION_EVENTS) 169 , m_orientation(0) 170 #endif 171 , m_inViewSourceMode(false) 172 , m_isDisconnected(false) 173 , m_excludeFromTextSearch(false) 174 #if PLATFORM(ANDROID) 175 // Temporary hack for http://b/5188895 176 , m_isDocumentUpToDate(true) 177 #endif 178 { 179 ASSERT(page); 180 AtomicString::init(); 181 HTMLNames::init(); 182 QualifiedName::init(); 183 MediaFeatureNames::init(); 184 SVGNames::init(); 185 XLinkNames::init(); 186 MathMLNames::init(); 187 XMLNSNames::init(); 188 XMLNames::init(); 189 190 #if ENABLE(WML) 191 WMLNames::init(); 192 #endif 193 194 if (!ownerElement) { 195 #if ENABLE(TILED_BACKING_STORE) 196 // Top level frame only for now. 197 setTiledBackingStoreEnabled(page->settings()->tiledBackingStoreEnabled()); 198 #endif 199 } else { 200 page->incrementFrameCount(); 201 202 // Make sure we will not end up with two frames referencing the same owner element. 203 Frame*& contentFrameSlot = ownerElement->m_contentFrame; 204 ASSERT(!contentFrameSlot || contentFrameSlot->ownerElement() != ownerElement); 205 contentFrameSlot = this; 206 } 207 208 #ifndef NDEBUG 209 frameCounter.increment(); 210 #endif 211 } 212 213 PassRefPtr<Frame> Frame::create(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* client) 214 { 215 RefPtr<Frame> frame = adoptRef(new Frame(page, ownerElement, client)); 216 if (!ownerElement) 217 page->setMainFrame(frame); 218 return frame.release(); 219 } 220 221 Frame::~Frame() 222 { 223 setView(0); 224 loader()->cancelAndClear(); 225 226 // FIXME: We should not be doing all this work inside the destructor 227 228 ASSERT(!m_lifeSupportTimer.isActive()); 229 230 #ifndef NDEBUG 231 frameCounter.decrement(); 232 #endif 233 234 disconnectOwnerElement(); 235 236 if (m_domWindow) 237 m_domWindow->disconnectFrame(); 238 script()->clearWindowShell(); 239 240 HashSet<DOMWindow*>::iterator end = m_liveFormerWindows.end(); 241 for (HashSet<DOMWindow*>::iterator it = m_liveFormerWindows.begin(); it != end; ++it) 242 (*it)->disconnectFrame(); 243 244 HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end(); 245 for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it) 246 (*it)->frameDestroyed(); 247 248 if (m_view) { 249 m_view->hide(); 250 m_view->clearFrame(); 251 } 252 253 ASSERT(!m_lifeSupportTimer.isActive()); 254 } 255 256 void Frame::addDestructionObserver(FrameDestructionObserver* observer) 257 { 258 m_destructionObservers.add(observer); 259 } 260 261 void Frame::removeDestructionObserver(FrameDestructionObserver* observer) 262 { 263 m_destructionObservers.remove(observer); 264 } 265 266 void Frame::setView(PassRefPtr<FrameView> view) 267 { 268 // We the custom scroll bars as early as possible to prevent m_doc->detach() 269 // from messing with the view such that its scroll bars won't be torn down. 270 // FIXME: We should revisit this. 271 if (m_view) 272 m_view->detachCustomScrollbars(); 273 274 // Detach the document now, so any onUnload handlers get run - if 275 // we wait until the view is destroyed, then things won't be 276 // hooked up enough for some JavaScript calls to work. 277 if (!view && m_doc && m_doc->attached() && !m_doc->inPageCache()) { 278 // FIXME: We don't call willRemove here. Why is that OK? 279 m_doc->detach(); 280 } 281 282 if (m_view) 283 m_view->unscheduleRelayout(); 284 285 eventHandler()->clear(); 286 287 m_view = view; 288 289 // Only one form submission is allowed per view of a part. 290 // Since this part may be getting reused as a result of being 291 // pulled from the back/forward cache, reset this flag. 292 loader()->resetMultipleFormSubmissionProtection(); 293 294 #if ENABLE(TILED_BACKING_STORE) 295 if (m_view && tiledBackingStore()) 296 m_view->setPaintsEntireContents(true); 297 #endif 298 } 299 300 void Frame::setDocument(PassRefPtr<Document> newDoc) 301 { 302 ASSERT(!newDoc || newDoc->frame()); 303 if (m_doc && m_doc->attached() && !m_doc->inPageCache()) { 304 // FIXME: We don't call willRemove here. Why is that OK? 305 m_doc->detach(); 306 } 307 308 m_doc = newDoc; 309 #if PLATFORM(ANDROID) 310 // Temporary hack for http://b/5188895 311 m_isDocumentUpToDate = true; 312 #endif 313 selection()->updateSecureKeyboardEntryIfActive(); 314 315 if (m_doc && !m_doc->attached()) 316 m_doc->attach(); 317 318 // Update the cached 'document' property, which is now stale. 319 m_script.updateDocument(); 320 321 if (m_page) 322 m_page->updateViewportArguments(); 323 } 324 325 #if ENABLE(ORIENTATION_EVENTS) 326 void Frame::sendOrientationChangeEvent(int orientation) 327 { 328 m_orientation = orientation; 329 if (Document* doc = document()) 330 doc->dispatchWindowEvent(Event::create(eventNames().orientationchangeEvent, false, false)); 331 } 332 #endif // ENABLE(ORIENTATION_EVENTS) 333 334 Settings* Frame::settings() const 335 { 336 return m_page ? m_page->settings() : 0; 337 } 338 339 static RegularExpression* createRegExpForLabels(const Vector<String>& labels) 340 { 341 // REVIEW- version of this call in FrameMac.mm caches based on the NSArray ptrs being 342 // the same across calls. We can't do that. 343 344 DEFINE_STATIC_LOCAL(RegularExpression, wordRegExp, ("\\w", TextCaseSensitive)); 345 String pattern("("); 346 unsigned int numLabels = labels.size(); 347 unsigned int i; 348 for (i = 0; i < numLabels; i++) { 349 String label = labels[i]; 350 351 bool startsWithWordChar = false; 352 bool endsWithWordChar = false; 353 if (label.length()) { 354 startsWithWordChar = wordRegExp.match(label.substring(0, 1)) >= 0; 355 endsWithWordChar = wordRegExp.match(label.substring(label.length() - 1, 1)) >= 0; 356 } 357 358 if (i) 359 pattern.append("|"); 360 // Search for word boundaries only if label starts/ends with "word characters". 361 // If we always searched for word boundaries, this wouldn't work for languages 362 // such as Japanese. 363 if (startsWithWordChar) 364 pattern.append("\\b"); 365 pattern.append(label); 366 if (endsWithWordChar) 367 pattern.append("\\b"); 368 } 369 pattern.append(")"); 370 return new RegularExpression(pattern, TextCaseInsensitive); 371 } 372 373 String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell, size_t* resultDistanceFromStartOfCell) 374 { 375 HTMLTableCellElement* aboveCell = cell->cellAbove(); 376 if (aboveCell) { 377 // search within the above cell we found for a match 378 size_t lengthSearched = 0; 379 for (Node* n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) { 380 if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) { 381 // For each text chunk, run the regexp 382 String nodeString = n->nodeValue(); 383 int pos = regExp->searchRev(nodeString); 384 if (pos >= 0) { 385 if (resultDistanceFromStartOfCell) 386 *resultDistanceFromStartOfCell = lengthSearched; 387 return nodeString.substring(pos, regExp->matchedLength()); 388 } 389 lengthSearched += nodeString.length(); 390 } 391 } 392 } 393 394 // Any reason in practice to search all cells in that are above cell? 395 if (resultDistanceFromStartOfCell) 396 *resultDistanceFromStartOfCell = notFound; 397 return String(); 398 } 399 400 String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element, size_t* resultDistance, bool* resultIsInCellAbove) 401 { 402 OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels)); 403 // We stop searching after we've seen this many chars 404 const unsigned int charsSearchedThreshold = 500; 405 // This is the absolute max we search. We allow a little more slop than 406 // charsSearchedThreshold, to make it more likely that we'll search whole nodes. 407 const unsigned int maxCharsSearched = 600; 408 // If the starting element is within a table, the cell that contains it 409 HTMLTableCellElement* startingTableCell = 0; 410 bool searchedCellAbove = false; 411 412 if (resultDistance) 413 *resultDistance = notFound; 414 if (resultIsInCellAbove) 415 *resultIsInCellAbove = false; 416 417 // walk backwards in the node tree, until another element, or form, or end of tree 418 int unsigned lengthSearched = 0; 419 Node* n; 420 for (n = element->traversePreviousNode(); 421 n && lengthSearched < charsSearchedThreshold; 422 n = n->traversePreviousNode()) 423 { 424 if (n->hasTagName(formTag) 425 || (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement())) 426 { 427 // We hit another form element or the start of the form - bail out 428 break; 429 } else if (n->hasTagName(tdTag) && !startingTableCell) { 430 startingTableCell = static_cast<HTMLTableCellElement*>(n); 431 } else if (n->hasTagName(trTag) && startingTableCell) { 432 String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance); 433 if (!result.isEmpty()) { 434 if (resultIsInCellAbove) 435 *resultIsInCellAbove = true; 436 return result; 437 } 438 searchedCellAbove = true; 439 } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) { 440 // For each text chunk, run the regexp 441 String nodeString = n->nodeValue(); 442 // add 100 for slop, to make it more likely that we'll search whole nodes 443 if (lengthSearched + nodeString.length() > maxCharsSearched) 444 nodeString = nodeString.right(charsSearchedThreshold - lengthSearched); 445 int pos = regExp->searchRev(nodeString); 446 if (pos >= 0) { 447 if (resultDistance) 448 *resultDistance = lengthSearched; 449 return nodeString.substring(pos, regExp->matchedLength()); 450 } 451 lengthSearched += nodeString.length(); 452 } 453 } 454 455 // If we started in a cell, but bailed because we found the start of the form or the 456 // previous element, we still might need to search the row above us for a label. 457 if (startingTableCell && !searchedCellAbove) { 458 String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance); 459 if (!result.isEmpty()) { 460 if (resultIsInCellAbove) 461 *resultIsInCellAbove = true; 462 return result; 463 } 464 } 465 return String(); 466 } 467 468 static String matchLabelsAgainstString(const Vector<String>& labels, const String& stringToMatch) 469 { 470 if (stringToMatch.isEmpty()) 471 return String(); 472 473 String mutableStringToMatch = stringToMatch; 474 475 // Make numbers and _'s in field names behave like word boundaries, e.g., "address2" 476 replace(mutableStringToMatch, RegularExpression("\\d", TextCaseSensitive), " "); 477 mutableStringToMatch.replace('_', ' '); 478 479 OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels)); 480 // Use the largest match we can find in the whole string 481 int pos; 482 int length; 483 int bestPos = -1; 484 int bestLength = -1; 485 int start = 0; 486 do { 487 pos = regExp->match(mutableStringToMatch, start); 488 if (pos != -1) { 489 length = regExp->matchedLength(); 490 if (length >= bestLength) { 491 bestPos = pos; 492 bestLength = length; 493 } 494 start = pos + 1; 495 } 496 } while (pos != -1); 497 498 if (bestPos != -1) 499 return mutableStringToMatch.substring(bestPos, bestLength); 500 return String(); 501 } 502 503 String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* element) 504 { 505 // Match against the name element, then against the id element if no match is found for the name element. 506 // See 7538330 for one popular site that benefits from the id element check. 507 // FIXME: This code is mirrored in FrameMac.mm. It would be nice to make the Mac code call the platform-agnostic 508 // code, which would require converting the NSArray of NSStrings to a Vector of Strings somewhere along the way. 509 String resultFromNameAttribute = matchLabelsAgainstString(labels, element->getAttribute(nameAttr)); 510 if (!resultFromNameAttribute.isEmpty()) 511 return resultFromNameAttribute; 512 513 return matchLabelsAgainstString(labels, element->getAttribute(idAttr)); 514 } 515 516 void Frame::setPrinting(bool printing, const FloatSize& pageSize, float maximumShrinkRatio, AdjustViewSizeOrNot shouldAdjustViewSize) 517 { 518 m_doc->setPrinting(printing); 519 view()->adjustMediaTypeForPrinting(printing); 520 521 m_doc->styleSelectorChanged(RecalcStyleImmediately); 522 view()->forceLayoutForPagination(pageSize, maximumShrinkRatio, shouldAdjustViewSize); 523 524 // Subframes of the one we're printing don't lay out to the page size. 525 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling()) 526 child->setPrinting(printing, IntSize(), 0, shouldAdjustViewSize); 527 } 528 529 void Frame::injectUserScripts(UserScriptInjectionTime injectionTime) 530 { 531 if (!m_page) 532 return; 533 534 if (loader()->stateMachine()->creatingInitialEmptyDocument() && !settings()->shouldInjectUserScriptsInInitialEmptyDocument()) 535 return; 536 537 // Walk the hashtable. Inject by world. 538 const UserScriptMap* userScripts = m_page->group().userScripts(); 539 if (!userScripts) 540 return; 541 UserScriptMap::const_iterator end = userScripts->end(); 542 for (UserScriptMap::const_iterator it = userScripts->begin(); it != end; ++it) 543 injectUserScriptsForWorld(it->first.get(), *it->second, injectionTime); 544 } 545 546 void Frame::injectUserScriptsForWorld(DOMWrapperWorld* world, const UserScriptVector& userScripts, UserScriptInjectionTime injectionTime) 547 { 548 if (userScripts.isEmpty()) 549 return; 550 551 Document* doc = document(); 552 if (!doc) 553 return; 554 555 Vector<ScriptSourceCode> sourceCode; 556 unsigned count = userScripts.size(); 557 for (unsigned i = 0; i < count; ++i) { 558 UserScript* script = userScripts[i].get(); 559 if (script->injectedFrames() == InjectInTopFrameOnly && ownerElement()) 560 continue; 561 562 if (script->injectionTime() == injectionTime && UserContentURLPattern::matchesPatterns(doc->url(), script->whitelist(), script->blacklist())) 563 m_script.evaluateInWorld(ScriptSourceCode(script->source(), script->url()), world); 564 } 565 } 566 567 #ifndef NDEBUG 568 static HashSet<Frame*>& keepAliveSet() 569 { 570 DEFINE_STATIC_LOCAL(HashSet<Frame*>, staticKeepAliveSet, ()); 571 return staticKeepAliveSet; 572 } 573 #endif 574 575 void Frame::keepAlive() 576 { 577 if (m_lifeSupportTimer.isActive()) 578 return; 579 #ifndef NDEBUG 580 keepAliveSet().add(this); 581 #endif 582 ref(); 583 m_lifeSupportTimer.startOneShot(0); 584 } 585 586 #ifndef NDEBUG 587 void Frame::cancelAllKeepAlive() 588 { 589 HashSet<Frame*>::iterator end = keepAliveSet().end(); 590 for (HashSet<Frame*>::iterator it = keepAliveSet().begin(); it != end; ++it) { 591 Frame* frame = *it; 592 frame->m_lifeSupportTimer.stop(); 593 frame->deref(); 594 } 595 keepAliveSet().clear(); 596 } 597 #endif 598 599 void Frame::lifeSupportTimerFired(Timer<Frame>*) 600 { 601 #ifndef NDEBUG 602 keepAliveSet().remove(this); 603 #endif 604 deref(); 605 } 606 607 void Frame::clearDOMWindow() 608 { 609 if (m_domWindow) { 610 m_liveFormerWindows.add(m_domWindow.get()); 611 m_domWindow->clear(); 612 } 613 m_domWindow = 0; 614 } 615 616 RenderView* Frame::contentRenderer() const 617 { 618 Document* doc = document(); 619 if (!doc) 620 return 0; 621 RenderObject* object = doc->renderer(); 622 if (!object) 623 return 0; 624 ASSERT(object->isRenderView()); 625 return toRenderView(object); 626 } 627 628 RenderPart* Frame::ownerRenderer() const 629 { 630 HTMLFrameOwnerElement* ownerElement = m_ownerElement; 631 if (!ownerElement) 632 return 0; 633 RenderObject* object = ownerElement->renderer(); 634 if (!object) 635 return 0; 636 // FIXME: If <object> is ever fixed to disassociate itself from frames 637 // that it has started but canceled, then this can turn into an ASSERT 638 // since m_ownerElement would be 0 when the load is canceled. 639 // https://bugs.webkit.org/show_bug.cgi?id=18585 640 if (!object->isRenderPart()) 641 return 0; 642 return toRenderPart(object); 643 } 644 645 Frame* Frame::frameForWidget(const Widget* widget) 646 { 647 ASSERT_ARG(widget, widget); 648 649 if (RenderWidget* renderer = RenderWidget::find(widget)) 650 if (Node* node = renderer->node()) 651 return node->document()->frame(); 652 653 // Assume all widgets are either a FrameView or owned by a RenderWidget. 654 // FIXME: That assumption is not right for scroll bars! 655 ASSERT(widget->isFrameView()); 656 return static_cast<const FrameView*>(widget)->frame(); 657 } 658 659 void Frame::clearTimers(FrameView *view, Document *document) 660 { 661 if (view) { 662 view->unscheduleRelayout(); 663 if (view->frame()) { 664 view->frame()->animation()->suspendAnimationsForDocument(document); 665 view->frame()->eventHandler()->stopAutoscrollTimer(); 666 } 667 } 668 } 669 670 void Frame::clearTimers() 671 { 672 clearTimers(m_view.get(), document()); 673 } 674 675 void Frame::setDOMWindow(DOMWindow* domWindow) 676 { 677 if (m_domWindow) { 678 m_liveFormerWindows.add(m_domWindow.get()); 679 m_domWindow->clear(); 680 } 681 m_domWindow = domWindow; 682 } 683 684 DOMWindow* Frame::domWindow() const 685 { 686 if (!m_domWindow) 687 m_domWindow = DOMWindow::create(const_cast<Frame*>(this)); 688 689 return m_domWindow.get(); 690 } 691 692 void Frame::clearFormerDOMWindow(DOMWindow* window) 693 { 694 m_liveFormerWindows.remove(window); 695 } 696 697 void Frame::pageDestroyed() 698 { 699 if (Frame* parent = tree()->parent()) 700 parent->loader()->checkLoadComplete(); 701 702 if (m_domWindow) { 703 m_domWindow->resetGeolocation(); 704 m_domWindow->pageDestroyed(); 705 } 706 707 // FIXME: It's unclear as to why this is called more than once, but it is, 708 // so page() could be NULL. 709 if (page() && page()->focusController()->focusedFrame() == this) 710 page()->focusController()->setFocusedFrame(0); 711 712 script()->clearWindowShell(); 713 script()->clearScriptObjects(); 714 script()->updatePlatformScriptObjects(); 715 716 detachFromPage(); 717 } 718 719 void Frame::disconnectOwnerElement() 720 { 721 if (m_ownerElement) { 722 if (Document* doc = document()) 723 doc->clearAXObjectCache(); 724 m_ownerElement->m_contentFrame = 0; 725 if (m_page) 726 m_page->decrementFrameCount(); 727 } 728 m_ownerElement = 0; 729 } 730 731 // The frame is moved in DOM, potentially to another page. 732 void Frame::transferChildFrameToNewDocument() 733 { 734 ASSERT(m_ownerElement); 735 Frame* newParent = m_ownerElement->document()->frame(); 736 ASSERT(newParent); 737 bool didTransfer = false; 738 739 // Switch page. 740 Page* newPage = newParent->page(); 741 Page* oldPage = m_page; 742 if (m_page != newPage) { 743 if (m_page) { 744 if (m_page->focusController()->focusedFrame() == this) 745 m_page->focusController()->setFocusedFrame(0); 746 747 m_page->decrementFrameCount(); 748 } 749 750 // FIXME: We should ideally allow existing Geolocation activities to continue 751 // when the Geolocation's iframe is reparented. 752 // See https://bugs.webkit.org/show_bug.cgi?id=55577 753 // and https://bugs.webkit.org/show_bug.cgi?id=52877 754 if (m_domWindow) 755 m_domWindow->resetGeolocation(); 756 757 m_page = newPage; 758 759 if (newPage) 760 newPage->incrementFrameCount(); 761 762 didTransfer = true; 763 } 764 765 // Update the frame tree. 766 didTransfer = newParent->tree()->transferChild(this) || didTransfer; 767 768 // Avoid unnecessary calls to client and frame subtree if the frame ended 769 // up on the same page and under the same parent frame. 770 if (didTransfer) { 771 // Let external clients update themselves. 772 loader()->client()->didTransferChildFrameToNewDocument(oldPage); 773 774 // Update resource tracking now that frame could be in a different page. 775 if (oldPage != newPage) 776 loader()->transferLoadingResourcesFromPage(oldPage); 777 778 // Do the same for all the children. 779 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling()) 780 child->transferChildFrameToNewDocument(); 781 } 782 } 783 784 String Frame::documentTypeString() const 785 { 786 if (DocumentType* doctype = document()->doctype()) 787 return createMarkup(doctype); 788 789 return String(); 790 } 791 792 VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint) 793 { 794 HitTestResult result = eventHandler()->hitTestResultAtPoint(framePoint, true); 795 Node* node = result.innerNode(); 796 if (!node) 797 return VisiblePosition(); 798 RenderObject* renderer = node->renderer(); 799 if (!renderer) 800 return VisiblePosition(); 801 VisiblePosition visiblePos = renderer->positionForPoint(result.localPoint()); 802 if (visiblePos.isNull()) 803 visiblePos = firstPositionInOrBeforeNode(node); 804 return visiblePos; 805 } 806 807 Document* Frame::documentAtPoint(const IntPoint& point) 808 { 809 if (!view()) 810 return 0; 811 812 IntPoint pt = view()->windowToContents(point); 813 HitTestResult result = HitTestResult(pt); 814 815 if (contentRenderer()) 816 result = eventHandler()->hitTestResultAtPoint(pt, false); 817 return result.innerNode() ? result.innerNode()->document() : 0; 818 } 819 820 PassRefPtr<Range> Frame::rangeForPoint(const IntPoint& framePoint) 821 { 822 VisiblePosition position = visiblePositionForPoint(framePoint); 823 if (position.isNull()) 824 return 0; 825 826 VisiblePosition previous = position.previous(); 827 if (previous.isNotNull()) { 828 RefPtr<Range> previousCharacterRange = makeRange(previous, position); 829 IntRect rect = editor()->firstRectForRange(previousCharacterRange.get()); 830 if (rect.contains(framePoint)) 831 return previousCharacterRange.release(); 832 } 833 834 VisiblePosition next = position.next(); 835 if (next.isNotNull()) { 836 RefPtr<Range> nextCharacterRange = makeRange(position, next); 837 IntRect rect = editor()->firstRectForRange(nextCharacterRange.get()); 838 if (rect.contains(framePoint)) 839 return nextCharacterRange.release(); 840 } 841 842 return 0; 843 } 844 845 void Frame::createView(const IntSize& viewportSize, 846 const Color& backgroundColor, bool transparent, 847 const IntSize& fixedLayoutSize, bool useFixedLayout, 848 ScrollbarMode horizontalScrollbarMode, bool horizontalLock, 849 ScrollbarMode verticalScrollbarMode, bool verticalLock) 850 { 851 ASSERT(this); 852 ASSERT(m_page); 853 854 bool isMainFrame = this == m_page->mainFrame(); 855 856 if (isMainFrame && view()) 857 view()->setParentVisible(false); 858 859 setView(0); 860 861 RefPtr<FrameView> frameView; 862 if (isMainFrame) { 863 frameView = FrameView::create(this, viewportSize); 864 frameView->setFixedLayoutSize(fixedLayoutSize); 865 frameView->setUseFixedLayout(useFixedLayout); 866 } else 867 frameView = FrameView::create(this); 868 869 frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock); 870 871 setView(frameView); 872 873 if (backgroundColor.isValid()) 874 frameView->updateBackgroundRecursively(backgroundColor, transparent); 875 876 if (isMainFrame) 877 frameView->setParentVisible(true); 878 879 if (ownerRenderer()) 880 ownerRenderer()->setWidget(frameView); 881 882 if (HTMLFrameOwnerElement* owner = ownerElement()) 883 view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff); 884 } 885 886 #if ENABLE(TILED_BACKING_STORE) 887 void Frame::setTiledBackingStoreEnabled(bool enabled) 888 { 889 if (!enabled) { 890 m_tiledBackingStore.clear(); 891 return; 892 } 893 if (m_tiledBackingStore) 894 return; 895 m_tiledBackingStore.set(new TiledBackingStore(this)); 896 if (m_view) 897 m_view->setPaintsEntireContents(true); 898 } 899 900 void Frame::tiledBackingStorePaintBegin() 901 { 902 if (!m_view) 903 return; 904 m_view->updateLayoutAndStyleIfNeededRecursive(); 905 m_view->flushDeferredRepaints(); 906 } 907 908 void Frame::tiledBackingStorePaint(GraphicsContext* context, const IntRect& rect) 909 { 910 if (!m_view) 911 return; 912 m_view->paintContents(context, rect); 913 } 914 915 void Frame::tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea) 916 { 917 if (!m_page || !m_view) 918 return; 919 unsigned size = paintedArea.size(); 920 // Request repaint from the system 921 for (int n = 0; n < size; ++n) 922 m_page->chrome()->invalidateContentsAndWindow(m_view->contentsToWindow(paintedArea[n]), false); 923 } 924 925 IntRect Frame::tiledBackingStoreContentsRect() 926 { 927 if (!m_view) 928 return IntRect(); 929 return IntRect(IntPoint(), m_view->contentsSize()); 930 } 931 932 IntRect Frame::tiledBackingStoreVisibleRect() 933 { 934 if (!m_page) 935 return IntRect(); 936 return m_page->chrome()->client()->visibleRectForTiledBackingStore(); 937 } 938 939 Color Frame::tiledBackingStoreBackgroundColor() const 940 { 941 if (!m_view) 942 return Color(); 943 return m_view->baseBackgroundColor(); 944 } 945 #endif 946 947 String Frame::layerTreeAsText(bool showDebugInfo) const 948 { 949 #if USE(ACCELERATED_COMPOSITING) 950 document()->updateLayout(); 951 952 if (!contentRenderer()) 953 return String(); 954 955 return contentRenderer()->compositor()->layerTreeAsText(showDebugInfo); 956 #else 957 return String(); 958 #endif 959 } 960 961 void Frame::setPageZoomFactor(float factor) 962 { 963 setPageAndTextZoomFactors(factor, m_textZoomFactor); 964 } 965 966 void Frame::setTextZoomFactor(float factor) 967 { 968 setPageAndTextZoomFactors(m_pageZoomFactor, factor); 969 } 970 971 void Frame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor) 972 { 973 if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor) 974 return; 975 976 Page* page = this->page(); 977 if (!page) 978 return; 979 980 Document* document = this->document(); 981 if (!document) 982 return; 983 984 m_editor.dismissCorrectionPanelAsIgnored(); 985 986 #if ENABLE(SVG) 987 // Respect SVGs zoomAndPan="disabled" property in standalone SVG documents. 988 // FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification. 989 if (document->isSVGDocument()) { 990 if (!static_cast<SVGDocument*>(document)->zoomAndPanEnabled()) 991 return; 992 if (document->renderer()) 993 document->renderer()->setNeedsLayout(true); 994 } 995 #endif 996 997 if (m_pageZoomFactor != pageZoomFactor) { 998 if (FrameView* view = this->view()) { 999 // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position. 1000 IntPoint scrollPosition = view->scrollPosition(); 1001 float percentDifference = (pageZoomFactor / m_pageZoomFactor); 1002 view->setScrollPosition(IntPoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference)); 1003 } 1004 } 1005 1006 m_pageZoomFactor = pageZoomFactor; 1007 m_textZoomFactor = textZoomFactor; 1008 1009 document->recalcStyle(Node::Force); 1010 1011 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling()) 1012 child->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor); 1013 1014 if (FrameView* view = this->view()) { 1015 if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout()) 1016 view->layout(); 1017 } 1018 } 1019 1020 #if USE(ACCELERATED_COMPOSITING) 1021 void Frame::updateContentsScale(float scale) 1022 { 1023 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling()) 1024 child->updateContentsScale(scale); 1025 1026 RenderView* root = contentRenderer(); 1027 if (root && root->compositor()) 1028 root->compositor()->updateContentsScale(scale); 1029 } 1030 #endif 1031 1032 void Frame::scalePage(float scale, const IntPoint& origin) 1033 { 1034 Document* document = this->document(); 1035 if (!document) 1036 return; 1037 1038 if (scale != m_pageScaleFactor) { 1039 m_pageScaleFactor = scale; 1040 1041 if (document->renderer()) 1042 document->renderer()->setNeedsLayout(true); 1043 1044 document->recalcStyle(Node::Force); 1045 1046 #if USE(ACCELERATED_COMPOSITING) 1047 updateContentsScale(scale); 1048 #endif 1049 } 1050 1051 if (FrameView* view = this->view()) { 1052 if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout()) 1053 view->layout(); 1054 view->setScrollPosition(origin); 1055 } 1056 } 1057 1058 } // namespace WebCore 1059