1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2001 Dirk Mueller (mueller (at) kde.org) 5 * (C) 2006 Alexey Proskuryakov (ap (at) webkit.org) 6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2011 Apple Inc. All rights reserved. 7 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) 8 * Copyright (C) 2008, 2009 Google Inc. All rights reserved. 9 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) 10 * 11 * This library is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU Library General Public 13 * License as published by the Free Software Foundation; either 14 * version 2 of the License, or (at your option) any later version. 15 * 16 * This library is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 * Library General Public License for more details. 20 * 21 * You should have received a copy of the GNU Library General Public License 22 * along with this library; see the file COPYING.LIB. If not, write to 23 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24 * Boston, MA 02110-1301, USA. 25 */ 26 27 #include "config.h" 28 #include "Document.h" 29 30 #include "AXObjectCache.h" 31 #include "AnimationController.h" 32 #include "Attr.h" 33 #include "Attribute.h" 34 #include "CDATASection.h" 35 #include "CSSPrimitiveValueCache.h" 36 #include "CSSStyleSelector.h" 37 #include "CSSStyleSheet.h" 38 #include "CSSValueKeywords.h" 39 #include "CachedCSSStyleSheet.h" 40 #include "CachedResourceLoader.h" 41 #include "Chrome.h" 42 #include "ChromeClient.h" 43 #include "Comment.h" 44 #include "Console.h" 45 #include "ContentSecurityPolicy.h" 46 #include "CookieJar.h" 47 #include "CustomEvent.h" 48 #include "DateComponents.h" 49 #include "DOMImplementation.h" 50 #include "DOMWindow.h" 51 #include "DeviceMotionEvent.h" 52 #include "DeviceOrientationEvent.h" 53 #include "DocumentFragment.h" 54 #include "DocumentLoader.h" 55 #include "DocumentMarkerController.h" 56 #include "DocumentType.h" 57 #include "EditingText.h" 58 #include "Editor.h" 59 #include "Element.h" 60 #include "EntityReference.h" 61 #include "Event.h" 62 #include "EventHandler.h" 63 #include "EventListener.h" 64 #include "EventNames.h" 65 #include "EventQueue.h" 66 #include "ExceptionCode.h" 67 #include "FocusController.h" 68 #include "FormAssociatedElement.h" 69 #include "Frame.h" 70 #include "FrameLoader.h" 71 #include "FrameLoaderClient.h" 72 #include "FrameTree.h" 73 #include "FrameView.h" 74 #include "HashChangeEvent.h" 75 #include "HTMLAllCollection.h" 76 #include "HTMLAnchorElement.h" 77 #include "HTMLBodyElement.h" 78 #include "HTMLCanvasElement.h" 79 #include "HTMLCollection.h" 80 #include "HTMLDocument.h" 81 #include "HTMLElementFactory.h" 82 #include "HTMLFrameOwnerElement.h" 83 #include "HTMLHeadElement.h" 84 #include "HTMLIFrameElement.h" 85 #include "HTMLInputElement.h" 86 #include "HTMLLinkElement.h" 87 #include "HTMLMapElement.h" 88 #include "HTMLNameCollection.h" 89 #include "HTMLNames.h" 90 #include "HTMLParserIdioms.h" 91 #include "HTMLStyleElement.h" 92 #include "HTMLTitleElement.h" 93 #include "HTTPParsers.h" 94 #include "HitTestRequest.h" 95 #include "HitTestResult.h" 96 #include "ImageLoader.h" 97 #include "InspectorInstrumentation.h" 98 #include "KeyboardEvent.h" 99 #include "Logging.h" 100 #include "MediaQueryList.h" 101 #include "MediaQueryMatcher.h" 102 #include "MessageEvent.h" 103 #include "MouseEvent.h" 104 #include "MouseEventWithHitTestResults.h" 105 #include "MutationEvent.h" 106 #include "NameNodeList.h" 107 #include "NestingLevelIncrementer.h" 108 #include "NodeFilter.h" 109 #include "NodeIterator.h" 110 #include "NodeWithIndex.h" 111 #include "OverflowEvent.h" 112 #include "Page.h" 113 #include "PageGroup.h" 114 #include "PageTransitionEvent.h" 115 #include "PlatformKeyboardEvent.h" 116 #include "PopStateEvent.h" 117 #include "ProcessingInstruction.h" 118 #include "ProgressEvent.h" 119 #include "RegisteredEventListener.h" 120 #include "RenderArena.h" 121 #include "RenderLayer.h" 122 #include "RenderLayerBacking.h" 123 #include "RenderTextControl.h" 124 #include "RenderView.h" 125 #include "RenderWidget.h" 126 #include "ScopedEventQueue.h" 127 #include "ScriptCallStack.h" 128 #include "ScriptController.h" 129 #include "ScriptElement.h" 130 #include "ScriptEventListener.h" 131 #include "ScriptRunner.h" 132 #include "SecurityOrigin.h" 133 #include "SegmentedString.h" 134 #include "SelectionController.h" 135 #include "Settings.h" 136 #include "StaticHashSetNodeList.h" 137 #include "StyleSheetList.h" 138 #include "TextEvent.h" 139 #include "TextResourceDecoder.h" 140 #include "Timer.h" 141 #include "TransformSource.h" 142 #include "TreeWalker.h" 143 #include "UIEvent.h" 144 #include "UserContentURLPattern.h" 145 #include "WebKitAnimationEvent.h" 146 #include "WebKitTransitionEvent.h" 147 #include "WheelEvent.h" 148 #include "XMLDocumentParser.h" 149 #include "XMLHttpRequest.h" 150 #include "XMLNSNames.h" 151 #include "XMLNames.h" 152 #include "htmlediting.h" 153 #include <wtf/CurrentTime.h> 154 #include <wtf/HashFunctions.h> 155 #include <wtf/MainThread.h> 156 #include <wtf/PassRefPtr.h> 157 #include <wtf/StdLibExtras.h> 158 #include <wtf/text/StringBuffer.h> 159 160 #if ENABLE(SHARED_WORKERS) 161 #include "SharedWorkerRepository.h" 162 #endif 163 164 #if ENABLE(DOM_STORAGE) 165 #include "StorageEvent.h" 166 #endif 167 168 #if ENABLE(XPATH) 169 #include "XPathEvaluator.h" 170 #include "XPathExpression.h" 171 #include "XPathNSResolver.h" 172 #include "XPathResult.h" 173 #endif 174 175 #if ENABLE(XSLT) 176 #include "XSLTProcessor.h" 177 #endif 178 179 #if ENABLE(SVG) 180 #include "SVGDocumentExtensions.h" 181 #include "SVGElementFactory.h" 182 #include "SVGNames.h" 183 #include "SVGStyleElement.h" 184 #include "SVGZoomEvent.h" 185 #endif 186 187 #ifdef ANDROID_META_SUPPORT 188 #include "PlatformBridge.h" 189 #include "Settings.h" 190 #endif 191 192 #if ENABLE(TOUCH_EVENTS) 193 #if USE(V8) 194 #include "RuntimeEnabledFeatures.h" 195 #endif 196 #include "TouchEvent.h" 197 #endif 198 199 #if ENABLE(WML) 200 #include "WMLDocument.h" 201 #include "WMLElement.h" 202 #include "WMLElementFactory.h" 203 #include "WMLNames.h" 204 #endif 205 206 #if ENABLE(MATHML) 207 #include "MathMLElement.h" 208 #include "MathMLElementFactory.h" 209 #include "MathMLNames.h" 210 #endif 211 212 #if ENABLE(XHTMLMP) 213 #include "HTMLNoScriptElement.h" 214 #endif 215 216 #if ENABLE(FULLSCREEN_API) 217 #include "RenderFullScreen.h" 218 #endif 219 220 #if ENABLE(REQUEST_ANIMATION_FRAME) 221 #include "RequestAnimationFrameCallback.h" 222 #include "ScriptedAnimationController.h" 223 #endif 224 225 using namespace std; 226 using namespace WTF; 227 using namespace Unicode; 228 229 namespace WebCore { 230 231 using namespace HTMLNames; 232 233 // #define INSTRUMENT_LAYOUT_SCHEDULING 1 234 235 static const unsigned cMaxWriteRecursionDepth = 21; 236 237 // This amount of time must have elapsed before we will even consider scheduling a layout without a delay. 238 // FIXME: For faster machines this value can really be lowered to 200. 250 is adequate, but a little high 239 // for dual G5s. :) 240 static const int cLayoutScheduleThreshold = 250; 241 242 // DOM Level 2 says (letters added): 243 // 244 // a) Name start characters must have one of the categories Ll, Lu, Lo, Lt, Nl. 245 // b) Name characters other than Name-start characters must have one of the categories Mc, Me, Mn, Lm, or Nd. 246 // c) Characters in the compatibility area (i.e. with character code greater than #xF900 and less than #xFFFE) are not allowed in XML names. 247 // d) Characters which have a font or compatibility decomposition (i.e. those with a "compatibility formatting tag" in field 5 of the database -- marked by field 5 beginning with a "<") are not allowed. 248 // e) The following characters are treated as name-start characters rather than name characters, because the property file classifies them as Alphabetic: [#x02BB-#x02C1], #x0559, #x06E5, #x06E6. 249 // f) Characters #x20DD-#x20E0 are excluded (in accordance with Unicode, section 5.14). 250 // g) Character #x00B7 is classified as an extender, because the property list so identifies it. 251 // h) Character #x0387 is added as a name character, because #x00B7 is its canonical equivalent. 252 // i) Characters ':' and '_' are allowed as name-start characters. 253 // j) Characters '-' and '.' are allowed as name characters. 254 // 255 // It also contains complete tables. If we decide it's better, we could include those instead of the following code. 256 257 static inline bool isValidNameStart(UChar32 c) 258 { 259 // rule (e) above 260 if ((c >= 0x02BB && c <= 0x02C1) || c == 0x559 || c == 0x6E5 || c == 0x6E6) 261 return true; 262 263 // rule (i) above 264 if (c == ':' || c == '_') 265 return true; 266 267 // rules (a) and (f) above 268 const uint32_t nameStartMask = Letter_Lowercase | Letter_Uppercase | Letter_Other | Letter_Titlecase | Number_Letter; 269 if (!(Unicode::category(c) & nameStartMask)) 270 return false; 271 272 // rule (c) above 273 if (c >= 0xF900 && c < 0xFFFE) 274 return false; 275 276 // rule (d) above 277 DecompositionType decompType = decompositionType(c); 278 if (decompType == DecompositionFont || decompType == DecompositionCompat) 279 return false; 280 281 return true; 282 } 283 284 static inline bool isValidNamePart(UChar32 c) 285 { 286 // rules (a), (e), and (i) above 287 if (isValidNameStart(c)) 288 return true; 289 290 // rules (g) and (h) above 291 if (c == 0x00B7 || c == 0x0387) 292 return true; 293 294 // rule (j) above 295 if (c == '-' || c == '.') 296 return true; 297 298 // rules (b) and (f) above 299 const uint32_t otherNamePartMask = Mark_NonSpacing | Mark_Enclosing | Mark_SpacingCombining | Letter_Modifier | Number_DecimalDigit; 300 if (!(Unicode::category(c) & otherNamePartMask)) 301 return false; 302 303 // rule (c) above 304 if (c >= 0xF900 && c < 0xFFFE) 305 return false; 306 307 // rule (d) above 308 DecompositionType decompType = decompositionType(c); 309 if (decompType == DecompositionFont || decompType == DecompositionCompat) 310 return false; 311 312 return true; 313 } 314 315 static Widget* widgetForNode(Node* focusedNode) 316 { 317 if (!focusedNode) 318 return 0; 319 RenderObject* renderer = focusedNode->renderer(); 320 if (!renderer || !renderer->isWidget()) 321 return 0; 322 return toRenderWidget(renderer)->widget(); 323 } 324 325 static bool acceptsEditingFocus(Node* node) 326 { 327 ASSERT(node); 328 ASSERT(node->rendererIsEditable()); 329 330 Node* root = node->rootEditableElement(); 331 Frame* frame = node->document()->frame(); 332 if (!frame || !root) 333 return false; 334 335 return frame->editor()->shouldBeginEditing(rangeOfContents(root).get()); 336 } 337 338 static bool disableRangeMutation(Page* page) 339 { 340 // This check is made on super-hot code paths, so we only want this on Tiger and Leopard. 341 #if defined(TARGETING_TIGER) || defined(TARGETING_LEOPARD) 342 // Disable Range mutation on document modifications in Tiger and Leopard Mail 343 // See <rdar://problem/5865171> 344 return page && (page->settings()->needsLeopardMailQuirks() || page->settings()->needsTigerMailQuirks()); 345 #else 346 UNUSED_PARAM(page); 347 return false; 348 #endif 349 } 350 351 static HashSet<Document*>* documentsThatNeedStyleRecalc = 0; 352 353 class DocumentWeakReference : public ThreadSafeRefCounted<DocumentWeakReference> { 354 public: 355 static PassRefPtr<DocumentWeakReference> create(Document* document) 356 { 357 return adoptRef(new DocumentWeakReference(document)); 358 } 359 360 Document* document() 361 { 362 ASSERT(isMainThread()); 363 return m_document; 364 } 365 366 void clear() 367 { 368 ASSERT(isMainThread()); 369 m_document = 0; 370 } 371 372 private: 373 DocumentWeakReference(Document* document) 374 : m_document(document) 375 { 376 ASSERT(isMainThread()); 377 } 378 379 Document* m_document; 380 }; 381 382 uint64_t Document::s_globalTreeVersion = 0; 383 384 Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML) 385 : TreeScope(this) 386 , m_guardRefCount(0) 387 , m_compatibilityMode(NoQuirksMode) 388 , m_compatibilityModeLocked(false) 389 , m_domTreeVersion(++s_globalTreeVersion) 390 #ifdef ANDROID_STYLE_VERSION 391 , m_styleVersion(0) 392 #endif 393 , m_styleSheets(StyleSheetList::create(this)) 394 , m_readyState(Complete) 395 , m_styleRecalcTimer(this, &Document::styleRecalcTimerFired) 396 , m_pendingStyleRecalcShouldForce(false) 397 , m_frameElementsShouldIgnoreScrolling(false) 398 , m_containsValidityStyleRules(false) 399 , m_updateFocusAppearanceRestoresSelection(false) 400 , m_ignoreDestructiveWriteCount(0) 401 , m_titleSetExplicitly(false) 402 , m_updateFocusAppearanceTimer(this, &Document::updateFocusAppearanceTimerFired) 403 , m_startTime(currentTime()) 404 , m_overMinimumLayoutThreshold(false) 405 , m_extraLayoutDelay(0) 406 , m_scriptRunner(ScriptRunner::create(this)) 407 , m_xmlVersion("1.0") 408 , m_xmlStandalone(false) 409 , m_savedRenderer(0) 410 , m_designMode(inherit) 411 #if ENABLE(SVG) 412 , m_svgExtensions(0) 413 #endif 414 #if ENABLE(DASHBOARD_SUPPORT) 415 , m_hasDashboardRegions(false) 416 , m_dashboardRegionsDirty(false) 417 #endif 418 , m_createRenderers(true) 419 , m_inPageCache(false) 420 , m_useSecureKeyboardEntryWhenActive(false) 421 , m_isXHTML(isXHTML) 422 , m_isHTML(isHTML) 423 , m_usesViewSourceStyles(false) 424 , m_sawElementsInKnownNamespaces(false) 425 , m_usingGeolocation(false) 426 , m_eventQueue(EventQueue::create(this)) 427 #if ENABLE(WML) 428 , m_containsWMLContent(false) 429 #endif 430 , m_weakReference(DocumentWeakReference::create(this)) 431 , m_idAttributeName(idAttr) 432 #if ENABLE(FULLSCREEN_API) 433 , m_areKeysEnabledInFullScreen(0) 434 , m_fullScreenRenderer(0) 435 , m_fullScreenChangeDelayTimer(this, &Document::fullScreenChangeDelayTimerFired) 436 #endif 437 , m_loadEventDelayCount(0) 438 , m_loadEventDelayTimer(this, &Document::loadEventDelayTimerFired) 439 , m_directionSetOnDocumentElement(false) 440 , m_writingModeSetOnDocumentElement(false) 441 , m_writeRecursionIsTooDeep(false) 442 , m_writeRecursionDepth(0) 443 { 444 m_document = this; 445 446 m_pageGroupUserSheetCacheValid = false; 447 448 m_printing = false; 449 m_paginatedForScreen = false; 450 451 m_ignoreAutofocus = false; 452 453 m_frame = frame; 454 455 // We depend on the url getting immediately set in subframes, but we 456 // also depend on the url NOT getting immediately set in opened windows. 457 // See fast/dom/early-frame-url.html 458 // and fast/dom/location-new-window-no-crash.html, respectively. 459 // FIXME: Can/should we unify this behavior? 460 if ((frame && frame->ownerElement()) || !url.isEmpty()) 461 setURL(url); 462 463 #if !PLATFORM(ANDROID) 464 m_axObjectCache = 0; 465 #endif 466 467 m_markers = new DocumentMarkerController(); 468 469 m_cachedResourceLoader = new CachedResourceLoader(this); 470 471 m_visuallyOrdered = false; 472 m_bParsing = false; 473 m_wellFormed = false; 474 475 m_textColor = Color::black; 476 m_listenerTypes = 0; 477 setInDocument(); 478 m_inStyleRecalc = false; 479 m_closeAfterStyleRecalc = false; 480 481 m_usesSiblingRules = false; 482 m_usesSiblingRulesOverride = false; 483 m_usesFirstLineRules = false; 484 m_usesFirstLetterRules = false; 485 m_usesBeforeAfterRules = false; 486 m_usesBeforeAfterRulesOverride = false; 487 m_usesRemUnits = false; 488 m_usesLinkRules = false; 489 490 m_gotoAnchorNeededAfterStylesheetsLoad = false; 491 492 m_didCalculateStyleSelector = false; 493 m_hasDirtyStyleSelector = false; 494 m_pendingStylesheets = 0; 495 m_ignorePendingStylesheets = false; 496 m_hasNodesWithPlaceholderStyle = false; 497 m_pendingSheetLayout = NoLayoutWithPendingSheets; 498 499 m_cssTarget = 0; 500 501 resetLinkColor(); 502 resetVisitedLinkColor(); 503 resetActiveLinkColor(); 504 505 m_processingLoadEvent = false; 506 507 initSecurityContext(); 508 initDNSPrefetch(); 509 510 static int docID = 0; 511 m_docID = docID++; 512 #if ENABLE(XHTMLMP) 513 m_shouldProcessNoScriptElement = !(m_frame && m_frame->script()->canExecuteScripts(NotAboutToExecuteScript)); 514 #endif 515 } 516 517 Document::~Document() 518 { 519 ASSERT(!renderer()); 520 ASSERT(!m_inPageCache); 521 ASSERT(!m_savedRenderer); 522 ASSERT(m_ranges.isEmpty()); 523 ASSERT(!m_styleRecalcTimer.isActive()); 524 ASSERT(!m_parentTreeScope); 525 526 m_scriptRunner.clear(); 527 528 removeAllEventListeners(); 529 530 // Currently we believe that Document can never outlive the parser. 531 // Although the Document may be replaced synchronously, DocumentParsers 532 // generally keep at least one reference to an Element which would in turn 533 // has a reference to the Document. If you hit this ASSERT, then that 534 // assumption is wrong. DocumentParser::detach() should ensure that even 535 // if the DocumentParser outlives the Document it won't cause badness. 536 ASSERT(!m_parser || m_parser->refCount() == 1); 537 detachParser(); 538 m_document = 0; 539 m_cachedResourceLoader.clear(); 540 541 m_renderArena.clear(); 542 543 clearAXObjectCache(); 544 545 m_decoder = 0; 546 547 for (size_t i = 0; i < m_nameCollectionInfo.size(); ++i) 548 deleteAllValues(m_nameCollectionInfo[i]); 549 550 if (m_styleSheets) 551 m_styleSheets->documentDestroyed(); 552 553 if (m_elemSheet) 554 m_elemSheet->clearOwnerNode(); 555 if (m_mappedElementSheet) 556 m_mappedElementSheet->clearOwnerNode(); 557 if (m_pageUserSheet) 558 m_pageUserSheet->clearOwnerNode(); 559 if (m_pageGroupUserSheets) { 560 for (size_t i = 0; i < m_pageGroupUserSheets->size(); ++i) 561 (*m_pageGroupUserSheets)[i]->clearOwnerNode(); 562 } 563 564 deleteRetiredCustomFonts(); 565 566 m_weakReference->clear(); 567 568 if (m_mediaQueryMatcher) 569 m_mediaQueryMatcher->documentDestroyed(); 570 571 if (m_implementation) 572 m_implementation->ownerDocumentDestroyed(); 573 } 574 575 void Document::removedLastRef() 576 { 577 ASSERT(!m_deletionHasBegun); 578 if (m_guardRefCount) { 579 // If removing a child removes the last self-only ref, we don't 580 // want the scope to be destructed until after 581 // removeAllChildren returns, so we guard ourselves with an 582 // extra self-only ref. 583 guardRef(); 584 585 // We must make sure not to be retaining any of our children through 586 // these extra pointers or we will create a reference cycle. 587 m_docType = 0; 588 m_focusedNode = 0; 589 m_hoverNode = 0; 590 m_activeNode = 0; 591 m_titleElement = 0; 592 m_documentElement = 0; 593 #if ENABLE(FULLSCREEN_API) 594 m_fullScreenElement = 0; 595 #endif 596 597 // removeAllChildren() doesn't always unregister IDs, 598 // so tear down scope information upfront to avoid having stale references in the map. 599 destroyTreeScopeData(); 600 removeAllChildren(); 601 602 m_markers->detach(); 603 604 detachParser(); 605 606 m_cssCanvasElements.clear(); 607 608 #if ENABLE(REQUEST_ANIMATION_FRAME) 609 // FIXME: consider using ActiveDOMObject. 610 m_scriptedAnimationController = 0; 611 #endif 612 613 #ifndef NDEBUG 614 m_inRemovedLastRefFunction = false; 615 #endif 616 617 guardDeref(); 618 } else { 619 #ifndef NDEBUG 620 m_deletionHasBegun = true; 621 #endif 622 delete this; 623 } 624 } 625 626 Element* Document::getElementById(const AtomicString& id) const 627 { 628 return TreeScope::getElementById(id); 629 } 630 631 MediaQueryMatcher* Document::mediaQueryMatcher() 632 { 633 if (!m_mediaQueryMatcher) 634 m_mediaQueryMatcher = MediaQueryMatcher::create(this); 635 return m_mediaQueryMatcher.get(); 636 } 637 638 void Document::setCompatibilityMode(CompatibilityMode mode) 639 { 640 if (m_compatibilityModeLocked || mode == m_compatibilityMode) 641 return; 642 ASSERT(!documentElement() && !m_styleSheets->length()); 643 bool wasInQuirksMode = inQuirksMode(); 644 m_compatibilityMode = mode; 645 if (inQuirksMode() != wasInQuirksMode) { 646 // All user stylesheets have to reparse using the different mode. 647 clearPageUserSheet(); 648 clearPageGroupUserSheets(); 649 } 650 } 651 652 String Document::compatMode() const 653 { 654 return inQuirksMode() ? "BackCompat" : "CSS1Compat"; 655 } 656 657 void Document::resetLinkColor() 658 { 659 m_linkColor = Color(0, 0, 238); 660 } 661 662 void Document::resetVisitedLinkColor() 663 { 664 m_visitedLinkColor = Color(85, 26, 139); 665 } 666 667 void Document::resetActiveLinkColor() 668 { 669 m_activeLinkColor.setNamedColor("red"); 670 } 671 672 void Document::setDocType(PassRefPtr<DocumentType> docType) 673 { 674 // This should never be called more than once. 675 ASSERT(!m_docType || !docType); 676 m_docType = docType; 677 if (m_docType) 678 m_docType->setTreeScope(this); 679 680 #ifdef ANDROID_META_SUPPORT 681 if (m_docType && !ownerElement() 682 && m_docType->publicId().startsWith("-//wapforum//dtd xhtml mobile 1.", false)) { 683 // fit mobile sites directly in the screen 684 processViewport("width=device-width"); 685 } 686 #endif 687 } 688 689 DOMImplementation* Document::implementation() 690 { 691 if (!m_implementation) 692 m_implementation = DOMImplementation::create(this); 693 return m_implementation.get(); 694 } 695 696 void Document::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) 697 { 698 TreeScope::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); 699 700 // Invalidate the document element we have cached in case it was replaced. 701 m_documentElement = 0; 702 } 703 704 void Document::cacheDocumentElement() const 705 { 706 ASSERT(!m_documentElement); 707 m_documentElement = firstElementChild(this); 708 } 709 710 PassRefPtr<Element> Document::createElement(const AtomicString& name, ExceptionCode& ec) 711 { 712 if (!isValidName(name)) { 713 ec = INVALID_CHARACTER_ERR; 714 return 0; 715 } 716 717 if (m_isXHTML) 718 return HTMLElementFactory::createHTMLElement(QualifiedName(nullAtom, name, xhtmlNamespaceURI), this, 0, false); 719 720 return createElement(QualifiedName(nullAtom, name, nullAtom), false); 721 } 722 723 PassRefPtr<DocumentFragment> Document::createDocumentFragment() 724 { 725 return DocumentFragment::create(document()); 726 } 727 728 PassRefPtr<Text> Document::createTextNode(const String& data) 729 { 730 return Text::create(this, data); 731 } 732 733 PassRefPtr<Comment> Document::createComment(const String& data) 734 { 735 return Comment::create(this, data); 736 } 737 738 PassRefPtr<CDATASection> Document::createCDATASection(const String& data, ExceptionCode& ec) 739 { 740 if (isHTMLDocument()) { 741 ec = NOT_SUPPORTED_ERR; 742 return 0; 743 } 744 return CDATASection::create(this, data); 745 } 746 747 PassRefPtr<ProcessingInstruction> Document::createProcessingInstruction(const String& target, const String& data, ExceptionCode& ec) 748 { 749 if (!isValidName(target)) { 750 ec = INVALID_CHARACTER_ERR; 751 return 0; 752 } 753 if (isHTMLDocument()) { 754 ec = NOT_SUPPORTED_ERR; 755 return 0; 756 } 757 return ProcessingInstruction::create(this, target, data); 758 } 759 760 PassRefPtr<EntityReference> Document::createEntityReference(const String& name, ExceptionCode& ec) 761 { 762 if (!isValidName(name)) { 763 ec = INVALID_CHARACTER_ERR; 764 return 0; 765 } 766 if (isHTMLDocument()) { 767 ec = NOT_SUPPORTED_ERR; 768 return 0; 769 } 770 return EntityReference::create(this, name); 771 } 772 773 PassRefPtr<EditingText> Document::createEditingTextNode(const String& text) 774 { 775 return EditingText::create(this, text); 776 } 777 778 PassRefPtr<CSSStyleDeclaration> Document::createCSSStyleDeclaration() 779 { 780 return CSSMutableStyleDeclaration::create(); 781 } 782 783 PassRefPtr<Node> Document::importNode(Node* importedNode, bool deep, ExceptionCode& ec) 784 { 785 ec = 0; 786 787 if (!importedNode 788 #if ENABLE(SVG) && ENABLE(DASHBOARD_SUPPORT) 789 || (importedNode->isSVGElement() && page() && page()->settings()->usesDashboardBackwardCompatibilityMode()) 790 #endif 791 ) { 792 ec = NOT_SUPPORTED_ERR; 793 return 0; 794 } 795 796 switch (importedNode->nodeType()) { 797 case TEXT_NODE: 798 return createTextNode(importedNode->nodeValue()); 799 case CDATA_SECTION_NODE: 800 return createCDATASection(importedNode->nodeValue(), ec); 801 case ENTITY_REFERENCE_NODE: 802 return createEntityReference(importedNode->nodeName(), ec); 803 case PROCESSING_INSTRUCTION_NODE: 804 return createProcessingInstruction(importedNode->nodeName(), importedNode->nodeValue(), ec); 805 case COMMENT_NODE: 806 return createComment(importedNode->nodeValue()); 807 case ELEMENT_NODE: { 808 Element* oldElement = static_cast<Element*>(importedNode); 809 RefPtr<Element> newElement = createElementNS(oldElement->namespaceURI(), oldElement->tagQName().toString(), ec); 810 811 if (ec) 812 return 0; 813 814 NamedNodeMap* attrs = oldElement->attributes(true); 815 if (attrs) { 816 unsigned length = attrs->length(); 817 for (unsigned i = 0; i < length; i++) { 818 Attribute* attr = attrs->attributeItem(i); 819 newElement->setAttribute(attr->name(), attr->value().impl(), ec); 820 if (ec) 821 return 0; 822 } 823 } 824 825 newElement->copyNonAttributeProperties(oldElement); 826 827 if (deep) { 828 for (Node* oldChild = oldElement->firstChild(); oldChild; oldChild = oldChild->nextSibling()) { 829 RefPtr<Node> newChild = importNode(oldChild, true, ec); 830 if (ec) 831 return 0; 832 newElement->appendChild(newChild.release(), ec); 833 if (ec) 834 return 0; 835 } 836 } 837 838 return newElement.release(); 839 } 840 case ATTRIBUTE_NODE: 841 return Attr::create(0, this, static_cast<Attr*>(importedNode)->attr()->clone()); 842 case DOCUMENT_FRAGMENT_NODE: { 843 DocumentFragment* oldFragment = static_cast<DocumentFragment*>(importedNode); 844 RefPtr<DocumentFragment> newFragment = createDocumentFragment(); 845 if (deep) { 846 for (Node* oldChild = oldFragment->firstChild(); oldChild; oldChild = oldChild->nextSibling()) { 847 RefPtr<Node> newChild = importNode(oldChild, true, ec); 848 if (ec) 849 return 0; 850 newFragment->appendChild(newChild.release(), ec); 851 if (ec) 852 return 0; 853 } 854 } 855 856 return newFragment.release(); 857 } 858 case ENTITY_NODE: 859 case NOTATION_NODE: 860 // FIXME: It should be possible to import these node types, however in DOM3 the DocumentType is readonly, so there isn't much sense in doing that. 861 // Ability to add these imported nodes to a DocumentType will be considered for addition to a future release of the DOM. 862 case DOCUMENT_NODE: 863 case DOCUMENT_TYPE_NODE: 864 case XPATH_NAMESPACE_NODE: 865 break; 866 } 867 868 ec = NOT_SUPPORTED_ERR; 869 return 0; 870 } 871 872 873 PassRefPtr<Node> Document::adoptNode(PassRefPtr<Node> source, ExceptionCode& ec) 874 { 875 if (!source) { 876 ec = NOT_SUPPORTED_ERR; 877 return 0; 878 } 879 880 if (source->isReadOnlyNode()) { 881 ec = NO_MODIFICATION_ALLOWED_ERR; 882 return 0; 883 } 884 885 EventQueueScope scope; 886 887 switch (source->nodeType()) { 888 case ENTITY_NODE: 889 case NOTATION_NODE: 890 case DOCUMENT_NODE: 891 case DOCUMENT_TYPE_NODE: 892 case XPATH_NAMESPACE_NODE: 893 ec = NOT_SUPPORTED_ERR; 894 return 0; 895 case ATTRIBUTE_NODE: { 896 Attr* attr = static_cast<Attr*>(source.get()); 897 if (attr->ownerElement()) 898 attr->ownerElement()->removeAttributeNode(attr, ec); 899 attr->setSpecified(true); 900 break; 901 } 902 default: 903 if (source->hasTagName(iframeTag)) { 904 HTMLIFrameElement* iframe = static_cast<HTMLIFrameElement*>(source.get()); 905 if (frame() && frame()->tree()->isDescendantOf(iframe->contentFrame())) { 906 ec = HIERARCHY_REQUEST_ERR; 907 return 0; 908 } 909 iframe->setRemainsAliveOnRemovalFromTree(attached() && source->attached()); 910 } 911 912 if (source->parentNode()) 913 source->parentNode()->removeChild(source.get(), ec); 914 } 915 916 source->setTreeScopeRecursively(this); 917 918 return source; 919 } 920 921 bool Document::hasPrefixNamespaceMismatch(const QualifiedName& qName) 922 { 923 // These checks are from DOM Core Level 2, createElementNS 924 // http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-DocCrElNS 925 if (!qName.prefix().isEmpty() && qName.namespaceURI().isNull()) // createElementNS(null, "html:div") 926 return true; 927 if (qName.prefix() == xmlAtom && qName.namespaceURI() != XMLNames::xmlNamespaceURI) // createElementNS("http://www.example.com", "xml:lang") 928 return true; 929 930 // Required by DOM Level 3 Core and unspecified by DOM Level 2 Core: 931 // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-DocCrElNS 932 // createElementNS("http://www.w3.org/2000/xmlns/", "foo:bar"), createElementNS(null, "xmlns:bar") 933 if ((qName.prefix() == xmlnsAtom && qName.namespaceURI() != XMLNSNames::xmlnsNamespaceURI) || (qName.prefix() != xmlnsAtom && qName.namespaceURI() == XMLNSNames::xmlnsNamespaceURI)) 934 return true; 935 936 return false; 937 } 938 939 // FIXME: This should really be in a possible ElementFactory class 940 PassRefPtr<Element> Document::createElement(const QualifiedName& qName, bool createdByParser) 941 { 942 RefPtr<Element> e; 943 944 // FIXME: Use registered namespaces and look up in a hash to find the right factory. 945 if (qName.namespaceURI() == xhtmlNamespaceURI) 946 e = HTMLElementFactory::createHTMLElement(qName, this, 0, createdByParser); 947 #if ENABLE(SVG) 948 else if (qName.namespaceURI() == SVGNames::svgNamespaceURI) 949 e = SVGElementFactory::createSVGElement(qName, this, createdByParser); 950 #endif 951 #if ENABLE(WML) 952 else if (qName.namespaceURI() == WMLNames::wmlNamespaceURI) 953 e = WMLElementFactory::createWMLElement(qName, this, createdByParser); 954 else if (isWMLDocument()) 955 e = WMLElementFactory::createWMLElement(QualifiedName(nullAtom, qName.localName(), WMLNames::wmlNamespaceURI), this, createdByParser); 956 #endif 957 #if ENABLE(MATHML) 958 else if (qName.namespaceURI() == MathMLNames::mathmlNamespaceURI) 959 e = MathMLElementFactory::createMathMLElement(qName, this, createdByParser); 960 #endif 961 962 if (e) 963 m_sawElementsInKnownNamespaces = true; 964 else 965 e = Element::create(qName, document()); 966 967 // <image> uses imgTag so we need a special rule. 968 #if ENABLE(WML) 969 if (!isWMLDocument()) 970 #endif 971 ASSERT((qName.matches(imageTag) && e->tagQName().matches(imgTag) && e->tagQName().prefix() == qName.prefix()) || qName == e->tagQName()); 972 973 return e.release(); 974 } 975 976 PassRefPtr<Element> Document::createElementNS(const String& namespaceURI, const String& qualifiedName, ExceptionCode& ec) 977 { 978 String prefix, localName; 979 if (!parseQualifiedName(qualifiedName, prefix, localName, ec)) 980 return 0; 981 982 QualifiedName qName(prefix, localName, namespaceURI); 983 if (hasPrefixNamespaceMismatch(qName)) { 984 ec = NAMESPACE_ERR; 985 return 0; 986 } 987 988 return createElement(qName, false); 989 } 990 991 String Document::readyState() const 992 { 993 DEFINE_STATIC_LOCAL(const String, loading, ("loading")); 994 DEFINE_STATIC_LOCAL(const String, interactive, ("interactive")); 995 DEFINE_STATIC_LOCAL(const String, complete, ("complete")); 996 997 switch (m_readyState) { 998 case Loading: 999 return loading; 1000 case Interactive: 1001 return interactive; 1002 case Complete: 1003 return complete; 1004 } 1005 1006 ASSERT_NOT_REACHED(); 1007 return String(); 1008 } 1009 1010 void Document::setReadyState(ReadyState readyState) 1011 { 1012 if (readyState == m_readyState) 1013 return; 1014 1015 switch (readyState) { 1016 case Loading: 1017 if (!m_documentTiming.domLoading) 1018 m_documentTiming.domLoading = currentTime(); 1019 break; 1020 case Interactive: 1021 if (!m_documentTiming.domInteractive) 1022 m_documentTiming.domInteractive = currentTime(); 1023 break; 1024 case Complete: 1025 if (!m_documentTiming.domComplete) 1026 m_documentTiming.domComplete = currentTime(); 1027 break; 1028 } 1029 1030 m_readyState = readyState; 1031 dispatchEvent(Event::create(eventNames().readystatechangeEvent, false, false)); 1032 } 1033 1034 String Document::encoding() const 1035 { 1036 if (TextResourceDecoder* d = decoder()) 1037 return d->encoding().domName(); 1038 return String(); 1039 } 1040 1041 String Document::defaultCharset() const 1042 { 1043 if (Settings* settings = this->settings()) 1044 return settings->defaultTextEncodingName(); 1045 return String(); 1046 } 1047 1048 void Document::setCharset(const String& charset) 1049 { 1050 if (!decoder()) 1051 return; 1052 decoder()->setEncoding(charset, TextResourceDecoder::UserChosenEncoding); 1053 } 1054 1055 void Document::setXMLVersion(const String& version, ExceptionCode& ec) 1056 { 1057 if (!implementation()->hasFeature("XML", String())) { 1058 ec = NOT_SUPPORTED_ERR; 1059 return; 1060 } 1061 1062 if (!XMLDocumentParser::supportsXMLVersion(version)) { 1063 ec = NOT_SUPPORTED_ERR; 1064 return; 1065 } 1066 1067 m_xmlVersion = version; 1068 } 1069 1070 void Document::setXMLStandalone(bool standalone, ExceptionCode& ec) 1071 { 1072 if (!implementation()->hasFeature("XML", String())) { 1073 ec = NOT_SUPPORTED_ERR; 1074 return; 1075 } 1076 1077 m_xmlStandalone = standalone; 1078 } 1079 1080 void Document::setDocumentURI(const String& uri) 1081 { 1082 m_documentURI = uri; 1083 updateBaseURL(); 1084 } 1085 1086 KURL Document::baseURI() const 1087 { 1088 return m_baseURL; 1089 } 1090 1091 void Document::setContent(const String& content) 1092 { 1093 open(); 1094 m_parser->append(content); 1095 close(); 1096 } 1097 1098 // FIXME: We need to discuss the DOM API here at some point. Ideas: 1099 // * making it receive a rect as parameter, i.e. nodesFromRect(x, y, w, h); 1100 // * making it receive the expading size of each direction separately, 1101 // i.e. nodesFromRect(x, y, topSize, rightSize, bottomSize, leftSize); 1102 PassRefPtr<NodeList> Document::nodesFromRect(int centerX, int centerY, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding, bool ignoreClipping) const 1103 { 1104 // FIXME: Share code between this, elementFromPoint and caretRangeFromPoint. 1105 if (!renderer()) 1106 return 0; 1107 Frame* frame = this->frame(); 1108 if (!frame) 1109 return 0; 1110 FrameView* frameView = frame->view(); 1111 if (!frameView) 1112 return 0; 1113 1114 float zoomFactor = frame->pageZoomFactor(); 1115 IntPoint point = roundedIntPoint(FloatPoint(centerX * zoomFactor + view()->scrollX(), centerY * zoomFactor + view()->scrollY())); 1116 1117 int type = HitTestRequest::ReadOnly | HitTestRequest::Active; 1118 1119 // When ignoreClipping is false, this method returns null for coordinates outside of the viewport. 1120 if (ignoreClipping) 1121 type |= HitTestRequest::IgnoreClipping; 1122 else if (!frameView->visibleContentRect().intersects(HitTestResult::rectForPoint(point, topPadding, rightPadding, bottomPadding, leftPadding))) 1123 return 0; 1124 1125 HitTestRequest request(type); 1126 1127 // Passing a zero padding will trigger a rect hit test, however for the purposes of nodesFromRect, 1128 // we special handle this case in order to return a valid NodeList. 1129 if (!topPadding && !rightPadding && !bottomPadding && !leftPadding) { 1130 HitTestResult result(point); 1131 return handleZeroPadding(request, result); 1132 } 1133 1134 HitTestResult result(point, topPadding, rightPadding, bottomPadding, leftPadding); 1135 renderView()->layer()->hitTest(request, result); 1136 1137 return StaticHashSetNodeList::adopt(result.rectBasedTestResult()); 1138 } 1139 1140 PassRefPtr<NodeList> Document::handleZeroPadding(const HitTestRequest& request, HitTestResult& result) const 1141 { 1142 renderView()->layer()->hitTest(request, result); 1143 1144 Node* node = result.innerNode(); 1145 if (!node) 1146 return 0; 1147 1148 node = node->shadowAncestorNode(); 1149 ListHashSet<RefPtr<Node> > list; 1150 list.add(node); 1151 return StaticHashSetNodeList::adopt(list); 1152 } 1153 1154 static Node* nodeFromPoint(Frame* frame, RenderView* renderView, int x, int y, IntPoint* localPoint = 0) 1155 { 1156 if (!frame) 1157 return 0; 1158 FrameView* frameView = frame->view(); 1159 if (!frameView) 1160 return 0; 1161 1162 float zoomFactor = frame->pageZoomFactor(); 1163 IntPoint point = roundedIntPoint(FloatPoint(x * zoomFactor + frameView->scrollX(), y * zoomFactor + frameView->scrollY())); 1164 1165 if (!frameView->visibleContentRect().contains(point)) 1166 return 0; 1167 1168 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active); 1169 HitTestResult result(point); 1170 renderView->layer()->hitTest(request, result); 1171 1172 if (localPoint) 1173 *localPoint = result.localPoint(); 1174 1175 return result.innerNode(); 1176 } 1177 1178 Element* Document::elementFromPoint(int x, int y) const 1179 { 1180 if (!renderer()) 1181 return 0; 1182 Node* node = nodeFromPoint(frame(), renderView(), x, y); 1183 while (node && !node->isElementNode()) 1184 node = node->parentNode(); 1185 if (node) 1186 node = node->shadowAncestorNode(); 1187 return static_cast<Element*>(node); 1188 } 1189 1190 PassRefPtr<Range> Document::caretRangeFromPoint(int x, int y) 1191 { 1192 if (!renderer()) 1193 return 0; 1194 IntPoint localPoint; 1195 Node* node = nodeFromPoint(frame(), renderView(), x, y, &localPoint); 1196 if (!node) 1197 return 0; 1198 1199 Node* shadowAncestorNode = node->shadowAncestorNode(); 1200 if (shadowAncestorNode != node) { 1201 unsigned offset = shadowAncestorNode->nodeIndex(); 1202 ContainerNode* container = shadowAncestorNode->parentNode(); 1203 return Range::create(this, container, offset, container, offset); 1204 } 1205 1206 RenderObject* renderer = node->renderer(); 1207 if (!renderer) 1208 return 0; 1209 VisiblePosition visiblePosition = renderer->positionForPoint(localPoint); 1210 if (visiblePosition.isNull()) 1211 return 0; 1212 1213 Position rangeCompliantPosition = visiblePosition.deepEquivalent().parentAnchoredEquivalent(); 1214 return Range::create(this, rangeCompliantPosition, rangeCompliantPosition); 1215 } 1216 1217 /* 1218 * Performs three operations: 1219 * 1. Convert control characters to spaces 1220 * 2. Trim leading and trailing spaces 1221 * 3. Collapse internal whitespace. 1222 */ 1223 static inline StringWithDirection canonicalizedTitle(Document* document, const StringWithDirection& titleWithDirection) 1224 { 1225 const String& title = titleWithDirection.string(); 1226 const UChar* characters = title.characters(); 1227 unsigned length = title.length(); 1228 unsigned i; 1229 1230 StringBuffer buffer(length); 1231 unsigned builderIndex = 0; 1232 1233 // Skip leading spaces and leading characters that would convert to spaces 1234 for (i = 0; i < length; ++i) { 1235 UChar c = characters[i]; 1236 if (!(c <= 0x20 || c == 0x7F)) 1237 break; 1238 } 1239 1240 if (i == length) 1241 return StringWithDirection(); 1242 1243 // Replace control characters with spaces, and backslashes with currency symbols, and collapse whitespace. 1244 bool previousCharWasWS = false; 1245 for (; i < length; ++i) { 1246 UChar c = characters[i]; 1247 if (c <= 0x20 || c == 0x7F || (WTF::Unicode::category(c) & (WTF::Unicode::Separator_Line | WTF::Unicode::Separator_Paragraph))) { 1248 if (previousCharWasWS) 1249 continue; 1250 buffer[builderIndex++] = ' '; 1251 previousCharWasWS = true; 1252 } else { 1253 buffer[builderIndex++] = c; 1254 previousCharWasWS = false; 1255 } 1256 } 1257 1258 // Strip trailing spaces 1259 while (builderIndex > 0) { 1260 --builderIndex; 1261 if (buffer[builderIndex] != ' ') 1262 break; 1263 } 1264 1265 if (!builderIndex && buffer[builderIndex] == ' ') 1266 return StringWithDirection(); 1267 1268 buffer.shrink(builderIndex + 1); 1269 1270 // Replace the backslashes with currency symbols if the encoding requires it. 1271 document->displayBufferModifiedByEncoding(buffer.characters(), buffer.length()); 1272 1273 return StringWithDirection(String::adopt(buffer), titleWithDirection.direction()); 1274 } 1275 1276 void Document::updateTitle(const StringWithDirection& title) 1277 { 1278 if (m_rawTitle == title) 1279 return; 1280 1281 m_rawTitle = title; 1282 m_title = canonicalizedTitle(this, m_rawTitle); 1283 if (Frame* f = frame()) 1284 f->loader()->setTitle(m_title); 1285 } 1286 1287 void Document::setTitle(const String& title) 1288 { 1289 // Title set by JavaScript -- overrides any title elements. 1290 m_titleSetExplicitly = true; 1291 if (!isHTMLDocument()) 1292 m_titleElement = 0; 1293 else if (!m_titleElement) { 1294 if (HTMLElement* headElement = head()) { 1295 m_titleElement = createElement(titleTag, false); 1296 ExceptionCode ec = 0; 1297 headElement->appendChild(m_titleElement, ec); 1298 ASSERT(!ec); 1299 } 1300 } 1301 1302 // The DOM API has no method of specifying direction, so assume LTR. 1303 updateTitle(StringWithDirection(title, LTR)); 1304 1305 if (m_titleElement) { 1306 ASSERT(m_titleElement->hasTagName(titleTag)); 1307 if (m_titleElement->hasTagName(titleTag)) 1308 static_cast<HTMLTitleElement*>(m_titleElement.get())->setText(title); 1309 } 1310 } 1311 1312 void Document::setTitleElement(const StringWithDirection& title, Element* titleElement) 1313 { 1314 if (titleElement != m_titleElement) { 1315 if (m_titleElement || m_titleSetExplicitly) 1316 // Only allow the first title element to change the title -- others have no effect. 1317 return; 1318 m_titleElement = titleElement; 1319 } 1320 1321 updateTitle(title); 1322 } 1323 1324 void Document::removeTitle(Element* titleElement) 1325 { 1326 if (m_titleElement != titleElement) 1327 return; 1328 1329 m_titleElement = 0; 1330 m_titleSetExplicitly = false; 1331 1332 // Update title based on first title element in the head, if one exists. 1333 if (HTMLElement* headElement = head()) { 1334 for (Node* e = headElement->firstChild(); e; e = e->nextSibling()) 1335 if (e->hasTagName(titleTag)) { 1336 HTMLTitleElement* titleElement = static_cast<HTMLTitleElement*>(e); 1337 setTitleElement(titleElement->textWithDirection(), titleElement); 1338 break; 1339 } 1340 } 1341 1342 if (!m_titleElement) 1343 updateTitle(StringWithDirection()); 1344 } 1345 1346 String Document::nodeName() const 1347 { 1348 return "#document"; 1349 } 1350 1351 Node::NodeType Document::nodeType() const 1352 { 1353 return DOCUMENT_NODE; 1354 } 1355 1356 FrameView* Document::view() const 1357 { 1358 return m_frame ? m_frame->view() : 0; 1359 } 1360 1361 Page* Document::page() const 1362 { 1363 return m_frame ? m_frame->page() : 0; 1364 } 1365 1366 Settings* Document::settings() const 1367 { 1368 return m_frame ? m_frame->settings() : 0; 1369 } 1370 1371 PassRefPtr<Range> Document::createRange() 1372 { 1373 return Range::create(this); 1374 } 1375 1376 PassRefPtr<NodeIterator> Document::createNodeIterator(Node* root, unsigned whatToShow, 1377 PassRefPtr<NodeFilter> filter, bool expandEntityReferences, ExceptionCode& ec) 1378 { 1379 if (!root) { 1380 ec = NOT_SUPPORTED_ERR; 1381 return 0; 1382 } 1383 return NodeIterator::create(root, whatToShow, filter, expandEntityReferences); 1384 } 1385 1386 PassRefPtr<TreeWalker> Document::createTreeWalker(Node* root, unsigned whatToShow, 1387 PassRefPtr<NodeFilter> filter, bool expandEntityReferences, ExceptionCode& ec) 1388 { 1389 if (!root) { 1390 ec = NOT_SUPPORTED_ERR; 1391 return 0; 1392 } 1393 return TreeWalker::create(root, whatToShow, filter, expandEntityReferences); 1394 } 1395 1396 void Document::scheduleForcedStyleRecalc() 1397 { 1398 m_pendingStyleRecalcShouldForce = true; 1399 scheduleStyleRecalc(); 1400 } 1401 1402 void Document::scheduleStyleRecalc() 1403 { 1404 if (m_styleRecalcTimer.isActive() || inPageCache()) 1405 return; 1406 1407 ASSERT(childNeedsStyleRecalc() || m_pendingStyleRecalcShouldForce); 1408 1409 if (!documentsThatNeedStyleRecalc) 1410 documentsThatNeedStyleRecalc = new HashSet<Document*>; 1411 documentsThatNeedStyleRecalc->add(this); 1412 1413 // FIXME: Why on earth is this here? This is clearly misplaced. 1414 invalidateAccessKeyMap(); 1415 1416 m_styleRecalcTimer.startOneShot(0); 1417 } 1418 1419 void Document::unscheduleStyleRecalc() 1420 { 1421 ASSERT(!childNeedsStyleRecalc()); 1422 1423 if (documentsThatNeedStyleRecalc) 1424 documentsThatNeedStyleRecalc->remove(this); 1425 1426 m_styleRecalcTimer.stop(); 1427 m_pendingStyleRecalcShouldForce = false; 1428 } 1429 1430 bool Document::isPendingStyleRecalc() const 1431 { 1432 return m_styleRecalcTimer.isActive() && !m_inStyleRecalc; 1433 } 1434 1435 void Document::styleRecalcTimerFired(Timer<Document>*) 1436 { 1437 updateStyleIfNeeded(); 1438 } 1439 1440 bool Document::childNeedsAndNotInStyleRecalc() 1441 { 1442 return childNeedsStyleRecalc() && !m_inStyleRecalc; 1443 } 1444 1445 void Document::recalcStyle(StyleChange change) 1446 { 1447 // we should not enter style recalc while painting 1448 if (view() && view()->isPainting()) { 1449 ASSERT(!view()->isPainting()); 1450 return; 1451 } 1452 1453 if (m_inStyleRecalc) 1454 return; // Guard against re-entrancy. -dwh 1455 1456 if (m_hasDirtyStyleSelector) 1457 recalcStyleSelector(); 1458 1459 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRecalculateStyle(this); 1460 1461 m_inStyleRecalc = true; 1462 suspendPostAttachCallbacks(); 1463 RenderWidget::suspendWidgetHierarchyUpdates(); 1464 1465 RefPtr<FrameView> frameView = view(); 1466 if (frameView) { 1467 frameView->pauseScheduledEvents(); 1468 frameView->beginDeferredRepaints(); 1469 } 1470 1471 ASSERT(!renderer() || renderArena()); 1472 if (!renderer() || !renderArena()) 1473 goto bail_out; 1474 1475 if (m_pendingStyleRecalcShouldForce) 1476 change = Force; 1477 1478 if (change == Force) { 1479 // style selector may set this again during recalc 1480 m_hasNodesWithPlaceholderStyle = false; 1481 1482 RefPtr<RenderStyle> documentStyle = CSSStyleSelector::styleForDocument(this); 1483 StyleChange ch = diff(documentStyle.get(), renderer()->style()); 1484 if (renderer() && ch != NoChange) 1485 renderer()->setStyle(documentStyle.release()); 1486 } 1487 1488 for (Node* n = firstChild(); n; n = n->nextSibling()) 1489 if (change >= Inherit || n->childNeedsStyleRecalc() || n->needsStyleRecalc()) 1490 n->recalcStyle(change); 1491 1492 // FIXME: Disabling the deletion of retired custom font data until 1493 // we fix all the stale style bugs (68804, 68624, etc). These bugs 1494 // indicate problems where some styles were not updated in recalcStyle, 1495 // thereby retaining stale copy of font data. To prevent that, we 1496 // disable this code for now and only delete retired custom font data 1497 // in Document destructor. 1498 // Now that all RenderStyles that pointed to retired fonts have been updated, the fonts can safely be deleted. 1499 // deleteRetiredCustomFonts(); 1500 1501 #if USE(ACCELERATED_COMPOSITING) 1502 if (view()) { 1503 bool layoutPending = view()->layoutPending() || renderer()->needsLayout(); 1504 // If we didn't update compositing layers because of layout(), we need to do so here. 1505 if (!layoutPending) 1506 view()->updateCompositingLayers(); 1507 } 1508 #endif 1509 1510 bail_out: 1511 clearNeedsStyleRecalc(); 1512 clearChildNeedsStyleRecalc(); 1513 unscheduleStyleRecalc(); 1514 1515 m_inStyleRecalc = false; 1516 1517 // Pseudo element removal and similar may only work with these flags still set. Reset them after the style recalc. 1518 if (m_styleSelector) { 1519 m_usesSiblingRules = m_styleSelector->usesSiblingRules(); 1520 m_usesFirstLineRules = m_styleSelector->usesFirstLineRules(); 1521 m_usesBeforeAfterRules = m_styleSelector->usesBeforeAfterRules(); 1522 m_usesLinkRules = m_styleSelector->usesLinkRules(); 1523 } 1524 1525 if (frameView) { 1526 frameView->resumeScheduledEvents(); 1527 frameView->endDeferredRepaints(); 1528 } 1529 RenderWidget::resumeWidgetHierarchyUpdates(); 1530 resumePostAttachCallbacks(); 1531 1532 // If we wanted to call implicitClose() during recalcStyle, do so now that we're finished. 1533 if (m_closeAfterStyleRecalc) { 1534 m_closeAfterStyleRecalc = false; 1535 implicitClose(); 1536 } 1537 1538 InspectorInstrumentation::didRecalculateStyle(cookie); 1539 } 1540 1541 void Document::updateStyleIfNeeded() 1542 { 1543 ASSERT(isMainThread()); 1544 ASSERT(!view() || (!view()->isInLayout() && !view()->isPainting())); 1545 1546 if ((!m_pendingStyleRecalcShouldForce && !childNeedsStyleRecalc()) || inPageCache()) 1547 return; 1548 1549 if (m_frame) 1550 m_frame->animation()->beginAnimationUpdate(); 1551 1552 recalcStyle(NoChange); 1553 1554 // Tell the animation controller that updateStyleIfNeeded is finished and it can do any post-processing 1555 if (m_frame) 1556 m_frame->animation()->endAnimationUpdate(); 1557 } 1558 1559 void Document::updateStyleForAllDocuments() 1560 { 1561 ASSERT(isMainThread()); 1562 if (!documentsThatNeedStyleRecalc) 1563 return; 1564 1565 while (documentsThatNeedStyleRecalc->size()) { 1566 HashSet<Document*>::iterator it = documentsThatNeedStyleRecalc->begin(); 1567 Document* doc = *it; 1568 documentsThatNeedStyleRecalc->remove(doc); 1569 doc->updateStyleIfNeeded(); 1570 } 1571 } 1572 1573 void Document::updateLayout() 1574 { 1575 ASSERT(isMainThread()); 1576 if (Element* oe = ownerElement()) 1577 oe->document()->updateLayout(); 1578 1579 updateStyleIfNeeded(); 1580 1581 // Only do a layout if changes have occurred that make it necessary. 1582 FrameView* v = view(); 1583 if (v && renderer() && (v->layoutPending() || renderer()->needsLayout())) 1584 v->layout(); 1585 } 1586 1587 // FIXME: This is a bad idea and needs to be removed eventually. 1588 // Other browsers load stylesheets before they continue parsing the web page. 1589 // Since we don't, we can run JavaScript code that needs answers before the 1590 // stylesheets are loaded. Doing a layout ignoring the pending stylesheets 1591 // lets us get reasonable answers. The long term solution to this problem is 1592 // to instead suspend JavaScript execution. 1593 void Document::updateLayoutIgnorePendingStylesheets() 1594 { 1595 bool oldIgnore = m_ignorePendingStylesheets; 1596 1597 if (!haveStylesheetsLoaded()) { 1598 m_ignorePendingStylesheets = true; 1599 // FIXME: We are willing to attempt to suppress painting with outdated style info only once. Our assumption is that it would be 1600 // dangerous to try to stop it a second time, after page content has already been loaded and displayed 1601 // with accurate style information. (Our suppression involves blanking the whole page at the 1602 // moment. If it were more refined, we might be able to do something better.) 1603 // It's worth noting though that this entire method is a hack, since what we really want to do is 1604 // suspend JS instead of doing a layout with inaccurate information. 1605 if (body() && !body()->renderer() && m_pendingSheetLayout == NoLayoutWithPendingSheets) { 1606 m_pendingSheetLayout = DidLayoutWithPendingSheets; 1607 styleSelectorChanged(RecalcStyleImmediately); 1608 } else if (m_hasNodesWithPlaceholderStyle) 1609 // If new nodes have been added or style recalc has been done with style sheets still pending, some nodes 1610 // may not have had their real style calculated yet. Normally this gets cleaned when style sheets arrive 1611 // but here we need up-to-date style immediately. 1612 recalcStyle(Force); 1613 } 1614 1615 updateLayout(); 1616 1617 m_ignorePendingStylesheets = oldIgnore; 1618 } 1619 1620 PassRefPtr<RenderStyle> Document::styleForElementIgnoringPendingStylesheets(Element* element) 1621 { 1622 ASSERT_ARG(element, element->document() == this); 1623 1624 bool oldIgnore = m_ignorePendingStylesheets; 1625 m_ignorePendingStylesheets = true; 1626 RefPtr<RenderStyle> style = styleSelector()->styleForElement(element, element->parentNode() ? element->parentNode()->computedStyle() : 0); 1627 m_ignorePendingStylesheets = oldIgnore; 1628 return style.release(); 1629 } 1630 1631 PassRefPtr<RenderStyle> Document::styleForPage(int pageIndex) 1632 { 1633 RefPtr<RenderStyle> style = styleSelector()->styleForPage(pageIndex); 1634 return style.release(); 1635 } 1636 1637 void Document::retireCustomFont(FontData* fontData) 1638 { 1639 m_retiredCustomFonts.append(adoptPtr(fontData)); 1640 } 1641 1642 void Document::deleteRetiredCustomFonts() 1643 { 1644 size_t size = m_retiredCustomFonts.size(); 1645 for (size_t i = 0; i < size; ++i) 1646 GlyphPageTreeNode::pruneTreeCustomFontData(m_retiredCustomFonts[i].get()); 1647 1648 m_retiredCustomFonts.clear(); 1649 } 1650 1651 bool Document::isPageBoxVisible(int pageIndex) 1652 { 1653 RefPtr<RenderStyle> style = styleForPage(pageIndex); 1654 return style->visibility() != HIDDEN; // display property doesn't apply to @page. 1655 } 1656 1657 void Document::pageSizeAndMarginsInPixels(int pageIndex, IntSize& pageSize, int& marginTop, int& marginRight, int& marginBottom, int& marginLeft) 1658 { 1659 RefPtr<RenderStyle> style = styleForPage(pageIndex); 1660 1661 int width = pageSize.width(); 1662 int height = pageSize.height(); 1663 switch (style->pageSizeType()) { 1664 case PAGE_SIZE_AUTO: 1665 break; 1666 case PAGE_SIZE_AUTO_LANDSCAPE: 1667 if (width < height) 1668 std::swap(width, height); 1669 break; 1670 case PAGE_SIZE_AUTO_PORTRAIT: 1671 if (width > height) 1672 std::swap(width, height); 1673 break; 1674 case PAGE_SIZE_RESOLVED: { 1675 LengthSize size = style->pageSize(); 1676 ASSERT(size.width().isFixed()); 1677 ASSERT(size.height().isFixed()); 1678 width = size.width().calcValue(0); 1679 height = size.height().calcValue(0); 1680 break; 1681 } 1682 default: 1683 ASSERT_NOT_REACHED(); 1684 } 1685 pageSize = IntSize(width, height); 1686 1687 // The percentage is calculated with respect to the width even for margin top and bottom. 1688 // http://www.w3.org/TR/CSS2/box.html#margin-properties 1689 marginTop = style->marginTop().isAuto() ? marginTop : style->marginTop().calcValue(width); 1690 marginRight = style->marginRight().isAuto() ? marginRight : style->marginRight().calcValue(width); 1691 marginBottom = style->marginBottom().isAuto() ? marginBottom : style->marginBottom().calcValue(width); 1692 marginLeft = style->marginLeft().isAuto() ? marginLeft : style->marginLeft().calcValue(width); 1693 } 1694 1695 PassRefPtr<CSSPrimitiveValueCache> Document::cssPrimitiveValueCache() const 1696 { 1697 if (!m_cssPrimitiveValueCache) 1698 m_cssPrimitiveValueCache = CSSPrimitiveValueCache::create(); 1699 return m_cssPrimitiveValueCache; 1700 } 1701 1702 void Document::createStyleSelector() 1703 { 1704 bool matchAuthorAndUserStyles = true; 1705 if (Settings* docSettings = settings()) 1706 matchAuthorAndUserStyles = docSettings->authorAndUserStylesEnabled(); 1707 m_styleSelector.set(new CSSStyleSelector(this, m_styleSheets.get(), m_mappedElementSheet.get(), pageUserSheet(), pageGroupUserSheets(), 1708 !inQuirksMode(), matchAuthorAndUserStyles)); 1709 // Delay resetting the flags until after next style recalc since unapplying the style may not work without these set (this is true at least with before/after). 1710 m_usesSiblingRules = m_usesSiblingRules || m_styleSelector->usesSiblingRules(); 1711 m_usesFirstLineRules = m_usesFirstLineRules || m_styleSelector->usesFirstLineRules(); 1712 m_usesBeforeAfterRules = m_usesBeforeAfterRules || m_styleSelector->usesBeforeAfterRules(); 1713 m_usesLinkRules = m_usesLinkRules || m_styleSelector->usesLinkRules(); 1714 } 1715 1716 void Document::attach() 1717 { 1718 ASSERT(!attached()); 1719 ASSERT(!m_inPageCache); 1720 #if !PLATFORM(ANDROID) 1721 ASSERT(!m_axObjectCache); 1722 #endif 1723 1724 if (!m_renderArena) 1725 m_renderArena = new RenderArena(); 1726 1727 // Create the rendering tree 1728 setRenderer(new (m_renderArena.get()) RenderView(this, view())); 1729 #if USE(ACCELERATED_COMPOSITING) 1730 renderView()->didMoveOnscreen(); 1731 #endif 1732 1733 recalcStyle(Force); 1734 1735 RenderObject* render = renderer(); 1736 setRenderer(0); 1737 1738 TreeScope::attach(); 1739 1740 setRenderer(render); 1741 } 1742 1743 void Document::detach() 1744 { 1745 ASSERT(attached()); 1746 ASSERT(!m_inPageCache); 1747 1748 clearAXObjectCache(); 1749 stopActiveDOMObjects(); 1750 m_eventQueue->cancelQueuedEvents(); 1751 1752 #if ENABLE(REQUEST_ANIMATION_FRAME) 1753 // FIXME: consider using ActiveDOMObject. 1754 m_scriptedAnimationController = 0; 1755 #endif 1756 1757 RenderObject* render = renderer(); 1758 1759 // Send out documentWillBecomeInactive() notifications to registered elements, 1760 // in order to stop media elements 1761 documentWillBecomeInactive(); 1762 1763 #if ENABLE(SHARED_WORKERS) 1764 SharedWorkerRepository::documentDetached(this); 1765 #endif 1766 1767 if (m_frame) { 1768 FrameView* view = m_frame->view(); 1769 if (view) 1770 view->detachCustomScrollbars(); 1771 } 1772 1773 // indicate destruction mode, i.e. attached() but renderer == 0 1774 setRenderer(0); 1775 1776 #if ENABLE(FULLSCREEN_API) 1777 if (m_fullScreenRenderer) 1778 setFullScreenRenderer(0); 1779 #endif 1780 1781 m_hoverNode = 0; 1782 m_focusedNode = 0; 1783 m_activeNode = 0; 1784 1785 TreeScope::detach(); 1786 1787 unscheduleStyleRecalc(); 1788 1789 if (render) 1790 render->destroy(); 1791 1792 // This is required, as our Frame might delete itself as soon as it detaches 1793 // us. However, this violates Node::detach() semantics, as it's never 1794 // possible to re-attach. Eventually Document::detach() should be renamed, 1795 // or this setting of the frame to 0 could be made explicit in each of the 1796 // callers of Document::detach(). 1797 m_frame = 0; 1798 m_renderArena.clear(); 1799 } 1800 1801 void Document::removeAllEventListeners() 1802 { 1803 #if ENABLE(TOUCH_EVENTS) 1804 Page* ownerPage = page(); 1805 if (!m_inPageCache && ownerPage && (m_frame == ownerPage->mainFrame()) && hasListenerType(Document::TOUCH_LISTENER)) { 1806 // Inform the Chrome Client that it no longer needs to forward touch 1807 // events to WebCore as the document removes all the event listeners. 1808 ownerPage->chrome()->client()->needTouchEvents(false); 1809 } 1810 #endif 1811 1812 EventTarget::removeAllEventListeners(); 1813 1814 if (DOMWindow* domWindow = this->domWindow()) 1815 domWindow->removeAllEventListeners(); 1816 for (Node* node = firstChild(); node; node = node->traverseNextNode()) 1817 node->removeAllEventListeners(); 1818 } 1819 1820 RenderView* Document::renderView() const 1821 { 1822 return toRenderView(renderer()); 1823 } 1824 1825 void Document::clearAXObjectCache() 1826 { 1827 #if PLATFORM(ANDROID) 1828 return; 1829 #else 1830 // clear cache in top document 1831 if (m_axObjectCache) { 1832 // Clear the cache member variable before calling delete because attempts 1833 // are made to access it during destruction. 1834 AXObjectCache* axObjectCache = m_axObjectCache; 1835 m_axObjectCache = 0; 1836 delete axObjectCache; 1837 return; 1838 } 1839 1840 // ask the top-level document to clear its cache 1841 Document* doc = topDocument(); 1842 if (doc != this) 1843 doc->clearAXObjectCache(); 1844 #endif 1845 } 1846 1847 bool Document::axObjectCacheExists() const 1848 { 1849 #if PLATFORM(ANDROID) 1850 return false; 1851 #else 1852 if (m_axObjectCache) 1853 return true; 1854 1855 Document* doc = topDocument(); 1856 if (doc != this) 1857 return doc->axObjectCacheExists(); 1858 1859 return false; 1860 #endif 1861 } 1862 1863 AXObjectCache* Document::axObjectCache() const 1864 { 1865 #if PLATFORM(ANDROID) 1866 return 0; 1867 #else 1868 // The only document that actually has a AXObjectCache is the top-level 1869 // document. This is because we need to be able to get from any WebCoreAXObject 1870 // to any other WebCoreAXObject on the same page. Using a single cache allows 1871 // lookups across nested webareas (i.e. multiple documents). 1872 1873 if (m_axObjectCache) { 1874 // return already known top-level cache 1875 if (!ownerElement()) 1876 return m_axObjectCache; 1877 1878 // In some pages with frames, the cache is created before the sub-webarea is 1879 // inserted into the tree. Here, we catch that case and just toss the old 1880 // cache and start over. 1881 // NOTE: This recovery may no longer be needed. I have been unable to trigger 1882 // it again. See rdar://5794454 1883 // FIXME: Can this be fixed when inserting the subframe instead of now? 1884 // FIXME: If this function was called to get the cache in order to remove 1885 // an AXObject, we are now deleting the cache as a whole and returning a 1886 // new empty cache that does not contain the AXObject! That should actually 1887 // be OK. I am concerned about other cases like this where accessing the 1888 // cache blows away the AXObject being operated on. 1889 delete m_axObjectCache; 1890 m_axObjectCache = 0; 1891 } 1892 1893 // ask the top-level document for its cache 1894 Document* doc = topDocument(); 1895 if (doc != this) 1896 return doc->axObjectCache(); 1897 1898 // this is the top-level document, so install a new cache 1899 m_axObjectCache = new AXObjectCache(this); 1900 return m_axObjectCache; 1901 #endif // ANDROID 1902 } 1903 1904 void Document::setVisuallyOrdered() 1905 { 1906 m_visuallyOrdered = true; 1907 if (renderer()) 1908 renderer()->style()->setVisuallyOrdered(true); 1909 } 1910 1911 PassRefPtr<DocumentParser> Document::createParser() 1912 { 1913 // FIXME: this should probably pass the frame instead 1914 return XMLDocumentParser::create(this, view()); 1915 } 1916 1917 ScriptableDocumentParser* Document::scriptableDocumentParser() const 1918 { 1919 return parser() ? parser()->asScriptableDocumentParser() : 0; 1920 } 1921 1922 void Document::open(Document* ownerDocument) 1923 { 1924 if (ownerDocument) { 1925 setURL(ownerDocument->url()); 1926 m_cookieURL = ownerDocument->cookieURL(); 1927 ScriptExecutionContext::setSecurityOrigin(ownerDocument->securityOrigin()); 1928 } 1929 1930 if (m_frame) { 1931 if (ScriptableDocumentParser* parser = scriptableDocumentParser()) { 1932 if (parser->isParsing()) { 1933 // FIXME: HTML5 doesn't tell us to check this, it might not be correct. 1934 if (parser->isExecutingScript()) 1935 return; 1936 1937 if (!parser->wasCreatedByScript() && parser->hasInsertionPoint()) 1938 return; 1939 } 1940 } 1941 1942 if (m_frame->loader()->state() == FrameStateProvisional) 1943 m_frame->loader()->stopAllLoaders(); 1944 } 1945 1946 removeAllEventListeners(); 1947 implicitOpen(); 1948 if (ScriptableDocumentParser* parser = scriptableDocumentParser()) 1949 parser->setWasCreatedByScript(true); 1950 1951 if (DOMWindow* domWindow = this->domWindow()) 1952 domWindow->removeAllEventListeners(); 1953 1954 if (m_frame) 1955 m_frame->loader()->didExplicitOpen(); 1956 } 1957 1958 void Document::detachParser() 1959 { 1960 if (!m_parser) 1961 return; 1962 m_parser->detach(); 1963 m_parser.clear(); 1964 } 1965 1966 void Document::cancelParsing() 1967 { 1968 if (!m_parser) 1969 return; 1970 1971 // We have to clear the parser to avoid possibly triggering 1972 // the onload handler when closing as a side effect of a cancel-style 1973 // change, such as opening a new document or closing the window while 1974 // still parsing 1975 detachParser(); 1976 explicitClose(); 1977 } 1978 1979 void Document::implicitOpen() 1980 { 1981 cancelParsing(); 1982 1983 removeChildren(); 1984 1985 setCompatibilityMode(NoQuirksMode); 1986 1987 m_parser = createParser(); 1988 setParsing(true); 1989 setReadyState(Loading); 1990 1991 // If we reload, the animation controller sticks around and has 1992 // a stale animation time. We need to update it here. 1993 if (m_frame && m_frame->animation()) 1994 m_frame->animation()->beginAnimationUpdate(); 1995 } 1996 1997 HTMLElement* Document::body() const 1998 { 1999 Node* de = documentElement(); 2000 if (!de) 2001 return 0; 2002 2003 // try to prefer a FRAMESET element over BODY 2004 Node* body = 0; 2005 for (Node* i = de->firstChild(); i; i = i->nextSibling()) { 2006 if (i->hasTagName(framesetTag)) 2007 return toHTMLElement(i); 2008 2009 if (i->hasTagName(bodyTag) && !body) 2010 body = i; 2011 } 2012 return toHTMLElement(body); 2013 } 2014 2015 void Document::setBody(PassRefPtr<HTMLElement> newBody, ExceptionCode& ec) 2016 { 2017 ec = 0; 2018 2019 if (!newBody || !documentElement() || !newBody->hasTagName(bodyTag)) { 2020 ec = HIERARCHY_REQUEST_ERR; 2021 return; 2022 } 2023 2024 if (newBody->document() && newBody->document() != this) { 2025 RefPtr<Node> node = importNode(newBody.get(), true, ec); 2026 if (ec) 2027 return; 2028 2029 newBody = toHTMLElement(node.get()); 2030 } 2031 2032 HTMLElement* b = body(); 2033 if (!b) 2034 documentElement()->appendChild(newBody, ec); 2035 else 2036 documentElement()->replaceChild(newBody, b, ec); 2037 } 2038 2039 HTMLHeadElement* Document::head() 2040 { 2041 Node* de = documentElement(); 2042 if (!de) 2043 return 0; 2044 2045 for (Node* e = de->firstChild(); e; e = e->nextSibling()) 2046 if (e->hasTagName(headTag)) 2047 return static_cast<HTMLHeadElement*>(e); 2048 2049 return 0; 2050 } 2051 2052 void Document::close() 2053 { 2054 // FIXME: We should follow the specification more closely: 2055 // http://www.whatwg.org/specs/web-apps/current-work/#dom-document-close 2056 2057 if (!scriptableDocumentParser() || !scriptableDocumentParser()->wasCreatedByScript()) 2058 return; 2059 2060 explicitClose(); 2061 } 2062 2063 void Document::explicitClose() 2064 { 2065 if (!m_frame) { 2066 // Because we have no frame, we don't know if all loading has completed, 2067 // so we just call implicitClose() immediately. FIXME: This might fire 2068 // the load event prematurely <http://bugs.webkit.org/show_bug.cgi?id=14568>. 2069 if (m_parser) 2070 m_parser->finish(); 2071 implicitClose(); 2072 return; 2073 } 2074 2075 // This code calls implicitClose() if all loading has completed. 2076 loader()->writer()->endIfNotLoadingMainResource(); 2077 if (m_frame) 2078 m_frame->loader()->checkCompleted(); 2079 } 2080 2081 void Document::implicitClose() 2082 { 2083 // If we're in the middle of recalcStyle, we need to defer the close until the style information is accurate and all elements are re-attached. 2084 if (m_inStyleRecalc) { 2085 m_closeAfterStyleRecalc = true; 2086 return; 2087 } 2088 2089 bool wasLocationChangePending = frame() && frame()->navigationScheduler()->locationChangePending(); 2090 bool doload = !parsing() && m_parser && !m_processingLoadEvent && !wasLocationChangePending; 2091 2092 if (!doload) 2093 return; 2094 2095 m_processingLoadEvent = true; 2096 2097 ScriptableDocumentParser* parser = scriptableDocumentParser(); 2098 m_wellFormed = parser && parser->wellFormed(); 2099 2100 // We have to clear the parser, in case someone document.write()s from the 2101 // onLoad event handler, as in Radar 3206524. 2102 detachParser(); 2103 2104 // Parser should have picked up all preloads by now 2105 m_cachedResourceLoader->clearPreloads(); 2106 2107 // FIXME: We kick off the icon loader when the Document is done parsing. 2108 // There are earlier opportunities we could start it: 2109 // -When the <head> finishes parsing 2110 // -When any new HTMLLinkElement is inserted into the document 2111 // But those add a dynamic component to the favicon that has UI 2112 // ramifications, and we need to decide what is the Right Thing To Do(tm) 2113 Frame* f = frame(); 2114 if (f) 2115 f->loader()->startIconLoader(); 2116 2117 // Resume the animations (or start them) 2118 if (f) 2119 f->animation()->resumeAnimationsForDocument(this); 2120 2121 ImageLoader::dispatchPendingBeforeLoadEvents(); 2122 ImageLoader::dispatchPendingLoadEvents(); 2123 dispatchWindowLoadEvent(); 2124 enqueuePageshowEvent(PageshowEventNotPersisted); 2125 enqueuePopstateEvent(m_pendingStateObject ? m_pendingStateObject.release() : SerializedScriptValue::nullValue()); 2126 2127 if (f) 2128 f->loader()->handledOnloadEvents(); 2129 #ifdef INSTRUMENT_LAYOUT_SCHEDULING 2130 if (!ownerElement()) 2131 printf("onload fired at %d\n", elapsedTime()); 2132 #endif 2133 2134 m_processingLoadEvent = false; 2135 2136 // An event handler may have removed the frame 2137 if (!frame()) 2138 return; 2139 2140 // Make sure both the initial layout and reflow happen after the onload 2141 // fires. This will improve onload scores, and other browsers do it. 2142 // If they wanna cheat, we can too. -dwh 2143 2144 if (frame()->navigationScheduler()->locationChangePending() && elapsedTime() < cLayoutScheduleThreshold) { 2145 // Just bail out. Before or during the onload we were shifted to another page. 2146 // The old i-Bench suite does this. When this happens don't bother painting or laying out. 2147 view()->unscheduleRelayout(); 2148 return; 2149 } 2150 2151 frame()->loader()->checkCallImplicitClose(); 2152 RenderObject* renderObject = renderer(); 2153 2154 // We used to force a synchronous display and flush here. This really isn't 2155 // necessary and can in fact be actively harmful if pages are loading at a rate of > 60fps 2156 // (if your platform is syncing flushes and limiting them to 60fps). 2157 m_overMinimumLayoutThreshold = true; 2158 if (!ownerElement() || (ownerElement()->renderer() && !ownerElement()->renderer()->needsLayout())) { 2159 updateStyleIfNeeded(); 2160 2161 // Always do a layout after loading if needed. 2162 if (view() && renderObject && (!renderObject->firstChild() || renderObject->needsLayout())) 2163 view()->layout(); 2164 } 2165 2166 #if PLATFORM(MAC) || PLATFORM(CHROMIUM) 2167 if (f && renderObject && this == topDocument() && AXObjectCache::accessibilityEnabled()) { 2168 // The AX cache may have been cleared at this point, but we need to make sure it contains an 2169 // AX object to send the notification to. getOrCreate will make sure that an valid AX object 2170 // exists in the cache (we ignore the return value because we don't need it here). This is 2171 // only safe to call when a layout is not in progress, so it can not be used in postNotification. 2172 axObjectCache()->getOrCreate(renderObject); 2173 axObjectCache()->postNotification(renderObject, AXObjectCache::AXLoadComplete, true); 2174 } 2175 #endif 2176 2177 #if ENABLE(SVG) 2178 // FIXME: Officially, time 0 is when the outermost <svg> receives its 2179 // SVGLoad event, but we don't implement those yet. This is close enough 2180 // for now. In some cases we should have fired earlier. 2181 if (svgExtensions()) 2182 accessSVGExtensions()->startAnimations(); 2183 #endif 2184 } 2185 2186 void Document::setParsing(bool b) 2187 { 2188 m_bParsing = b; 2189 if (!m_bParsing && view()) 2190 view()->scheduleRelayout(); 2191 2192 #ifdef INSTRUMENT_LAYOUT_SCHEDULING 2193 if (!ownerElement() && !m_bParsing) 2194 printf("Parsing finished at %d\n", elapsedTime()); 2195 #endif 2196 } 2197 2198 bool Document::shouldScheduleLayout() 2199 { 2200 // This function will only be called when FrameView thinks a layout is needed. 2201 // This enforces a couple extra rules. 2202 // 2203 // (a) Only schedule a layout once the stylesheets are loaded. 2204 // (b) Only schedule layout once we have a body element. 2205 2206 return (haveStylesheetsLoaded() && body()) 2207 || (documentElement() && !documentElement()->hasTagName(htmlTag)); 2208 } 2209 2210 bool Document::isLayoutTimerActive() 2211 { 2212 if (!view() || !view()->layoutPending()) 2213 return false; 2214 bool isPendingLayoutImmediate = minimumLayoutDelay() == m_extraLayoutDelay; 2215 return isPendingLayoutImmediate; 2216 } 2217 2218 int Document::minimumLayoutDelay() 2219 { 2220 if (m_overMinimumLayoutThreshold) 2221 return m_extraLayoutDelay; 2222 2223 int elapsed = elapsedTime(); 2224 m_overMinimumLayoutThreshold = elapsed > cLayoutScheduleThreshold; 2225 2226 // We'll want to schedule the timer to fire at the minimum layout threshold. 2227 return max(0, cLayoutScheduleThreshold - elapsed) + m_extraLayoutDelay; 2228 } 2229 2230 int Document::elapsedTime() const 2231 { 2232 return static_cast<int>((currentTime() - m_startTime) * 1000); 2233 } 2234 2235 void Document::write(const SegmentedString& text, Document* ownerDocument) 2236 { 2237 NestingLevelIncrementer nestingLevelIncrementer(m_writeRecursionDepth); 2238 2239 m_writeRecursionIsTooDeep = (m_writeRecursionDepth > 1) && m_writeRecursionIsTooDeep; 2240 m_writeRecursionIsTooDeep = (m_writeRecursionDepth > cMaxWriteRecursionDepth) || m_writeRecursionIsTooDeep; 2241 2242 if (m_writeRecursionIsTooDeep) 2243 return; 2244 2245 #ifdef INSTRUMENT_LAYOUT_SCHEDULING 2246 if (!ownerElement()) 2247 printf("Beginning a document.write at %d\n", elapsedTime()); 2248 #endif 2249 2250 bool hasInsertionPoint = m_parser && m_parser->hasInsertionPoint(); 2251 if (!hasInsertionPoint && m_ignoreDestructiveWriteCount) 2252 return; 2253 2254 if (!hasInsertionPoint) 2255 open(ownerDocument); 2256 2257 ASSERT(m_parser); 2258 m_parser->insert(text); 2259 2260 #ifdef INSTRUMENT_LAYOUT_SCHEDULING 2261 if (!ownerElement()) 2262 printf("Ending a document.write at %d\n", elapsedTime()); 2263 #endif 2264 } 2265 2266 void Document::write(const String& text, Document* ownerDocument) 2267 { 2268 write(SegmentedString(text), ownerDocument); 2269 } 2270 2271 void Document::writeln(const String& text, Document* ownerDocument) 2272 { 2273 write(text, ownerDocument); 2274 write("\n", ownerDocument); 2275 } 2276 2277 void Document::finishParsing() 2278 { 2279 #ifdef INSTRUMENT_LAYOUT_SCHEDULING 2280 if (!ownerElement()) 2281 printf("Received all data at %d\n", elapsedTime()); 2282 #endif 2283 2284 // Let the parser go through as much data as it can. There will be three possible outcomes after 2285 // finish() is called: 2286 // (1) All remaining data is parsed, document isn't loaded yet 2287 // (2) All remaining data is parsed, document is loaded, parser gets deleted 2288 // (3) Data is still remaining to be parsed. 2289 if (m_parser) 2290 m_parser->finish(); 2291 } 2292 2293 const KURL& Document::virtualURL() const 2294 { 2295 return m_url; 2296 } 2297 2298 KURL Document::virtualCompleteURL(const String& url) const 2299 { 2300 return completeURL(url); 2301 } 2302 2303 double Document::minimumTimerInterval() const 2304 { 2305 Page* p = page(); 2306 if (!p) 2307 return ScriptExecutionContext::minimumTimerInterval(); 2308 return p->settings()->minDOMTimerInterval(); 2309 } 2310 2311 EventTarget* Document::errorEventTarget() 2312 { 2313 return domWindow(); 2314 } 2315 2316 void Document::logExceptionToConsole(const String& errorMessage, int lineNumber, const String& sourceURL, PassRefPtr<ScriptCallStack> callStack) 2317 { 2318 MessageType messageType = callStack ? UncaughtExceptionMessageType : LogMessageType; 2319 addMessage(JSMessageSource, messageType, ErrorMessageLevel, errorMessage, lineNumber, sourceURL, callStack); 2320 } 2321 2322 void Document::setURL(const KURL& url) 2323 { 2324 const KURL& newURL = url.isEmpty() ? blankURL() : url; 2325 if (newURL == m_url) 2326 return; 2327 2328 m_url = newURL; 2329 m_documentURI = m_url.string(); 2330 updateBaseURL(); 2331 } 2332 2333 void Document::updateBaseURL() 2334 { 2335 // DOM 3 Core: When the Document supports the feature "HTML" [DOM Level 2 HTML], the base URI is computed using 2336 // first the value of the href attribute of the HTML BASE element if any, and the value of the documentURI attribute 2337 // from the Document interface otherwise. 2338 if (m_baseElementURL.isEmpty()) { 2339 // The documentURI attribute is an arbitrary string. DOM 3 Core does not specify how it should be resolved, 2340 // so we use a null base URL. 2341 m_baseURL = KURL(KURL(), documentURI()); 2342 } else 2343 m_baseURL = m_baseElementURL; 2344 if (!m_baseURL.isValid()) 2345 m_baseURL = KURL(); 2346 2347 if (m_elemSheet) 2348 m_elemSheet->setFinalURL(m_baseURL); 2349 if (m_mappedElementSheet) 2350 m_mappedElementSheet->setFinalURL(m_baseURL); 2351 } 2352 2353 void Document::processBaseElement() 2354 { 2355 // Find the first href attribute in a base element and the first target attribute in a base element. 2356 const AtomicString* href = 0; 2357 const AtomicString* target = 0; 2358 for (Node* node = document()->firstChild(); node && (!href || !target); node = node->traverseNextNode()) { 2359 if (node->hasTagName(baseTag)) { 2360 if (!href) { 2361 const AtomicString& value = static_cast<Element*>(node)->fastGetAttribute(hrefAttr); 2362 if (!value.isNull()) 2363 href = &value; 2364 } 2365 if (!target) { 2366 const AtomicString& value = static_cast<Element*>(node)->fastGetAttribute(targetAttr); 2367 if (!value.isNull()) 2368 target = &value; 2369 } 2370 } 2371 } 2372 2373 // FIXME: Since this doesn't share code with completeURL it may not handle encodings correctly. 2374 KURL baseElementURL; 2375 if (href) { 2376 String strippedHref = stripLeadingAndTrailingHTMLSpaces(*href); 2377 if (!strippedHref.isEmpty()) 2378 baseElementURL = KURL(url(), strippedHref); 2379 } 2380 if (m_baseElementURL != baseElementURL) { 2381 m_baseElementURL = baseElementURL; 2382 updateBaseURL(); 2383 } 2384 2385 m_baseTarget = target ? *target : nullAtom; 2386 } 2387 2388 String Document::userAgent(const KURL& url) const 2389 { 2390 return frame() ? frame()->loader()->userAgent(url) : String(); 2391 } 2392 2393 CSSStyleSheet* Document::pageUserSheet() 2394 { 2395 if (m_pageUserSheet) 2396 return m_pageUserSheet.get(); 2397 2398 Page* owningPage = page(); 2399 if (!owningPage) 2400 return 0; 2401 2402 String userSheetText = owningPage->userStyleSheet(); 2403 if (userSheetText.isEmpty()) 2404 return 0; 2405 2406 // Parse the sheet and cache it. 2407 m_pageUserSheet = CSSStyleSheet::createInline(this, settings()->userStyleSheetLocation()); 2408 m_pageUserSheet->setIsUserStyleSheet(true); 2409 m_pageUserSheet->parseString(userSheetText, !inQuirksMode()); 2410 return m_pageUserSheet.get(); 2411 } 2412 2413 void Document::clearPageUserSheet() 2414 { 2415 if (m_pageUserSheet) { 2416 m_pageUserSheet = 0; 2417 styleSelectorChanged(DeferRecalcStyle); 2418 } 2419 } 2420 2421 void Document::updatePageUserSheet() 2422 { 2423 clearPageUserSheet(); 2424 if (pageUserSheet()) 2425 styleSelectorChanged(RecalcStyleImmediately); 2426 } 2427 2428 const Vector<RefPtr<CSSStyleSheet> >* Document::pageGroupUserSheets() const 2429 { 2430 if (m_pageGroupUserSheetCacheValid) 2431 return m_pageGroupUserSheets.get(); 2432 2433 m_pageGroupUserSheetCacheValid = true; 2434 2435 Page* owningPage = page(); 2436 if (!owningPage) 2437 return 0; 2438 2439 const PageGroup& pageGroup = owningPage->group(); 2440 const UserStyleSheetMap* sheetsMap = pageGroup.userStyleSheets(); 2441 if (!sheetsMap) 2442 return 0; 2443 2444 UserStyleSheetMap::const_iterator end = sheetsMap->end(); 2445 for (UserStyleSheetMap::const_iterator it = sheetsMap->begin(); it != end; ++it) { 2446 const UserStyleSheetVector* sheets = it->second; 2447 for (unsigned i = 0; i < sheets->size(); ++i) { 2448 const UserStyleSheet* sheet = sheets->at(i).get(); 2449 if (sheet->injectedFrames() == InjectInTopFrameOnly && ownerElement()) 2450 continue; 2451 if (!UserContentURLPattern::matchesPatterns(url(), sheet->whitelist(), sheet->blacklist())) 2452 continue; 2453 RefPtr<CSSStyleSheet> parsedSheet = CSSStyleSheet::createInline(const_cast<Document*>(this), sheet->url()); 2454 parsedSheet->setIsUserStyleSheet(sheet->level() == UserStyleUserLevel); 2455 parsedSheet->parseString(sheet->source(), !inQuirksMode()); 2456 if (!m_pageGroupUserSheets) 2457 m_pageGroupUserSheets.set(new Vector<RefPtr<CSSStyleSheet> >); 2458 m_pageGroupUserSheets->append(parsedSheet.release()); 2459 } 2460 } 2461 2462 return m_pageGroupUserSheets.get(); 2463 } 2464 2465 void Document::clearPageGroupUserSheets() 2466 { 2467 m_pageGroupUserSheetCacheValid = false; 2468 if (m_pageGroupUserSheets && m_pageGroupUserSheets->size()) { 2469 m_pageGroupUserSheets->clear(); 2470 styleSelectorChanged(DeferRecalcStyle); 2471 } 2472 } 2473 2474 void Document::updatePageGroupUserSheets() 2475 { 2476 clearPageGroupUserSheets(); 2477 if (pageGroupUserSheets() && pageGroupUserSheets()->size()) 2478 styleSelectorChanged(RecalcStyleImmediately); 2479 } 2480 2481 CSSStyleSheet* Document::elementSheet() 2482 { 2483 if (!m_elemSheet) 2484 m_elemSheet = CSSStyleSheet::createInline(this, m_baseURL); 2485 return m_elemSheet.get(); 2486 } 2487 2488 CSSStyleSheet* Document::mappedElementSheet() 2489 { 2490 if (!m_mappedElementSheet) 2491 m_mappedElementSheet = CSSStyleSheet::createInline(this, m_baseURL); 2492 return m_mappedElementSheet.get(); 2493 } 2494 2495 static Node* nextNodeWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent* event) 2496 { 2497 // Search is inclusive of start 2498 for (Node* n = start; n; n = n->traverseNextNode()) 2499 if (n->isKeyboardFocusable(event) && n->tabIndex() == tabIndex) 2500 return n; 2501 2502 return 0; 2503 } 2504 2505 static Node* previousNodeWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent* event) 2506 { 2507 // Search is inclusive of start 2508 for (Node* n = start; n; n = n->traversePreviousNode()) 2509 if (n->isKeyboardFocusable(event) && n->tabIndex() == tabIndex) 2510 return n; 2511 2512 return 0; 2513 } 2514 2515 static Node* nextNodeWithGreaterTabIndex(Node* start, int tabIndex, KeyboardEvent* event) 2516 { 2517 // Search is inclusive of start 2518 int winningTabIndex = SHRT_MAX + 1; 2519 Node* winner = 0; 2520 for (Node* n = start; n; n = n->traverseNextNode()) 2521 if (n->isKeyboardFocusable(event) && n->tabIndex() > tabIndex && n->tabIndex() < winningTabIndex) { 2522 winner = n; 2523 winningTabIndex = n->tabIndex(); 2524 } 2525 2526 return winner; 2527 } 2528 2529 static Node* previousNodeWithLowerTabIndex(Node* start, int tabIndex, KeyboardEvent* event) 2530 { 2531 // Search is inclusive of start 2532 int winningTabIndex = 0; 2533 Node* winner = 0; 2534 for (Node* n = start; n; n = n->traversePreviousNode()) 2535 if (n->isKeyboardFocusable(event) && n->tabIndex() < tabIndex && n->tabIndex() > winningTabIndex) { 2536 winner = n; 2537 winningTabIndex = n->tabIndex(); 2538 } 2539 2540 return winner; 2541 } 2542 2543 Node* Document::nextFocusableNode(Node* start, KeyboardEvent* event) 2544 { 2545 if (start) { 2546 // If a node is excluded from the normal tabbing cycle, the next focusable node is determined by tree order 2547 if (start->tabIndex() < 0) { 2548 for (Node* n = start->traverseNextNode(); n; n = n->traverseNextNode()) 2549 if (n->isKeyboardFocusable(event) && n->tabIndex() >= 0) 2550 return n; 2551 } 2552 2553 // First try to find a node with the same tabindex as start that comes after start in the document. 2554 if (Node* winner = nextNodeWithExactTabIndex(start->traverseNextNode(), start->tabIndex(), event)) 2555 return winner; 2556 2557 if (!start->tabIndex()) 2558 // We've reached the last node in the document with a tabindex of 0. This is the end of the tabbing order. 2559 return 0; 2560 } 2561 2562 // Look for the first node in the document that: 2563 // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if start is null), and 2564 // 2) comes first in the document, if there's a tie. 2565 if (Node* winner = nextNodeWithGreaterTabIndex(this, start ? start->tabIndex() : 0, event)) 2566 return winner; 2567 2568 // There are no nodes with a tabindex greater than start's tabindex, 2569 // so find the first node with a tabindex of 0. 2570 return nextNodeWithExactTabIndex(this, 0, event); 2571 } 2572 2573 Node* Document::previousFocusableNode(Node* start, KeyboardEvent* event) 2574 { 2575 Node* last; 2576 for (last = this; last->lastChild(); last = last->lastChild()) { } 2577 2578 // First try to find the last node in the document that comes before start and has the same tabindex as start. 2579 // If start is null, find the last node in the document with a tabindex of 0. 2580 Node* startingNode; 2581 int startingTabIndex; 2582 if (start) { 2583 startingNode = start->traversePreviousNode(); 2584 startingTabIndex = start->tabIndex(); 2585 } else { 2586 startingNode = last; 2587 startingTabIndex = 0; 2588 } 2589 2590 // However, if a node is excluded from the normal tabbing cycle, the previous focusable node is determined by tree order 2591 if (startingTabIndex < 0) { 2592 for (Node* n = startingNode; n; n = n->traversePreviousNode()) 2593 if (n->isKeyboardFocusable(event) && n->tabIndex() >= 0) 2594 return n; 2595 } 2596 2597 if (Node* winner = previousNodeWithExactTabIndex(startingNode, startingTabIndex, event)) 2598 return winner; 2599 2600 // There are no nodes before start with the same tabindex as start, so look for a node that: 2601 // 1) has the highest non-zero tabindex (that is less than start's tabindex), and 2602 // 2) comes last in the document, if there's a tie. 2603 startingTabIndex = (start && start->tabIndex()) ? start->tabIndex() : SHRT_MAX; 2604 return previousNodeWithLowerTabIndex(last, startingTabIndex, event); 2605 } 2606 2607 int Document::nodeAbsIndex(Node *node) 2608 { 2609 ASSERT(node->document() == this); 2610 2611 int absIndex = 0; 2612 for (Node* n = node; n && n != this; n = n->traversePreviousNode()) 2613 absIndex++; 2614 return absIndex; 2615 } 2616 2617 Node* Document::nodeWithAbsIndex(int absIndex) 2618 { 2619 Node* n = this; 2620 for (int i = 0; n && (i < absIndex); i++) 2621 n = n->traverseNextNode(); 2622 return n; 2623 } 2624 2625 #ifdef ANDROID_META_SUPPORT 2626 void Document::processMetadataSettings(const String& content) 2627 { 2628 ASSERT(!content.isNull()); 2629 processArguments(content, 0, 0); 2630 } 2631 #endif 2632 2633 void Document::processHttpEquiv(const String& equiv, const String& content) 2634 { 2635 ASSERT(!equiv.isNull() && !content.isNull()); 2636 2637 Frame* frame = this->frame(); 2638 2639 if (equalIgnoringCase(equiv, "default-style")) { 2640 // The preferred style set has been overridden as per section 2641 // 14.3.2 of the HTML4.0 specification. We need to update the 2642 // sheet used variable and then update our style selector. 2643 // For more info, see the test at: 2644 // http://www.hixie.ch/tests/evil/css/import/main/preferred.html 2645 // -dwh 2646 m_selectedStylesheetSet = content; 2647 m_preferredStylesheetSet = content; 2648 styleSelectorChanged(DeferRecalcStyle); 2649 } else if (equalIgnoringCase(equiv, "refresh")) { 2650 double delay; 2651 String url; 2652 if (frame && parseHTTPRefresh(content, true, delay, url)) { 2653 if (url.isEmpty()) 2654 url = m_url.string(); 2655 else 2656 url = completeURL(url).string(); 2657 frame->navigationScheduler()->scheduleRedirect(delay, url); 2658 } 2659 } else if (equalIgnoringCase(equiv, "set-cookie")) { 2660 // FIXME: make setCookie work on XML documents too; e.g. in case of <html:meta .....> 2661 if (isHTMLDocument()) { 2662 ExceptionCode ec; // Exception (for sandboxed documents) ignored. 2663 static_cast<HTMLDocument*>(this)->setCookie(content, ec); 2664 } 2665 } else if (equalIgnoringCase(equiv, "content-language")) 2666 setContentLanguage(content); 2667 else if (equalIgnoringCase(equiv, "x-dns-prefetch-control")) 2668 parseDNSPrefetchControlHeader(content); 2669 else if (equalIgnoringCase(equiv, "x-frame-options")) { 2670 if (frame) { 2671 FrameLoader* frameLoader = frame->loader(); 2672 if (frameLoader->shouldInterruptLoadForXFrameOptions(content, url())) { 2673 frameLoader->stopAllLoaders(); 2674 frame->navigationScheduler()->scheduleLocationChange(securityOrigin(), blankURL(), String()); 2675 2676 DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to display document because display forbidden by X-Frame-Options.\n")); 2677 frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); 2678 } 2679 } 2680 } else if (equalIgnoringCase(equiv, "x-webkit-csp")) 2681 contentSecurityPolicy()->didReceiveHeader(content); 2682 } 2683 2684 // Though isspace() considers \t and \v to be whitespace, Win IE doesn't. 2685 static bool isSeparator(UChar c) 2686 { 2687 return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '=' || c == ',' || c == '\0'; 2688 } 2689 2690 void Document::processArguments(const String& features, void* data, ArgumentsCallback callback) 2691 { 2692 // Tread lightly in this code -- it was specifically designed to mimic Win IE's parsing behavior. 2693 int keyBegin, keyEnd; 2694 int valueBegin, valueEnd; 2695 2696 int i = 0; 2697 int length = features.length(); 2698 String buffer = features.lower(); 2699 while (i < length) { 2700 // skip to first non-separator, but don't skip past the end of the string 2701 while (isSeparator(buffer[i])) { 2702 if (i >= length) 2703 break; 2704 i++; 2705 } 2706 keyBegin = i; 2707 2708 // skip to first separator 2709 while (!isSeparator(buffer[i])) 2710 i++; 2711 keyEnd = i; 2712 2713 // skip to first '=', but don't skip past a ',' or the end of the string 2714 while (buffer[i] != '=') { 2715 if (buffer[i] == ',' || i >= length) 2716 break; 2717 i++; 2718 } 2719 2720 // skip to first non-separator, but don't skip past a ',' or the end of the string 2721 while (isSeparator(buffer[i])) { 2722 if (buffer[i] == ',' || i >= length) 2723 break; 2724 i++; 2725 } 2726 valueBegin = i; 2727 2728 // skip to first separator 2729 while (!isSeparator(buffer[i])) 2730 i++; 2731 valueEnd = i; 2732 2733 ASSERT(i <= length); 2734 2735 String keyString = buffer.substring(keyBegin, keyEnd - keyBegin); 2736 String valueString = buffer.substring(valueBegin, valueEnd - valueBegin); 2737 #ifdef ANDROID_META_SUPPORT 2738 if (frame()) 2739 frame()->settings()->setMetadataSettings(keyString, valueString); 2740 if (callback && data) 2741 #endif 2742 callback(keyString, valueString, this, data); 2743 } 2744 } 2745 2746 void Document::processViewport(const String& features) 2747 { 2748 ASSERT(!features.isNull()); 2749 2750 m_viewportArguments = ViewportArguments(); 2751 processArguments(features, (void*)&m_viewportArguments, &setViewportFeature); 2752 2753 Frame* frame = this->frame(); 2754 if (!frame || !frame->page()) 2755 return; 2756 2757 frame->page()->updateViewportArguments(); 2758 } 2759 2760 MouseEventWithHitTestResults Document::prepareMouseEvent(const HitTestRequest& request, const IntPoint& documentPoint, const PlatformMouseEvent& event) 2761 { 2762 ASSERT(!renderer() || renderer()->isRenderView()); 2763 2764 if (!renderer()) 2765 return MouseEventWithHitTestResults(event, HitTestResult(IntPoint())); 2766 2767 HitTestResult result(documentPoint); 2768 renderView()->layer()->hitTest(request, result); 2769 2770 if (!request.readOnly()) 2771 updateStyleIfNeeded(); 2772 2773 return MouseEventWithHitTestResults(event, result); 2774 } 2775 2776 // DOM Section 1.1.1 2777 bool Document::childTypeAllowed(NodeType type) const 2778 { 2779 switch (type) { 2780 case ATTRIBUTE_NODE: 2781 case CDATA_SECTION_NODE: 2782 case DOCUMENT_FRAGMENT_NODE: 2783 case DOCUMENT_NODE: 2784 case ENTITY_NODE: 2785 case ENTITY_REFERENCE_NODE: 2786 case NOTATION_NODE: 2787 case TEXT_NODE: 2788 case XPATH_NAMESPACE_NODE: 2789 return false; 2790 case COMMENT_NODE: 2791 case PROCESSING_INSTRUCTION_NODE: 2792 return true; 2793 case DOCUMENT_TYPE_NODE: 2794 case ELEMENT_NODE: 2795 // Documents may contain no more than one of each of these. 2796 // (One Element and one DocumentType.) 2797 for (Node* c = firstChild(); c; c = c->nextSibling()) 2798 if (c->nodeType() == type) 2799 return false; 2800 return true; 2801 } 2802 return false; 2803 } 2804 2805 bool Document::canReplaceChild(Node* newChild, Node* oldChild) 2806 { 2807 if (!oldChild) 2808 // ContainerNode::replaceChild will raise a NOT_FOUND_ERR. 2809 return true; 2810 2811 if (oldChild->nodeType() == newChild->nodeType()) 2812 return true; 2813 2814 int numDoctypes = 0; 2815 int numElements = 0; 2816 2817 // First, check how many doctypes and elements we have, not counting 2818 // the child we're about to remove. 2819 for (Node* c = firstChild(); c; c = c->nextSibling()) { 2820 if (c == oldChild) 2821 continue; 2822 2823 switch (c->nodeType()) { 2824 case DOCUMENT_TYPE_NODE: 2825 numDoctypes++; 2826 break; 2827 case ELEMENT_NODE: 2828 numElements++; 2829 break; 2830 default: 2831 break; 2832 } 2833 } 2834 2835 // Then, see how many doctypes and elements might be added by the new child. 2836 if (newChild->nodeType() == DOCUMENT_FRAGMENT_NODE) { 2837 for (Node* c = firstChild(); c; c = c->nextSibling()) { 2838 switch (c->nodeType()) { 2839 case ATTRIBUTE_NODE: 2840 case CDATA_SECTION_NODE: 2841 case DOCUMENT_FRAGMENT_NODE: 2842 case DOCUMENT_NODE: 2843 case ENTITY_NODE: 2844 case ENTITY_REFERENCE_NODE: 2845 case NOTATION_NODE: 2846 case TEXT_NODE: 2847 case XPATH_NAMESPACE_NODE: 2848 return false; 2849 case COMMENT_NODE: 2850 case PROCESSING_INSTRUCTION_NODE: 2851 break; 2852 case DOCUMENT_TYPE_NODE: 2853 numDoctypes++; 2854 break; 2855 case ELEMENT_NODE: 2856 numElements++; 2857 break; 2858 } 2859 } 2860 } else { 2861 switch (newChild->nodeType()) { 2862 case ATTRIBUTE_NODE: 2863 case CDATA_SECTION_NODE: 2864 case DOCUMENT_FRAGMENT_NODE: 2865 case DOCUMENT_NODE: 2866 case ENTITY_NODE: 2867 case ENTITY_REFERENCE_NODE: 2868 case NOTATION_NODE: 2869 case TEXT_NODE: 2870 case XPATH_NAMESPACE_NODE: 2871 return false; 2872 case COMMENT_NODE: 2873 case PROCESSING_INSTRUCTION_NODE: 2874 return true; 2875 case DOCUMENT_TYPE_NODE: 2876 numDoctypes++; 2877 break; 2878 case ELEMENT_NODE: 2879 numElements++; 2880 break; 2881 } 2882 } 2883 2884 if (numElements > 1 || numDoctypes > 1) 2885 return false; 2886 2887 return true; 2888 } 2889 2890 PassRefPtr<Node> Document::cloneNode(bool /*deep*/) 2891 { 2892 // Spec says cloning Document nodes is "implementation dependent" 2893 // so we do not support it... 2894 return 0; 2895 } 2896 2897 StyleSheetList* Document::styleSheets() 2898 { 2899 return m_styleSheets.get(); 2900 } 2901 2902 String Document::preferredStylesheetSet() const 2903 { 2904 return m_preferredStylesheetSet; 2905 } 2906 2907 String Document::selectedStylesheetSet() const 2908 { 2909 return m_selectedStylesheetSet; 2910 } 2911 2912 void Document::setSelectedStylesheetSet(const String& aString) 2913 { 2914 m_selectedStylesheetSet = aString; 2915 styleSelectorChanged(DeferRecalcStyle); 2916 } 2917 2918 // This method is called whenever a top-level stylesheet has finished loading. 2919 void Document::removePendingSheet() 2920 { 2921 // Make sure we knew this sheet was pending, and that our count isn't out of sync. 2922 ASSERT(m_pendingStylesheets > 0); 2923 2924 m_pendingStylesheets--; 2925 2926 #ifdef INSTRUMENT_LAYOUT_SCHEDULING 2927 if (!ownerElement()) 2928 printf("Stylesheet loaded at time %d. %d stylesheets still remain.\n", elapsedTime(), m_pendingStylesheets); 2929 #endif 2930 2931 if (m_pendingStylesheets) 2932 return; 2933 2934 styleSelectorChanged(RecalcStyleImmediately); 2935 2936 if (ScriptableDocumentParser* parser = scriptableDocumentParser()) 2937 parser->executeScriptsWaitingForStylesheets(); 2938 2939 if (m_gotoAnchorNeededAfterStylesheetsLoad && view()) 2940 view()->scrollToFragment(m_url); 2941 } 2942 2943 void Document::styleSelectorChanged(StyleSelectorUpdateFlag updateFlag) 2944 { 2945 // Don't bother updating, since we haven't loaded all our style info yet 2946 // and haven't calculated the style selector for the first time. 2947 if (!attached() || (!m_didCalculateStyleSelector && !haveStylesheetsLoaded())) 2948 return; 2949 2950 #ifdef INSTRUMENT_LAYOUT_SCHEDULING 2951 if (!ownerElement()) 2952 printf("Beginning update of style selector at time %d.\n", elapsedTime()); 2953 #endif 2954 2955 recalcStyleSelector(); 2956 2957 if (updateFlag == DeferRecalcStyle) { 2958 scheduleForcedStyleRecalc(); 2959 return; 2960 } 2961 2962 if (didLayoutWithPendingStylesheets() && m_pendingStylesheets <= 0) { 2963 m_pendingSheetLayout = IgnoreLayoutWithPendingSheets; 2964 if (renderer()) 2965 renderer()->repaint(); 2966 } 2967 2968 // This recalcStyle initiates a new recalc cycle. We need to bracket it to 2969 // make sure animations get the correct update time 2970 if (m_frame) 2971 m_frame->animation()->beginAnimationUpdate(); 2972 recalcStyle(Force); 2973 if (m_frame) 2974 m_frame->animation()->endAnimationUpdate(); 2975 2976 #ifdef INSTRUMENT_LAYOUT_SCHEDULING 2977 if (!ownerElement()) 2978 printf("Finished update of style selector at time %d\n", elapsedTime()); 2979 #endif 2980 2981 if (renderer()) { 2982 renderer()->setNeedsLayoutAndPrefWidthsRecalc(); 2983 if (view()) 2984 view()->scheduleRelayout(); 2985 } 2986 2987 if (m_mediaQueryMatcher) 2988 m_mediaQueryMatcher->styleSelectorChanged(); 2989 } 2990 2991 void Document::addStyleSheetCandidateNode(Node* node, bool createdByParser) 2992 { 2993 if (!node->inDocument()) 2994 return; 2995 2996 // Until the <body> exists, we have no choice but to compare document positions, 2997 // since styles outside of the body and head continue to be shunted into the head 2998 // (and thus can shift to end up before dynamically added DOM content that is also 2999 // outside the body). 3000 if ((createdByParser && body()) || m_styleSheetCandidateNodes.isEmpty()) { 3001 m_styleSheetCandidateNodes.add(node); 3002 return; 3003 } 3004 3005 // Determine an appropriate insertion point. 3006 StyleSheetCandidateListHashSet::iterator begin = m_styleSheetCandidateNodes.begin(); 3007 StyleSheetCandidateListHashSet::iterator end = m_styleSheetCandidateNodes.end(); 3008 StyleSheetCandidateListHashSet::iterator it = end; 3009 Node* followingNode = 0; 3010 do { 3011 --it; 3012 Node* n = *it; 3013 unsigned short position = n->compareDocumentPosition(node); 3014 if (position == DOCUMENT_POSITION_FOLLOWING) { 3015 m_styleSheetCandidateNodes.insertBefore(followingNode, node); 3016 return; 3017 } 3018 followingNode = n; 3019 } while (it != begin); 3020 3021 m_styleSheetCandidateNodes.insertBefore(followingNode, node); 3022 } 3023 3024 void Document::removeStyleSheetCandidateNode(Node* node) 3025 { 3026 m_styleSheetCandidateNodes.remove(node); 3027 } 3028 3029 void Document::recalcStyleSelector() 3030 { 3031 if (m_inStyleRecalc) { 3032 // SVG <use> element may manage to invalidate style selector in the middle of a style recalc. 3033 // https://bugs.webkit.org/show_bug.cgi?id=54344 3034 // FIXME: This should be fixed in SVG and this code replaced with ASSERT(!m_inStyleRecalc). 3035 m_hasDirtyStyleSelector = true; 3036 scheduleForcedStyleRecalc(); 3037 return; 3038 } 3039 if (!renderer() || !attached()) 3040 return; 3041 3042 StyleSheetVector sheets; 3043 3044 bool matchAuthorAndUserStyles = true; 3045 if (Settings* settings = this->settings()) 3046 matchAuthorAndUserStyles = settings->authorAndUserStylesEnabled(); 3047 3048 StyleSheetCandidateListHashSet::iterator begin = m_styleSheetCandidateNodes.begin(); 3049 StyleSheetCandidateListHashSet::iterator end = m_styleSheetCandidateNodes.end(); 3050 if (!matchAuthorAndUserStyles) 3051 end = begin; 3052 for (StyleSheetCandidateListHashSet::iterator it = begin; it != end; ++it) { 3053 Node* n = *it; 3054 3055 StyleSheet* sheet = 0; 3056 3057 if (n->nodeType() == PROCESSING_INSTRUCTION_NODE) { 3058 // Processing instruction (XML documents only). 3059 // We don't support linking to embedded CSS stylesheets, see <https://bugs.webkit.org/show_bug.cgi?id=49281> for discussion. 3060 ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(n); 3061 sheet = pi->sheet(); 3062 #if ENABLE(XSLT) 3063 // Don't apply XSL transforms to already transformed documents -- <rdar://problem/4132806> 3064 if (pi->isXSL() && !transformSourceDocument()) { 3065 // Don't apply XSL transforms until loading is finished. 3066 if (!parsing()) 3067 applyXSLTransform(pi); 3068 return; 3069 } 3070 #endif 3071 } else if ((n->isHTMLElement() && (n->hasTagName(linkTag) || n->hasTagName(styleTag))) 3072 #if ENABLE(SVG) 3073 || (n->isSVGElement() && n->hasTagName(SVGNames::styleTag)) 3074 #endif 3075 ) { 3076 Element* e = static_cast<Element*>(n); 3077 AtomicString title = e->getAttribute(titleAttr); 3078 bool enabledViaScript = false; 3079 if (e->hasLocalName(linkTag)) { 3080 // <LINK> element 3081 HTMLLinkElement* linkElement = static_cast<HTMLLinkElement*>(n); 3082 if (linkElement->isDisabled()) 3083 continue; 3084 enabledViaScript = linkElement->isEnabledViaScript(); 3085 if (linkElement->isLoading()) { 3086 // it is loading but we should still decide which style sheet set to use 3087 if (!enabledViaScript && !title.isEmpty() && m_preferredStylesheetSet.isEmpty()) { 3088 const AtomicString& rel = e->getAttribute(relAttr); 3089 if (!rel.contains("alternate")) { 3090 m_preferredStylesheetSet = title; 3091 m_selectedStylesheetSet = title; 3092 } 3093 } 3094 continue; 3095 } 3096 if (!linkElement->sheet()) 3097 title = nullAtom; 3098 } 3099 3100 // Get the current preferred styleset. This is the 3101 // set of sheets that will be enabled. 3102 #if ENABLE(SVG) 3103 if (n->isSVGElement() && n->hasTagName(SVGNames::styleTag)) 3104 sheet = static_cast<SVGStyleElement*>(n)->sheet(); 3105 else 3106 #endif 3107 if (e->hasLocalName(linkTag)) 3108 sheet = static_cast<HTMLLinkElement*>(n)->sheet(); 3109 else 3110 // <STYLE> element 3111 sheet = static_cast<HTMLStyleElement*>(n)->sheet(); 3112 3113 // Check to see if this sheet belongs to a styleset 3114 // (thus making it PREFERRED or ALTERNATE rather than 3115 // PERSISTENT). 3116 if (!enabledViaScript && !title.isEmpty()) { 3117 // Yes, we have a title. 3118 if (m_preferredStylesheetSet.isEmpty()) { 3119 // No preferred set has been established. If 3120 // we are NOT an alternate sheet, then establish 3121 // us as the preferred set. Otherwise, just ignore 3122 // this sheet. 3123 AtomicString rel = e->getAttribute(relAttr); 3124 if (e->hasLocalName(styleTag) || !rel.contains("alternate")) 3125 m_preferredStylesheetSet = m_selectedStylesheetSet = title; 3126 } 3127 3128 if (title != m_preferredStylesheetSet) 3129 sheet = 0; 3130 } 3131 } 3132 3133 if (sheet) 3134 sheets.append(sheet); 3135 } 3136 3137 m_styleSheets->swap(sheets); 3138 3139 m_styleSelector.clear(); 3140 m_didCalculateStyleSelector = true; 3141 m_hasDirtyStyleSelector = false; 3142 } 3143 3144 void Document::setHoverNode(PassRefPtr<Node> newHoverNode) 3145 { 3146 m_hoverNode = newHoverNode; 3147 } 3148 3149 void Document::setActiveNode(PassRefPtr<Node> newActiveNode) 3150 { 3151 m_activeNode = newActiveNode; 3152 } 3153 3154 void Document::focusedNodeRemoved() 3155 { 3156 setFocusedNode(0); 3157 } 3158 3159 void Document::removeFocusedNodeOfSubtree(Node* node, bool amongChildrenOnly) 3160 { 3161 if (!m_focusedNode || this->inPageCache()) // If the document is in the page cache, then we don't need to clear out the focused node. 3162 return; 3163 3164 bool nodeInSubtree = false; 3165 if (amongChildrenOnly) 3166 nodeInSubtree = m_focusedNode->isDescendantOf(node); 3167 else 3168 nodeInSubtree = (m_focusedNode == node) || m_focusedNode->isDescendantOf(node); 3169 3170 if (nodeInSubtree) 3171 document()->focusedNodeRemoved(); 3172 } 3173 3174 void Document::hoveredNodeDetached(Node* node) 3175 { 3176 if (!m_hoverNode || (node != m_hoverNode && (!m_hoverNode->isTextNode() || node != m_hoverNode->parentNode()))) 3177 return; 3178 3179 m_hoverNode = node->parentNode(); 3180 while (m_hoverNode && !m_hoverNode->renderer()) 3181 m_hoverNode = m_hoverNode->parentNode(); 3182 if (frame()) 3183 frame()->eventHandler()->scheduleHoverStateUpdate(); 3184 } 3185 3186 void Document::activeChainNodeDetached(Node* node) 3187 { 3188 if (!m_activeNode || (node != m_activeNode && (!m_activeNode->isTextNode() || node != m_activeNode->parentNode()))) 3189 return; 3190 3191 m_activeNode = node->parentNode(); 3192 while (m_activeNode && !m_activeNode->renderer()) 3193 m_activeNode = m_activeNode->parentNode(); 3194 } 3195 3196 #if ENABLE(DASHBOARD_SUPPORT) 3197 const Vector<DashboardRegionValue>& Document::dashboardRegions() const 3198 { 3199 return m_dashboardRegions; 3200 } 3201 3202 void Document::setDashboardRegions(const Vector<DashboardRegionValue>& regions) 3203 { 3204 m_dashboardRegions = regions; 3205 setDashboardRegionsDirty(false); 3206 } 3207 #endif 3208 3209 bool Document::setFocusedNode(PassRefPtr<Node> newFocusedNode) 3210 { 3211 // Make sure newFocusedNode is actually in this document 3212 if (newFocusedNode && (newFocusedNode->document() != this)) 3213 return true; 3214 3215 if (m_focusedNode == newFocusedNode) 3216 return true; 3217 3218 if (m_inPageCache) 3219 return false; 3220 3221 bool focusChangeBlocked = false; 3222 RefPtr<Node> oldFocusedNode = m_focusedNode; 3223 m_focusedNode = 0; 3224 3225 // Remove focus from the existing focus node (if any) 3226 if (oldFocusedNode && !oldFocusedNode->inDetach()) { 3227 if (oldFocusedNode->active()) 3228 oldFocusedNode->setActive(false); 3229 3230 oldFocusedNode->setFocus(false); 3231 3232 // Dispatch a change event for text fields or textareas that have been edited 3233 if (oldFocusedNode->isElementNode()) { 3234 Element* element = static_cast<Element*>(oldFocusedNode.get()); 3235 if (element->wasChangedSinceLastFormControlChangeEvent()) 3236 element->dispatchFormControlChangeEvent(); 3237 } 3238 3239 // Dispatch the blur event and let the node do any other blur related activities (important for text fields) 3240 oldFocusedNode->dispatchBlurEvent(); 3241 3242 if (m_focusedNode) { 3243 // handler shifted focus 3244 focusChangeBlocked = true; 3245 newFocusedNode = 0; 3246 } 3247 3248 oldFocusedNode->dispatchUIEvent(eventNames().focusoutEvent, 0, 0); // DOM level 3 name for the bubbling blur event. 3249 // FIXME: We should remove firing DOMFocusOutEvent event when we are sure no content depends 3250 // on it, probably when <rdar://problem/8503958> is resolved. 3251 oldFocusedNode->dispatchUIEvent(eventNames().DOMFocusOutEvent, 0, 0); // DOM level 2 name for compatibility. 3252 3253 if (m_focusedNode) { 3254 // handler shifted focus 3255 focusChangeBlocked = true; 3256 newFocusedNode = 0; 3257 } 3258 if (oldFocusedNode == this && oldFocusedNode->hasOneRef()) 3259 return true; 3260 3261 if (oldFocusedNode == oldFocusedNode->rootEditableElement()) 3262 frame()->editor()->didEndEditing(); 3263 3264 if (view()) { 3265 Widget* oldWidget = widgetForNode(oldFocusedNode.get()); 3266 if (oldWidget) 3267 oldWidget->setFocus(false); 3268 else 3269 view()->setFocus(false); 3270 } 3271 } 3272 3273 if (newFocusedNode) { 3274 if (newFocusedNode == newFocusedNode->rootEditableElement() && !acceptsEditingFocus(newFocusedNode.get())) { 3275 // delegate blocks focus change 3276 focusChangeBlocked = true; 3277 goto SetFocusedNodeDone; 3278 } 3279 // Set focus on the new node 3280 m_focusedNode = newFocusedNode.get(); 3281 3282 // Dispatch the focus event and let the node do any other focus related activities (important for text fields) 3283 m_focusedNode->dispatchFocusEvent(); 3284 3285 if (m_focusedNode != newFocusedNode) { 3286 // handler shifted focus 3287 focusChangeBlocked = true; 3288 goto SetFocusedNodeDone; 3289 } 3290 3291 m_focusedNode->dispatchUIEvent(eventNames().focusinEvent, 0, 0); // DOM level 3 bubbling focus event. 3292 // FIXME: We should remove firing DOMFocusInEvent event when we are sure no content depends 3293 // on it, probably when <rdar://problem/8503958> is resolved. 3294 m_focusedNode->dispatchUIEvent(eventNames().DOMFocusInEvent, 0, 0); // DOM level 2 for compatibility. 3295 3296 if (m_focusedNode != newFocusedNode) { 3297 // handler shifted focus 3298 focusChangeBlocked = true; 3299 goto SetFocusedNodeDone; 3300 } 3301 m_focusedNode->setFocus(true); 3302 3303 if (m_focusedNode == m_focusedNode->rootEditableElement()) 3304 frame()->editor()->didBeginEditing(); 3305 3306 // eww, I suck. set the qt focus correctly 3307 // ### find a better place in the code for this 3308 if (view()) { 3309 Widget* focusWidget = widgetForNode(m_focusedNode.get()); 3310 if (focusWidget) { 3311 // Make sure a widget has the right size before giving it focus. 3312 // Otherwise, we are testing edge cases of the Widget code. 3313 // Specifically, in WebCore this does not work well for text fields. 3314 updateLayout(); 3315 // Re-get the widget in case updating the layout changed things. 3316 focusWidget = widgetForNode(m_focusedNode.get()); 3317 } 3318 if (focusWidget) 3319 focusWidget->setFocus(true); 3320 else 3321 view()->setFocus(true); 3322 } 3323 } 3324 3325 #if PLATFORM(MAC) || PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(CHROMIUM) 3326 if (!focusChangeBlocked && m_focusedNode && AXObjectCache::accessibilityEnabled()) { 3327 RenderObject* oldFocusedRenderer = 0; 3328 RenderObject* newFocusedRenderer = 0; 3329 3330 if (oldFocusedNode) 3331 oldFocusedRenderer = oldFocusedNode->renderer(); 3332 if (newFocusedNode) 3333 newFocusedRenderer = newFocusedNode->renderer(); 3334 3335 axObjectCache()->handleFocusedUIElementChanged(oldFocusedRenderer, newFocusedRenderer); 3336 } 3337 #endif 3338 if (!focusChangeBlocked) 3339 page()->chrome()->focusedNodeChanged(m_focusedNode.get()); 3340 3341 SetFocusedNodeDone: 3342 updateStyleIfNeeded(); 3343 return !focusChangeBlocked; 3344 } 3345 3346 void Document::getFocusableNodes(Vector<RefPtr<Node> >& nodes) 3347 { 3348 updateLayout(); 3349 3350 for (Node* node = firstChild(); node; node = node->traverseNextNode()) { 3351 if (node->isFocusable()) 3352 nodes.append(node); 3353 } 3354 } 3355 3356 void Document::setCSSTarget(Element* n) 3357 { 3358 if (m_cssTarget) 3359 m_cssTarget->setNeedsStyleRecalc(); 3360 m_cssTarget = n; 3361 if (n) 3362 n->setNeedsStyleRecalc(); 3363 } 3364 3365 void Document::attachNodeIterator(NodeIterator* ni) 3366 { 3367 m_nodeIterators.add(ni); 3368 } 3369 3370 void Document::detachNodeIterator(NodeIterator* ni) 3371 { 3372 // The node iterator can be detached without having been attached if its root node didn't have a document 3373 // when the iterator was created, but has it now. 3374 m_nodeIterators.remove(ni); 3375 } 3376 3377 void Document::moveNodeIteratorsToNewDocument(Node* node, Document* newDocument) 3378 { 3379 HashSet<NodeIterator*> nodeIteratorsList = m_nodeIterators; 3380 HashSet<NodeIterator*>::const_iterator nodeIteratorsEnd = nodeIteratorsList.end(); 3381 for (HashSet<NodeIterator*>::const_iterator it = nodeIteratorsList.begin(); it != nodeIteratorsEnd; ++it) { 3382 if ((*it)->root() == node) { 3383 detachNodeIterator(*it); 3384 newDocument->attachNodeIterator(*it); 3385 } 3386 } 3387 } 3388 3389 void Document::nodeChildrenChanged(ContainerNode* container) 3390 { 3391 if (!disableRangeMutation(page()) && !m_ranges.isEmpty()) { 3392 HashSet<Range*>::const_iterator end = m_ranges.end(); 3393 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) 3394 (*it)->nodeChildrenChanged(container); 3395 } 3396 } 3397 3398 void Document::nodeChildrenWillBeRemoved(ContainerNode* container) 3399 { 3400 if (!disableRangeMutation(page()) && !m_ranges.isEmpty()) { 3401 HashSet<Range*>::const_iterator end = m_ranges.end(); 3402 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) 3403 (*it)->nodeChildrenWillBeRemoved(container); 3404 } 3405 3406 HashSet<NodeIterator*>::const_iterator nodeIteratorsEnd = m_nodeIterators.end(); 3407 for (HashSet<NodeIterator*>::const_iterator it = m_nodeIterators.begin(); it != nodeIteratorsEnd; ++it) { 3408 for (Node* n = container->firstChild(); n; n = n->nextSibling()) 3409 (*it)->nodeWillBeRemoved(n); 3410 } 3411 3412 if (Frame* frame = this->frame()) { 3413 for (Node* n = container->firstChild(); n; n = n->nextSibling()) { 3414 frame->selection()->nodeWillBeRemoved(n); 3415 frame->page()->dragCaretController()->nodeWillBeRemoved(n); 3416 } 3417 } 3418 } 3419 3420 void Document::nodeWillBeRemoved(Node* n) 3421 { 3422 HashSet<NodeIterator*>::const_iterator nodeIteratorsEnd = m_nodeIterators.end(); 3423 for (HashSet<NodeIterator*>::const_iterator it = m_nodeIterators.begin(); it != nodeIteratorsEnd; ++it) 3424 (*it)->nodeWillBeRemoved(n); 3425 3426 if (!disableRangeMutation(page()) && !m_ranges.isEmpty()) { 3427 HashSet<Range*>::const_iterator rangesEnd = m_ranges.end(); 3428 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != rangesEnd; ++it) 3429 (*it)->nodeWillBeRemoved(n); 3430 } 3431 3432 if (Frame* frame = this->frame()) { 3433 frame->selection()->nodeWillBeRemoved(n); 3434 frame->page()->dragCaretController()->nodeWillBeRemoved(n); 3435 } 3436 3437 #if ENABLE(FULLSCREEN_API) 3438 // If the current full screen element or any of its ancestors is removed, set the current 3439 // full screen element to the document root, and fire a fullscreenchange event to inform 3440 // clients of the DOM. 3441 ASSERT(n); 3442 if (n->contains(m_fullScreenElement.get())) { 3443 ASSERT(n != documentElement()); 3444 3445 if (m_fullScreenRenderer) 3446 m_fullScreenRenderer->remove(); 3447 3448 setFullScreenRenderer(0); 3449 m_fullScreenElement = documentElement(); 3450 recalcStyle(Force); 3451 m_fullScreenChangeDelayTimer.startOneShot(0); 3452 } 3453 #endif 3454 } 3455 3456 void Document::textInserted(Node* text, unsigned offset, unsigned length) 3457 { 3458 if (!disableRangeMutation(page()) && !m_ranges.isEmpty()) { 3459 HashSet<Range*>::const_iterator end = m_ranges.end(); 3460 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) 3461 (*it)->textInserted(text, offset, length); 3462 } 3463 3464 // Update the markers for spelling and grammar checking. 3465 m_markers->shiftMarkers(text, offset, length); 3466 } 3467 3468 void Document::textRemoved(Node* text, unsigned offset, unsigned length) 3469 { 3470 if (!disableRangeMutation(page()) && !m_ranges.isEmpty()) { 3471 HashSet<Range*>::const_iterator end = m_ranges.end(); 3472 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) 3473 (*it)->textRemoved(text, offset, length); 3474 } 3475 3476 // Update the markers for spelling and grammar checking. 3477 m_markers->removeMarkers(text, offset, length); 3478 m_markers->shiftMarkers(text, offset + length, 0 - length); 3479 } 3480 3481 void Document::textNodesMerged(Text* oldNode, unsigned offset) 3482 { 3483 if (!disableRangeMutation(page()) && !m_ranges.isEmpty()) { 3484 NodeWithIndex oldNodeWithIndex(oldNode); 3485 HashSet<Range*>::const_iterator end = m_ranges.end(); 3486 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) 3487 (*it)->textNodesMerged(oldNodeWithIndex, offset); 3488 } 3489 3490 // FIXME: This should update markers for spelling and grammar checking. 3491 } 3492 3493 void Document::textNodeSplit(Text* oldNode) 3494 { 3495 if (!disableRangeMutation(page()) && !m_ranges.isEmpty()) { 3496 HashSet<Range*>::const_iterator end = m_ranges.end(); 3497 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) 3498 (*it)->textNodeSplit(oldNode); 3499 } 3500 3501 // FIXME: This should update markers for spelling and grammar checking. 3502 } 3503 3504 // FIXME: eventually, this should return a DOMWindow stored in the document. 3505 DOMWindow* Document::domWindow() const 3506 { 3507 if (!frame()) 3508 return 0; 3509 3510 // The m_frame pointer is not (not always?) zeroed out when the document is put into b/f cache, so the frame can hold an unrelated document/window pair. 3511 // FIXME: We should always zero out the frame pointer on navigation to avoid accidentally accessing the new frame content. 3512 if (m_frame->document() != this) 3513 return 0; 3514 3515 return frame()->domWindow(); 3516 } 3517 3518 void Document::setWindowAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener) 3519 { 3520 DOMWindow* domWindow = this->domWindow(); 3521 if (!domWindow) 3522 return; 3523 domWindow->setAttributeEventListener(eventType, listener); 3524 } 3525 3526 EventListener* Document::getWindowAttributeEventListener(const AtomicString& eventType) 3527 { 3528 DOMWindow* domWindow = this->domWindow(); 3529 if (!domWindow) 3530 return 0; 3531 return domWindow->getAttributeEventListener(eventType); 3532 } 3533 3534 void Document::dispatchWindowEvent(PassRefPtr<Event> event, PassRefPtr<EventTarget> target) 3535 { 3536 ASSERT(!eventDispatchForbidden()); 3537 DOMWindow* domWindow = this->domWindow(); 3538 if (!domWindow) 3539 return; 3540 domWindow->dispatchEvent(event, target); 3541 } 3542 3543 void Document::dispatchWindowLoadEvent() 3544 { 3545 ASSERT(!eventDispatchForbidden()); 3546 DOMWindow* domWindow = this->domWindow(); 3547 if (!domWindow) 3548 return; 3549 domWindow->dispatchLoadEvent(); 3550 } 3551 3552 void Document::enqueueWindowEvent(PassRefPtr<Event> event) 3553 { 3554 event->setTarget(domWindow()); 3555 m_eventQueue->enqueueEvent(event); 3556 } 3557 3558 void Document::enqueueDocumentEvent(PassRefPtr<Event> event) 3559 { 3560 event->setTarget(this); 3561 m_eventQueue->enqueueEvent(event); 3562 } 3563 3564 PassRefPtr<Event> Document::createEvent(const String& eventType, ExceptionCode& ec) 3565 { 3566 RefPtr<Event> event; 3567 if (eventType == "Event" || eventType == "Events" || eventType == "HTMLEvents") 3568 event = Event::create(); 3569 else if (eventType == "CustomEvent") 3570 event = CustomEvent::create(); 3571 else if (eventType == "KeyboardEvent" || eventType == "KeyboardEvents") 3572 event = KeyboardEvent::create(); 3573 else if (eventType == "MessageEvent") 3574 event = MessageEvent::create(); 3575 else if (eventType == "MouseEvent" || eventType == "MouseEvents") 3576 event = MouseEvent::create(); 3577 else if (eventType == "MutationEvent" || eventType == "MutationEvents") 3578 event = MutationEvent::create(); 3579 else if (eventType == "OverflowEvent") 3580 event = OverflowEvent::create(); 3581 else if (eventType == "PageTransitionEvent") 3582 event = PageTransitionEvent::create(); 3583 else if (eventType == "ProgressEvent") 3584 event = ProgressEvent::create(); 3585 #if ENABLE(DOM_STORAGE) 3586 else if (eventType == "StorageEvent") 3587 event = StorageEvent::create(); 3588 #endif 3589 else if (eventType == "TextEvent") 3590 event = TextEvent::create(); 3591 else if (eventType == "UIEvent" || eventType == "UIEvents") 3592 event = UIEvent::create(); 3593 else if (eventType == "WebKitAnimationEvent") 3594 event = WebKitAnimationEvent::create(); 3595 else if (eventType == "WebKitTransitionEvent") 3596 event = WebKitTransitionEvent::create(); 3597 else if (eventType == "WheelEvent") 3598 event = WheelEvent::create(); 3599 #if ENABLE(SVG) 3600 else if (eventType == "SVGEvents") 3601 event = Event::create(); 3602 else if (eventType == "SVGZoomEvents") 3603 event = SVGZoomEvent::create(); 3604 #endif 3605 #if ENABLE(TOUCH_EVENTS) 3606 #if USE(V8) 3607 else if (eventType == "TouchEvent" && RuntimeEnabledFeatures::touchEnabled()) 3608 #else 3609 else if (eventType == "TouchEvent") 3610 #endif 3611 event = TouchEvent::create(); 3612 #endif 3613 #if ENABLE(DEVICE_ORIENTATION) 3614 else if (eventType == "DeviceMotionEvent") 3615 event = DeviceMotionEvent::create(); 3616 else if (eventType == "DeviceOrientationEvent") 3617 event = DeviceOrientationEvent::create(); 3618 #endif 3619 #if ENABLE(ORIENTATION_EVENTS) 3620 else if (eventType == "OrientationEvent") 3621 event = Event::create(); 3622 #endif 3623 if (event) 3624 return event.release(); 3625 3626 ec = NOT_SUPPORTED_ERR; 3627 return 0; 3628 } 3629 3630 void Document::addListenerTypeIfNeeded(const AtomicString& eventType) 3631 { 3632 if (eventType == eventNames().DOMSubtreeModifiedEvent) 3633 addListenerType(DOMSUBTREEMODIFIED_LISTENER); 3634 else if (eventType == eventNames().DOMNodeInsertedEvent) 3635 addListenerType(DOMNODEINSERTED_LISTENER); 3636 else if (eventType == eventNames().DOMNodeRemovedEvent) 3637 addListenerType(DOMNODEREMOVED_LISTENER); 3638 else if (eventType == eventNames().DOMNodeRemovedFromDocumentEvent) 3639 addListenerType(DOMNODEREMOVEDFROMDOCUMENT_LISTENER); 3640 else if (eventType == eventNames().DOMNodeInsertedIntoDocumentEvent) 3641 addListenerType(DOMNODEINSERTEDINTODOCUMENT_LISTENER); 3642 else if (eventType == eventNames().DOMAttrModifiedEvent) 3643 addListenerType(DOMATTRMODIFIED_LISTENER); 3644 else if (eventType == eventNames().DOMCharacterDataModifiedEvent) 3645 addListenerType(DOMCHARACTERDATAMODIFIED_LISTENER); 3646 else if (eventType == eventNames().overflowchangedEvent) 3647 addListenerType(OVERFLOWCHANGED_LISTENER); 3648 else if (eventType == eventNames().webkitAnimationStartEvent) 3649 addListenerType(ANIMATIONSTART_LISTENER); 3650 else if (eventType == eventNames().webkitAnimationEndEvent) 3651 addListenerType(ANIMATIONEND_LISTENER); 3652 else if (eventType == eventNames().webkitAnimationIterationEvent) 3653 addListenerType(ANIMATIONITERATION_LISTENER); 3654 else if (eventType == eventNames().webkitTransitionEndEvent) 3655 addListenerType(TRANSITIONEND_LISTENER); 3656 else if (eventType == eventNames().beforeloadEvent) 3657 addListenerType(BEFORELOAD_LISTENER); 3658 else if (eventType == eventNames().beforeprocessEvent) 3659 addListenerType(BEFOREPROCESS_LISTENER); 3660 #if ENABLE(TOUCH_EVENTS) 3661 else if (eventType == eventNames().touchstartEvent 3662 || eventType == eventNames().touchmoveEvent 3663 || eventType == eventNames().touchendEvent 3664 || eventType == eventNames().touchcancelEvent) { 3665 addListenerType(TOUCH_LISTENER); 3666 if (Page* page = this->page()) 3667 page->chrome()->client()->needTouchEvents(true); 3668 } 3669 #endif 3670 } 3671 3672 CSSStyleDeclaration* Document::getOverrideStyle(Element*, const String&) 3673 { 3674 return 0; 3675 } 3676 3677 HTMLFrameOwnerElement* Document::ownerElement() const 3678 { 3679 if (!frame()) 3680 return 0; 3681 return frame()->ownerElement(); 3682 } 3683 3684 String Document::cookie(ExceptionCode& ec) const 3685 { 3686 if (page() && !page()->cookieEnabled()) 3687 return String(); 3688 3689 // FIXME: The HTML5 DOM spec states that this attribute can raise an 3690 // INVALID_STATE_ERR exception on getting if the Document has no 3691 // browsing context. 3692 3693 if (!securityOrigin()->canAccessCookies()) { 3694 ec = SECURITY_ERR; 3695 return String(); 3696 } 3697 3698 KURL cookieURL = this->cookieURL(); 3699 if (cookieURL.isEmpty()) 3700 return String(); 3701 3702 return cookies(this, cookieURL); 3703 } 3704 3705 void Document::setCookie(const String& value, ExceptionCode& ec) 3706 { 3707 if (page() && !page()->cookieEnabled()) 3708 return; 3709 3710 // FIXME: The HTML5 DOM spec states that this attribute can raise an 3711 // INVALID_STATE_ERR exception on setting if the Document has no 3712 // browsing context. 3713 3714 if (!securityOrigin()->canAccessCookies()) { 3715 ec = SECURITY_ERR; 3716 return; 3717 } 3718 3719 KURL cookieURL = this->cookieURL(); 3720 if (cookieURL.isEmpty()) 3721 return; 3722 3723 setCookies(this, cookieURL, value); 3724 } 3725 3726 String Document::referrer() const 3727 { 3728 if (frame()) 3729 return frame()->loader()->referrer(); 3730 return String(); 3731 } 3732 3733 String Document::domain() const 3734 { 3735 return securityOrigin()->domain(); 3736 } 3737 3738 void Document::setDomain(const String& newDomain, ExceptionCode& ec) 3739 { 3740 if (SecurityOrigin::isDomainRelaxationForbiddenForURLScheme(securityOrigin()->protocol())) { 3741 ec = SECURITY_ERR; 3742 return; 3743 } 3744 3745 // Both NS and IE specify that changing the domain is only allowed when 3746 // the new domain is a suffix of the old domain. 3747 3748 // FIXME: We should add logging indicating why a domain was not allowed. 3749 3750 // If the new domain is the same as the old domain, still call 3751 // securityOrigin()->setDomainForDOM. This will change the 3752 // security check behavior. For example, if a page loaded on port 8000 3753 // assigns its current domain using document.domain, the page will 3754 // allow other pages loaded on different ports in the same domain that 3755 // have also assigned to access this page. 3756 if (equalIgnoringCase(domain(), newDomain)) { 3757 securityOrigin()->setDomainFromDOM(newDomain); 3758 if (m_frame) 3759 m_frame->script()->updateSecurityOrigin(); 3760 return; 3761 } 3762 3763 int oldLength = domain().length(); 3764 int newLength = newDomain.length(); 3765 // e.g. newDomain = webkit.org (10) and domain() = www.webkit.org (14) 3766 if (newLength >= oldLength) { 3767 ec = SECURITY_ERR; 3768 return; 3769 } 3770 3771 String test = domain(); 3772 // Check that it's a subdomain, not e.g. "ebkit.org" 3773 if (test[oldLength - newLength - 1] != '.') { 3774 ec = SECURITY_ERR; 3775 return; 3776 } 3777 3778 // Now test is "webkit.org" from domain() 3779 // and we check that it's the same thing as newDomain 3780 test.remove(0, oldLength - newLength); 3781 if (test != newDomain) { 3782 ec = SECURITY_ERR; 3783 return; 3784 } 3785 3786 securityOrigin()->setDomainFromDOM(newDomain); 3787 if (m_frame) 3788 m_frame->script()->updateSecurityOrigin(); 3789 } 3790 3791 // http://www.whatwg.org/specs/web-apps/current-work/#dom-document-lastmodified 3792 String Document::lastModified() const 3793 { 3794 DateComponents date; 3795 bool foundDate = false; 3796 if (m_frame) { 3797 String httpLastModified; 3798 if (DocumentLoader* documentLoader = loader()) 3799 httpLastModified = documentLoader->response().httpHeaderField("Last-Modified"); 3800 if (!httpLastModified.isEmpty()) { 3801 date.setMillisecondsSinceEpochForDateTime(parseDate(httpLastModified)); 3802 foundDate = true; 3803 } 3804 } 3805 // FIXME: If this document came from the file system, the HTML5 3806 // specificiation tells us to read the last modification date from the file 3807 // system. 3808 if (!foundDate) 3809 date.setMillisecondsSinceEpochForDateTime(currentTimeMS()); 3810 return String::format("%02d/%02d/%04d %02d:%02d:%02d", date.month() + 1, date.monthDay(), date.fullYear(), date.hour(), date.minute(), date.second()); 3811 } 3812 3813 static bool isValidNameNonASCII(const UChar* characters, unsigned length) 3814 { 3815 unsigned i = 0; 3816 3817 UChar32 c; 3818 U16_NEXT(characters, i, length, c) 3819 if (!isValidNameStart(c)) 3820 return false; 3821 3822 while (i < length) { 3823 U16_NEXT(characters, i, length, c) 3824 if (!isValidNamePart(c)) 3825 return false; 3826 } 3827 3828 return true; 3829 } 3830 3831 static inline bool isValidNameASCII(const UChar* characters, unsigned length) 3832 { 3833 UChar c = characters[0]; 3834 if (!(isASCIIAlpha(c) || c == ':' || c == '_')) 3835 return false; 3836 3837 for (unsigned i = 1; i < length; ++i) { 3838 c = characters[i]; 3839 if (!(isASCIIAlphanumeric(c) || c == ':' || c == '_' || c == '-' || c == '.')) 3840 return false; 3841 } 3842 3843 return true; 3844 } 3845 3846 bool Document::isValidName(const String& name) 3847 { 3848 unsigned length = name.length(); 3849 if (!length) 3850 return false; 3851 3852 const UChar* characters = name.characters(); 3853 return isValidNameASCII(characters, length) || isValidNameNonASCII(characters, length); 3854 } 3855 3856 bool Document::parseQualifiedName(const String& qualifiedName, String& prefix, String& localName, ExceptionCode& ec) 3857 { 3858 unsigned length = qualifiedName.length(); 3859 3860 if (!length) { 3861 ec = INVALID_CHARACTER_ERR; 3862 return false; 3863 } 3864 3865 bool nameStart = true; 3866 bool sawColon = false; 3867 int colonPos = 0; 3868 3869 const UChar* s = qualifiedName.characters(); 3870 for (unsigned i = 0; i < length;) { 3871 UChar32 c; 3872 U16_NEXT(s, i, length, c) 3873 if (c == ':') { 3874 if (sawColon) { 3875 ec = NAMESPACE_ERR; 3876 return false; // multiple colons: not allowed 3877 } 3878 nameStart = true; 3879 sawColon = true; 3880 colonPos = i - 1; 3881 } else if (nameStart) { 3882 if (!isValidNameStart(c)) { 3883 ec = INVALID_CHARACTER_ERR; 3884 return false; 3885 } 3886 nameStart = false; 3887 } else { 3888 if (!isValidNamePart(c)) { 3889 ec = INVALID_CHARACTER_ERR; 3890 return false; 3891 } 3892 } 3893 } 3894 3895 if (!sawColon) { 3896 prefix = String(); 3897 localName = qualifiedName; 3898 } else { 3899 prefix = qualifiedName.substring(0, colonPos); 3900 if (prefix.isEmpty()) { 3901 ec = NAMESPACE_ERR; 3902 return false; 3903 } 3904 localName = qualifiedName.substring(colonPos + 1); 3905 } 3906 3907 if (localName.isEmpty()) { 3908 ec = NAMESPACE_ERR; 3909 return false; 3910 } 3911 3912 return true; 3913 } 3914 3915 void Document::setDecoder(PassRefPtr<TextResourceDecoder> decoder) 3916 { 3917 m_decoder = decoder; 3918 } 3919 3920 KURL Document::completeURL(const String& url) const 3921 { 3922 // Always return a null URL when passed a null string. 3923 // FIXME: Should we change the KURL constructor to have this behavior? 3924 // See also [CSS]StyleSheet::completeURL(const String&) 3925 if (url.isNull()) 3926 return KURL(); 3927 const KURL& baseURL = ((m_baseURL.isEmpty() || m_baseURL == blankURL()) && parentDocument()) ? parentDocument()->baseURL() : m_baseURL; 3928 if (!m_decoder) 3929 return KURL(baseURL, url); 3930 return KURL(baseURL, url, m_decoder->encoding()); 3931 } 3932 3933 void Document::setInPageCache(bool flag) 3934 { 3935 if (m_inPageCache == flag) 3936 return; 3937 3938 m_inPageCache = flag; 3939 if (flag) { 3940 ASSERT(!m_savedRenderer); 3941 m_savedRenderer = renderer(); 3942 if (FrameView* v = view()) 3943 v->resetScrollbarsAndClearContentsSize(); 3944 m_styleRecalcTimer.stop(); 3945 } else { 3946 ASSERT(!renderer() || renderer() == m_savedRenderer); 3947 ASSERT(m_renderArena); 3948 setRenderer(m_savedRenderer); 3949 m_savedRenderer = 0; 3950 3951 if (frame() && frame()->page()) 3952 frame()->page()->updateViewportArguments(); 3953 3954 if (childNeedsStyleRecalc()) 3955 scheduleStyleRecalc(); 3956 } 3957 } 3958 3959 void Document::documentWillBecomeInactive() 3960 { 3961 #if USE(ACCELERATED_COMPOSITING) 3962 if (renderer()) 3963 renderView()->willMoveOffscreen(); 3964 #endif 3965 3966 HashSet<Element*>::iterator end = m_documentActivationCallbackElements.end(); 3967 for (HashSet<Element*>::iterator i = m_documentActivationCallbackElements.begin(); i != end; ++i) 3968 (*i)->documentWillBecomeInactive(); 3969 } 3970 3971 void Document::documentDidBecomeActive() 3972 { 3973 HashSet<Element*>::iterator end = m_documentActivationCallbackElements.end(); 3974 for (HashSet<Element*>::iterator i = m_documentActivationCallbackElements.begin(); i != end; ++i) 3975 (*i)->documentDidBecomeActive(); 3976 3977 #if USE(ACCELERATED_COMPOSITING) 3978 if (renderer()) 3979 renderView()->didMoveOnscreen(); 3980 #endif 3981 3982 ASSERT(m_frame); 3983 m_frame->loader()->client()->dispatchDidBecomeFrameset(isFrameSet()); 3984 } 3985 3986 void Document::registerForDocumentActivationCallbacks(Element* e) 3987 { 3988 m_documentActivationCallbackElements.add(e); 3989 } 3990 3991 void Document::unregisterForDocumentActivationCallbacks(Element* e) 3992 { 3993 m_documentActivationCallbackElements.remove(e); 3994 } 3995 3996 void Document::mediaVolumeDidChange() 3997 { 3998 HashSet<Element*>::iterator end = m_mediaVolumeCallbackElements.end(); 3999 for (HashSet<Element*>::iterator i = m_mediaVolumeCallbackElements.begin(); i != end; ++i) 4000 (*i)->mediaVolumeDidChange(); 4001 } 4002 4003 void Document::registerForMediaVolumeCallbacks(Element* e) 4004 { 4005 m_mediaVolumeCallbackElements.add(e); 4006 } 4007 4008 void Document::unregisterForMediaVolumeCallbacks(Element* e) 4009 { 4010 m_mediaVolumeCallbackElements.remove(e); 4011 } 4012 4013 void Document::privateBrowsingStateDidChange() 4014 { 4015 HashSet<Element*>::iterator end = m_privateBrowsingStateChangedElements.end(); 4016 for (HashSet<Element*>::iterator it = m_privateBrowsingStateChangedElements.begin(); it != end; ++it) 4017 (*it)->privateBrowsingStateDidChange(); 4018 } 4019 4020 void Document::registerForPrivateBrowsingStateChangedCallbacks(Element* e) 4021 { 4022 m_privateBrowsingStateChangedElements.add(e); 4023 } 4024 4025 void Document::unregisterForPrivateBrowsingStateChangedCallbacks(Element* e) 4026 { 4027 m_privateBrowsingStateChangedElements.remove(e); 4028 } 4029 4030 void Document::setShouldCreateRenderers(bool f) 4031 { 4032 m_createRenderers = f; 4033 } 4034 4035 bool Document::shouldCreateRenderers() 4036 { 4037 return m_createRenderers; 4038 } 4039 4040 // Support for Javascript execCommand, and related methods 4041 4042 static Editor::Command command(Document* document, const String& commandName, bool userInterface = false) 4043 { 4044 Frame* frame = document->frame(); 4045 if (!frame || frame->document() != document) 4046 return Editor::Command(); 4047 4048 document->updateStyleIfNeeded(); 4049 4050 return frame->editor()->command(commandName, 4051 userInterface ? CommandFromDOMWithUserInterface : CommandFromDOM); 4052 } 4053 4054 bool Document::execCommand(const String& commandName, bool userInterface, const String& value) 4055 { 4056 return command(this, commandName, userInterface).execute(value); 4057 } 4058 4059 bool Document::queryCommandEnabled(const String& commandName) 4060 { 4061 return command(this, commandName).isEnabled(); 4062 } 4063 4064 bool Document::queryCommandIndeterm(const String& commandName) 4065 { 4066 return command(this, commandName).state() == MixedTriState; 4067 } 4068 4069 bool Document::queryCommandState(const String& commandName) 4070 { 4071 return command(this, commandName).state() == TrueTriState; 4072 } 4073 4074 bool Document::queryCommandSupported(const String& commandName) 4075 { 4076 return command(this, commandName).isSupported(); 4077 } 4078 4079 String Document::queryCommandValue(const String& commandName) 4080 { 4081 return command(this, commandName).value(); 4082 } 4083 4084 #if ENABLE(XSLT) 4085 4086 void Document::applyXSLTransform(ProcessingInstruction* pi) 4087 { 4088 RefPtr<XSLTProcessor> processor = XSLTProcessor::create(); 4089 processor->setXSLStyleSheet(static_cast<XSLStyleSheet*>(pi->sheet())); 4090 String resultMIMEType; 4091 String newSource; 4092 String resultEncoding; 4093 if (!processor->transformToString(this, resultMIMEType, newSource, resultEncoding)) 4094 return; 4095 // FIXME: If the transform failed we should probably report an error (like Mozilla does). 4096 processor->createDocumentFromSource(newSource, resultEncoding, resultMIMEType, this, frame()); 4097 } 4098 4099 void Document::setTransformSource(PassOwnPtr<TransformSource> source) 4100 { 4101 if (m_transformSource == source) 4102 return; 4103 m_transformSource = source; 4104 } 4105 4106 #endif 4107 4108 void Document::setDesignMode(InheritedBool value) 4109 { 4110 m_designMode = value; 4111 for (Frame* frame = m_frame; frame && frame->document(); frame = frame->tree()->traverseNext(m_frame)) 4112 frame->document()->scheduleForcedStyleRecalc(); 4113 } 4114 4115 Document::InheritedBool Document::getDesignMode() const 4116 { 4117 return m_designMode; 4118 } 4119 4120 bool Document::inDesignMode() const 4121 { 4122 for (const Document* d = this; d; d = d->parentDocument()) { 4123 if (d->m_designMode != inherit) 4124 return d->m_designMode; 4125 } 4126 return false; 4127 } 4128 4129 Document* Document::parentDocument() const 4130 { 4131 if (!m_frame) 4132 return 0; 4133 Frame* parent = m_frame->tree()->parent(); 4134 if (!parent) 4135 return 0; 4136 return parent->document(); 4137 } 4138 4139 Document* Document::topDocument() const 4140 { 4141 Document* doc = const_cast<Document *>(this); 4142 Element* element; 4143 while ((element = doc->ownerElement())) 4144 doc = element->document(); 4145 4146 return doc; 4147 } 4148 4149 PassRefPtr<Attr> Document::createAttribute(const String& name, ExceptionCode& ec) 4150 { 4151 return createAttributeNS(String(), name, ec, true); 4152 } 4153 4154 PassRefPtr<Attr> Document::createAttributeNS(const String& namespaceURI, const String& qualifiedName, ExceptionCode& ec, bool shouldIgnoreNamespaceChecks) 4155 { 4156 String prefix, localName; 4157 if (!parseQualifiedName(qualifiedName, prefix, localName, ec)) 4158 return 0; 4159 4160 QualifiedName qName(prefix, localName, namespaceURI); 4161 if (!shouldIgnoreNamespaceChecks && hasPrefixNamespaceMismatch(qName)) { 4162 ec = NAMESPACE_ERR; 4163 return 0; 4164 } 4165 4166 // Spec: DOM Level 2 Core: http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-DocCrAttrNS 4167 if (!shouldIgnoreNamespaceChecks && qName.localName() == xmlnsAtom && qName.namespaceURI() != XMLNSNames::xmlnsNamespaceURI) { 4168 ec = NAMESPACE_ERR; 4169 return 0; 4170 } 4171 4172 // FIXME: Assume this is a mapped attribute, since createAttribute isn't namespace-aware. There's no harm to XML 4173 // documents if we're wrong. 4174 return Attr::create(0, this, Attribute::createMapped(qName, StringImpl::empty())); 4175 } 4176 4177 #if ENABLE(SVG) 4178 const SVGDocumentExtensions* Document::svgExtensions() 4179 { 4180 return m_svgExtensions.get(); 4181 } 4182 4183 SVGDocumentExtensions* Document::accessSVGExtensions() 4184 { 4185 if (!m_svgExtensions) 4186 m_svgExtensions = adoptPtr(new SVGDocumentExtensions(this)); 4187 return m_svgExtensions.get(); 4188 } 4189 4190 bool Document::hasSVGRootNode() const 4191 { 4192 return documentElement() && documentElement()->hasTagName(SVGNames::svgTag); 4193 } 4194 #endif 4195 4196 PassRefPtr<HTMLCollection> Document::images() 4197 { 4198 return HTMLCollection::create(this, DocImages); 4199 } 4200 4201 PassRefPtr<HTMLCollection> Document::applets() 4202 { 4203 return HTMLCollection::create(this, DocApplets); 4204 } 4205 4206 PassRefPtr<HTMLCollection> Document::embeds() 4207 { 4208 return HTMLCollection::create(this, DocEmbeds); 4209 } 4210 4211 PassRefPtr<HTMLCollection> Document::plugins() 4212 { 4213 // This is an alias for embeds() required for the JS DOM bindings. 4214 return HTMLCollection::create(this, DocEmbeds); 4215 } 4216 4217 PassRefPtr<HTMLCollection> Document::objects() 4218 { 4219 return HTMLCollection::create(this, DocObjects); 4220 } 4221 4222 PassRefPtr<HTMLCollection> Document::scripts() 4223 { 4224 return HTMLCollection::create(this, DocScripts); 4225 } 4226 4227 PassRefPtr<HTMLCollection> Document::links() 4228 { 4229 return HTMLCollection::create(this, DocLinks); 4230 } 4231 4232 PassRefPtr<HTMLCollection> Document::forms() 4233 { 4234 return HTMLCollection::create(this, DocForms); 4235 } 4236 4237 PassRefPtr<HTMLCollection> Document::anchors() 4238 { 4239 return HTMLCollection::create(this, DocAnchors); 4240 } 4241 4242 PassRefPtr<HTMLAllCollection> Document::all() 4243 { 4244 return HTMLAllCollection::create(this); 4245 } 4246 4247 PassRefPtr<HTMLCollection> Document::windowNamedItems(const String &name) 4248 { 4249 return HTMLNameCollection::create(this, WindowNamedItems, name); 4250 } 4251 4252 PassRefPtr<HTMLCollection> Document::documentNamedItems(const String &name) 4253 { 4254 return HTMLNameCollection::create(this, DocumentNamedItems, name); 4255 } 4256 4257 CollectionCache* Document::nameCollectionInfo(CollectionType type, const AtomicString& name) 4258 { 4259 ASSERT(type >= FirstNamedDocumentCachedType); 4260 unsigned index = type - FirstNamedDocumentCachedType; 4261 ASSERT(index < NumNamedDocumentCachedTypes); 4262 4263 NamedCollectionMap& map = m_nameCollectionInfo[index]; 4264 NamedCollectionMap::iterator iter = map.find(name.impl()); 4265 if (iter == map.end()) 4266 iter = map.add(name.impl(), new CollectionCache).first; 4267 iter->second->checkConsistency(); 4268 return iter->second; 4269 } 4270 4271 void Document::finishedParsing() 4272 { 4273 ASSERT(!scriptableDocumentParser() || !m_parser->isParsing()); 4274 ASSERT(!scriptableDocumentParser() || m_readyState != Loading); 4275 setParsing(false); 4276 if (!m_documentTiming.domContentLoadedEventStart) 4277 m_documentTiming.domContentLoadedEventStart = currentTime(); 4278 dispatchEvent(Event::create(eventNames().DOMContentLoadedEvent, true, false)); 4279 if (!m_documentTiming.domContentLoadedEventEnd) 4280 m_documentTiming.domContentLoadedEventEnd = currentTime(); 4281 4282 if (RefPtr<Frame> f = frame()) { 4283 // FrameLoader::finishedParsing() might end up calling Document::implicitClose() if all 4284 // resource loads are complete. HTMLObjectElements can start loading their resources from 4285 // post attach callbacks triggered by recalcStyle(). This means if we parse out an <object> 4286 // tag and then reach the end of the document without updating styles, we might not have yet 4287 // started the resource load and might fire the window load event too early. To avoid this 4288 // we force the styles to be up to date before calling FrameLoader::finishedParsing(). 4289 // See https://bugs.webkit.org/show_bug.cgi?id=36864 starting around comment 35. 4290 updateStyleIfNeeded(); 4291 4292 f->loader()->finishedParsing(); 4293 4294 InspectorInstrumentation::domContentLoadedEventFired(f.get(), url()); 4295 } 4296 } 4297 4298 Vector<String> Document::formElementsState() const 4299 { 4300 Vector<String> stateVector; 4301 stateVector.reserveInitialCapacity(m_formElementsWithState.size() * 3); 4302 typedef FormElementListHashSet::const_iterator Iterator; 4303 Iterator end = m_formElementsWithState.end(); 4304 for (Iterator it = m_formElementsWithState.begin(); it != end; ++it) { 4305 Element* elementWithState = *it; 4306 String value; 4307 if (!elementWithState->shouldSaveAndRestoreFormControlState()) 4308 continue; 4309 if (!elementWithState->saveFormControlState(value)) 4310 continue; 4311 stateVector.append(elementWithState->formControlName().string()); 4312 stateVector.append(elementWithState->formControlType().string()); 4313 stateVector.append(value); 4314 } 4315 return stateVector; 4316 } 4317 4318 #if ENABLE(XPATH) 4319 4320 PassRefPtr<XPathExpression> Document::createExpression(const String& expression, 4321 XPathNSResolver* resolver, 4322 ExceptionCode& ec) 4323 { 4324 if (!m_xpathEvaluator) 4325 m_xpathEvaluator = XPathEvaluator::create(); 4326 return m_xpathEvaluator->createExpression(expression, resolver, ec); 4327 } 4328 4329 PassRefPtr<XPathNSResolver> Document::createNSResolver(Node* nodeResolver) 4330 { 4331 if (!m_xpathEvaluator) 4332 m_xpathEvaluator = XPathEvaluator::create(); 4333 return m_xpathEvaluator->createNSResolver(nodeResolver); 4334 } 4335 4336 PassRefPtr<XPathResult> Document::evaluate(const String& expression, 4337 Node* contextNode, 4338 XPathNSResolver* resolver, 4339 unsigned short type, 4340 XPathResult* result, 4341 ExceptionCode& ec) 4342 { 4343 if (!m_xpathEvaluator) 4344 m_xpathEvaluator = XPathEvaluator::create(); 4345 return m_xpathEvaluator->evaluate(expression, contextNode, resolver, type, result, ec); 4346 } 4347 4348 #endif // ENABLE(XPATH) 4349 4350 void Document::setStateForNewFormElements(const Vector<String>& stateVector) 4351 { 4352 // Walk the state vector backwards so that the value to use for each 4353 // name/type pair first is the one at the end of each individual vector 4354 // in the FormElementStateMap. We're using them like stacks. 4355 typedef FormElementStateMap::iterator Iterator; 4356 m_formElementsWithState.clear(); 4357 for (size_t i = stateVector.size() / 3 * 3; i; i -= 3) { 4358 AtomicString a = stateVector[i - 3]; 4359 AtomicString b = stateVector[i - 2]; 4360 const String& c = stateVector[i - 1]; 4361 FormElementKey key(a.impl(), b.impl()); 4362 Iterator it = m_stateForNewFormElements.find(key); 4363 if (it != m_stateForNewFormElements.end()) 4364 it->second.append(c); 4365 else { 4366 Vector<String> v(1); 4367 v[0] = c; 4368 m_stateForNewFormElements.set(key, v); 4369 } 4370 } 4371 } 4372 4373 bool Document::hasStateForNewFormElements() const 4374 { 4375 return !m_stateForNewFormElements.isEmpty(); 4376 } 4377 4378 bool Document::takeStateForFormElement(AtomicStringImpl* name, AtomicStringImpl* type, String& state) 4379 { 4380 typedef FormElementStateMap::iterator Iterator; 4381 Iterator it = m_stateForNewFormElements.find(FormElementKey(name, type)); 4382 if (it == m_stateForNewFormElements.end()) 4383 return false; 4384 ASSERT(it->second.size()); 4385 state = it->second.last(); 4386 if (it->second.size() > 1) 4387 it->second.removeLast(); 4388 else 4389 m_stateForNewFormElements.remove(it); 4390 return true; 4391 } 4392 4393 FormElementKey::FormElementKey(AtomicStringImpl* name, AtomicStringImpl* type) 4394 : m_name(name), m_type(type) 4395 { 4396 ref(); 4397 } 4398 4399 FormElementKey::~FormElementKey() 4400 { 4401 deref(); 4402 } 4403 4404 FormElementKey::FormElementKey(const FormElementKey& other) 4405 : m_name(other.name()), m_type(other.type()) 4406 { 4407 ref(); 4408 } 4409 4410 FormElementKey& FormElementKey::operator=(const FormElementKey& other) 4411 { 4412 other.ref(); 4413 deref(); 4414 m_name = other.name(); 4415 m_type = other.type(); 4416 return *this; 4417 } 4418 4419 void FormElementKey::ref() const 4420 { 4421 if (name()) 4422 name()->ref(); 4423 if (type()) 4424 type()->ref(); 4425 } 4426 4427 void FormElementKey::deref() const 4428 { 4429 if (name()) 4430 name()->deref(); 4431 if (type()) 4432 type()->deref(); 4433 } 4434 4435 unsigned FormElementKeyHash::hash(const FormElementKey& key) 4436 { 4437 return StringHasher::hashMemory<sizeof(FormElementKey)>(&key); 4438 } 4439 4440 void Document::setIconURL(const String& iconURL, const String& type) 4441 { 4442 // FIXME - <rdar://problem/4727645> - At some point in the future, we might actually honor the "type" 4443 if (m_iconURL.isEmpty()) 4444 m_iconURL = iconURL; 4445 else if (!type.isEmpty()) 4446 m_iconURL = iconURL; 4447 if (Frame* f = frame()) 4448 f->loader()->setIconURL(m_iconURL); 4449 } 4450 4451 void Document::registerFormElementWithFormAttribute(FormAssociatedElement* element) 4452 { 4453 ASSERT(toHTMLElement(element)->fastHasAttribute(formAttr)); 4454 m_formElementsWithFormAttribute.add(element); 4455 } 4456 4457 void Document::unregisterFormElementWithFormAttribute(FormAssociatedElement* element) 4458 { 4459 m_formElementsWithFormAttribute.remove(element); 4460 } 4461 4462 void Document::resetFormElementsOwner(HTMLFormElement* form) 4463 { 4464 typedef FormAssociatedElementListHashSet::iterator Iterator; 4465 Iterator end = m_formElementsWithFormAttribute.end(); 4466 for (Iterator it = m_formElementsWithFormAttribute.begin(); it != end; ++it) 4467 (*it)->resetFormOwner(form); 4468 } 4469 4470 void Document::setUseSecureKeyboardEntryWhenActive(bool usesSecureKeyboard) 4471 { 4472 if (m_useSecureKeyboardEntryWhenActive == usesSecureKeyboard) 4473 return; 4474 4475 m_useSecureKeyboardEntryWhenActive = usesSecureKeyboard; 4476 m_frame->selection()->updateSecureKeyboardEntryIfActive(); 4477 } 4478 4479 bool Document::useSecureKeyboardEntryWhenActive() const 4480 { 4481 return m_useSecureKeyboardEntryWhenActive; 4482 } 4483 4484 void Document::initSecurityContext() 4485 { 4486 if (securityOrigin() && !securityOrigin()->isEmpty()) 4487 return; // m_securityOrigin has already been initialized. 4488 4489 if (!m_frame) { 4490 // No source for a security context. 4491 // This can occur via document.implementation.createDocument(). 4492 m_cookieURL = KURL(ParsedURLString, ""); 4493 ScriptExecutionContext::setSecurityOrigin(SecurityOrigin::createEmpty()); 4494 m_contentSecurityPolicy = ContentSecurityPolicy::create(); 4495 return; 4496 } 4497 4498 // In the common case, create the security context from the currently 4499 // loading URL with a fresh content security policy. 4500 m_cookieURL = m_url; 4501 ScriptExecutionContext::setSecurityOrigin(SecurityOrigin::create(m_url, m_frame->loader()->sandboxFlags())); 4502 m_contentSecurityPolicy = ContentSecurityPolicy::create(securityOrigin()); 4503 4504 if (SecurityOrigin::allowSubstituteDataAccessToLocal()) { 4505 // If this document was loaded with substituteData, then the document can 4506 // load local resources. See https://bugs.webkit.org/show_bug.cgi?id=16756 4507 // and https://bugs.webkit.org/show_bug.cgi?id=19760 for further 4508 // discussion. 4509 4510 DocumentLoader* documentLoader = loader(); 4511 if (documentLoader && documentLoader->substituteData().isValid()) 4512 securityOrigin()->grantLoadLocalResources(); 4513 } 4514 4515 if (Settings* settings = this->settings()) { 4516 if (!settings->isWebSecurityEnabled()) { 4517 // Web security is turned off. We should let this document access every 4518 // other document. This is used primary by testing harnesses for web 4519 // sites. 4520 securityOrigin()->grantUniversalAccess(); 4521 4522 } else if (settings->allowUniversalAccessFromFileURLs() && securityOrigin()->isLocal()) { 4523 // Some clients want file:// URLs to have universal access, but that 4524 // setting is dangerous for other clients. 4525 securityOrigin()->grantUniversalAccess(); 4526 } else if (!settings->allowFileAccessFromFileURLs() && securityOrigin()->isLocal()) { 4527 // Some clients want file:// URLs to have even tighter restrictions by 4528 // default, and not be able to access other local files. 4529 securityOrigin()->enforceFilePathSeparation(); 4530 } 4531 } 4532 4533 if (!securityOrigin()->isEmpty()) 4534 return; 4535 4536 // If we do not obtain a meaningful origin from the URL, then we try to 4537 // find one via the frame hierarchy. 4538 4539 Frame* ownerFrame = m_frame->tree()->parent(); 4540 if (!ownerFrame) 4541 ownerFrame = m_frame->loader()->opener(); 4542 4543 if (ownerFrame) { 4544 m_cookieURL = ownerFrame->document()->cookieURL(); 4545 // We alias the SecurityOrigins to match Firefox, see Bug 15313 4546 // https://bugs.webkit.org/show_bug.cgi?id=15313 4547 ScriptExecutionContext::setSecurityOrigin(ownerFrame->document()->securityOrigin()); 4548 // FIXME: Consider moving m_contentSecurityPolicy into SecurityOrigin. 4549 m_contentSecurityPolicy = ownerFrame->document()->contentSecurityPolicy(); 4550 } 4551 } 4552 4553 void Document::setSecurityOrigin(SecurityOrigin* securityOrigin) 4554 { 4555 ScriptExecutionContext::setSecurityOrigin(securityOrigin); 4556 // FIXME: Find a better place to enable DNS prefetch, which is a loader concept, 4557 // not applicable to arbitrary documents. 4558 initDNSPrefetch(); 4559 } 4560 4561 #if ENABLE(DATABASE) 4562 4563 bool Document::allowDatabaseAccess() const 4564 { 4565 if (!page() || page()->settings()->privateBrowsingEnabled()) 4566 return false; 4567 return true; 4568 } 4569 4570 void Document::databaseExceededQuota(const String& name) 4571 { 4572 Page* currentPage = page(); 4573 if (currentPage) 4574 currentPage->chrome()->client()->exceededDatabaseQuota(document()->frame(), name); 4575 } 4576 4577 #endif 4578 4579 bool Document::isContextThread() const 4580 { 4581 return isMainThread(); 4582 } 4583 4584 void Document::updateURLForPushOrReplaceState(const KURL& url) 4585 { 4586 Frame* f = frame(); 4587 if (!f) 4588 return; 4589 4590 setURL(url); 4591 f->loader()->setOutgoingReferrer(url); 4592 4593 if (DocumentLoader* documentLoader = loader()) 4594 documentLoader->replaceRequestURLForSameDocumentNavigation(url); 4595 } 4596 4597 void Document::statePopped(SerializedScriptValue* stateObject) 4598 { 4599 if (!frame()) 4600 return; 4601 4602 // Per step 11 of section 6.5.9 (history traversal) of the HTML5 spec, we 4603 // defer firing of popstate until we're in the complete state. 4604 if (m_readyState == Complete) 4605 enqueuePopstateEvent(stateObject); 4606 else 4607 m_pendingStateObject = stateObject; 4608 } 4609 4610 void Document::updateFocusAppearanceSoon(bool restorePreviousSelection) 4611 { 4612 m_updateFocusAppearanceRestoresSelection = restorePreviousSelection; 4613 if (!m_updateFocusAppearanceTimer.isActive()) 4614 m_updateFocusAppearanceTimer.startOneShot(0); 4615 } 4616 4617 void Document::cancelFocusAppearanceUpdate() 4618 { 4619 m_updateFocusAppearanceTimer.stop(); 4620 } 4621 4622 void Document::updateFocusAppearanceTimerFired(Timer<Document>*) 4623 { 4624 Node* node = focusedNode(); 4625 if (!node) 4626 return; 4627 if (!node->isElementNode()) 4628 return; 4629 4630 updateLayout(); 4631 4632 Element* element = static_cast<Element*>(node); 4633 if (element->isFocusable()) 4634 element->updateFocusAppearance(m_updateFocusAppearanceRestoresSelection); 4635 } 4636 4637 // FF method for accessing the selection added for compatibility. 4638 DOMSelection* Document::getSelection() const 4639 { 4640 return frame() ? frame()->domWindow()->getSelection() : 0; 4641 } 4642 4643 #if ENABLE(WML) 4644 void Document::resetWMLPageState() 4645 { 4646 if (WMLPageState* pageState = wmlPageStateForDocument(this)) 4647 pageState->reset(); 4648 } 4649 4650 void Document::initializeWMLPageState() 4651 { 4652 if (!isWMLDocument()) 4653 return; 4654 4655 static_cast<WMLDocument*>(this)->initialize(); 4656 } 4657 #endif 4658 4659 void Document::attachRange(Range* range) 4660 { 4661 ASSERT(!m_ranges.contains(range)); 4662 m_ranges.add(range); 4663 } 4664 4665 void Document::detachRange(Range* range) 4666 { 4667 // We don't ASSERT m_ranges.contains(range) to allow us to call this 4668 // unconditionally to fix: https://bugs.webkit.org/show_bug.cgi?id=26044 4669 m_ranges.remove(range); 4670 } 4671 4672 CanvasRenderingContext* Document::getCSSCanvasContext(const String& type, const String& name, int width, int height) 4673 { 4674 HTMLCanvasElement* result = getCSSCanvasElement(name); 4675 if (!result) 4676 return 0; 4677 result->setSize(IntSize(width, height)); 4678 return result->getContext(type); 4679 } 4680 4681 HTMLCanvasElement* Document::getCSSCanvasElement(const String& name) 4682 { 4683 RefPtr<HTMLCanvasElement> result = m_cssCanvasElements.get(name).get(); 4684 if (!result) { 4685 result = HTMLCanvasElement::create(this); 4686 m_cssCanvasElements.set(name, result); 4687 } 4688 return result.get(); 4689 } 4690 4691 void Document::initDNSPrefetch() 4692 { 4693 Settings* settings = this->settings(); 4694 4695 m_haveExplicitlyDisabledDNSPrefetch = false; 4696 m_isDNSPrefetchEnabled = settings && settings->dnsPrefetchingEnabled() && securityOrigin()->protocol() == "http"; 4697 4698 // Inherit DNS prefetch opt-out from parent frame 4699 if (Document* parent = parentDocument()) { 4700 if (!parent->isDNSPrefetchEnabled()) 4701 m_isDNSPrefetchEnabled = false; 4702 } 4703 } 4704 4705 void Document::parseDNSPrefetchControlHeader(const String& dnsPrefetchControl) 4706 { 4707 if (equalIgnoringCase(dnsPrefetchControl, "on") && !m_haveExplicitlyDisabledDNSPrefetch) { 4708 m_isDNSPrefetchEnabled = true; 4709 return; 4710 } 4711 4712 m_isDNSPrefetchEnabled = false; 4713 m_haveExplicitlyDisabledDNSPrefetch = true; 4714 } 4715 4716 void Document::addMessage(MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceURL, PassRefPtr<ScriptCallStack> callStack) 4717 { 4718 if (DOMWindow* window = domWindow()) 4719 window->console()->addMessage(source, type, level, message, lineNumber, sourceURL, callStack); 4720 } 4721 4722 struct PerformTaskContext { 4723 WTF_MAKE_NONCOPYABLE(PerformTaskContext); WTF_MAKE_FAST_ALLOCATED; 4724 public: 4725 PerformTaskContext(PassRefPtr<DocumentWeakReference> documentReference, PassOwnPtr<ScriptExecutionContext::Task> task) 4726 : documentReference(documentReference) 4727 , task(task) 4728 { 4729 } 4730 4731 RefPtr<DocumentWeakReference> documentReference; 4732 OwnPtr<ScriptExecutionContext::Task> task; 4733 }; 4734 4735 static void performTask(void* ctx) 4736 { 4737 ASSERT(isMainThread()); 4738 4739 PerformTaskContext* context = reinterpret_cast<PerformTaskContext*>(ctx); 4740 ASSERT(context); 4741 4742 if (Document* document = context->documentReference->document()) 4743 context->task->performTask(document); 4744 4745 delete context; 4746 } 4747 4748 void Document::postTask(PassOwnPtr<Task> task) 4749 { 4750 callOnMainThread(performTask, new PerformTaskContext(m_weakReference, task)); 4751 } 4752 4753 void Document::suspendScriptedAnimationControllerCallbacks() 4754 { 4755 #if ENABLE(REQUEST_ANIMATION_FRAME) 4756 if (m_scriptedAnimationController) 4757 m_scriptedAnimationController->suspend(); 4758 #endif 4759 } 4760 4761 void Document::resumeScriptedAnimationControllerCallbacks() 4762 { 4763 #if ENABLE(REQUEST_ANIMATION_FRAME) 4764 if (m_scriptedAnimationController) 4765 m_scriptedAnimationController->resume(); 4766 #endif 4767 } 4768 4769 String Document::displayStringModifiedByEncoding(const String& str) const 4770 { 4771 if (m_decoder) 4772 return m_decoder->encoding().displayString(str.impl()); 4773 return str; 4774 } 4775 4776 PassRefPtr<StringImpl> Document::displayStringModifiedByEncoding(PassRefPtr<StringImpl> str) const 4777 { 4778 if (m_decoder) 4779 return m_decoder->encoding().displayString(str); 4780 return str; 4781 } 4782 4783 void Document::displayBufferModifiedByEncoding(UChar* buffer, unsigned len) const 4784 { 4785 if (m_decoder) 4786 m_decoder->encoding().displayBuffer(buffer, len); 4787 } 4788 4789 void Document::enqueuePageshowEvent(PageshowEventPersistence persisted) 4790 { 4791 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=36334 Pageshow event needs to fire asynchronously. 4792 dispatchWindowEvent(PageTransitionEvent::create(eventNames().pageshowEvent, persisted), this); 4793 } 4794 4795 void Document::enqueueHashchangeEvent(const String& oldURL, const String& newURL) 4796 { 4797 enqueueWindowEvent(HashChangeEvent::create(oldURL, newURL)); 4798 } 4799 4800 void Document::enqueuePopstateEvent(PassRefPtr<SerializedScriptValue> stateObject) 4801 { 4802 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=36202 Popstate event needs to fire asynchronously 4803 dispatchWindowEvent(PopStateEvent::create(stateObject)); 4804 } 4805 4806 void Document::addMediaCanStartListener(MediaCanStartListener* listener) 4807 { 4808 ASSERT(!m_mediaCanStartListeners.contains(listener)); 4809 m_mediaCanStartListeners.add(listener); 4810 } 4811 4812 void Document::removeMediaCanStartListener(MediaCanStartListener* listener) 4813 { 4814 ASSERT(m_mediaCanStartListeners.contains(listener)); 4815 m_mediaCanStartListeners.remove(listener); 4816 } 4817 4818 MediaCanStartListener* Document::takeAnyMediaCanStartListener() 4819 { 4820 HashSet<MediaCanStartListener*>::iterator slot = m_mediaCanStartListeners.begin(); 4821 if (slot == m_mediaCanStartListeners.end()) 4822 return 0; 4823 MediaCanStartListener* listener = *slot; 4824 m_mediaCanStartListeners.remove(slot); 4825 return listener; 4826 } 4827 4828 #if ENABLE(XHTMLMP) 4829 bool Document::isXHTMLMPDocument() const 4830 { 4831 if (!frame() || !frame()->loader()) 4832 return false; 4833 // As per section 7.2 of OMA-WAP-XHTMLMP-V1_1-20061020-A.pdf, a conforming user agent 4834 // MUST accept XHTMLMP document identified as "application/vnd.wap.xhtml+xml" 4835 // and SHOULD accept it identified as "application/xhtml+xml" , "application/xhtml+xml" is a 4836 // general MIME type for all XHTML documents, not only for XHTMLMP 4837 return loader()->writer()->mimeType() == "application/vnd.wap.xhtml+xml"; 4838 } 4839 #endif 4840 4841 #if ENABLE(FULLSCREEN_API) 4842 bool Document::fullScreenIsAllowedForElement(Element* element) const 4843 { 4844 ASSERT(element); 4845 while (HTMLFrameOwnerElement* ownerElement = element->document()->ownerElement()) { 4846 if (!ownerElement->hasTagName(frameTag) && !ownerElement->hasTagName(iframeTag)) 4847 continue; 4848 4849 if (!static_cast<HTMLFrameElementBase*>(ownerElement)->allowFullScreen()) 4850 return false; 4851 element = ownerElement; 4852 } 4853 return true; 4854 } 4855 4856 void Document::webkitRequestFullScreenForElement(Element* element, unsigned short flags) 4857 { 4858 if (!page() || !page()->settings()->fullScreenEnabled()) 4859 return; 4860 4861 if (!element) 4862 element = documentElement(); 4863 4864 if (!fullScreenIsAllowedForElement(element)) 4865 return; 4866 4867 if (!ScriptController::processingUserGesture()) 4868 return; 4869 4870 if (!page()->chrome()->client()->supportsFullScreenForElement(element, flags & Element::ALLOW_KEYBOARD_INPUT)) 4871 return; 4872 4873 m_areKeysEnabledInFullScreen = flags & Element::ALLOW_KEYBOARD_INPUT; 4874 page()->chrome()->client()->enterFullScreenForElement(element); 4875 } 4876 4877 void Document::webkitCancelFullScreen() 4878 { 4879 if (!page() || !m_fullScreenElement) 4880 return; 4881 4882 page()->chrome()->client()->exitFullScreenForElement(m_fullScreenElement.get()); 4883 #if PLATFORM(ANDROID) 4884 // The next time we try to enter full screen, we need this change to know 4885 // we are not in full screen any more. 4886 m_fullScreenElement = 0; 4887 #endif 4888 } 4889 4890 void Document::webkitWillEnterFullScreenForElement(Element* element) 4891 { 4892 ASSERT(element); 4893 ASSERT(page() && page()->settings()->fullScreenEnabled()); 4894 4895 m_fullScreenElement = element; 4896 4897 #if PLATFORM(ANDROID) 4898 // Our approach on Poster handling is android specific: we are passing the 4899 // poster from java side to native and we can't keep the content if the 4900 // video element is detached and its RenderLayer object is deleted. 4901 if(!(m_fullScreenElement->hasTagName(HTMLNames::videoTag))) { 4902 #endif 4903 if (m_fullScreenElement != documentElement()) 4904 m_fullScreenElement->detach(); 4905 4906 recalcStyle(Force); 4907 #if PLATFORM(ANDROID) 4908 } 4909 #endif 4910 4911 if (m_fullScreenRenderer) { 4912 m_fullScreenRenderer->setAnimating(true); 4913 #if USE(ACCELERATED_COMPOSITING) 4914 view()->updateCompositingLayers(); 4915 #if PLATFORM(ANDROID) 4916 if (!m_fullScreenRenderer->layer()) 4917 return; 4918 #endif 4919 if (m_fullScreenRenderer->layer()->isComposited()) 4920 page()->chrome()->client()->setRootFullScreenLayer(m_fullScreenRenderer->layer()->backing()->graphicsLayer()); 4921 #endif 4922 } 4923 } 4924 4925 void Document::webkitDidEnterFullScreenForElement(Element*) 4926 { 4927 if (m_fullScreenRenderer) { 4928 m_fullScreenRenderer->setAnimating(false); 4929 #if USE(ACCELERATED_COMPOSITING) 4930 view()->updateCompositingLayers(); 4931 page()->chrome()->client()->setRootFullScreenLayer(0); 4932 #endif 4933 } 4934 m_fullScreenChangeDelayTimer.startOneShot(0); 4935 } 4936 4937 void Document::webkitWillExitFullScreenForElement(Element*) 4938 { 4939 if (m_fullScreenRenderer) { 4940 m_fullScreenRenderer->setAnimating(true); 4941 #if USE(ACCELERATED_COMPOSITING) 4942 view()->updateCompositingLayers(); 4943 if (m_fullScreenRenderer->layer()->isComposited()) 4944 page()->chrome()->client()->setRootFullScreenLayer(m_fullScreenRenderer->layer()->backing()->graphicsLayer()); 4945 #endif 4946 } 4947 } 4948 4949 void Document::webkitDidExitFullScreenForElement(Element*) 4950 { 4951 m_areKeysEnabledInFullScreen = false; 4952 4953 if (m_fullScreenRenderer) 4954 m_fullScreenRenderer->remove(); 4955 4956 if (m_fullScreenElement != documentElement()) 4957 m_fullScreenElement->detach(); 4958 4959 m_fullScreenElement = 0; 4960 setFullScreenRenderer(0); 4961 #if USE(ACCELERATED_COMPOSITING) 4962 page()->chrome()->client()->setRootFullScreenLayer(0); 4963 #endif 4964 recalcStyle(Force); 4965 4966 m_fullScreenChangeDelayTimer.startOneShot(0); 4967 } 4968 4969 void Document::setFullScreenRenderer(RenderFullScreen* renderer) 4970 { 4971 if (renderer == m_fullScreenRenderer) 4972 return; 4973 4974 if (m_fullScreenRenderer) 4975 m_fullScreenRenderer->destroy(); 4976 m_fullScreenRenderer = renderer; 4977 4978 // This notification can come in after the page has been destroyed. 4979 if (page()) 4980 page()->chrome()->client()->fullScreenRendererChanged(m_fullScreenRenderer); 4981 } 4982 4983 void Document::setFullScreenRendererSize(const IntSize& size) 4984 { 4985 ASSERT(m_fullScreenRenderer); 4986 if (!m_fullScreenRenderer) 4987 return; 4988 4989 if (m_fullScreenRenderer) { 4990 RefPtr<RenderStyle> newStyle = RenderStyle::clone(m_fullScreenRenderer->style()); 4991 newStyle->setWidth(Length(size.width(), WebCore::Fixed)); 4992 newStyle->setHeight(Length(size.height(), WebCore::Fixed)); 4993 newStyle->setTop(Length(0, WebCore::Fixed)); 4994 newStyle->setLeft(Length(0, WebCore::Fixed)); 4995 m_fullScreenRenderer->setStyle(newStyle); 4996 updateLayout(); 4997 } 4998 } 4999 5000 void Document::setFullScreenRendererBackgroundColor(Color backgroundColor) 5001 { 5002 if (!m_fullScreenRenderer) 5003 return; 5004 5005 RefPtr<RenderStyle> newStyle = RenderStyle::clone(m_fullScreenRenderer->style()); 5006 newStyle->setBackgroundColor(backgroundColor); 5007 m_fullScreenRenderer->setStyle(newStyle); 5008 } 5009 5010 void Document::fullScreenChangeDelayTimerFired(Timer<Document>*) 5011 { 5012 Element* element = m_fullScreenElement.get(); 5013 if (!element) 5014 element = documentElement(); 5015 5016 element->dispatchEvent(Event::create(eventNames().webkitfullscreenchangeEvent, true, false)); 5017 } 5018 5019 #endif 5020 5021 void Document::decrementLoadEventDelayCount() 5022 { 5023 ASSERT(m_loadEventDelayCount); 5024 --m_loadEventDelayCount; 5025 5026 if (frame() && !m_loadEventDelayCount && !m_loadEventDelayTimer.isActive()) 5027 m_loadEventDelayTimer.startOneShot(0); 5028 } 5029 5030 void Document::loadEventDelayTimerFired(Timer<Document>*) 5031 { 5032 if (frame()) 5033 frame()->loader()->checkCompleted(); 5034 } 5035 5036 #if ENABLE(REQUEST_ANIMATION_FRAME) 5037 int Document::webkitRequestAnimationFrame(PassRefPtr<RequestAnimationFrameCallback> callback, Element* animationElement) 5038 { 5039 if (!m_scriptedAnimationController) 5040 m_scriptedAnimationController = ScriptedAnimationController::create(this); 5041 5042 return m_scriptedAnimationController->registerCallback(callback, animationElement); 5043 } 5044 5045 void Document::webkitCancelRequestAnimationFrame(int id) 5046 { 5047 if (!m_scriptedAnimationController) 5048 return; 5049 m_scriptedAnimationController->cancelCallback(id); 5050 } 5051 5052 void Document::serviceScriptedAnimations(DOMTimeStamp time) 5053 { 5054 if (!m_scriptedAnimationController) 5055 return; 5056 m_scriptedAnimationController->serviceScriptedAnimations(time); 5057 } 5058 #endif 5059 5060 #if ENABLE(TOUCH_EVENTS) 5061 PassRefPtr<Touch> Document::createTouch(DOMWindow* window, EventTarget* target, int identifier, int pageX, int pageY, int screenX, int screenY, ExceptionCode&) const 5062 { 5063 // FIXME: It's not clear from the documentation at 5064 // http://developer.apple.com/library/safari/#documentation/UserExperience/Reference/DocumentAdditionsReference/DocumentAdditions/DocumentAdditions.html 5065 // when this method should throw and nor is it by inspection of iOS behavior. It would be nice to verify any cases where it throws under iOS 5066 // and implement them here. See https://bugs.webkit.org/show_bug.cgi?id=47819 5067 Frame* frame = window ? window->frame() : this->frame(); 5068 return Touch::create(frame, target, identifier, screenX, screenY, pageX, pageY); 5069 } 5070 #endif 5071 5072 DocumentLoader* Document::loader() const 5073 { 5074 if (!m_frame) 5075 return 0; 5076 5077 DocumentLoader* loader = m_frame->loader()->activeDocumentLoader(); 5078 if (!loader) 5079 return 0; 5080 5081 #if PLATFORM(ANDROID) 5082 // Temporary hack for http://b/5188895 5083 bool isDocumentUpToDate = m_frame->isDocumentUpToDate(); 5084 #else 5085 bool isDocumentUpToDate = true; 5086 #endif 5087 if (isDocumentUpToDate && m_frame->document() != this) 5088 return 0; 5089 5090 return loader; 5091 } 5092 5093 } // namespace WebCore 5094