2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * (C) 2006 Alexey Proskuryakov (ap@webkit.org)
6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 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)
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.
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.
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.
30 #include "AXObjectCache.h"
31 #include "AnimationController.h"
32 #include "AsyncScriptRunner.h"
34 #include "Attribute.h"
35 #include "CDATASection.h"
36 #include "CSSStyleSelector.h"
37 #include "CSSStyleSheet.h"
38 #include "CSSValueKeywords.h"
39 #include "CachedCSSStyleSheet.h"
40 #include "CachedResourceLoader.h"
42 #include "ChromeClient.h"
45 #include "CookieJar.h"
46 #include "CustomEvent.h"
47 #include "DateComponents.h"
48 #include "DOMImplementation.h"
49 #include "DOMWindow.h"
50 #include "DeviceMotionEvent.h"
51 #include "DeviceOrientationEvent.h"
52 #include "DocumentFragment.h"
53 #include "DocumentLoader.h"
54 #include "DocumentMarkerController.h"
55 #include "DocumentType.h"
56 #include "EditingText.h"
58 #include "EntityReference.h"
60 #include "EventHandler.h"
61 #include "EventListener.h"
62 #include "EventNames.h"
63 #include "EventQueue.h"
64 #include "ExceptionCode.h"
65 #include "FocusController.h"
66 #include "FormAssociatedElement.h"
68 #include "FrameLoader.h"
69 #include "FrameLoaderClient.h"
70 #include "FrameTree.h"
71 #include "FrameView.h"
72 #include "HashChangeEvent.h"
73 #include "HTMLAllCollection.h"
74 #include "HTMLAnchorElement.h"
75 #include "HTMLBodyElement.h"
76 #include "HTMLCanvasElement.h"
77 #include "HTMLCollection.h"
78 #include "HTMLDocument.h"
79 #include "HTMLElementFactory.h"
80 #include "HTMLFrameOwnerElement.h"
81 #include "HTMLHeadElement.h"
82 #include "HTMLIFrameElement.h"
83 #include "HTMLInputElement.h"
84 #include "HTMLLinkElement.h"
85 #include "HTMLMapElement.h"
86 #include "HTMLNameCollection.h"
87 #include "HTMLNames.h"
88 #include "HTMLParserIdioms.h"
89 #include "HTMLStyleElement.h"
90 #include "HTMLTitleElement.h"
91 #include "HTTPParsers.h"
92 #include "HitTestRequest.h"
93 #include "HitTestResult.h"
94 #include "ImageLoader.h"
95 #include "InspectorController.h"
96 #include "InspectorInstrumentation.h"
97 #include "KeyboardEvent.h"
99 #include "MediaQueryList.h"
100 #include "MediaQueryMatcher.h"
101 #include "MessageEvent.h"
102 #include "MouseEvent.h"
103 #include "MouseEventWithHitTestResults.h"
104 #include "MutationEvent.h"
105 #include "NameNodeList.h"
106 #include "NodeFilter.h"
107 #include "NodeIterator.h"
108 #include "NodeWithIndex.h"
109 #include "OverflowEvent.h"
111 #include "PageGroup.h"
112 #include "PageTransitionEvent.h"
113 #include "PlatformKeyboardEvent.h"
114 #include "PopStateEvent.h"
115 #include "ProcessingInstruction.h"
116 #include "ProgressEvent.h"
117 #include "RegisteredEventListener.h"
118 #include "RenderArena.h"
119 #include "RenderLayer.h"
120 #include "RenderTextControl.h"
121 #include "RenderView.h"
122 #include "RenderWidget.h"
123 #include "ScriptController.h"
124 #include "ScriptElement.h"
125 #include "ScriptEventListener.h"
126 #include "SecurityOrigin.h"
127 #include "SegmentedString.h"
128 #include "SelectionController.h"
129 #include "Settings.h"
130 #include "StaticHashSetNodeList.h"
131 #include "StyleSheetList.h"
132 #include "TextEvent.h"
133 #include "TextResourceDecoder.h"
135 #include "TransformSource.h"
136 #include "TreeWalker.h"
138 #include "UserContentURLPattern.h"
139 #include "WebKitAnimationEvent.h"
140 #include "WebKitTransitionEvent.h"
141 #include "WheelEvent.h"
142 #include "XMLDocumentParser.h"
143 #include "XMLHttpRequest.h"
144 #include "XMLNSNames.h"
145 #include "XMLNames.h"
146 #include "XSSAuditor.h"
147 #include "htmlediting.h"
148 #include <wtf/CurrentTime.h>
149 #include <wtf/HashFunctions.h>
150 #include <wtf/MainThread.h>
151 #include <wtf/PassRefPtr.h>
152 #include <wtf/StdLibExtras.h>
153 #include <wtf/text/StringBuffer.h>
155 #if ENABLE(SHARED_WORKERS)
156 #include "SharedWorkerRepository.h"
159 #if ENABLE(DOM_STORAGE)
160 #include "StorageEvent.h"
164 #include "XPathEvaluator.h"
165 #include "XPathExpression.h"
166 #include "XPathNSResolver.h"
167 #include "XPathResult.h"
171 #include "XSLTProcessor.h"
175 #include "SVGDocumentExtensions.h"
176 #include "SVGElementFactory.h"
177 #include "SVGNames.h"
178 #include "SVGStyleElement.h"
179 #include "SVGZoomEvent.h"
182 #if ENABLE(TOUCH_EVENTS)
184 #include "RuntimeEnabledFeatures.h"
186 #include "TouchEvent.h"
190 #include "WMLDocument.h"
191 #include "WMLElement.h"
192 #include "WMLElementFactory.h"
193 #include "WMLNames.h"
197 #include "MathMLElement.h"
198 #include "MathMLElementFactory.h"
199 #include "MathMLNames.h"
203 #include "HTMLNoScriptElement.h"
206 #if ENABLE(FULLSCREEN_API)
207 #include "RenderFullScreen.h"
212 using namespace Unicode;
216 using namespace HTMLNames;
218 // #define INSTRUMENT_LAYOUT_SCHEDULING 1
220 // This amount of time must have elapsed before we will even consider scheduling a layout without a delay.
221 // FIXME: For faster machines this value can really be lowered to 200. 250 is adequate, but a little high
223 static const int cLayoutScheduleThreshold = 250;
225 // These functions can't have internal linkage because they are used as template arguments.
226 bool keyMatchesId(AtomicStringImpl*, Element*);
227 bool keyMatchesMapName(AtomicStringImpl*, Element*);
228 bool keyMatchesLowercasedMapName(AtomicStringImpl*, Element*);
230 // DOM Level 2 says (letters added):
232 // a) Name start characters must have one of the categories Ll, Lu, Lo, Lt, Nl.
233 // b) Name characters other than Name-start characters must have one of the categories Mc, Me, Mn, Lm, or Nd.
234 // c) Characters in the compatibility area (i.e. with character code greater than #xF900 and less than #xFFFE) are not allowed in XML names.
235 // 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.
236 // 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.
237 // f) Characters #x20DD-#x20E0 are excluded (in accordance with Unicode, section 5.14).
238 // g) Character #x00B7 is classified as an extender, because the property list so identifies it.
239 // h) Character #x0387 is added as a name character, because #x00B7 is its canonical equivalent.
240 // i) Characters ':' and '_' are allowed as name-start characters.
241 // j) Characters '-' and '.' are allowed as name characters.
243 // It also contains complete tables. If we decide it's better, we could include those instead of the following code.
245 static inline bool isValidNameStart(UChar32 c)
248 if ((c >= 0x02BB && c <= 0x02C1) || c == 0x559 || c == 0x6E5 || c == 0x6E6)
252 if (c == ':' || c == '_')
255 // rules (a) and (f) above
256 const uint32_t nameStartMask = Letter_Lowercase | Letter_Uppercase | Letter_Other | Letter_Titlecase | Number_Letter;
257 if (!(Unicode::category(c) & nameStartMask))
261 if (c >= 0xF900 && c < 0xFFFE)
265 DecompositionType decompType = decompositionType(c);
266 if (decompType == DecompositionFont || decompType == DecompositionCompat)
272 static inline bool isValidNamePart(UChar32 c)
274 // rules (a), (e), and (i) above
275 if (isValidNameStart(c))
278 // rules (g) and (h) above
279 if (c == 0x00B7 || c == 0x0387)
283 if (c == '-' || c == '.')
286 // rules (b) and (f) above
287 const uint32_t otherNamePartMask = Mark_NonSpacing | Mark_Enclosing | Mark_SpacingCombining | Letter_Modifier | Number_DecimalDigit;
288 if (!(Unicode::category(c) & otherNamePartMask))
292 if (c >= 0xF900 && c < 0xFFFE)
296 DecompositionType decompType = decompositionType(c);
297 if (decompType == DecompositionFont || decompType == DecompositionCompat)
303 static Widget* widgetForNode(Node* focusedNode)
307 RenderObject* renderer = focusedNode->renderer();
308 if (!renderer || !renderer->isWidget())
310 return toRenderWidget(renderer)->widget();
313 static bool acceptsEditingFocus(Node* node)
316 ASSERT(node->isContentEditable());
318 Node* root = node->rootEditableElement();
319 Frame* frame = node->document()->frame();
323 return frame->editor()->shouldBeginEditing(rangeOfContents(root).get());
326 static bool disableRangeMutation(Page* page)
329 // Disable Range mutation on document modifications in Tiger and Leopard Mail
330 // See <rdar://problem/5865171>
331 return page && (page->settings()->needsLeopardMailQuirks() || page->settings()->needsTigerMailQuirks());
337 static HashSet<Document*>* documentsThatNeedStyleRecalc = 0;
339 class DocumentWeakReference : public ThreadSafeShared<DocumentWeakReference> {
341 static PassRefPtr<DocumentWeakReference> create(Document* document)
343 return adoptRef(new DocumentWeakReference(document));
348 ASSERT(isMainThread());
354 ASSERT(isMainThread());
359 DocumentWeakReference(Document* document)
360 : m_document(document)
362 ASSERT(isMainThread());
365 Document* m_document;
368 Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML, const KURL& baseURL)
370 , m_compatibilityMode(NoQuirksMode)
371 , m_compatibilityModeLocked(false)
372 , m_domTreeVersion(0)
373 , m_styleSheets(StyleSheetList::create(this))
374 , m_readyState(Complete)
375 , m_styleRecalcTimer(this, &Document::styleRecalcTimerFired)
376 , m_pendingStyleRecalcShouldForce(false)
377 , m_frameElementsShouldIgnoreScrolling(false)
378 , m_containsValidityStyleRules(false)
379 , m_updateFocusAppearanceRestoresSelection(false)
380 , m_ignoreDestructiveWriteCount(0)
383 , m_titleSetExplicitly(false)
384 , m_updateFocusAppearanceTimer(this, &Document::updateFocusAppearanceTimerFired)
385 , m_startTime(currentTime())
386 , m_overMinimumLayoutThreshold(false)
387 , m_extraLayoutDelay(0)
388 , m_asyncScriptRunner(AsyncScriptRunner::create(this))
389 , m_xmlVersion("1.0")
390 , m_xmlStandalone(false)
392 , m_designMode(inherit)
393 , m_selfOnlyRefCount(0)
397 #if ENABLE(DASHBOARD_SUPPORT)
398 , m_hasDashboardRegions(false)
399 , m_dashboardRegionsDirty(false)
401 , m_accessKeyMapValid(false)
402 , m_createRenderers(true)
403 , m_inPageCache(false)
404 , m_useSecureKeyboardEntryWhenActive(false)
407 , m_numNodeListCaches(0)
409 , m_normalWorldWrapperCache(0)
411 , m_usingGeolocation(false)
412 , m_eventQueue(adoptPtr(new EventQueue))
414 , m_containsWMLContent(false)
416 , m_weakReference(DocumentWeakReference::create(this))
417 , m_idAttributeName(idAttr)
418 #if ENABLE(FULLSCREEN_API)
420 , m_areKeysEnabledInFullScreen(0)
421 , m_fullScreenRenderer(0)
422 , m_fullScreenChangeDelayTimer(this, &Document::fullScreenChangeDelayTimerFired)
424 , m_loadEventDelayCount(0)
425 , m_loadEventDelayTimer(this, &Document::loadEventDelayTimerFired)
426 , m_directionSetOnDocumentElement(false)
427 , m_writingModeSetOnDocumentElement(false)
431 m_pageGroupUserSheetCacheValid = false;
434 m_paginatedForScreen = false;
436 m_ignoreAutofocus = false;
440 if (frame || !url.isEmpty())
443 // Setting of m_baseURL needs to happen after the setURL call, since that
444 // calls updateBaseURL, which would clobber the passed in value.
445 if (!baseURL.isNull())
450 m_markers = new DocumentMarkerController();
452 m_cachedResourceLoader = new CachedResourceLoader(this);
454 m_visuallyOrdered = false;
456 m_wellFormed = false;
458 m_textColor = Color::black;
461 m_inStyleRecalc = false;
462 m_closeAfterStyleRecalc = false;
464 m_usesDescendantRules = false;
465 m_usesSiblingRules = false;
466 m_usesFirstLineRules = false;
467 m_usesFirstLetterRules = false;
468 m_usesBeforeAfterRules = false;
469 m_usesRemUnits = false;
470 m_usesLinkRules = false;
472 m_gotoAnchorNeededAfterStylesheetsLoad = false;
474 m_didCalculateStyleSelector = false;
475 m_pendingStylesheets = 0;
476 m_ignorePendingStylesheets = false;
477 m_hasNodesWithPlaceholderStyle = false;
478 m_pendingSheetLayout = NoLayoutWithPendingSheets;
483 resetVisitedLinkColor();
484 resetActiveLinkColor();
486 m_processingLoadEvent = false;
488 initSecurityContext();
491 static int docID = 0;
494 m_shouldProcessNoScriptElement = !(m_frame && m_frame->script()->canExecuteScripts(NotAboutToExecuteScript));
498 inline void Document::DocumentOrderedMap::clear()
501 m_duplicateCounts.clear();
504 void Document::removedLastRef()
506 ASSERT(!m_deletionHasBegun);
507 if (m_selfOnlyRefCount) {
508 // If removing a child removes the last self-only ref, we don't
509 // want the document to be destructed until after
510 // removeAllChildren returns, so we guard ourselves with an
511 // extra self-only ref.
514 // We must make sure not to be retaining any of our children through
515 // these extra pointers or we will create a reference cycle.
521 m_documentElement = 0;
522 #if ENABLE(FULLSCREEN_API)
523 m_fullScreenElement = 0;
526 // removeAllChildren() doesn't always unregister IDs, do it upfront to avoid having stale references in the map.
527 m_elementsById.clear();
535 m_cssCanvasElements.clear();
538 m_inRemovedLastRefFunction = false;
544 m_deletionHasBegun = true;
550 Document::~Document()
553 ASSERT(!m_inPageCache);
554 ASSERT(!m_savedRenderer);
555 ASSERT(m_ranges.isEmpty());
556 ASSERT(!m_styleRecalcTimer.isActive());
558 m_asyncScriptRunner.clear();
560 removeAllEventListeners();
563 destroyAllWrapperCaches();
566 // Currently we believe that Document can never outlive the parser.
567 // Although the Document may be replaced synchronously, DocumentParsers
568 // generally keep at least one reference to an Element which would in turn
569 // has a reference to the Document. If you hit this ASSERT, then that
570 // assumption is wrong. DocumentParser::detach() should ensure that even
571 // if the DocumentParser outlives the Document it won't cause badness.
572 ASSERT(!m_parser || m_parser->refCount() == 1);
575 m_cachedResourceLoader.clear();
577 m_renderArena.clear();
579 clearAXObjectCache();
583 for (size_t i = 0; i < m_nameCollectionInfo.size(); ++i)
584 deleteAllValues(m_nameCollectionInfo[i]);
587 m_styleSheets->documentDestroyed();
590 m_elemSheet->clearOwnerNode();
591 if (m_mappedElementSheet)
592 m_mappedElementSheet->clearOwnerNode();
594 m_pageUserSheet->clearOwnerNode();
595 if (m_pageGroupUserSheets) {
596 for (size_t i = 0; i < m_pageGroupUserSheets->size(); ++i)
597 (*m_pageGroupUserSheets)[i]->clearOwnerNode();
600 m_weakReference->clear();
602 if (m_mediaQueryMatcher)
603 m_mediaQueryMatcher->documentDestroyed();
606 MediaQueryMatcher* Document::mediaQueryMatcher()
608 if (!m_mediaQueryMatcher)
609 m_mediaQueryMatcher = MediaQueryMatcher::create(this);
610 return m_mediaQueryMatcher.get();
614 Document::JSWrapperCache* Document::createWrapperCache(DOMWrapperWorld* world)
616 JSWrapperCache* wrapperCache = new JSWrapperCache;
617 m_wrapperCacheMap.set(world, wrapperCache);
618 if (world->isNormal()) {
619 ASSERT(!m_normalWorldWrapperCache);
620 m_normalWorldWrapperCache = wrapperCache;
622 world->didCreateWrapperCache(this);
626 void Document::destroyWrapperCache(DOMWrapperWorld* world)
628 Document::JSWrapperCache* wrappers = wrapperCacheMap().take(world);
631 world->didDestroyWrapperCache(this);
634 void Document::destroyAllWrapperCaches()
636 JSWrapperCacheMap& wrapperCacheMap = this->wrapperCacheMap();
637 while (!wrapperCacheMap.isEmpty())
638 destroyWrapperCache(wrapperCacheMap.begin()->first);
642 void Document::setCompatibilityMode(CompatibilityMode mode)
644 if (m_compatibilityModeLocked || mode == m_compatibilityMode)
646 ASSERT(!documentElement() && !m_styleSheets->length());
647 bool wasInQuirksMode = inQuirksMode();
648 m_compatibilityMode = mode;
649 if (inQuirksMode() != wasInQuirksMode) {
650 // All user stylesheets have to reparse using the different mode.
651 clearPageUserSheet();
652 clearPageGroupUserSheets();
656 String Document::compatMode() const
658 return inQuirksMode() ? "BackCompat" : "CSS1Compat";
661 void Document::resetLinkColor()
663 m_linkColor = Color(0, 0, 238);
666 void Document::resetVisitedLinkColor()
668 m_visitedLinkColor = Color(85, 26, 139);
671 void Document::resetActiveLinkColor()
673 m_activeLinkColor.setNamedColor("red");
676 void Document::setDocType(PassRefPtr<DocumentType> docType)
678 // This should never be called more than once.
679 ASSERT(!m_docType || !docType);
682 m_docType->setDocument(this);
685 DOMImplementation* Document::implementation() const
687 if (!m_implementation)
688 m_implementation = DOMImplementation::create();
689 return m_implementation.get();
692 void Document::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
694 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
696 // Invalidate the document element we have cached in case it was replaced.
697 m_documentElement = 0;
700 void Document::cacheDocumentElement() const
702 ASSERT(!m_documentElement);
703 Node* n = firstChild();
704 while (n && !n->isElementNode())
705 n = n->nextSibling();
706 m_documentElement = static_cast<Element*>(n);
709 PassRefPtr<Element> Document::createElement(const AtomicString& name, ExceptionCode& ec)
711 if (!isValidName(name)) {
712 ec = INVALID_CHARACTER_ERR;
717 return HTMLElementFactory::createHTMLElement(QualifiedName(nullAtom, name, xhtmlNamespaceURI), this, 0, false);
719 return createElement(QualifiedName(nullAtom, name, nullAtom), false);
722 PassRefPtr<DocumentFragment> Document::createDocumentFragment()
724 return DocumentFragment::create(document());
727 PassRefPtr<Text> Document::createTextNode(const String& data)
729 return Text::create(this, data);
732 PassRefPtr<Comment> Document::createComment(const String& data)
734 return Comment::create(this, data);
737 PassRefPtr<CDATASection> Document::createCDATASection(const String& data, ExceptionCode& ec)
739 if (isHTMLDocument()) {
740 ec = NOT_SUPPORTED_ERR;
743 return CDATASection::create(this, data);
746 PassRefPtr<ProcessingInstruction> Document::createProcessingInstruction(const String& target, const String& data, ExceptionCode& ec)
748 if (!isValidName(target)) {
749 ec = INVALID_CHARACTER_ERR;
752 if (isHTMLDocument()) {
753 ec = NOT_SUPPORTED_ERR;
756 return ProcessingInstruction::create(this, target, data);
759 PassRefPtr<EntityReference> Document::createEntityReference(const String& name, ExceptionCode& ec)
761 if (!isValidName(name)) {
762 ec = INVALID_CHARACTER_ERR;
765 if (isHTMLDocument()) {
766 ec = NOT_SUPPORTED_ERR;
769 return EntityReference::create(this, name);
772 PassRefPtr<EditingText> Document::createEditingTextNode(const String& text)
774 return EditingText::create(this, text);
777 PassRefPtr<CSSStyleDeclaration> Document::createCSSStyleDeclaration()
779 return CSSMutableStyleDeclaration::create();
782 PassRefPtr<Node> Document::importNode(Node* importedNode, bool deep, ExceptionCode& ec)
787 #if ENABLE(SVG) && ENABLE(DASHBOARD_SUPPORT)
788 || (importedNode->isSVGElement() && page() && page()->settings()->usesDashboardBackwardCompatibilityMode())
791 ec = NOT_SUPPORTED_ERR;
795 switch (importedNode->nodeType()) {
797 return createTextNode(importedNode->nodeValue());
798 case CDATA_SECTION_NODE:
799 return createCDATASection(importedNode->nodeValue(), ec);
800 case ENTITY_REFERENCE_NODE:
801 return createEntityReference(importedNode->nodeName(), ec);
802 case PROCESSING_INSTRUCTION_NODE:
803 return createProcessingInstruction(importedNode->nodeName(), importedNode->nodeValue(), ec);
805 return createComment(importedNode->nodeValue());
807 Element* oldElement = static_cast<Element*>(importedNode);
808 RefPtr<Element> newElement = createElementNS(oldElement->namespaceURI(), oldElement->tagQName().toString(), ec);
813 NamedNodeMap* attrs = oldElement->attributes(true);
815 unsigned length = attrs->length();
816 for (unsigned i = 0; i < length; i++) {
817 Attribute* attr = attrs->attributeItem(i);
818 newElement->setAttribute(attr->name(), attr->value().impl(), ec);
824 newElement->copyNonAttributeProperties(oldElement);
827 for (Node* oldChild = oldElement->firstChild(); oldChild; oldChild = oldChild->nextSibling()) {
828 RefPtr<Node> newChild = importNode(oldChild, true, ec);
831 newElement->appendChild(newChild.release(), ec);
837 return newElement.release();
840 return Attr::create(0, this, static_cast<Attr*>(importedNode)->attr()->clone());
841 case DOCUMENT_FRAGMENT_NODE: {
842 DocumentFragment* oldFragment = static_cast<DocumentFragment*>(importedNode);
843 RefPtr<DocumentFragment> newFragment = createDocumentFragment();
845 for (Node* oldChild = oldFragment->firstChild(); oldChild; oldChild = oldChild->nextSibling()) {
846 RefPtr<Node> newChild = importNode(oldChild, true, ec);
849 newFragment->appendChild(newChild.release(), ec);
855 return newFragment.release();
859 // 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.
860 // Ability to add these imported nodes to a DocumentType will be considered for addition to a future release of the DOM.
862 case DOCUMENT_TYPE_NODE:
863 case XPATH_NAMESPACE_NODE:
867 ec = NOT_SUPPORTED_ERR;
872 PassRefPtr<Node> Document::adoptNode(PassRefPtr<Node> source, ExceptionCode& ec)
875 ec = NOT_SUPPORTED_ERR;
879 if (source->isReadOnlyNode()) {
880 ec = NO_MODIFICATION_ALLOWED_ERR;
884 switch (source->nodeType()) {
888 case DOCUMENT_TYPE_NODE:
889 case XPATH_NAMESPACE_NODE:
890 ec = NOT_SUPPORTED_ERR;
892 case ATTRIBUTE_NODE: {
893 Attr* attr = static_cast<Attr*>(source.get());
894 if (attr->ownerElement())
895 attr->ownerElement()->removeAttributeNode(attr, ec);
896 attr->setSpecified(true);
900 if (source->hasTagName(iframeTag)) {
901 HTMLIFrameElement* iframe = static_cast<HTMLIFrameElement*>(source.get());
902 if (frame() && frame()->tree()->isDescendantOf(iframe->contentFrame())) {
903 ec = HIERARCHY_REQUEST_ERR;
906 iframe->setRemainsAliveOnRemovalFromTree(attached() && source->attached());
909 if (source->parentNode())
910 source->parentNode()->removeChild(source.get(), ec);
913 for (Node* node = source.get(); node; node = node->traverseNextNode(source.get()))
914 node->setDocument(this);
919 bool Document::hasPrefixNamespaceMismatch(const QualifiedName& qName)
921 // These checks are from DOM Core Level 2, createElementNS
922 // http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-DocCrElNS
923 if (!qName.prefix().isEmpty() && qName.namespaceURI().isNull()) // createElementNS(null, "html:div")
925 if (qName.prefix() == xmlAtom && qName.namespaceURI() != XMLNames::xmlNamespaceURI) // createElementNS("http://www.example.com", "xml:lang")
928 // Required by DOM Level 3 Core and unspecified by DOM Level 2 Core:
929 // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-DocCrElNS
930 // createElementNS("http://www.w3.org/2000/xmlns/", "foo:bar"), createElementNS(null, "xmlns:bar")
931 if ((qName.prefix() == xmlnsAtom && qName.namespaceURI() != XMLNSNames::xmlnsNamespaceURI) || (qName.prefix() != xmlnsAtom && qName.namespaceURI() == XMLNSNames::xmlnsNamespaceURI))
937 // FIXME: This should really be in a possible ElementFactory class
938 PassRefPtr<Element> Document::createElement(const QualifiedName& qName, bool createdByParser)
942 // FIXME: Use registered namespaces and look up in a hash to find the right factory.
943 if (qName.namespaceURI() == xhtmlNamespaceURI)
944 e = HTMLElementFactory::createHTMLElement(qName, this, 0, createdByParser);
946 else if (qName.namespaceURI() == SVGNames::svgNamespaceURI)
947 e = SVGElementFactory::createSVGElement(qName, this, createdByParser);
950 else if (qName.namespaceURI() == WMLNames::wmlNamespaceURI)
951 e = WMLElementFactory::createWMLElement(qName, this, createdByParser);
952 else if (isWMLDocument())
953 e = WMLElementFactory::createWMLElement(QualifiedName(nullAtom, qName.localName(), WMLNames::wmlNamespaceURI), this, createdByParser);
956 else if (qName.namespaceURI() == MathMLNames::mathmlNamespaceURI)
957 e = MathMLElementFactory::createMathMLElement(qName, this, createdByParser);
961 e = Element::create(qName, document());
963 // <image> uses imgTag so we need a special rule.
965 if (!isWMLDocument())
967 ASSERT((qName.matches(imageTag) && e->tagQName().matches(imgTag) && e->tagQName().prefix() == qName.prefix()) || qName == e->tagQName());
972 PassRefPtr<Element> Document::createElementNS(const String& namespaceURI, const String& qualifiedName, ExceptionCode& ec)
974 String prefix, localName;
975 if (!parseQualifiedName(qualifiedName, prefix, localName, ec))
978 QualifiedName qName(prefix, localName, namespaceURI);
979 if (hasPrefixNamespaceMismatch(qName)) {
984 return createElement(qName, false);
987 inline void Document::DocumentOrderedMap::add(AtomicStringImpl* key, Element* element)
992 if (!m_duplicateCounts.contains(key)) {
993 // Fast path. The key is not already in m_duplicateCounts, so we assume that it's
994 // also not already in m_map and try to add it. If that add succeeds, we're done.
995 pair<Map::iterator, bool> addResult = m_map.add(key, element);
996 if (addResult.second)
999 // The add failed, so this key was already cached in m_map.
1000 // There are multiple elements with this key. Remove the m_map
1001 // cache for this key so get searches for it next time it is called.
1002 m_map.remove(addResult.first);
1003 m_duplicateCounts.add(key);
1005 // There are multiple elements with this key. Remove the m_map
1006 // cache for this key so get will search for it next time it is called.
1007 Map::iterator cachedItem = m_map.find(key);
1008 if (cachedItem != m_map.end()) {
1009 m_map.remove(cachedItem);
1010 m_duplicateCounts.add(key);
1014 m_duplicateCounts.add(key);
1017 inline void Document::DocumentOrderedMap::remove(AtomicStringImpl* key, Element* element)
1022 m_map.checkConsistency();
1023 Map::iterator cachedItem = m_map.find(key);
1024 if (cachedItem != m_map.end() && cachedItem->second == element)
1025 m_map.remove(cachedItem);
1027 m_duplicateCounts.remove(key);
1030 template<bool keyMatches(AtomicStringImpl*, Element*)> inline Element* Document::DocumentOrderedMap::get(AtomicStringImpl* key, const Document* document) const
1034 m_map.checkConsistency();
1036 Element* element = m_map.get(key);
1040 if (m_duplicateCounts.contains(key)) {
1041 // We know there's at least one node that matches; iterate to find the first one.
1042 for (Node* node = document->firstChild(); node; node = node->traverseNextNode()) {
1043 if (!node->isElementNode())
1045 element = static_cast<Element*>(node);
1046 if (!keyMatches(key, element))
1048 m_duplicateCounts.remove(key);
1049 m_map.set(key, element);
1052 ASSERT_NOT_REACHED();
1058 inline bool keyMatchesId(AtomicStringImpl* key, Element* element)
1060 return element->hasID() && element->getIdAttribute().impl() == key;
1063 Element* Document::getElementById(const AtomicString& elementId) const
1065 if (elementId.isEmpty())
1067 return m_elementsById.get<keyMatchesId>(elementId.impl(), this);
1070 String Document::readyState() const
1072 DEFINE_STATIC_LOCAL(const String, loading, ("loading"));
1073 DEFINE_STATIC_LOCAL(const String, interactive, ("interactive"));
1074 DEFINE_STATIC_LOCAL(const String, complete, ("complete"));
1076 switch (m_readyState) {
1085 ASSERT_NOT_REACHED();
1089 void Document::setReadyState(ReadyState readyState)
1091 if (readyState == m_readyState)
1094 switch (readyState) {
1096 if (!m_documentTiming.domLoading)
1097 m_documentTiming.domLoading = currentTime();
1100 if (!m_documentTiming.domInteractive)
1101 m_documentTiming.domInteractive = currentTime();
1104 if (!m_documentTiming.domComplete)
1105 m_documentTiming.domComplete = currentTime();
1109 m_readyState = readyState;
1110 dispatchEvent(Event::create(eventNames().readystatechangeEvent, false, false));
1113 String Document::encoding() const
1115 if (TextResourceDecoder* d = decoder())
1116 return d->encoding().domName();
1120 String Document::defaultCharset() const
1122 if (Settings* settings = this->settings())
1123 return settings->defaultTextEncodingName();
1127 void Document::setCharset(const String& charset)
1131 decoder()->setEncoding(charset, TextResourceDecoder::UserChosenEncoding);
1134 void Document::setXMLVersion(const String& version, ExceptionCode& ec)
1136 if (!implementation()->hasFeature("XML", String())) {
1137 ec = NOT_SUPPORTED_ERR;
1141 if (!XMLDocumentParser::supportsXMLVersion(version)) {
1142 ec = NOT_SUPPORTED_ERR;
1146 m_xmlVersion = version;
1149 void Document::setXMLStandalone(bool standalone, ExceptionCode& ec)
1151 if (!implementation()->hasFeature("XML", String())) {
1152 ec = NOT_SUPPORTED_ERR;
1156 m_xmlStandalone = standalone;
1159 void Document::setDocumentURI(const String& uri)
1161 m_documentURI = uri;
1165 KURL Document::baseURI() const
1170 // FIXME: We need to discuss the DOM API here at some point. Ideas:
1171 // * making it receive a rect as parameter, i.e. nodesFromRect(x, y, w, h);
1172 // * making it receive the expading size of each direction separately,
1173 // i.e. nodesFromRect(x, y, topSize, rightSize, bottomSize, leftSize);
1174 PassRefPtr<NodeList> Document::nodesFromRect(int centerX, int centerY, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding, bool ignoreClipping) const
1176 // FIXME: Share code between this, elementFromPoint and caretRangeFromPoint.
1179 Frame* frame = this->frame();
1182 FrameView* frameView = frame->view();
1186 float zoomFactor = frame->pageZoomFactor();
1187 IntPoint point = roundedIntPoint(FloatPoint(centerX * zoomFactor + view()->scrollX(), centerY * zoomFactor + view()->scrollY()));
1189 int type = HitTestRequest::ReadOnly | HitTestRequest::Active;
1191 // When ignoreClipping is false, this method returns null for coordinates outside of the viewport.
1193 type |= HitTestRequest::IgnoreClipping;
1194 else if (!frameView->visibleContentRect().intersects(HitTestResult::rectForPoint(point, topPadding, rightPadding, bottomPadding, leftPadding)))
1197 HitTestRequest request(type);
1199 // Passing a zero padding will trigger a rect hit test, however for the purposes of nodesFromRect,
1200 // we special handle this case in order to return a valid NodeList.
1201 if (!topPadding && !rightPadding && !bottomPadding && !leftPadding) {
1202 HitTestResult result(point);
1203 return handleZeroPadding(request, result);
1206 HitTestResult result(point, topPadding, rightPadding, bottomPadding, leftPadding);
1207 renderView()->layer()->hitTest(request, result);
1209 return StaticHashSetNodeList::adopt(result.rectBasedTestResult());
1212 PassRefPtr<NodeList> Document::handleZeroPadding(const HitTestRequest& request, HitTestResult& result) const
1214 renderView()->layer()->hitTest(request, result);
1216 Node* node = result.innerNode();
1220 node = node->shadowAncestorNode();
1221 ListHashSet<RefPtr<Node> > list;
1223 return StaticHashSetNodeList::adopt(list);
1226 Element* Document::elementFromPoint(int x, int y) const
1228 // FIXME: Share code between this and caretRangeFromPoint.
1231 Frame* frame = this->frame();
1234 FrameView* frameView = frame->view();
1238 float zoomFactor = frame->pageZoomFactor();
1239 IntPoint point = roundedIntPoint(FloatPoint(x * zoomFactor + view()->scrollX(), y * zoomFactor + view()->scrollY()));
1241 if (!frameView->visibleContentRect().contains(point))
1244 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
1245 HitTestResult result(point);
1246 renderView()->layer()->hitTest(request, result);
1248 Node* n = result.innerNode();
1249 while (n && !n->isElementNode())
1250 n = n->parentNode();
1252 n = n->shadowAncestorNode();
1253 return static_cast<Element*>(n);
1256 PassRefPtr<Range> Document::caretRangeFromPoint(int x, int y)
1258 // FIXME: Share code between this and elementFromPoint.
1261 Frame* frame = this->frame();
1264 FrameView* frameView = frame->view();
1268 float zoomFactor = frame->pageZoomFactor();
1269 IntPoint point = roundedIntPoint(FloatPoint(x * zoomFactor + view()->scrollX(), y * zoomFactor + view()->scrollY()));
1271 if (!frameView->visibleContentRect().contains(point))
1274 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
1275 HitTestResult result(point);
1276 renderView()->layer()->hitTest(request, result);
1278 Node* node = result.innerNode();
1282 Node* shadowAncestorNode = node->shadowAncestorNode();
1283 if (shadowAncestorNode != node) {
1284 unsigned offset = shadowAncestorNode->nodeIndex();
1285 ContainerNode* container = shadowAncestorNode->parentNode();
1286 return Range::create(this, container, offset, container, offset);
1289 RenderObject* renderer = node->renderer();
1292 VisiblePosition visiblePosition = renderer->positionForPoint(result.localPoint());
1293 if (visiblePosition.isNull())
1296 Position rangeCompliantPosition = rangeCompliantEquivalent(visiblePosition);
1297 return Range::create(this, rangeCompliantPosition, rangeCompliantPosition);
1300 void Document::addElementById(const AtomicString& elementId, Element* element)
1302 m_elementsById.add(elementId.impl(), element);
1305 void Document::removeElementById(const AtomicString& elementId, Element* element)
1307 m_elementsById.remove(elementId.impl(), element);
1310 Element* Document::getElementByAccessKey(const String& key) const
1314 if (!m_accessKeyMapValid) {
1315 for (Node* n = firstChild(); n; n = n->traverseNextNode()) {
1316 if (!n->isElementNode())
1318 Element* element = static_cast<Element*>(n);
1319 const AtomicString& accessKey = element->getAttribute(accesskeyAttr);
1320 if (!accessKey.isEmpty())
1321 m_elementsByAccessKey.set(accessKey.impl(), element);
1323 m_accessKeyMapValid = true;
1325 return m_elementsByAccessKey.get(key.impl());
1329 * Performs three operations:
1330 * 1. Convert control characters to spaces
1331 * 2. Trim leading and trailing spaces
1332 * 3. Collapse internal whitespace.
1334 static inline String canonicalizedTitle(Document* document, const String& title)
1336 const UChar* characters = title.characters();
1337 unsigned length = title.length();
1340 StringBuffer buffer(length);
1341 unsigned builderIndex = 0;
1343 // Skip leading spaces and leading characters that would convert to spaces
1344 for (i = 0; i < length; ++i) {
1345 UChar c = characters[i];
1346 if (!(c <= 0x20 || c == 0x7F))
1353 // Replace control characters with spaces, and backslashes with currency symbols, and collapse whitespace.
1354 bool previousCharWasWS = false;
1355 for (; i < length; ++i) {
1356 UChar c = characters[i];
1357 if (c <= 0x20 || c == 0x7F || (WTF::Unicode::category(c) & (WTF::Unicode::Separator_Line | WTF::Unicode::Separator_Paragraph))) {
1358 if (previousCharWasWS)
1360 buffer[builderIndex++] = ' ';
1361 previousCharWasWS = true;
1363 buffer[builderIndex++] = c;
1364 previousCharWasWS = false;
1368 // Strip trailing spaces
1369 while (builderIndex > 0) {
1371 if (buffer[builderIndex] != ' ')
1375 if (!builderIndex && buffer[builderIndex] == ' ')
1378 buffer.shrink(builderIndex + 1);
1380 // Replace the backslashes with currency symbols if the encoding requires it.
1381 document->displayBufferModifiedByEncoding(buffer.characters(), buffer.length());
1383 return String::adopt(buffer);
1386 void Document::updateTitle()
1388 m_title = canonicalizedTitle(this, m_rawTitle);
1389 if (Frame* f = frame())
1390 f->loader()->setTitle(m_title);
1393 void Document::setTitle(const String& title, Element* titleElement)
1395 if (!titleElement) {
1396 // Title set by JavaScript -- overrides any title elements.
1397 m_titleSetExplicitly = true;
1398 if (!isHTMLDocument())
1400 else if (!m_titleElement) {
1401 if (HTMLElement* headElement = head()) {
1402 m_titleElement = createElement(titleTag, false);
1403 ExceptionCode ec = 0;
1404 headElement->appendChild(m_titleElement, ec);
1408 } else if (titleElement != m_titleElement) {
1409 if (m_titleElement || m_titleSetExplicitly)
1410 // Only allow the first title element to change the title -- others have no effect.
1412 m_titleElement = titleElement;
1415 if (m_rawTitle == title)
1421 if (m_titleSetExplicitly && m_titleElement && m_titleElement->hasTagName(titleTag) && !titleElement)
1422 static_cast<HTMLTitleElement*>(m_titleElement.get())->setText(m_title);
1425 void Document::removeTitle(Element* titleElement)
1427 if (m_titleElement != titleElement)
1431 m_titleSetExplicitly = false;
1433 // Update title based on first title element in the head, if one exists.
1434 if (HTMLElement* headElement = head()) {
1435 for (Node* e = headElement->firstChild(); e; e = e->nextSibling())
1436 if (e->hasTagName(titleTag)) {
1437 HTMLTitleElement* titleElement = static_cast<HTMLTitleElement*>(e);
1438 setTitle(titleElement->text(), titleElement);
1443 if (!m_titleElement && !m_rawTitle.isEmpty()) {
1449 String Document::nodeName() const
1454 Node::NodeType Document::nodeType() const
1456 return DOCUMENT_NODE;
1459 FrameView* Document::view() const
1461 return m_frame ? m_frame->view() : 0;
1464 Page* Document::page() const
1466 return m_frame ? m_frame->page() : 0;
1469 Settings* Document::settings() const
1471 return m_frame ? m_frame->settings() : 0;
1474 PassRefPtr<Range> Document::createRange()
1476 return Range::create(this);
1479 PassRefPtr<NodeIterator> Document::createNodeIterator(Node* root, unsigned whatToShow,
1480 PassRefPtr<NodeFilter> filter, bool expandEntityReferences, ExceptionCode& ec)
1483 ec = NOT_SUPPORTED_ERR;
1486 return NodeIterator::create(root, whatToShow, filter, expandEntityReferences);
1489 PassRefPtr<TreeWalker> Document::createTreeWalker(Node* root, unsigned whatToShow,
1490 PassRefPtr<NodeFilter> filter, bool expandEntityReferences, ExceptionCode& ec)
1493 ec = NOT_SUPPORTED_ERR;
1496 return TreeWalker::create(root, whatToShow, filter, expandEntityReferences);
1499 void Document::scheduleForcedStyleRecalc()
1501 m_pendingStyleRecalcShouldForce = true;
1502 scheduleStyleRecalc();
1505 void Document::scheduleStyleRecalc()
1507 if (m_styleRecalcTimer.isActive() || inPageCache())
1510 ASSERT(childNeedsStyleRecalc() || m_pendingStyleRecalcShouldForce);
1512 if (!documentsThatNeedStyleRecalc)
1513 documentsThatNeedStyleRecalc = new HashSet<Document*>;
1514 documentsThatNeedStyleRecalc->add(this);
1516 // FIXME: Why on earth is this here? This is clearly misplaced.
1517 if (m_accessKeyMapValid) {
1518 m_accessKeyMapValid = false;
1519 m_elementsByAccessKey.clear();
1522 m_styleRecalcTimer.startOneShot(0);
1525 void Document::unscheduleStyleRecalc()
1527 ASSERT(!childNeedsStyleRecalc());
1529 if (documentsThatNeedStyleRecalc)
1530 documentsThatNeedStyleRecalc->remove(this);
1532 m_styleRecalcTimer.stop();
1533 m_pendingStyleRecalcShouldForce = false;
1536 bool Document::isPendingStyleRecalc() const
1538 return m_styleRecalcTimer.isActive() && !m_inStyleRecalc;
1541 void Document::styleRecalcTimerFired(Timer<Document>*)
1543 updateStyleIfNeeded();
1546 bool Document::childNeedsAndNotInStyleRecalc()
1548 return childNeedsStyleRecalc() && !m_inStyleRecalc;
1551 void Document::recalcStyle(StyleChange change)
1553 // we should not enter style recalc while painting
1554 if (view() && view()->isPainting()) {
1555 ASSERT(!view()->isPainting());
1559 if (m_inStyleRecalc)
1560 return; // Guard against re-entrancy. -dwh
1562 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRecalculateStyle(this);
1564 m_inStyleRecalc = true;
1565 suspendPostAttachCallbacks();
1566 RenderWidget::suspendWidgetHierarchyUpdates();
1568 view()->pauseScheduledEvents();
1570 ASSERT(!renderer() || renderArena());
1571 if (!renderer() || !renderArena())
1574 if (m_pendingStyleRecalcShouldForce)
1577 if (change == Force) {
1578 // style selector may set this again during recalc
1579 m_hasNodesWithPlaceholderStyle = false;
1581 RefPtr<RenderStyle> documentStyle = CSSStyleSelector::styleForDocument(this);
1582 StyleChange ch = diff(documentStyle.get(), renderer()->style());
1583 if (renderer() && ch != NoChange)
1584 renderer()->setStyle(documentStyle.release());
1587 for (Node* n = firstChild(); n; n = n->nextSibling())
1588 if (change >= Inherit || n->childNeedsStyleRecalc() || n->needsStyleRecalc())
1589 n->recalcStyle(change);
1591 #if USE(ACCELERATED_COMPOSITING)
1593 bool layoutPending = view()->layoutPending() || renderer()->needsLayout();
1594 // If we didn't update compositing layers because of layout(), we need to do so here.
1596 view()->updateCompositingLayers();
1601 clearNeedsStyleRecalc();
1602 clearChildNeedsStyleRecalc();
1603 unscheduleStyleRecalc();
1606 view()->resumeScheduledEvents();
1607 RenderWidget::resumeWidgetHierarchyUpdates();
1608 resumePostAttachCallbacks();
1609 m_inStyleRecalc = false;
1611 // If we wanted to call implicitClose() during recalcStyle, do so now that we're finished.
1612 if (m_closeAfterStyleRecalc) {
1613 m_closeAfterStyleRecalc = false;
1617 InspectorInstrumentation::didRecalculateStyle(cookie);
1620 void Document::updateStyleIfNeeded()
1622 ASSERT(isMainThread());
1623 ASSERT(!view() || (!view()->isInLayout() && !view()->isPainting()));
1625 if ((!m_pendingStyleRecalcShouldForce && !childNeedsStyleRecalc()) || inPageCache())
1629 m_frame->animation()->beginAnimationUpdate();
1631 recalcStyle(NoChange);
1633 // Tell the animation controller that updateStyleIfNeeded is finished and it can do any post-processing
1635 m_frame->animation()->endAnimationUpdate();
1638 void Document::updateStyleForAllDocuments()
1640 ASSERT(isMainThread());
1641 if (!documentsThatNeedStyleRecalc)
1644 while (documentsThatNeedStyleRecalc->size()) {
1645 HashSet<Document*>::iterator it = documentsThatNeedStyleRecalc->begin();
1646 Document* doc = *it;
1647 documentsThatNeedStyleRecalc->remove(doc);
1648 doc->updateStyleIfNeeded();
1652 void Document::updateLayout()
1654 ASSERT(isMainThread());
1655 if (Element* oe = ownerElement())
1656 oe->document()->updateLayout();
1658 updateStyleIfNeeded();
1660 // Only do a layout if changes have occurred that make it necessary.
1661 FrameView* v = view();
1662 if (v && renderer() && (v->layoutPending() || renderer()->needsLayout()))
1666 // FIXME: This is a bad idea and needs to be removed eventually.
1667 // Other browsers load stylesheets before they continue parsing the web page.
1668 // Since we don't, we can run JavaScript code that needs answers before the
1669 // stylesheets are loaded. Doing a layout ignoring the pending stylesheets
1670 // lets us get reasonable answers. The long term solution to this problem is
1671 // to instead suspend JavaScript execution.
1672 void Document::updateLayoutIgnorePendingStylesheets()
1674 bool oldIgnore = m_ignorePendingStylesheets;
1676 if (!haveStylesheetsLoaded()) {
1677 m_ignorePendingStylesheets = true;
1678 // FIXME: We are willing to attempt to suppress painting with outdated style info only once. Our assumption is that it would be
1679 // dangerous to try to stop it a second time, after page content has already been loaded and displayed
1680 // with accurate style information. (Our suppression involves blanking the whole page at the
1681 // moment. If it were more refined, we might be able to do something better.)
1682 // It's worth noting though that this entire method is a hack, since what we really want to do is
1683 // suspend JS instead of doing a layout with inaccurate information.
1684 if (body() && !body()->renderer() && m_pendingSheetLayout == NoLayoutWithPendingSheets) {
1685 m_pendingSheetLayout = DidLayoutWithPendingSheets;
1686 styleSelectorChanged(RecalcStyleImmediately);
1687 } else if (m_hasNodesWithPlaceholderStyle)
1688 // If new nodes have been added or style recalc has been done with style sheets still pending, some nodes
1689 // may not have had their real style calculated yet. Normally this gets cleaned when style sheets arrive
1690 // but here we need up-to-date style immediately.
1696 m_ignorePendingStylesheets = oldIgnore;
1699 PassRefPtr<RenderStyle> Document::styleForElementIgnoringPendingStylesheets(Element* element)
1701 ASSERT_ARG(element, element->document() == this);
1703 bool oldIgnore = m_ignorePendingStylesheets;
1704 m_ignorePendingStylesheets = true;
1705 RefPtr<RenderStyle> style = styleSelector()->styleForElement(element, element->parentNode() ? element->parentNode()->computedStyle() : 0);
1706 m_ignorePendingStylesheets = oldIgnore;
1707 return style.release();
1710 PassRefPtr<RenderStyle> Document::styleForPage(int pageIndex)
1712 RefPtr<RenderStyle> style = styleSelector()->styleForPage(pageIndex);
1713 return style.release();
1716 bool Document::isPageBoxVisible(int pageIndex)
1718 RefPtr<RenderStyle> style = styleForPage(pageIndex);
1719 return style->visibility() != HIDDEN; // display property doesn't apply to @page.
1722 void Document::pageSizeAndMarginsInPixels(int pageIndex, IntSize& pageSize, int& marginTop, int& marginRight, int& marginBottom, int& marginLeft)
1724 RefPtr<RenderStyle> style = styleForPage(pageIndex);
1726 int width = pageSize.width();
1727 int height = pageSize.height();
1728 switch (style->pageSizeType()) {
1729 case PAGE_SIZE_AUTO:
1731 case PAGE_SIZE_AUTO_LANDSCAPE:
1733 std::swap(width, height);
1735 case PAGE_SIZE_AUTO_PORTRAIT:
1737 std::swap(width, height);
1739 case PAGE_SIZE_RESOLVED: {
1740 LengthSize size = style->pageSize();
1741 ASSERT(size.width().isFixed());
1742 ASSERT(size.height().isFixed());
1743 width = size.width().calcValue(0);
1744 height = size.height().calcValue(0);
1748 ASSERT_NOT_REACHED();
1750 pageSize = IntSize(width, height);
1752 // The percentage is calculated with respect to the width even for margin top and bottom.
1753 // http://www.w3.org/TR/CSS2/box.html#margin-properties
1754 marginTop = style->marginTop().isAuto() ? marginTop : style->marginTop().calcValue(width);
1755 marginRight = style->marginRight().isAuto() ? marginRight : style->marginRight().calcValue(width);
1756 marginBottom = style->marginBottom().isAuto() ? marginBottom : style->marginBottom().calcValue(width);
1757 marginLeft = style->marginLeft().isAuto() ? marginLeft : style->marginLeft().calcValue(width);
1760 void Document::createStyleSelector()
1762 bool matchAuthorAndUserStyles = true;
1763 if (Settings* docSettings = settings())
1764 matchAuthorAndUserStyles = docSettings->authorAndUserStylesEnabled();
1765 m_styleSelector.set(new CSSStyleSelector(this, m_styleSheets.get(), m_mappedElementSheet.get(), pageUserSheet(), pageGroupUserSheets(),
1766 !inQuirksMode(), matchAuthorAndUserStyles));
1769 void Document::attach()
1771 ASSERT(!attached());
1772 ASSERT(!m_inPageCache);
1773 ASSERT(!m_axObjectCache);
1776 m_renderArena = new RenderArena();
1778 // Create the rendering tree
1779 setRenderer(new (m_renderArena.get()) RenderView(this, view()));
1780 #if USE(ACCELERATED_COMPOSITING)
1781 renderView()->didMoveOnscreen();
1786 RenderObject* render = renderer();
1789 ContainerNode::attach();
1791 setRenderer(render);
1794 void Document::detach()
1797 ASSERT(!m_inPageCache);
1799 clearAXObjectCache();
1800 stopActiveDOMObjects();
1802 RenderObject* render = renderer();
1804 // Send out documentWillBecomeInactive() notifications to registered elements,
1805 // in order to stop media elements
1806 documentWillBecomeInactive();
1808 #if ENABLE(SHARED_WORKERS)
1809 SharedWorkerRepository::documentDetached(this);
1813 FrameView* view = m_frame->view();
1815 view->detachCustomScrollbars();
1817 #if ENABLE(TOUCH_EVENTS)
1818 Page* ownerPage = page();
1819 if (ownerPage && (m_frame == ownerPage->mainFrame())) {
1820 // Inform the Chrome Client that it no longer needs to
1821 // foward touch events to WebCore as the document is being
1822 // destroyed. It may start again if a subsequent page
1823 // registers a touch event listener.
1824 ownerPage->chrome()->client()->needTouchEvents(false);
1829 // indicate destruction mode, i.e. attached() but renderer == 0
1832 #if ENABLE(FULLSCREEN_API)
1833 if (m_fullScreenRenderer)
1834 setFullScreenRenderer(0);
1841 ContainerNode::detach();
1843 unscheduleStyleRecalc();
1848 // This is required, as our Frame might delete itself as soon as it detaches
1849 // us. However, this violates Node::detach() semantics, as it's never
1850 // possible to re-attach. Eventually Document::detach() should be renamed,
1851 // or this setting of the frame to 0 could be made explicit in each of the
1852 // callers of Document::detach().
1854 m_renderArena.clear();
1857 void Document::removeAllEventListeners()
1859 EventTarget::removeAllEventListeners();
1861 if (DOMWindow* domWindow = this->domWindow())
1862 domWindow->removeAllEventListeners();
1863 for (Node* node = firstChild(); node; node = node->traverseNextNode())
1864 node->removeAllEventListeners();
1867 RenderView* Document::renderView() const
1869 return toRenderView(renderer());
1872 void Document::clearAXObjectCache()
1874 // clear cache in top document
1875 if (m_axObjectCache) {
1876 // Clear the cache member variable before calling delete because attempts
1877 // are made to access it during destruction.
1878 AXObjectCache* axObjectCache = m_axObjectCache;
1879 m_axObjectCache = 0;
1880 delete axObjectCache;
1884 // ask the top-level document to clear its cache
1885 Document* doc = topDocument();
1887 doc->clearAXObjectCache();
1890 bool Document::axObjectCacheExists() const
1892 if (m_axObjectCache)
1895 Document* doc = topDocument();
1897 return doc->axObjectCacheExists();
1902 AXObjectCache* Document::axObjectCache() const
1904 // The only document that actually has a AXObjectCache is the top-level
1905 // document. This is because we need to be able to get from any WebCoreAXObject
1906 // to any other WebCoreAXObject on the same page. Using a single cache allows
1907 // lookups across nested webareas (i.e. multiple documents).
1909 if (m_axObjectCache) {
1910 // return already known top-level cache
1911 if (!ownerElement())
1912 return m_axObjectCache;
1914 // In some pages with frames, the cache is created before the sub-webarea is
1915 // inserted into the tree. Here, we catch that case and just toss the old
1916 // cache and start over.
1917 // NOTE: This recovery may no longer be needed. I have been unable to trigger
1918 // it again. See rdar://5794454
1919 // FIXME: Can this be fixed when inserting the subframe instead of now?
1920 // FIXME: If this function was called to get the cache in order to remove
1921 // an AXObject, we are now deleting the cache as a whole and returning a
1922 // new empty cache that does not contain the AXObject! That should actually
1923 // be OK. I am concerned about other cases like this where accessing the
1924 // cache blows away the AXObject being operated on.
1925 delete m_axObjectCache;
1926 m_axObjectCache = 0;
1929 // ask the top-level document for its cache
1930 Document* doc = topDocument();
1932 return doc->axObjectCache();
1934 // this is the top-level document, so install a new cache
1935 m_axObjectCache = new AXObjectCache(this);
1936 return m_axObjectCache;
1939 void Document::setVisuallyOrdered()
1941 m_visuallyOrdered = true;
1943 renderer()->style()->setVisuallyOrdered(true);
1946 PassRefPtr<DocumentParser> Document::createParser()
1948 // FIXME: this should probably pass the frame instead
1949 return XMLDocumentParser::create(this, view());
1952 ScriptableDocumentParser* Document::scriptableDocumentParser() const
1954 return parser() ? parser()->asScriptableDocumentParser() : 0;
1957 void Document::open(Document* ownerDocument)
1959 if (ownerDocument) {
1960 setURL(ownerDocument->url());
1961 m_cookieURL = ownerDocument->cookieURL();
1962 ScriptExecutionContext::setSecurityOrigin(ownerDocument->securityOrigin());
1966 ScriptableDocumentParser* parser = scriptableDocumentParser();
1967 if (m_frame->loader()->isLoadingMainResource() || (parser && parser->isParsing() && parser->isExecutingScript()))
1970 if (m_frame->loader()->state() == FrameStateProvisional)
1971 m_frame->loader()->stopAllLoaders();
1974 removeAllEventListeners();
1977 if (DOMWindow* domWindow = this->domWindow())
1978 domWindow->removeAllEventListeners();
1981 m_frame->loader()->didExplicitOpen();
1984 void Document::detachParser()
1992 void Document::cancelParsing()
1995 // We have to clear the parser to avoid possibly triggering
1996 // the onload handler when closing as a side effect of a cancel-style
1997 // change, such as opening a new document or closing the window while
2004 void Document::implicitOpen()
2010 setCompatibilityMode(NoQuirksMode);
2012 m_parser = createParser();
2014 setReadyState(Loading);
2016 ScriptableDocumentParser* parser = scriptableDocumentParser();
2017 if (m_frame && parser)
2018 parser->setXSSAuditor(m_frame->script()->xssAuditor());
2020 // If we reload, the animation controller sticks around and has
2021 // a stale animation time. We need to update it here.
2022 if (m_frame && m_frame->animation())
2023 m_frame->animation()->beginAnimationUpdate();
2026 HTMLElement* Document::body() const
2028 Node* de = documentElement();
2032 // try to prefer a FRAMESET element over BODY
2034 for (Node* i = de->firstChild(); i; i = i->nextSibling()) {
2035 if (i->hasTagName(framesetTag))
2036 return static_cast<HTMLElement*>(i);
2038 if (i->hasTagName(bodyTag) && !body)
2041 return static_cast<HTMLElement*>(body);
2044 void Document::setBody(PassRefPtr<HTMLElement> newBody, ExceptionCode& ec)
2046 if (!newBody || !documentElement()) {
2047 ec = HIERARCHY_REQUEST_ERR;
2051 HTMLElement* b = body();
2053 documentElement()->appendChild(newBody, ec);
2055 documentElement()->replaceChild(newBody, b, ec);
2058 HTMLHeadElement* Document::head()
2060 Node* de = documentElement();
2064 for (Node* e = de->firstChild(); e; e = e->nextSibling())
2065 if (e->hasTagName(headTag))
2066 return static_cast<HTMLHeadElement*>(e);
2071 void Document::close()
2073 Frame* frame = this->frame();
2075 // This code calls implicitClose() if all loading has completed.
2076 FrameLoader* frameLoader = frame->loader();
2077 frameLoader->writer()->endIfNotLoadingMainResource();
2078 frameLoader->checkCompleted();
2080 // Because we have no frame, we don't know if all loading has completed,
2081 // so we just call implicitClose() immediately. FIXME: This might fire
2082 // the load event prematurely <http://bugs.webkit.org/show_bug.cgi?id=14568>.
2087 void Document::implicitClose()
2089 // 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.
2090 if (m_inStyleRecalc) {
2091 m_closeAfterStyleRecalc = true;
2095 bool wasLocationChangePending = frame() && frame()->navigationScheduler()->locationChangePending();
2096 bool doload = !parsing() && m_parser && !m_processingLoadEvent && !wasLocationChangePending;
2101 m_processingLoadEvent = true;
2103 ScriptableDocumentParser* parser = scriptableDocumentParser();
2104 m_wellFormed = parser && parser->wellFormed();
2106 // We have to clear the parser, in case someone document.write()s from the
2107 // onLoad event handler, as in Radar 3206524.
2110 // Parser should have picked up all preloads by now
2111 m_cachedResourceLoader->clearPreloads();
2113 // FIXME: We kick off the icon loader when the Document is done parsing.
2114 // There are earlier opportunities we could start it:
2115 // -When the <head> finishes parsing
2116 // -When any new HTMLLinkElement is inserted into the document
2117 // But those add a dynamic component to the favicon that has UI
2118 // ramifications, and we need to decide what is the Right Thing To Do(tm)
2121 f->loader()->startIconLoader();
2123 // Resume the animations (or start them)
2125 f->animation()->resumeAnimationsForDocument(this);
2127 ImageLoader::dispatchPendingBeforeLoadEvents();
2128 ImageLoader::dispatchPendingLoadEvents();
2129 dispatchWindowLoadEvent();
2130 enqueuePageshowEvent(PageshowEventNotPersisted);
2131 enqueuePopstateEvent(m_pendingStateObject ? m_pendingStateObject.release() : SerializedScriptValue::nullValue());
2134 f->loader()->handledOnloadEvents();
2135 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2136 if (!ownerElement())
2137 printf("onload fired at %d\n", elapsedTime());
2140 m_processingLoadEvent = false;
2142 // An event handler may have removed the frame
2146 // Make sure both the initial layout and reflow happen after the onload
2147 // fires. This will improve onload scores, and other browsers do it.
2148 // If they wanna cheat, we can too. -dwh
2150 if (frame()->navigationScheduler()->locationChangePending() && elapsedTime() < cLayoutScheduleThreshold) {
2151 // Just bail out. Before or during the onload we were shifted to another page.
2152 // The old i-Bench suite does this. When this happens don't bother painting or laying out.
2153 view()->unscheduleRelayout();
2157 frame()->loader()->checkCallImplicitClose();
2158 RenderObject* renderObject = renderer();
2160 // We used to force a synchronous display and flush here. This really isn't
2161 // necessary and can in fact be actively harmful if pages are loading at a rate of > 60fps
2162 // (if your platform is syncing flushes and limiting them to 60fps).
2163 m_overMinimumLayoutThreshold = true;
2164 if (!ownerElement() || (ownerElement()->renderer() && !ownerElement()->renderer()->needsLayout())) {
2165 updateStyleIfNeeded();
2167 // Always do a layout after loading if needed.
2168 if (view() && renderObject && (!renderObject->firstChild() || renderObject->needsLayout()))
2172 #if PLATFORM(MAC) || PLATFORM(CHROMIUM)
2173 if (f && renderObject && this == topDocument() && AXObjectCache::accessibilityEnabled()) {
2174 // The AX cache may have been cleared at this point, but we need to make sure it contains an
2175 // AX object to send the notification to. getOrCreate will make sure that an valid AX object
2176 // exists in the cache (we ignore the return value because we don't need it here). This is
2177 // only safe to call when a layout is not in progress, so it can not be used in postNotification.
2178 axObjectCache()->getOrCreate(renderObject);
2179 axObjectCache()->postNotification(renderObject, AXObjectCache::AXLoadComplete, true);
2184 // FIXME: Officially, time 0 is when the outermost <svg> receives its
2185 // SVGLoad event, but we don't implement those yet. This is close enough
2186 // for now. In some cases we should have fired earlier.
2187 if (svgExtensions())
2188 accessSVGExtensions()->startAnimations();
2192 void Document::setParsing(bool b)
2195 if (!m_bParsing && view())
2196 view()->scheduleRelayout();
2198 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2199 if (!ownerElement() && !m_bParsing)
2200 printf("Parsing finished at %d\n", elapsedTime());
2204 bool Document::shouldScheduleLayout()
2206 // This function will only be called when FrameView thinks a layout is needed.
2207 // This enforces a couple extra rules.
2209 // (a) Only schedule a layout once the stylesheets are loaded.
2210 // (b) Only schedule layout once we have a body element.
2212 return (haveStylesheetsLoaded() && body())
2213 || (documentElement() && !documentElement()->hasTagName(htmlTag));
2216 int Document::minimumLayoutDelay()
2218 if (m_overMinimumLayoutThreshold)
2219 return m_extraLayoutDelay;
2221 int elapsed = elapsedTime();
2222 m_overMinimumLayoutThreshold = elapsed > cLayoutScheduleThreshold;
2224 // We'll want to schedule the timer to fire at the minimum layout threshold.
2225 return max(0, cLayoutScheduleThreshold - elapsed) + m_extraLayoutDelay;
2228 int Document::elapsedTime() const
2230 return static_cast<int>((currentTime() - m_startTime) * 1000);
2233 void Document::write(const SegmentedString& text, Document* ownerDocument)
2235 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2236 if (!ownerElement())
2237 printf("Beginning a document.write at %d\n", elapsedTime());
2240 bool hasInsertionPoint = m_parser && m_parser->hasInsertionPoint();
2241 if (!hasInsertionPoint && m_ignoreDestructiveWriteCount)
2244 if (!hasInsertionPoint)
2245 open(ownerDocument);
2248 m_parser->insert(text);
2250 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2251 if (!ownerElement())
2252 printf("Ending a document.write at %d\n", elapsedTime());
2256 void Document::write(const String& text, Document* ownerDocument)
2258 write(SegmentedString(text), ownerDocument);
2261 void Document::writeln(const String& text, Document* ownerDocument)
2263 write(text, ownerDocument);
2264 write("\n", ownerDocument);
2267 void Document::finishParsing()
2269 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2270 if (!ownerElement())
2271 printf("Received all data at %d\n", elapsedTime());
2274 // Let the parser go through as much data as it can. There will be three possible outcomes after
2275 // finish() is called:
2276 // (1) All remaining data is parsed, document isn't loaded yet
2277 // (2) All remaining data is parsed, document is loaded, parser gets deleted
2278 // (3) Data is still remaining to be parsed.
2283 const KURL& Document::virtualURL() const
2288 KURL Document::virtualCompleteURL(const String& url) const
2290 return completeURL(url);
2293 void Document::setURL(const KURL& url)
2295 const KURL& newURL = url.isEmpty() ? blankURL() : url;
2296 if (newURL == m_url)
2300 m_documentURI = m_url.string();
2304 void Document::updateBaseURL()
2306 // DOM 3 Core: When the Document supports the feature "HTML" [DOM Level 2 HTML], the base URI is computed using
2307 // first the value of the href attribute of the HTML BASE element if any, and the value of the documentURI attribute
2308 // from the Document interface otherwise.
2309 if (m_baseElementURL.isEmpty()) {
2310 // The documentURI attribute is an arbitrary string. DOM 3 Core does not specify how it should be resolved,
2311 // so we use a null base URL.
2312 m_baseURL = KURL(KURL(), documentURI());
2314 m_baseURL = m_baseElementURL;
2315 if (!m_baseURL.isValid())
2319 m_elemSheet->setFinalURL(m_baseURL);
2320 if (m_mappedElementSheet)
2321 m_mappedElementSheet->setFinalURL(m_baseURL);
2324 void Document::processBaseElement()
2326 // Find the first href attribute in a base element and the first target attribute in a base element.
2327 const AtomicString* href = 0;
2328 const AtomicString* target = 0;
2329 for (Node* node = document()->firstChild(); node && (!href || !target); node = node->traverseNextNode()) {
2330 if (node->hasTagName(baseTag)) {
2332 const AtomicString& value = static_cast<Element*>(node)->fastGetAttribute(hrefAttr);
2333 if (!value.isNull())
2337 const AtomicString& value = static_cast<Element*>(node)->fastGetAttribute(targetAttr);
2338 if (!value.isNull())
2344 // FIXME: Since this doesn't share code with completeURL it may not handle encodings correctly.
2345 KURL baseElementURL;
2347 String strippedHref = stripLeadingAndTrailingHTMLSpaces(*href);
2348 if (!strippedHref.isEmpty() && (!frame() || frame()->script()->xssAuditor()->canSetBaseElementURL(*href)))
2349 baseElementURL = KURL(url(), strippedHref);
2351 if (m_baseElementURL != baseElementURL) {
2352 m_baseElementURL = baseElementURL;
2356 m_baseTarget = target ? *target : nullAtom;
2359 String Document::userAgent(const KURL& url) const
2361 return frame() ? frame()->loader()->userAgent(url) : String();
2364 CSSStyleSheet* Document::pageUserSheet()
2366 if (m_pageUserSheet)
2367 return m_pageUserSheet.get();
2369 Page* owningPage = page();
2373 String userSheetText = owningPage->userStyleSheet();
2374 if (userSheetText.isEmpty())
2377 // Parse the sheet and cache it.
2378 m_pageUserSheet = CSSStyleSheet::createInline(this, settings()->userStyleSheetLocation());
2379 m_pageUserSheet->setIsUserStyleSheet(true);
2380 m_pageUserSheet->parseString(userSheetText, !inQuirksMode());
2381 return m_pageUserSheet.get();
2384 void Document::clearPageUserSheet()
2386 if (m_pageUserSheet) {
2387 m_pageUserSheet = 0;
2388 styleSelectorChanged(DeferRecalcStyle);
2392 void Document::updatePageUserSheet()
2394 clearPageUserSheet();
2395 if (pageUserSheet())
2396 styleSelectorChanged(RecalcStyleImmediately);
2399 const Vector<RefPtr<CSSStyleSheet> >* Document::pageGroupUserSheets() const
2401 if (m_pageGroupUserSheetCacheValid)
2402 return m_pageGroupUserSheets.get();
2404 m_pageGroupUserSheetCacheValid = true;
2406 Page* owningPage = page();
2410 const PageGroup& pageGroup = owningPage->group();
2411 const UserStyleSheetMap* sheetsMap = pageGroup.userStyleSheets();
2415 UserStyleSheetMap::const_iterator end = sheetsMap->end();
2416 for (UserStyleSheetMap::const_iterator it = sheetsMap->begin(); it != end; ++it) {
2417 const UserStyleSheetVector* sheets = it->second;
2418 for (unsigned i = 0; i < sheets->size(); ++i) {
2419 const UserStyleSheet* sheet = sheets->at(i).get();
2420 if (sheet->injectedFrames() == InjectInTopFrameOnly && ownerElement())
2422 if (!UserContentURLPattern::matchesPatterns(url(), sheet->whitelist(), sheet->blacklist()))
2424 RefPtr<CSSStyleSheet> parsedSheet = CSSStyleSheet::createInline(const_cast<Document*>(this), sheet->url());
2425 parsedSheet->setIsUserStyleSheet(sheet->level() == UserStyleUserLevel);
2426 parsedSheet->parseString(sheet->source(), !inQuirksMode());
2427 if (!m_pageGroupUserSheets)
2428 m_pageGroupUserSheets.set(new Vector<RefPtr<CSSStyleSheet> >);
2429 m_pageGroupUserSheets->append(parsedSheet.release());
2433 return m_pageGroupUserSheets.get();
2436 void Document::clearPageGroupUserSheets()
2438 m_pageGroupUserSheetCacheValid = false;
2439 if (m_pageGroupUserSheets && m_pageGroupUserSheets->size()) {
2440 m_pageGroupUserSheets->clear();
2441 styleSelectorChanged(DeferRecalcStyle);
2445 void Document::updatePageGroupUserSheets()
2447 clearPageGroupUserSheets();
2448 if (pageGroupUserSheets() && pageGroupUserSheets()->size())
2449 styleSelectorChanged(RecalcStyleImmediately);
2452 CSSStyleSheet* Document::elementSheet()
2455 m_elemSheet = CSSStyleSheet::createInline(this, m_baseURL);
2456 return m_elemSheet.get();
2459 CSSStyleSheet* Document::mappedElementSheet()
2461 if (!m_mappedElementSheet)
2462 m_mappedElementSheet = CSSStyleSheet::createInline(this, m_baseURL);
2463 return m_mappedElementSheet.get();
2466 static Node* nextNodeWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent* event)
2468 // Search is inclusive of start
2469 for (Node* n = start; n; n = n->traverseNextNode())
2470 if (n->isKeyboardFocusable(event) && n->tabIndex() == tabIndex)
2476 static Node* previousNodeWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent* event)
2478 // Search is inclusive of start
2479 for (Node* n = start; n; n = n->traversePreviousNode())
2480 if (n->isKeyboardFocusable(event) && n->tabIndex() == tabIndex)
2486 static Node* nextNodeWithGreaterTabIndex(Node* start, int tabIndex, KeyboardEvent* event)
2488 // Search is inclusive of start
2489 int winningTabIndex = SHRT_MAX + 1;
2491 for (Node* n = start; n; n = n->traverseNextNode())
2492 if (n->isKeyboardFocusable(event) && n->tabIndex() > tabIndex && n->tabIndex() < winningTabIndex) {
2494 winningTabIndex = n->tabIndex();
2500 static Node* previousNodeWithLowerTabIndex(Node* start, int tabIndex, KeyboardEvent* event)
2502 // Search is inclusive of start
2503 int winningTabIndex = 0;
2505 for (Node* n = start; n; n = n->traversePreviousNode())
2506 if (n->isKeyboardFocusable(event) && n->tabIndex() < tabIndex && n->tabIndex() > winningTabIndex) {
2508 winningTabIndex = n->tabIndex();
2514 Node* Document::nextFocusableNode(Node* start, KeyboardEvent* event)
2517 // If a node is excluded from the normal tabbing cycle, the next focusable node is determined by tree order
2518 if (start->tabIndex() < 0) {
2519 for (Node* n = start->traverseNextNode(); n; n = n->traverseNextNode())
2520 if (n->isKeyboardFocusable(event) && n->tabIndex() >= 0)
2524 // First try to find a node with the same tabindex as start that comes after start in the document.
2525 if (Node* winner = nextNodeWithExactTabIndex(start->traverseNextNode(), start->tabIndex(), event))
2528 if (!start->tabIndex())
2529 // We've reached the last node in the document with a tabindex of 0. This is the end of the tabbing order.
2533 // Look for the first node in the document that:
2534 // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if start is null), and
2535 // 2) comes first in the document, if there's a tie.
2536 if (Node* winner = nextNodeWithGreaterTabIndex(this, start ? start->tabIndex() : 0, event))
2539 // There are no nodes with a tabindex greater than start's tabindex,
2540 // so find the first node with a tabindex of 0.
2541 return nextNodeWithExactTabIndex(this, 0, event);
2544 Node* Document::previousFocusableNode(Node* start, KeyboardEvent* event)
2547 for (last = this; last->lastChild(); last = last->lastChild()) { }
2549 // First try to find the last node in the document that comes before start and has the same tabindex as start.
2550 // If start is null, find the last node in the document with a tabindex of 0.
2552 int startingTabIndex;
2554 startingNode = start->traversePreviousNode();
2555 startingTabIndex = start->tabIndex();
2557 startingNode = last;
2558 startingTabIndex = 0;
2561 // However, if a node is excluded from the normal tabbing cycle, the previous focusable node is determined by tree order
2562 if (startingTabIndex < 0) {
2563 for (Node* n = startingNode; n; n = n->traversePreviousNode())
2564 if (n->isKeyboardFocusable(event) && n->tabIndex() >= 0)
2568 if (Node* winner = previousNodeWithExactTabIndex(startingNode, startingTabIndex, event))
2571 // There are no nodes before start with the same tabindex as start, so look for a node that:
2572 // 1) has the highest non-zero tabindex (that is less than start's tabindex), and
2573 // 2) comes last in the document, if there's a tie.
2574 startingTabIndex = (start && start->tabIndex()) ? start->tabIndex() : SHRT_MAX;
2575 return previousNodeWithLowerTabIndex(last, startingTabIndex, event);
2578 int Document::nodeAbsIndex(Node *node)
2580 ASSERT(node->document() == this);
2583 for (Node* n = node; n && n != this; n = n->traversePreviousNode())
2588 Node* Document::nodeWithAbsIndex(int absIndex)
2591 for (int i = 0; n && (i < absIndex); i++)
2592 n = n->traverseNextNode();
2596 void Document::processHttpEquiv(const String& equiv, const String& content)
2598 ASSERT(!equiv.isNull() && !content.isNull());
2600 Frame* frame = this->frame();
2602 if (equalIgnoringCase(equiv, "default-style")) {
2603 // The preferred style set has been overridden as per section
2604 // 14.3.2 of the HTML4.0 specification. We need to update the
2605 // sheet used variable and then update our style selector.
2606 // For more info, see the test at:
2607 // http://www.hixie.ch/tests/evil/css/import/main/preferred.html
2609 m_selectedStylesheetSet = content;
2610 m_preferredStylesheetSet = content;
2611 styleSelectorChanged(DeferRecalcStyle);
2612 } else if (equalIgnoringCase(equiv, "refresh")) {
2615 if (frame && parseHTTPRefresh(content, true, delay, url)) {
2617 url = frame->loader()->url().string();
2619 url = completeURL(url).string();
2620 frame->navigationScheduler()->scheduleRedirect(delay, url);
2622 } else if (equalIgnoringCase(equiv, "set-cookie")) {
2623 // FIXME: make setCookie work on XML documents too; e.g. in case of <html:meta .....>
2624 if (isHTMLDocument()) {
2625 ExceptionCode ec; // Exception (for sandboxed documents) ignored.
2626 static_cast<HTMLDocument*>(this)->setCookie(content, ec);
2628 } else if (equalIgnoringCase(equiv, "content-language"))
2629 setContentLanguage(content);
2630 else if (equalIgnoringCase(equiv, "x-dns-prefetch-control"))
2631 parseDNSPrefetchControlHeader(content);
2632 else if (equalIgnoringCase(equiv, "x-frame-options")) {
2634 FrameLoader* frameLoader = frame->loader();
2635 if (frameLoader->shouldInterruptLoadForXFrameOptions(content, url())) {
2636 frameLoader->stopAllLoaders();
2637 frame->navigationScheduler()->scheduleLocationChange(securityOrigin(), blankURL(), String());
2639 DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to display document because display forbidden by X-Frame-Options.\n"));
2640 frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String());
2646 // Though isspace() considers \t and \v to be whitespace, Win IE doesn't.
2647 static bool isSeparator(UChar c)
2649 return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '=' || c == ',' || c == '\0';
2652 void Document::processArguments(const String& features, void* data, ArgumentsCallback callback)
2654 // Tread lightly in this code -- it was specifically designed to mimic Win IE's parsing behavior.
2655 int keyBegin, keyEnd;
2656 int valueBegin, valueEnd;
2659 int length = features.length();
2660 String buffer = features.lower();
2661 while (i < length) {
2662 // skip to first non-separator, but don't skip past the end of the string
2663 while (isSeparator(buffer[i])) {
2670 // skip to first separator
2671 while (!isSeparator(buffer[i]))
2675 // skip to first '=', but don't skip past a ',' or the end of the string
2676 while (buffer[i] != '=') {
2677 if (buffer[i] == ',' || i >= length)
2682 // skip to first non-separator, but don't skip past a ',' or the end of the string
2683 while (isSeparator(buffer[i])) {
2684 if (buffer[i] == ',' || i >= length)
2690 // skip to first separator
2691 while (!isSeparator(buffer[i]))
2695 ASSERT(i <= length);
2697 String keyString = buffer.substring(keyBegin, keyEnd - keyBegin);
2698 String valueString = buffer.substring(valueBegin, valueEnd - valueBegin);
2699 callback(keyString, valueString, this, data);
2703 void Document::processViewport(const String& features)
2705 ASSERT(!features.isNull());
2707 m_viewportArguments = ViewportArguments();
2708 processArguments(features, (void*)&m_viewportArguments, &setViewportFeature);
2710 Frame* frame = this->frame();
2711 if (!frame || !frame->page())
2714 frame->page()->updateViewportArguments();
2717 MouseEventWithHitTestResults Document::prepareMouseEvent(const HitTestRequest& request, const IntPoint& documentPoint, const PlatformMouseEvent& event)
2719 ASSERT(!renderer() || renderer()->isRenderView());
2722 return MouseEventWithHitTestResults(event, HitTestResult(IntPoint()));
2724 HitTestResult result(documentPoint);
2725 renderView()->layer()->hitTest(request, result);
2727 if (!request.readOnly())
2728 updateStyleIfNeeded();
2730 return MouseEventWithHitTestResults(event, result);
2733 // DOM Section 1.1.1
2734 bool Document::childTypeAllowed(NodeType type)
2737 case ATTRIBUTE_NODE:
2738 case CDATA_SECTION_NODE:
2739 case DOCUMENT_FRAGMENT_NODE:
2742 case ENTITY_REFERENCE_NODE:
2745 case XPATH_NAMESPACE_NODE:
2748 case PROCESSING_INSTRUCTION_NODE:
2750 case DOCUMENT_TYPE_NODE:
2752 // Documents may contain no more than one of each of these.
2753 // (One Element and one DocumentType.)
2754 for (Node* c = firstChild(); c; c = c->nextSibling())
2755 if (c->nodeType() == type)
2762 bool Document::canReplaceChild(Node* newChild, Node* oldChild)
2765 // ContainerNode::replaceChild will raise a NOT_FOUND_ERR.
2768 if (oldChild->nodeType() == newChild->nodeType())
2771 int numDoctypes = 0;
2772 int numElements = 0;
2774 // First, check how many doctypes and elements we have, not counting
2775 // the child we're about to remove.
2776 for (Node* c = firstChild(); c; c = c->nextSibling()) {
2780 switch (c->nodeType()) {
2781 case DOCUMENT_TYPE_NODE:
2792 // Then, see how many doctypes and elements might be added by the new child.
2793 if (newChild->nodeType() == DOCUMENT_FRAGMENT_NODE) {
2794 for (Node* c = firstChild(); c; c = c->nextSibling()) {
2795 switch (c->nodeType()) {
2796 case ATTRIBUTE_NODE:
2797 case CDATA_SECTION_NODE:
2798 case DOCUMENT_FRAGMENT_NODE:
2801 case ENTITY_REFERENCE_NODE:
2804 case XPATH_NAMESPACE_NODE:
2807 case PROCESSING_INSTRUCTION_NODE:
2809 case DOCUMENT_TYPE_NODE:
2818 switch (newChild->nodeType()) {
2819 case ATTRIBUTE_NODE:
2820 case CDATA_SECTION_NODE:
2821 case DOCUMENT_FRAGMENT_NODE:
2824 case ENTITY_REFERENCE_NODE:
2827 case XPATH_NAMESPACE_NODE:
2830 case PROCESSING_INSTRUCTION_NODE:
2832 case DOCUMENT_TYPE_NODE:
2841 if (numElements > 1 || numDoctypes > 1)
2847 PassRefPtr<Node> Document::cloneNode(bool /*deep*/)
2849 // Spec says cloning Document nodes is "implementation dependent"
2850 // so we do not support it...
2854 StyleSheetList* Document::styleSheets()
2856 return m_styleSheets.get();
2859 String Document::preferredStylesheetSet() const
2861 return m_preferredStylesheetSet;
2864 String Document::selectedStylesheetSet() const
2866 return m_selectedStylesheetSet;
2869 void Document::setSelectedStylesheetSet(const String& aString)
2871 m_selectedStylesheetSet = aString;
2872 styleSelectorChanged(DeferRecalcStyle);
2875 // This method is called whenever a top-level stylesheet has finished loading.
2876 void Document::removePendingSheet()
2878 // Make sure we knew this sheet was pending, and that our count isn't out of sync.
2879 ASSERT(m_pendingStylesheets > 0);
2881 m_pendingStylesheets--;
2883 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2884 if (!ownerElement())
2885 printf("Stylesheet loaded at time %d. %d stylesheets still remain.\n", elapsedTime(), m_pendingStylesheets);
2888 if (m_pendingStylesheets)
2891 styleSelectorChanged(RecalcStyleImmediately);
2893 ScriptableDocumentParser* parser = scriptableDocumentParser();
2895 parser->executeScriptsWaitingForStylesheets();
2897 if (m_gotoAnchorNeededAfterStylesheetsLoad && view())
2898 view()->scrollToFragment(m_frame->loader()->url());
2901 void Document::styleSelectorChanged(StyleSelectorUpdateFlag updateFlag)
2903 // Don't bother updating, since we haven't loaded all our style info yet
2904 // and haven't calculated the style selector for the first time.
2905 if (!attached() || (!m_didCalculateStyleSelector && !haveStylesheetsLoaded()))
2908 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2909 if (!ownerElement())
2910 printf("Beginning update of style selector at time %d.\n", elapsedTime());
2913 recalcStyleSelector();
2915 if (updateFlag == DeferRecalcStyle) {
2916 scheduleForcedStyleRecalc();
2920 if (didLayoutWithPendingStylesheets() && m_pendingStylesheets <= 0) {
2921 m_pendingSheetLayout = IgnoreLayoutWithPendingSheets;
2923 renderer()->repaint();
2926 // This recalcStyle initiates a new recalc cycle. We need to bracket it to
2927 // make sure animations get the correct update time
2929 m_frame->animation()->beginAnimationUpdate();
2932 m_frame->animation()->endAnimationUpdate();
2934 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2935 if (!ownerElement())
2936 printf("Finished update of style selector at time %d\n", elapsedTime());
2940 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
2942 view()->scheduleRelayout();
2945 if (m_mediaQueryMatcher)
2946 m_mediaQueryMatcher->styleSelectorChanged();
2949 void Document::addStyleSheetCandidateNode(Node* node, bool createdByParser)
2951 // Until the <body> exists, we have no choice but to compare document positions,
2952 // since styles outside of the body and head continue to be shunted into the head
2953 // (and thus can shift to end up before dynamically added DOM content that is also
2954 // outside the body).
2955 if ((createdByParser && body()) || m_styleSheetCandidateNodes.isEmpty()) {
2956 m_styleSheetCandidateNodes.add(node);
2960 // Determine an appropriate insertion point.
2961 StyleSheetCandidateListHashSet::iterator begin = m_styleSheetCandidateNodes.begin();
2962 StyleSheetCandidateListHashSet::iterator end = m_styleSheetCandidateNodes.end();
2963 StyleSheetCandidateListHashSet::iterator it = end;
2964 Node* followingNode = 0;
2968 unsigned short position = n->compareDocumentPosition(node);
2969 if (position == DOCUMENT_POSITION_FOLLOWING) {
2970 m_styleSheetCandidateNodes.insertBefore(followingNode, node);
2974 } while (it != begin);
2976 m_styleSheetCandidateNodes.insertBefore(followingNode, node);
2979 void Document::removeStyleSheetCandidateNode(Node* node)
2981 m_styleSheetCandidateNodes.remove(node);
2984 void Document::recalcStyleSelector()
2986 if (!renderer() || !attached())
2989 StyleSheetVector sheets;
2991 bool matchAuthorAndUserStyles = true;
2992 if (Settings* settings = this->settings())
2993 matchAuthorAndUserStyles = settings->authorAndUserStylesEnabled();
2995 StyleSheetCandidateListHashSet::iterator begin = m_styleSheetCandidateNodes.begin();
2996 StyleSheetCandidateListHashSet::iterator end = m_styleSheetCandidateNodes.end();
2997 if (!matchAuthorAndUserStyles)
2999 for (StyleSheetCandidateListHashSet::iterator it = begin; it != end; ++it) {
3002 StyleSheet* sheet = 0;
3004 if (n->nodeType() == PROCESSING_INSTRUCTION_NODE) {
3005 // Processing instruction (XML documents only).
3006 // We don't support linking to embedded CSS stylesheets, see <https://bugs.webkit.org/show_bug.cgi?id=49281> for discussion.
3007 ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(n);
3008 sheet = pi->sheet();
3010 // Don't apply XSL transforms to already transformed documents -- <rdar://problem/4132806>
3011 if (pi->isXSL() && !transformSourceDocument()) {
3012 // Don't apply XSL transforms until loading is finished.
3014 applyXSLTransform(pi);
3018 } else if ((n->isHTMLElement() && (n->hasTagName(linkTag) || n->hasTagName(styleTag)))
3020 || (n->isSVGElement() && n->hasTagName(SVGNames::styleTag))
3023 Element* e = static_cast<Element*>(n);
3024 AtomicString title = e->getAttribute(titleAttr);
3025 bool enabledViaScript = false;
3026 if (e->hasLocalName(linkTag)) {
3028 HTMLLinkElement* linkElement = static_cast<HTMLLinkElement*>(n);
3029 if (linkElement->isDisabled())
3031 enabledViaScript = linkElement->isEnabledViaScript();
3032 if (linkElement->isLoading()) {
3033 // it is loading but we should still decide which style sheet set to use
3034 if (!enabledViaScript && !title.isEmpty() && m_preferredStylesheetSet.isEmpty()) {
3035 const AtomicString& rel = e->getAttribute(relAttr);
3036 if (!rel.contains("alternate")) {
3037 m_preferredStylesheetSet = title;
3038 m_selectedStylesheetSet = title;
3043 if (!linkElement->sheet())
3047 // Get the current preferred styleset. This is the
3048 // set of sheets that will be enabled.
3050 if (n->isSVGElement() && n->hasTagName(SVGNames::styleTag))
3051 sheet = static_cast<SVGStyleElement*>(n)->sheet();
3054 if (e->hasLocalName(linkTag))
3055 sheet = static_cast<HTMLLinkElement*>(n)->sheet();
3058 sheet = static_cast<HTMLStyleElement*>(n)->sheet();
3060 // Check to see if this sheet belongs to a styleset
3061 // (thus making it PREFERRED or ALTERNATE rather than
3063 if (!enabledViaScript && !title.isEmpty()) {
3064 // Yes, we have a title.
3065 if (m_preferredStylesheetSet.isEmpty()) {
3066 // No preferred set has been established. If
3067 // we are NOT an alternate sheet, then establish
3068 // us as the preferred set. Otherwise, just ignore
3070 AtomicString rel = e->getAttribute(relAttr);
3071 if (e->hasLocalName(styleTag) || !rel.contains("alternate"))
3072 m_preferredStylesheetSet = m_selectedStylesheetSet = title;
3075 if (title != m_preferredStylesheetSet)
3081 sheets.append(sheet);
3084 m_styleSheets->swap(sheets);
3086 m_styleSelector.clear();
3087 m_didCalculateStyleSelector = true;
3090 void Document::setHoverNode(PassRefPtr<Node> newHoverNode)
3092 m_hoverNode = newHoverNode;
3095 void Document::setActiveNode(PassRefPtr<Node> newActiveNode)
3097 m_activeNode = newActiveNode;
3100 void Document::focusedNodeRemoved()
3105 void Document::removeFocusedNodeOfSubtree(Node* node, bool amongChildrenOnly)
3107 if (!m_focusedNode || this->inPageCache()) // If the document is in the page cache, then we don't need to clear out the focused node.
3110 bool nodeInSubtree = false;
3111 if (amongChildrenOnly)
3112 nodeInSubtree = m_focusedNode->isDescendantOf(node);
3114 nodeInSubtree = (m_focusedNode == node) || m_focusedNode->isDescendantOf(node);
3117 document()->focusedNodeRemoved();
3120 void Document::hoveredNodeDetached(Node* node)
3122 if (!m_hoverNode || (node != m_hoverNode && (!m_hoverNode->isTextNode() || node != m_hoverNode->parentNode())))
3125 m_hoverNode = node->parentNode();
3126 while (m_hoverNode && !m_hoverNode->renderer())
3127 m_hoverNode = m_hoverNode->parentNode();
3129 frame()->eventHandler()->scheduleHoverStateUpdate();
3132 void Document::activeChainNodeDetached(Node* node)
3134 if (!m_activeNode || (node != m_activeNode && (!m_activeNode->isTextNode() || node != m_activeNode->parentNode())))
3137 m_activeNode = node->parentNode();
3138 while (m_activeNode && !m_activeNode->renderer())
3139 m_activeNode = m_activeNode->parentNode();
3142 #if ENABLE(DASHBOARD_SUPPORT)
3143 const Vector<DashboardRegionValue>& Document::dashboardRegions() const
3145 return m_dashboardRegions;
3148 void Document::setDashboardRegions(const Vector<DashboardRegionValue>& regions)
3150 m_dashboardRegions = regions;
3151 setDashboardRegionsDirty(false);
3155 bool Document::setFocusedNode(PassRefPtr<Node> newFocusedNode)
3157 // Make sure newFocusedNode is actually in this document
3158 if (newFocusedNode && (newFocusedNode->document() != this))
3161 if (m_focusedNode == newFocusedNode)
3167 bool focusChangeBlocked = false;
3168 RefPtr<Node> oldFocusedNode = m_focusedNode;
3171 // Remove focus from the existing focus node (if any)
3172 if (oldFocusedNode && !oldFocusedNode->inDetach()) {
3173 if (oldFocusedNode->active())
3174 oldFocusedNode->setActive(false);
3176 oldFocusedNode->setFocus(false);
3178 // Dispatch a change event for text fields or textareas that have been edited
3179 RenderObject* r = oldFocusedNode->renderer();
3180 if (r && r->isTextControl() && toRenderTextControl(r)->wasChangedSinceLastChangeEvent()) {
3181 static_cast<Element*>(oldFocusedNode.get())->dispatchFormControlChangeEvent();
3182 r = oldFocusedNode->renderer();
3183 if (r && r->isTextControl())
3184 toRenderTextControl(r)->setChangedSinceLastChangeEvent(false);
3187 // Dispatch the blur event and let the node do any other blur related activities (important for text fields)
3188 oldFocusedNode->dispatchBlurEvent();
3190 if (m_focusedNode) {
3191 // handler shifted focus
3192 focusChangeBlocked = true;
3196 oldFocusedNode->dispatchUIEvent(eventNames().focusoutEvent, 0, 0); // DOM level 3 name for the bubbling blur event.
3197 // FIXME: We should remove firing DOMFocusOutEvent event when we are sure no content depends
3198 // on it, probably when <rdar://problem/8503958> is resolved.
3199 oldFocusedNode->dispatchUIEvent(eventNames().DOMFocusOutEvent, 0, 0); // DOM level 2 name for compatibility.
3201 if (m_focusedNode) {
3202 // handler shifted focus
3203 focusChangeBlocked = true;
3206 if (oldFocusedNode == this && oldFocusedNode->hasOneRef())
3209 if (oldFocusedNode == oldFocusedNode->rootEditableElement())
3210 frame()->editor()->didEndEditing();
3213 Widget* oldWidget = widgetForNode(oldFocusedNode.get());
3215 oldWidget->setFocus(false);
3217 view()->setFocus(false);
3221 if (newFocusedNode) {
3222 if (newFocusedNode == newFocusedNode->rootEditableElement() && !acceptsEditingFocus(newFocusedNode.get())) {
3223 // delegate blocks focus change
3224 focusChangeBlocked = true;
3225 goto SetFocusedNodeDone;
3227 // Set focus on the new node
3228 m_focusedNode = newFocusedNode.get();
3230 // Dispatch the focus event and let the node do any other focus related activities (important for text fields)
3231 m_focusedNode->dispatchFocusEvent();
3233 if (m_focusedNode != newFocusedNode) {
3234 // handler shifted focus
3235 focusChangeBlocked = true;
3236 goto SetFocusedNodeDone;
3239 m_focusedNode->dispatchUIEvent(eventNames().focusinEvent, 0, 0); // DOM level 3 bubbling focus event.
3240 // FIXME: We should remove firing DOMFocusInEvent event when we are sure no content depends
3241 // on it, probably when <rdar://problem/8503958> is resolved.
3242 m_focusedNode->dispatchUIEvent(eventNames().DOMFocusInEvent, 0, 0); // DOM level 2 for compatibility.
3244 if (m_focusedNode != newFocusedNode) {
3245 // handler shifted focus
3246 focusChangeBlocked = true;
3247 goto SetFocusedNodeDone;
3249 m_focusedNode->setFocus(true);
3251 if (m_focusedNode == m_focusedNode->rootEditableElement())
3252 frame()->editor()->didBeginEditing();
3254 // eww, I suck. set the qt focus correctly
3255 // ### find a better place in the code for this
3257 Widget* focusWidget = widgetForNode(m_focusedNode.get());
3259 // Make sure a widget has the right size before giving it focus.
3260 // Otherwise, we are testing edge cases of the Widget code.
3261 // Specifically, in WebCore this does not work well for text fields.
3263 // Re-get the widget in case updating the layout changed things.
3264 focusWidget = widgetForNode(m_focusedNode.get());
3267 focusWidget->setFocus(true);
3269 view()->setFocus(true);
3273 #if PLATFORM(MAC) || PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(CHROMIUM)
3274 if (!focusChangeBlocked && m_focusedNode && AXObjectCache::accessibilityEnabled()) {
3275 RenderObject* oldFocusedRenderer = 0;
3276 RenderObject* newFocusedRenderer = 0;
3279 oldFocusedRenderer = oldFocusedNode->renderer();
3281 newFocusedRenderer = newFocusedNode->renderer();
3283 axObjectCache()->handleFocusedUIElementChanged(oldFocusedRenderer, newFocusedRenderer);
3286 if (!focusChangeBlocked)
3287 page()->chrome()->focusedNodeChanged(m_focusedNode.get());
3290 updateStyleIfNeeded();
3291 return !focusChangeBlocked;
3294 void Document::getFocusableNodes(Vector<RefPtr<Node> >& nodes)
3298 for (Node* node = firstChild(); node; node = node->traverseNextNode()) {
3299 if (node->isFocusable())
3304 void Document::setCSSTarget(Element* n)
3307 m_cssTarget->setNeedsStyleRecalc();
3310 n->setNeedsStyleRecalc();
3313 void Document::attachNodeIterator(NodeIterator* ni)
3315 m_nodeIterators.add(ni);
3318 void Document::detachNodeIterator(NodeIterator* ni)
3320 // The node iterator can be detached without having been attached if its root node didn't have a document
3321 // when the iterator was created, but has it now.
3322 m_nodeIterators.remove(ni);
3325 void Document::moveNodeIteratorsToNewDocument(Node* node, Document* newDocument)
3327 HashSet<NodeIterator*> nodeIteratorsList = m_nodeIterators;
3328 HashSet<NodeIterator*>::const_iterator nodeIteratorsEnd = nodeIteratorsList.end();
3329 for (HashSet<NodeIterator*>::const_iterator it = nodeIteratorsList.begin(); it != nodeIteratorsEnd; ++it) {
3330 if ((*it)->root() == node) {
3331 detachNodeIterator(*it);
3332 newDocument->attachNodeIterator(*it);
3337 void Document::nodeChildrenChanged(ContainerNode* container)
3339 if (!disableRangeMutation(page())) {
3340 HashSet<Range*>::const_iterator end = m_ranges.end();
3341 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it)
3342 (*it)->nodeChildrenChanged(container);
3346 void Document::nodeChildrenWillBeRemoved(ContainerNode* container)
3348 if (!disableRangeMutation(page())) {
3349 HashSet<Range*>::const_iterator end = m_ranges.end();
3350 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it)
3351 (*it)->nodeChildrenWillBeRemoved(container);
3354 HashSet<NodeIterator*>::const_iterator nodeIteratorsEnd = m_nodeIterators.end();
3355 for (HashSet<NodeIterator*>::const_iterator it = m_nodeIterators.begin(); it != nodeIteratorsEnd; ++it) {
3356 for (Node* n = container->firstChild(); n; n = n->nextSibling())
3357 (*it)->nodeWillBeRemoved(n);
3360 if (Frame* frame = this->frame()) {
3361 for (Node* n = container->firstChild(); n; n = n->nextSibling()) {
3362 frame->selection()->nodeWillBeRemoved(n);
3363 frame->page()->dragCaretController()->nodeWillBeRemoved(n);
3368 void Document::nodeWillBeRemoved(Node* n)
3370 HashSet<NodeIterator*>::const_iterator nodeIteratorsEnd = m_nodeIterators.end();
3371 for (HashSet<NodeIterator*>::const_iterator it = m_nodeIterators.begin(); it != nodeIteratorsEnd; ++it)
3372 (*it)->nodeWillBeRemoved(n);
3374 if (!disableRangeMutation(page())) {
3375 HashSet<Range*>::const_iterator rangesEnd = m_ranges.end();
3376 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != rangesEnd; ++it)
3377 (*it)->nodeWillBeRemoved(n);
3380 if (Frame* frame = this->frame()) {
3381 frame->selection()->nodeWillBeRemoved(n);
3382 frame->page()->dragCaretController()->nodeWillBeRemoved(n);
3385 #if ENABLE(FULLSCREEN_API)
3386 // If the current full screen element or any of its ancestors is removed, set the current
3387 // full screen element to the document root, and fire a fullscreenchange event to inform
3388 // clients of the DOM.
3390 if (n->contains(m_fullScreenElement.get())) {
3391 ASSERT(n != documentElement());
3392 setFullScreenRenderer(0);
3393 m_fullScreenElement = documentElement();
3394 m_fullScreenElement->setNeedsStyleRecalc();
3395 m_fullScreenElement->detach();
3396 updateStyleIfNeeded();
3397 m_fullScreenChangeDelayTimer.startOneShot(0);
3402 void Document::textInserted(Node* text, unsigned offset, unsigned length)
3404 if (!disableRangeMutation(page())) {
3405 HashSet<Range*>::const_iterator end = m_ranges.end();
3406 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it)
3407 (*it)->textInserted(text, offset, length);
3410 // Update the markers for spelling and grammar checking.
3411 m_markers->shiftMarkers(text, offset, length);
3414 void Document::textRemoved(Node* text, unsigned offset, unsigned length)
3416 if (!disableRangeMutation(page())) {
3417 HashSet<Range*>::const_iterator end = m_ranges.end();
3418 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it)
3419 (*it)->textRemoved(text, offset, length);
3422 // Update the markers for spelling and grammar checking.
3423 m_markers->removeMarkers(text, offset, length);
3424 m_markers->shiftMarkers(text, offset + length, 0 - length);
3427 void Document::textNodesMerged(Text* oldNode, unsigned offset)
3429 if (!disableRangeMutation(page())) {
3430 NodeWithIndex oldNodeWithIndex(oldNode);
3431 HashSet<Range*>::const_iterator end = m_ranges.end();
3432 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it)
3433 (*it)->textNodesMerged(oldNodeWithIndex, offset);
3436 // FIXME: This should update markers for spelling and grammar checking.
3439 void Document::textNodeSplit(Text* oldNode)
3441 if (!disableRangeMutation(page())) {
3442 HashSet<Range*>::const_iterator end = m_ranges.end();
3443 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it)
3444 (*it)->textNodeSplit(oldNode);
3447 // FIXME: This should update markers for spelling and grammar checking.
3450 // FIXME: eventually, this should return a DOMWindow stored in the document.
3451 DOMWindow* Document::domWindow() const
3456 // 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.
3457 // FIXME: We should always zero out the frame pointer on navigation to avoid accidentally accessing the new frame content.
3458 if (m_frame->document() != this)
3461 return frame()->domWindow();
3464 void Document::setWindowAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener)
3466 DOMWindow* domWindow = this->domWindow();
3469 domWindow->setAttributeEventListener(eventType, listener);
3472 EventListener* Document::getWindowAttributeEventListener(const AtomicString& eventType)
3474 DOMWindow* domWindow = this->domWindow();
3477 return domWindow->getAttributeEventListener(eventType);
3480 void Document::dispatchWindowEvent(PassRefPtr<Event> event, PassRefPtr<EventTarget> target)
3482 ASSERT(!eventDispatchForbidden());
3483 DOMWindow* domWindow = this->domWindow();
3486 domWindow->dispatchEvent(event, target);
3489 void Document::dispatchWindowLoadEvent()
3491 ASSERT(!eventDispatchForbidden());
3492 DOMWindow* domWindow = this->domWindow();
3495 domWindow->dispatchLoadEvent();
3498 void Document::enqueueWindowEvent(PassRefPtr<Event> event)
3500 event->setTarget(domWindow());
3501 m_eventQueue->enqueueEvent(event);
3504 PassRefPtr<Event> Document::createEvent(const String& eventType, ExceptionCode& ec)
3506 RefPtr<Event> event;
3507 if (eventType == "Event" || eventType == "Events" || eventType == "HTMLEvents")
3508 event = Event::create();
3509 else if (eventType == "CustomEvent")
3510 event = CustomEvent::create();
3511 else if (eventType == "KeyboardEvent" || eventType == "KeyboardEvents")
3512 event = KeyboardEvent::create();
3513 else if (eventType == "MessageEvent")
3514 event = MessageEvent::create();
3515 else if (eventType == "MouseEvent" || eventType == "MouseEvents")
3516 event = MouseEvent::create();
3517 else if (eventType == "MutationEvent" || eventType == "MutationEvents")
3518 event = MutationEvent::create();
3519 else if (eventType == "OverflowEvent")
3520 event = OverflowEvent::create();
3521 else if (eventType == "PageTransitionEvent")
3522 event = PageTransitionEvent::create();
3523 else if (eventType == "ProgressEvent")
3524 event = ProgressEvent::create();
3525 #if ENABLE(DOM_STORAGE)
3526 else if (eventType == "StorageEvent")
3527 event = StorageEvent::create();
3529 else if (eventType == "TextEvent")
3530 event = TextEvent::create();
3531 else if (eventType == "UIEvent" || eventType == "UIEvents")
3532 event = UIEvent::create();
3533 else if (eventType == "WebKitAnimationEvent")
3534 event = WebKitAnimationEvent::create();
3535 else if (eventType == "WebKitTransitionEvent")
3536 event = WebKitTransitionEvent::create();
3537 else if (eventType == "WheelEvent")
3538 event = WheelEvent::create();
3540 else if (eventType == "SVGEvents")
3541 event = Event::create();
3542 else if (eventType == "SVGZoomEvents")
3543 event = SVGZoomEvent::create();
3545 #if ENABLE(TOUCH_EVENTS)
3547 else if (eventType == "TouchEvent" && RuntimeEnabledFeatures::touchEnabled())
3549 else if (eventType == "TouchEvent")
3551 event = TouchEvent::create();
3553 #if ENABLE(DEVICE_ORIENTATION)
3554 else if (eventType == "DeviceMotionEvent")
3555 event = DeviceMotionEvent::create();
3556 else if (eventType == "DeviceOrientationEvent")
3557 event = DeviceOrientationEvent::create();
3559 #if ENABLE(ORIENTATION_EVENTS)
3560 else if (eventType == "OrientationEvent")
3561 event = Event::create();
3564 return event.release();
3566 ec = NOT_SUPPORTED_ERR;
3570 void Document::addListenerTypeIfNeeded(const AtomicString& eventType)
3572 if (eventType == eventNames().DOMSubtreeModifiedEvent)
3573 addListenerType(DOMSUBTREEMODIFIED_LISTENER);
3574 else if (eventType == eventNames().DOMNodeInsertedEvent)
3575 addListenerType(DOMNODEINSERTED_LISTENER);
3576 else if (eventType == eventNames().DOMNodeRemovedEvent)
3577 addListenerType(DOMNODEREMOVED_LISTENER);
3578 else if (eventType == eventNames().DOMNodeRemovedFromDocumentEvent)
3579 addListenerType(DOMNODEREMOVEDFROMDOCUMENT_LISTENER);
3580 else if (eventType == eventNames().DOMNodeInsertedIntoDocumentEvent)
3581 addListenerType(DOMNODEINSERTEDINTODOCUMENT_LISTENER);
3582 else if (eventType == eventNames().DOMAttrModifiedEvent)
3583 addListenerType(DOMATTRMODIFIED_LISTENER);
3584 else if (eventType == eventNames().DOMCharacterDataModifiedEvent)
3585 addListenerType(DOMCHARACTERDATAMODIFIED_LISTENER);
3586 else if (eventType == eventNames().overflowchangedEvent)
3587 addListenerType(OVERFLOWCHANGED_LISTENER);
3588 else if (eventType == eventNames().webkitAnimationStartEvent)
3589 addListenerType(ANIMATIONSTART_LISTENER);
3590 else if (eventType == eventNames().webkitAnimationEndEvent)
3591 addListenerType(ANIMATIONEND_LISTENER);
3592 else if (eventType == eventNames().webkitAnimationIterationEvent)
3593 addListenerType(ANIMATIONITERATION_LISTENER);
3594 else if (eventType == eventNames().webkitTransitionEndEvent)
3595 addListenerType(TRANSITIONEND_LISTENER);
3596 else if (eventType == eventNames().beforeloadEvent)
3597 addListenerType(BEFORELOAD_LISTENER);
3598 else if (eventType == eventNames().beforeprocessEvent)
3599 addListenerType(BEFOREPROCESS_LISTENER);
3600 #if ENABLE(TOUCH_EVENTS)
3601 else if (eventType == eventNames().touchstartEvent
3602 || eventType == eventNames().touchmoveEvent
3603 || eventType == eventNames().touchendEvent
3604 || eventType == eventNames().touchcancelEvent) {
3605 addListenerType(TOUCH_LISTENER);
3606 if (Page* page = this->page())
3607 page->chrome()->client()->needTouchEvents(true);
3612 CSSStyleDeclaration* Document::getOverrideStyle(Element*, const String&)
3617 HTMLFrameOwnerElement* Document::ownerElement() const
3621 return frame()->ownerElement();
3624 String Document::cookie(ExceptionCode& ec) const
3626 if (page() && !page()->cookieEnabled())
3629 // FIXME: The HTML5 DOM spec states that this attribute can raise an
3630 // INVALID_STATE_ERR exception on getting if the Document has no
3631 // browsing context.
3633 if (!securityOrigin()->canAccessCookies()) {
3638 KURL cookieURL = this->cookieURL();
3639 if (cookieURL.isEmpty())
3642 return cookies(this, cookieURL);
3645 void Document::setCookie(const String& value, ExceptionCode& ec)
3647 if (page() && !page()->cookieEnabled())
3650 // FIXME: The HTML5 DOM spec states that this attribute can raise an
3651 // INVALID_STATE_ERR exception on setting if the Document has no
3652 // browsing context.
3654 if (!securityOrigin()->canAccessCookies()) {
3659 KURL cookieURL = this->cookieURL();
3660 if (cookieURL.isEmpty())
3663 setCookies(this, cookieURL, value);
3666 String Document::referrer() const
3669 return frame()->loader()->referrer();
3673 String Document::domain() const
3675 return securityOrigin()->domain();
3678 void Document::setDomain(const String& newDomain, ExceptionCode& ec)
3680 if (SecurityOrigin::isDomainRelaxationForbiddenForURLScheme(securityOrigin()->protocol())) {
3685 // Both NS and IE specify that changing the domain is only allowed when
3686 // the new domain is a suffix of the old domain.
3688 // FIXME: We should add logging indicating why a domain was not allowed.
3690 // If the new domain is the same as the old domain, still call
3691 // securityOrigin()->setDomainForDOM. This will change the
3692 // security check behavior. For example, if a page loaded on port 8000
3693 // assigns its current domain using document.domain, the page will
3694 // allow other pages loaded on different ports in the same domain that
3695 // have also assigned to access this page.
3696 if (equalIgnoringCase(domain(), newDomain)) {
3697 securityOrigin()->setDomainFromDOM(newDomain);
3699 m_frame->script()->updateSecurityOrigin();
3703 int oldLength = domain().length();
3704 int newLength = newDomain.length();
3705 // e.g. newDomain = webkit.org (10) and domain() = www.webkit.org (14)
3706 if (newLength >= oldLength) {
3711 String test = domain();
3712 // Check that it's a subdomain, not e.g. "ebkit.org"
3713 if (test[oldLength - newLength - 1] != '.') {
3718 // Now test is "webkit.org" from domain()
3719 // and we check that it's the same thing as newDomain
3720 test.remove(0, oldLength - newLength);
3721 if (test != newDomain) {
3726 securityOrigin()->setDomainFromDOM(newDomain);
3728 m_frame->script()->updateSecurityOrigin();
3731 // http://www.whatwg.org/specs/web-apps/current-work/#dom-document-lastmodified
3732 String Document::lastModified() const
3734 DateComponents date;
3735 bool foundDate = false;
3737 String httpLastModified = m_frame->loader()->documentLoader()->response().httpHeaderField("Last-Modified");
3738 if (!httpLastModified.isEmpty()) {
3739 date.setMillisecondsSinceEpochForDateTime(parseDate(httpLastModified));
3743 // FIXME: If this document came from the file system, the HTML5
3744 // specificiation tells us to read the last modification date from the file
3747 date.setMillisecondsSinceEpochForDateTime(currentTimeMS());
3748 return String::format("%02d/%02d/%04d %02d:%02d:%02d", date.month() + 1, date.monthDay(), date.fullYear(), date.hour(), date.minute(), date.second());
3751 static bool isValidNameNonASCII(const UChar* characters, unsigned length)
3756 U16_NEXT(characters, i, length, c)
3757 if (!isValidNameStart(c))
3760 while (i < length) {
3761 U16_NEXT(characters, i, length, c)
3762 if (!isValidNamePart(c))
3769 static inline bool isValidNameASCII(const UChar* characters, unsigned length)
3771 UChar c = characters[0];
3772 if (!(isASCIIAlpha(c) || c == ':' || c == '_'))
3775 for (unsigned i = 1; i < length; ++i) {
3777 if (!(isASCIIAlphanumeric(c) || c == ':' || c == '_' || c == '-' || c == '.'))
3784 bool Document::isValidName(const String& name)
3786 unsigned length = name.length();
3790 const UChar* characters = name.characters();
3791 return isValidNameASCII(characters, length) || isValidNameNonASCII(characters, length);
3794 bool Document::parseQualifiedName(const String& qualifiedName, String& prefix, String& localName, ExceptionCode& ec)
3796 unsigned length = qualifiedName.length();
3799 ec = INVALID_CHARACTER_ERR;
3803 bool nameStart = true;
3804 bool sawColon = false;
3807 const UChar* s = qualifiedName.characters();
3808 for (unsigned i = 0; i < length;) {
3810 U16_NEXT(s, i, length, c)
3814 return false; // multiple colons: not allowed
3819 } else if (nameStart) {
3820 if (!isValidNameStart(c)) {
3821 ec = INVALID_CHARACTER_ERR;
3826 if (!isValidNamePart(c)) {
3827 ec = INVALID_CHARACTER_ERR;
3835 localName = qualifiedName;
3837 prefix = qualifiedName.substring(0, colonPos);
3838 if (prefix.isEmpty()) {
3842 localName = qualifiedName.substring(colonPos + 1);
3845 if (localName.isEmpty()) {
3853 void Document::addImageMap(HTMLMapElement* imageMap)
3855 AtomicStringImpl* name = imageMap->getName().impl();
3858 m_imageMapsByName.add(name, imageMap);
3861 void Document::removeImageMap(HTMLMapElement* imageMap)
3863 AtomicStringImpl* name = imageMap->getName().impl();
3866 m_imageMapsByName.remove(name, imageMap);
3869 inline bool keyMatchesMapName(AtomicStringImpl* key, Element* element)
3871 return element->hasTagName(mapTag) && static_cast<HTMLMapElement*>(element)->getName().impl() == key;
3874 inline bool keyMatchesLowercasedMapName(AtomicStringImpl* key, Element* element)
3876 return element->hasTagName(mapTag) && static_cast<HTMLMapElement*>(element)->getName().lower().impl() == key;
3879 HTMLMapElement* Document::getImageMap(const String& url) const
3883 size_t hashPos = url.find('#');
3884 String name = (hashPos == notFound ? url : url.substring(hashPos + 1)).impl();
3885 if (isHTMLDocument())
3886 return static_cast<HTMLMapElement*>(m_imageMapsByName.get<keyMatchesLowercasedMapName>(AtomicString(name.lower()).impl(), this));
3887 return static_cast<HTMLMapElement*>(m_imageMapsByName.get<keyMatchesMapName>(AtomicString(name).impl(), this));
3890 void Document::setDecoder(PassRefPtr<TextResourceDecoder> decoder)
3892 m_decoder = decoder;
3895 KURL Document::completeURL(const String& url) const
3897 // Always return a null URL when passed a null string.
3898 // FIXME: Should we change the KURL constructor to have this behavior?
3899 // See also [CSS]StyleSheet::completeURL(const String&)
3902 const KURL& baseURL = ((m_baseURL.isEmpty() || m_baseURL == blankURL()) && parentDocument()) ? parentDocument()->baseURL() : m_baseURL;
3904 return KURL(baseURL, url);
3905 return KURL(baseURL, url, m_decoder->encoding());
3908 void Document::setInPageCache(bool flag)
3910 if (m_inPageCache == flag)
3913 m_inPageCache = flag;
3915 ASSERT(!m_savedRenderer);
3916 m_savedRenderer = renderer();
3917 if (FrameView* v = view())
3918 v->resetScrollbars();
3919 m_styleRecalcTimer.stop();
3921 ASSERT(!renderer() || renderer() == m_savedRenderer);
3922 ASSERT(m_renderArena);
3923 setRenderer(m_savedRenderer);
3924 m_savedRenderer = 0;
3926 if (frame() && frame()->page())
3927 frame()->page()->updateViewportArguments();
3929 if (childNeedsStyleRecalc())
3930 scheduleStyleRecalc();
3934 void Document::documentWillBecomeInactive()
3936 #if USE(ACCELERATED_COMPOSITING)
3938 renderView()->willMoveOffscreen();
3941 HashSet<Element*>::iterator end = m_documentActivationCallbackElements.end();
3942 for (HashSet<Element*>::iterator i = m_documentActivationCallbackElements.begin(); i != end; ++i)
3943 (*i)->documentWillBecomeInactive();
3946 void Document::documentDidBecomeActive()
3948 HashSet<Element*>::iterator end = m_documentActivationCallbackElements.end();
3949 for (HashSet<Element*>::iterator i = m_documentActivationCallbackElements.begin(); i != end; ++i)
3950 (*i)->documentDidBecomeActive();
3952 #if USE(ACCELERATED_COMPOSITING)
3954 renderView()->didMoveOnscreen();
3958 m_frame->loader()->client()->dispatchDidBecomeFrameset(isFrameSet());
3961 void Document::registerForDocumentActivationCallbacks(Element* e)
3963 m_documentActivationCallbackElements.add(e);
3966 void Document::unregisterForDocumentActivationCallbacks(Element* e)
3968 m_documentActivationCallbackElements.remove(e);
3971 void Document::mediaVolumeDidChange()
3973 HashSet<Element*>::iterator end = m_mediaVolumeCallbackElements.end();
3974 for (HashSet<Element*>::iterator i = m_mediaVolumeCallbackElements.begin(); i != end; ++i)
3975 (*i)->mediaVolumeDidChange();
3978 void Document::registerForMediaVolumeCallbacks(Element* e)
3980 m_mediaVolumeCallbackElements.add(e);
3983 void Document::unregisterForMediaVolumeCallbacks(Element* e)
3985 m_mediaVolumeCallbackElements.remove(e);
3988 void Document::setShouldCreateRenderers(bool f)
3990 m_createRenderers = f;
3993 bool Document::shouldCreateRenderers()
3995 return m_createRenderers;
3998 // Support for Javascript execCommand, and related methods
4000 static Editor::Command command(Document* document, const String& commandName, bool userInterface = false)
4002 Frame* frame = document->frame();
4003 if (!frame || frame->document() != document)
4004 return Editor::Command();
4006 document->updateStyleIfNeeded();
4008 return frame->editor()->command(commandName,
4009 userInterface ? CommandFromDOMWithUserInterface : CommandFromDOM);
4012 bool Document::execCommand(const String& commandName, bool userInterface, const String& value)
4014 return command(this, commandName, userInterface).execute(value);
4017 bool Document::queryCommandEnabled(const String& commandName)
4019 return command(this, commandName).isEnabled();
4022 bool Document::queryCommandIndeterm(const String& commandName)
4024 return command(this, commandName).state() == MixedTriState;
4027 bool Document::queryCommandState(const String& commandName)
4029 return command(this, commandName).state() == TrueTriState;
4032 bool Document::queryCommandSupported(const String& commandName)
4034 return command(this, commandName).isSupported();
4037 String Document::queryCommandValue(const String& commandName)
4039 return command(this, commandName).value();
4044 void Document::applyXSLTransform(ProcessingInstruction* pi)
4046 RefPtr<XSLTProcessor> processor = XSLTProcessor::create();
4047 processor->setXSLStyleSheet(static_cast<XSLStyleSheet*>(pi->sheet()));
4048 String resultMIMEType;
4050 String resultEncoding;
4051 if (!processor->transformToString(this, resultMIMEType, newSource, resultEncoding))
4053 // FIXME: If the transform failed we should probably report an error (like Mozilla does).
4054 processor->createDocumentFromSource(newSource, resultEncoding, resultMIMEType, this, frame());
4057 void Document::setTransformSource(PassOwnPtr<TransformSource> source)
4059 if (m_transformSource == source)
4061 m_transformSource = source;
4066 void Document::setDesignMode(InheritedBool value)
4068 m_designMode = value;
4071 Document::InheritedBool Document::getDesignMode() const
4073 return m_designMode;
4076 bool Document::inDesignMode() const
4078 for (const Document* d = this; d; d = d->parentDocument()) {
4079 if (d->m_designMode != inherit)
4080 return d->m_designMode;
4085 Document* Document::parentDocument() const
4089 Frame* parent = m_frame->tree()->parent();
4092 return parent->document();
4095 Document* Document::topDocument() const
4097 Document* doc = const_cast<Document *>(this);
4099 while ((element = doc->ownerElement()))
4100 doc = element->document();
4105 PassRefPtr<Attr> Document::createAttribute(const String& name, ExceptionCode& ec)
4107 return createAttributeNS(String(), name, ec, true);
4110 PassRefPtr<Attr> Document::createAttributeNS(const String& namespaceURI, const String& qualifiedName, ExceptionCode& ec, bool shouldIgnoreNamespaceChecks)
4112 String prefix, localName;
4113 if (!parseQualifiedName(qualifiedName, prefix, localName, ec))
4116 QualifiedName qName(prefix, localName, namespaceURI);
4117 if (!shouldIgnoreNamespaceChecks && hasPrefixNamespaceMismatch(qName)) {
4122 // Spec: DOM Level 2 Core: http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-DocCrAttrNS
4123 if (!shouldIgnoreNamespaceChecks && qName.localName() == xmlnsAtom && qName.namespaceURI() != XMLNSNames::xmlnsNamespaceURI) {
4128 // FIXME: Assume this is a mapped attribute, since createAttribute isn't namespace-aware. There's no harm to XML
4129 // documents if we're wrong.
4130 return Attr::create(0, this, Attribute::createMapped(qName, StringImpl::empty()));
4134 const SVGDocumentExtensions* Document::svgExtensions()
4136 return m_svgExtensions.get();
4139 SVGDocumentExtensions* Document::accessSVGExtensions()
4141 if (!m_svgExtensions)
4142 m_svgExtensions = adoptPtr(new SVGDocumentExtensions(this));
4143 return m_svgExtensions.get();
4146 bool Document::hasSVGRootNode() const
4148 return documentElement() && documentElement()->hasTagName(SVGNames::svgTag);
4152 PassRefPtr<HTMLCollection> Document::images()
4154 return HTMLCollection::create(this, DocImages);
4157 PassRefPtr<HTMLCollection> Document::applets()
4159 return HTMLCollection::create(this, DocApplets);
4162 PassRefPtr<HTMLCollection> Document::embeds()
4164 return HTMLCollection::create(this, DocEmbeds);
4167 PassRefPtr<HTMLCollection> Document::plugins()
4169 // This is an alias for embeds() required for the JS DOM bindings.
4170 return HTMLCollection::create(this, DocEmbeds);
4173 PassRefPtr<HTMLCollection> Document::objects()
4175 return HTMLCollection::create(this, DocObjects);
4178 PassRefPtr<HTMLCollection> Document::scripts()
4180 return HTMLCollection::create(this, DocScripts);
4183 PassRefPtr<HTMLCollection> Document::links()
4185 return HTMLCollection::create(this, DocLinks);
4188 PassRefPtr<HTMLCollection> Document::forms()
4190 return HTMLCollection::create(this, DocForms);
4193 PassRefPtr<HTMLCollection> Document::anchors()
4195 return HTMLCollection::create(this, DocAnchors);
4198 PassRefPtr<HTMLAllCollection> Document::all()
4200 return HTMLAllCollection::create(this);
4203 PassRefPtr<HTMLCollection> Document::windowNamedItems(const String &name)
4205 return HTMLNameCollection::create(this, WindowNamedItems, name);
4208 PassRefPtr<HTMLCollection> Document::documentNamedItems(const String &name)
4210 return HTMLNameCollection::create(this, DocumentNamedItems, name);
4213 CollectionCache* Document::nameCollectionInfo(CollectionType type, const AtomicString& name)
4215 ASSERT(type >= FirstNamedDocumentCachedType);
4216 unsigned index = type - FirstNamedDocumentCachedType;
4217 ASSERT(index < NumNamedDocumentCachedTypes);
4219 NamedCollectionMap& map = m_nameCollectionInfo[index];
4220 NamedCollectionMap::iterator iter = map.find(name.impl());
4221 if (iter == map.end())
4222 iter = map.add(name.impl(), new CollectionCache).first;
4223 iter->second->checkConsistency();
4224 return iter->second;
4227 void Document::finishedParsing()
4229 ASSERT(!scriptableDocumentParser() || !m_parser->isParsing());
4230 ASSERT(!scriptableDocumentParser() || m_readyState != Loading);
4232 if (!m_documentTiming.domContentLoadedEventStart)
4233 m_documentTiming.domContentLoadedEventStart = currentTime();
4234 dispatchEvent(Event::create(eventNames().DOMContentLoadedEvent, true, false));
4235 if (!m_documentTiming.domContentLoadedEventEnd)
4236 m_documentTiming.domContentLoadedEventEnd = currentTime();
4238 if (Frame* f = frame()) {
4239 // FrameLoader::finishedParsing() might end up calling Document::implicitClose() if all
4240 // resource loads are complete. HTMLObjectElements can start loading their resources from
4241 // post attach callbacks triggered by recalcStyle(). This means if we parse out an <object>
4242 // tag and then reach the end of the document without updating styles, we might not have yet
4243 // started the resource load and might fire the window load event too early. To avoid this
4244 // we force the styles to be up to date before calling FrameLoader::finishedParsing().
4245 // See https://bugs.webkit.org/show_bug.cgi?id=36864 starting around comment 35.
4246 updateStyleIfNeeded();
4248 f->loader()->finishedParsing();
4250 #if ENABLE(INSPECTOR)
4254 if (InspectorController* controller = page()->inspectorController())
4255 controller->mainResourceFiredDOMContentEvent(f->loader()->documentLoader(), url());
4260 Vector<String> Document::formElementsState() const
4262 Vector<String> stateVector;
4263 stateVector.reserveInitialCapacity(m_formElementsWithState.size() * 3);
4264 typedef FormElementListHashSet::const_iterator Iterator;
4265 Iterator end = m_formElementsWithState.end();
4266 for (Iterator it = m_formElementsWithState.begin(); it != end; ++it) {
4267 Element* elementWithState = *it;
4269 if (!elementWithState->shouldSaveAndRestoreFormControlState())
4271 if (!elementWithState->saveFormControlState(value))
4273 stateVector.append(elementWithState->formControlName().string());
4274 stateVector.append(elementWithState->formControlType().string());
4275 stateVector.append(value);
4282 PassRefPtr<XPathExpression> Document::createExpression(const String& expression,
4283 XPathNSResolver* resolver,
4286 if (!m_xpathEvaluator)
4287 m_xpathEvaluator = XPathEvaluator::create();
4288 return m_xpathEvaluator->createExpression(expression, resolver, ec);
4291 PassRefPtr<XPathNSResolver> Document::createNSResolver(Node* nodeResolver)
4293 if (!m_xpathEvaluator)
4294 m_xpathEvaluator = XPathEvaluator::create();
4295 return m_xpathEvaluator->createNSResolver(nodeResolver);
4298 PassRefPtr<XPathResult> Document::evaluate(const String& expression,
4300 XPathNSResolver* resolver,
4301 unsigned short type,
4302 XPathResult* result,
4305 if (!m_xpathEvaluator)
4306 m_xpathEvaluator = XPathEvaluator::create();
4307 return m_xpathEvaluator->evaluate(expression, contextNode, resolver, type, result, ec);
4310 #endif // ENABLE(XPATH)
4312 void Document::setStateForNewFormElements(const Vector<String>& stateVector)
4314 // Walk the state vector backwards so that the value to use for each
4315 // name/type pair first is the one at the end of each individual vector
4316 // in the FormElementStateMap. We're using them like stacks.
4317 typedef FormElementStateMap::iterator Iterator;
4318 m_formElementsWithState.clear();
4319 for (size_t i = stateVector.size() / 3 * 3; i; i -= 3) {
4320 AtomicString a = stateVector[i - 3];
4321 AtomicString b = stateVector[i - 2];
4322 const String& c = stateVector[i - 1];
4323 FormElementKey key(a.impl(), b.impl());
4324 Iterator it = m_stateForNewFormElements.find(key);
4325 if (it != m_stateForNewFormElements.end())
4326 it->second.append(c);
4328 Vector<String> v(1);
4330 m_stateForNewFormElements.set(key, v);
4335 bool Document::hasStateForNewFormElements() const
4337 return !m_stateForNewFormElements.isEmpty();
4340 bool Document::takeStateForFormElement(AtomicStringImpl* name, AtomicStringImpl* type, String& state)
4342 typedef FormElementStateMap::iterator Iterator;
4343 Iterator it = m_stateForNewFormElements.find(FormElementKey(name, type));
4344 if (it == m_stateForNewFormElements.end())
4346 ASSERT(it->second.size());
4347 state = it->second.last();
4348 if (it->second.size() > 1)
4349 it->second.removeLast();
4351 m_stateForNewFormElements.remove(it);
4355 FormElementKey::FormElementKey(AtomicStringImpl* name, AtomicStringImpl* type)
4356 : m_name(name), m_type(type)
4361 FormElementKey::~FormElementKey()
4366 FormElementKey::FormElementKey(const FormElementKey& other)
4367 : m_name(other.name()), m_type(other.type())
4372 FormElementKey& FormElementKey::operator=(const FormElementKey& other)
4376 m_name = other.name();
4377 m_type = other.type();
4381 void FormElementKey::ref() const
4389 void FormElementKey::deref() const
4397 unsigned FormElementKeyHash::hash(const FormElementKey& key)
4399 return WTF::StringHasher::createBlobHash<sizeof(FormElementKey)>(&key);
4402 void Document::setIconURL(const String& iconURL, const String& type)
4404 // FIXME - <rdar://problem/4727645> - At some point in the future, we might actually honor the "type"
4405 if (m_iconURL.isEmpty())
4406 m_iconURL = iconURL;
4407 else if (!type.isEmpty())
4408 m_iconURL = iconURL;
4409 if (Frame* f = frame())
4410 f->loader()->setIconURL(m_iconURL);
4413 void Document::registerFormElementWithFormAttribute(FormAssociatedElement* element)