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