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 Apple Inc. All rights reserved.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
27 #include "AXObjectCache.h"
28 #include "CDATASection.h"
29 #include "CSSHelper.h"
30 #include "CSSStyleSelector.h"
31 #include "CSSStyleSheet.h"
32 #include "CSSValueKeywords.h"
33 #include "ClassNodeList.h"
35 #include "CookieJar.h"
36 #include "DOMImplementation.h"
37 #include "DocLoader.h"
38 #include "DocumentFragment.h"
39 #include "DocumentLoader.h"
40 #include "DocumentType.h"
41 #include "EditingText.h"
43 #include "EditorClient.h"
44 #include "EntityReference.h"
46 #include "EventHandler.h"
47 #include "EventListener.h"
48 #include "EventNames.h"
49 #include "ExceptionCode.h"
50 #include "FocusController.h"
52 #include "FrameLoader.h"
53 #include "FrameTree.h"
54 #include "FrameView.h"
55 #include "HTMLBodyElement.h"
56 #include "HTMLDocument.h"
57 #include "HTMLElementFactory.h"
58 #include "HTMLFrameOwnerElement.h"
59 #include "HTMLHeadElement.h"
60 #include "HTMLImageLoader.h"
61 #include "HTMLInputElement.h"
62 #include "HTMLLinkElement.h"
63 #include "HTMLMapElement.h"
64 #include "HTMLNameCollection.h"
65 #include "HTMLNames.h"
66 #include "HTMLStyleElement.h"
67 #include "HTMLTitleElement.h"
68 #include "HTTPParsers.h"
69 #include "HitTestRequest.h"
70 #include "HitTestResult.h"
71 #include "KeyboardEvent.h"
73 #include "MouseEvent.h"
74 #include "MouseEventWithHitTestResults.h"
75 #include "MutationEvent.h"
76 #include "NameNodeList.h"
77 #include "NodeFilter.h"
78 #include "NodeIterator.h"
79 #include "OverflowEvent.h"
81 #include "PlatformKeyboardEvent.h"
82 #include "ProcessingInstruction.h"
83 #include "ProgressEvent.h"
84 #include "RegisteredEventListener.h"
85 #include "RegularExpression.h"
86 #include "RenderArena.h"
87 #include "RenderView.h"
88 #include "RenderWidget.h"
89 #include "SecurityOrigin.h"
90 #include "SegmentedString.h"
91 #include "SelectionController.h"
93 #include "StringHash.h"
94 #include "StyleSheetList.h"
95 #include "SystemTime.h"
96 #include "TextEvent.h"
97 #include "TextIterator.h"
98 #include "TextResourceDecoder.h"
99 #include "TreeWalker.h"
101 #include "WheelEvent.h"
102 #include "XMLHttpRequest.h"
103 #include "XMLTokenizer.h"
104 #include "kjs_binding.h"
105 #include "kjs_proxy.h"
108 #include "DatabaseThread.h"
112 #include "XPathEvaluator.h"
113 #include "XPathExpression.h"
114 #include "XPathNSResolver.h"
115 #include "XPathResult.h"
119 #include "XSLTProcessor.h"
123 #include "XBLBindingManager.h"
127 #include "SVGDocumentExtensions.h"
128 #include "SVGElementFactory.h"
129 #include "SVGZoomEvent.h"
130 #include "SVGStyleElement.h"
131 #include "TimeScheduler.h"
136 using namespace Unicode;
140 using namespace EventNames;
141 using namespace HTMLNames;
143 // #define INSTRUMENT_LAYOUT_SCHEDULING 1
145 // This amount of time must have elapsed before we will even consider scheduling a layout without a delay.
146 // FIXME: For faster machines this value can really be lowered to 200. 250 is adequate, but a little high
148 static const int cLayoutScheduleThreshold = 250;
150 // Use 1 to represent the document's default form.
151 static HTMLFormElement* const defaultForm = reinterpret_cast<HTMLFormElement*>(1);
153 // Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's
154 static const unsigned PHI = 0x9e3779b9U;
156 // DOM Level 2 says (letters added):
158 // a) Name start characters must have one of the categories Ll, Lu, Lo, Lt, Nl.
159 // b) Name characters other than Name-start characters must have one of the categories Mc, Me, Mn, Lm, or Nd.
160 // c) Characters in the compatibility area (i.e. with character code greater than #xF900 and less than #xFFFE) are not allowed in XML names.
161 // 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.
162 // 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.
163 // f) Characters #x20DD-#x20E0 are excluded (in accordance with Unicode, section 5.14).
164 // g) Character #x00B7 is classified as an extender, because the property list so identifies it.
165 // h) Character #x0387 is added as a name character, because #x00B7 is its canonical equivalent.
166 // i) Characters ':' and '_' are allowed as name-start characters.
167 // j) Characters '-' and '.' are allowed as name characters.
169 // It also contains complete tables. If we decide it's better, we could include those instead of the following code.
171 static inline bool isValidNameStart(UChar32 c)
174 if ((c >= 0x02BB && c <= 0x02C1) || c == 0x559 || c == 0x6E5 || c == 0x6E6)
178 if (c == ':' || c == '_')
181 // rules (a) and (f) above
182 const uint32_t nameStartMask = Letter_Lowercase | Letter_Uppercase | Letter_Other | Letter_Titlecase | Number_Letter;
183 if (!(Unicode::category(c) & nameStartMask))
187 if (c >= 0xF900 && c < 0xFFFE)
191 DecompositionType decompType = decompositionType(c);
192 if (decompType == DecompositionFont || decompType == DecompositionCompat)
198 static inline bool isValidNamePart(UChar32 c)
200 // rules (a), (e), and (i) above
201 if (isValidNameStart(c))
204 // rules (g) and (h) above
205 if (c == 0x00B7 || c == 0x0387)
209 if (c == '-' || c == '.')
212 // rules (b) and (f) above
213 const uint32_t otherNamePartMask = Mark_NonSpacing | Mark_Enclosing | Mark_SpacingCombining | Letter_Modifier | Number_DecimalDigit;
214 if (!(Unicode::category(c) & otherNamePartMask))
218 if (c >= 0xF900 && c < 0xFFFE)
222 DecompositionType decompType = decompositionType(c);
223 if (decompType == DecompositionFont || decompType == DecompositionCompat)
229 static Widget* widgetForNode(Node* focusedNode)
233 RenderObject* renderer = focusedNode->renderer();
234 if (!renderer || !renderer->isWidget())
236 return static_cast<RenderWidget*>(renderer)->widget();
239 static bool acceptsEditingFocus(Node *node)
242 ASSERT(node->isContentEditable());
244 Node *root = node->rootEditableElement();
245 Frame* frame = node->document()->frame();
249 return frame->editor()->shouldBeginEditing(rangeOfContents(root).get());
252 DeprecatedPtrList<Document>* Document::changedDocuments = 0;
254 // FrameView might be 0
255 Document::Document(DOMImplementation* impl, Frame* frame, bool isXHTML)
257 , m_implementation(impl)
258 , m_domtree_version(0)
259 , m_styleSheets(new StyleSheetList(this))
261 , m_titleSetExplicitly(false)
262 , m_imageLoadEventTimer(this, &Document::imageLoadEventTimerFired)
263 , m_updateFocusAppearanceTimer(this, &Document::updateFocusAppearanceTimerFired)
265 , m_transformSource(0)
267 , m_xmlVersion("1.0")
268 , m_xmlStandalone(false)
270 , m_bindingManager(new XBLBindingManager(this))
274 , m_designMode(inherit)
275 , m_selfOnlyRefCount(0)
279 , m_hasDashboardRegions(false)
280 , m_dashboardRegionsDirty(false)
281 , m_accessKeyMapValid(false)
282 , m_createRenderers(true)
283 , m_inPageCache(false)
284 , m_isAllowedToLoadLocalResources(false)
285 , m_useSecureKeyboardEntryWhenActive(false)
288 #if USE(LOW_BANDWIDTH_DISPLAY)
289 , m_inLowBandwidthDisplay(false)
292 m_document.resetSkippingRef(this);
301 // FIXME: DocLoader probably no longer needs the frame argument
302 m_docLoader = new DocLoader(frame, this);
304 visuallyOrdered = false;
306 m_docChanged = false;
308 m_wellFormed = false;
312 m_textColor = Color::black;
315 m_inStyleRecalc = false;
316 m_closeAfterStyleRecalc = false;
317 m_usesDescendantRules = false;
318 m_usesSiblingRules = false;
319 m_usesFirstLineRules = false;
320 m_usesFirstLetterRules = false;
321 m_gotoAnchorNeededAfterStylesheetsLoad = false;
323 bool matchAuthorAndUserStyles = true;
324 if (Settings* settings = this->settings())
325 matchAuthorAndUserStyles = settings->authorAndUserStylesEnabled();
326 m_styleSelector = new CSSStyleSelector(this, m_usersheet, m_styleSheets.get(), m_mappedElementSheet.get(), !inCompatMode(), matchAuthorAndUserStyles);
328 m_didCalculateStyleSelector = false;
329 m_pendingStylesheets = 0;
330 m_ignorePendingStylesheets = false;
331 m_hasNodesWithPlaceholderStyle = false;
332 m_pendingSheetLayout = NoLayoutWithPendingSheets;
337 resetVisitedLinkColor();
338 resetActiveLinkColor();
340 m_processingLoadEvent = false;
341 m_startTime = currentTime();
342 m_overMinimumLayoutThreshold = false;
344 initSecurityOrigin();
346 static int docID = 0;
350 void Document::removedLastRef()
352 ASSERT(!m_deletionHasBegun);
353 if (m_selfOnlyRefCount) {
354 // If removing a child removes the last self-only ref, we don't
355 // want the document to be destructed until after
356 // removeAllChildren returns, so we guard ourselves with an
357 // extra self-only ref.
359 DocPtr<Document> guard(this);
361 // We must make sure not to be retaining any of our children through
362 // these extra pointers or we will create a reference cycle.
368 m_documentElement = 0;
372 deleteAllValues(m_markers);
379 m_inRemovedLastRefFunction = false;
383 m_deletionHasBegun = true;
389 Document::~Document()
392 ASSERT(!m_inPageCache);
393 ASSERT(!m_savedRenderer);
395 removeAllEventListeners();
398 delete m_svgExtensions;
401 XMLHttpRequest::detachRequests(this);
404 KJS::ScriptInterpreter::forgetAllDOMNodesForDocument(this);
407 if (m_docChanged && changedDocuments)
408 changedDocuments->remove(this);
410 m_document.resetSkippingRef(0);
411 delete m_styleSelector;
415 delete m_renderArena;
420 xmlFreeDoc((xmlDocPtr)m_transformSource);
424 delete m_bindingManager;
427 deleteAllValues(m_markers);
429 if (m_axObjectCache) {
430 delete m_axObjectCache;
435 unsigned count = sizeof(m_nameCollectionInfo) / sizeof(m_nameCollectionInfo[0]);
436 for (unsigned i = 0; i < count; i++)
437 deleteAllValues(m_nameCollectionInfo[i]);
440 if (m_databaseThread) {
441 m_databaseThread->documentGoingAway();
442 m_databaseThread = 0;
447 m_styleSheets->documentDestroyed();
450 void Document::resetLinkColor()
452 m_linkColor = Color(0, 0, 238);
455 void Document::resetVisitedLinkColor()
457 m_visitedLinkColor = Color(85, 26, 139);
460 void Document::resetActiveLinkColor()
462 m_activeLinkColor.setNamedColor("red");
465 void Document::setDocType(PassRefPtr<DocumentType> docType)
470 DocumentType *Document::doctype() const
472 return m_docType.get();
475 DOMImplementation* Document::implementation() const
477 return m_implementation.get();
480 void Document::childrenChanged()
482 // invalidate the document element we have cached in case it was replaced
483 m_documentElement = 0;
486 Element* Document::documentElement() const
488 if (!m_documentElement) {
489 Node* n = firstChild();
490 while (n && !n->isElementNode())
491 n = n->nextSibling();
492 m_documentElement = static_cast<Element*>(n);
495 return m_documentElement.get();
498 PassRefPtr<Element> Document::createElement(const String &name, ExceptionCode& ec)
501 if (!isValidName(name)) {
502 ec = INVALID_CHARACTER_ERR;
506 return HTMLElementFactory::createHTMLElement(AtomicString(name), this, 0, false);
508 return createElementNS(nullAtom, name, ec);
511 PassRefPtr<DocumentFragment> Document::createDocumentFragment()
513 return new DocumentFragment(document());
516 PassRefPtr<Text> Document::createTextNode(const String &data)
518 return new Text(this, data);
521 PassRefPtr<Comment> Document::createComment (const String &data)
523 return new Comment(this, data);
526 PassRefPtr<CDATASection> Document::createCDATASection(const String &data, ExceptionCode& ec)
528 if (isHTMLDocument()) {
529 ec = NOT_SUPPORTED_ERR;
532 return new CDATASection(this, data);
535 PassRefPtr<ProcessingInstruction> Document::createProcessingInstruction(const String &target, const String &data, ExceptionCode& ec)
537 if (!isValidName(target)) {
538 ec = INVALID_CHARACTER_ERR;
541 if (isHTMLDocument()) {
542 ec = NOT_SUPPORTED_ERR;
545 return new ProcessingInstruction(this, target, data);
548 PassRefPtr<EntityReference> Document::createEntityReference(const String &name, ExceptionCode& ec)
550 if (!isValidName(name)) {
551 ec = INVALID_CHARACTER_ERR;
554 if (isHTMLDocument()) {
555 ec = NOT_SUPPORTED_ERR;
558 return new EntityReference(this, name);
561 PassRefPtr<EditingText> Document::createEditingTextNode(const String &text)
563 return new EditingText(this, text);
566 PassRefPtr<CSSStyleDeclaration> Document::createCSSStyleDeclaration()
568 return new CSSMutableStyleDeclaration;
571 PassRefPtr<Node> Document::importNode(Node* importedNode, bool deep, ExceptionCode& ec)
577 || (importedNode->isSVGElement() && page() && page()->settings()->usesDashboardBackwardCompatibilityMode())
580 ec = NOT_SUPPORTED_ERR;
584 switch (importedNode->nodeType()) {
586 return createTextNode(importedNode->nodeValue());
587 case CDATA_SECTION_NODE:
588 return createCDATASection(importedNode->nodeValue(), ec);
589 case ENTITY_REFERENCE_NODE:
590 return createEntityReference(importedNode->nodeName(), ec);
591 case PROCESSING_INSTRUCTION_NODE:
592 return createProcessingInstruction(importedNode->nodeName(), importedNode->nodeValue(), ec);
594 return createComment(importedNode->nodeValue());
596 Element* oldElement = static_cast<Element*>(importedNode);
597 RefPtr<Element> newElement = createElementNS(oldElement->namespaceURI(), oldElement->tagQName().toString(), ec);
602 NamedAttrMap* attrs = oldElement->attributes(true);
604 unsigned length = attrs->length();
605 for (unsigned i = 0; i < length; i++) {
606 Attribute* attr = attrs->attributeItem(i);
607 newElement->setAttribute(attr->name(), attr->value().impl(), ec);
613 newElement->copyNonAttributeProperties(oldElement);
616 for (Node* oldChild = oldElement->firstChild(); oldChild; oldChild = oldChild->nextSibling()) {
617 RefPtr<Node> newChild = importNode(oldChild, true, ec);
620 newElement->appendChild(newChild.release(), ec);
626 return newElement.release();
628 case ATTRIBUTE_NODE: {
629 RefPtr<Attr> newAttr = new Attr(0, this, static_cast<Attr*>(importedNode)->attr()->clone());
630 newAttr->createTextChild();
631 return newAttr.release();
633 case DOCUMENT_FRAGMENT_NODE: {
634 DocumentFragment* oldFragment = static_cast<DocumentFragment*>(importedNode);
635 RefPtr<DocumentFragment> newFragment = createDocumentFragment();
637 for (Node* oldChild = oldFragment->firstChild(); oldChild; oldChild = oldChild->nextSibling()) {
638 RefPtr<Node> newChild = importNode(oldChild, true, ec);
641 newFragment->appendChild(newChild.release(), ec);
647 return newFragment.release();
651 // 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.
652 // Ability to add these imported nodes to a DocumentType will be considered for addition to a future release of the DOM.
654 case DOCUMENT_TYPE_NODE:
655 case XPATH_NAMESPACE_NODE:
659 ec = NOT_SUPPORTED_ERR;
664 PassRefPtr<Node> Document::adoptNode(PassRefPtr<Node> source, ExceptionCode& ec)
667 ec = NOT_SUPPORTED_ERR;
671 switch (source->nodeType()) {
675 case DOCUMENT_TYPE_NODE:
676 case XPATH_NAMESPACE_NODE:
677 ec = NOT_SUPPORTED_ERR;
679 case ATTRIBUTE_NODE: {
680 Attr* attr = static_cast<Attr*>(source.get());
681 if (attr->ownerElement())
682 attr->ownerElement()->removeAttributeNode(attr, ec);
683 attr->m_attrWasSpecifiedOrElementHasRareData = true;
687 if (source->parentNode())
688 source->parentNode()->removeChild(source.get(), ec);
691 for (Node* node = source.get(); node; node = node->traverseNextNode(source.get()))
692 node->setDocument(this);
697 // FIXME: This should really be in a possible ElementFactory class
698 PassRefPtr<Element> Document::createElement(const QualifiedName& qName, bool createdByParser, ExceptionCode& ec)
702 // FIXME: Use registered namespaces and look up in a hash to find the right factory.
703 if (qName.namespaceURI() == xhtmlNamespaceURI)
704 e = HTMLElementFactory::createHTMLElement(qName.localName(), this, 0, createdByParser);
706 else if (qName.namespaceURI() == SVGNames::svgNamespaceURI)
707 e = SVGElementFactory::createSVGElement(qName, this, createdByParser);
711 e = new Element(qName, document());
713 if (e && !qName.prefix().isNull()) {
715 e->setPrefix(qName.prefix(), ec);
723 PassRefPtr<Element> Document::createElementNS(const String &_namespaceURI, const String &qualifiedName, ExceptionCode& ec)
725 String prefix, localName;
726 if (!parseQualifiedName(qualifiedName, prefix, localName)) {
727 ec = INVALID_CHARACTER_ERR;
732 QualifiedName qName = QualifiedName(AtomicString(prefix), AtomicString(localName), AtomicString(_namespaceURI));
734 return createElement(qName, false, ec);
737 Element *Document::getElementById(const AtomicString& elementId) const
739 if (elementId.length() == 0)
742 Element *element = m_elementsById.get(elementId.impl());
746 if (m_duplicateIds.contains(elementId.impl())) {
747 // We know there's at least one node with this id, but we don't know what the first one is.
748 for (Node *n = traverseNextNode(); n != 0; n = n->traverseNextNode()) {
749 if (n->isElementNode()) {
750 element = static_cast<Element*>(n);
751 if (element->hasID() && element->getAttribute(idAttr) == elementId) {
752 m_duplicateIds.remove(elementId.impl());
753 m_elementsById.set(elementId.impl(), element);
758 ASSERT_NOT_REACHED();
763 String Document::readyState() const
765 if (Frame* f = frame()) {
766 if (f->loader()->isComplete())
771 // FIXME: What does "interactive" mean?
772 // FIXME: Missing support for "uninitialized".
777 String Document::inputEncoding() const
779 if (TextResourceDecoder* d = decoder())
780 return d->encoding().name();
784 String Document::defaultCharset() const
786 if (Settings* settings = this->settings())
787 return settings->defaultTextEncodingName();
791 void Document::setCharset(const String& charset)
795 decoder()->setEncoding(charset, TextResourceDecoder::UserChosenEncoding);
798 void Document::setXMLVersion(const String& version, ExceptionCode& ec)
800 // FIXME: also raise NOT_SUPPORTED_ERR if the version is set to a value that is not supported by this Document.
801 if (!implementation()->hasFeature("XML", String())) {
802 ec = NOT_SUPPORTED_ERR;
806 m_xmlVersion = version;
809 void Document::setXMLStandalone(bool standalone, ExceptionCode& ec)
811 if (!implementation()->hasFeature("XML", String())) {
812 ec = NOT_SUPPORTED_ERR;
816 m_xmlStandalone = standalone;
819 String Document::documentURI() const
824 void Document::setDocumentURI(const String &uri)
826 m_baseURL = uri.deprecatedString();
829 String Document::baseURI() const
831 return documentURI();
834 Element* Document::elementFromPoint(int x, int y) const
839 HitTestRequest request(true, true);
840 HitTestResult result(IntPoint(x, y));
841 renderer()->layer()->hitTest(request, result);
843 Node* n = result.innerNode();
844 while (n && !n->isElementNode())
847 n = n->shadowAncestorNode();
848 return static_cast<Element*>(n);
851 void Document::addElementById(const AtomicString& elementId, Element* element)
853 typedef HashMap<AtomicStringImpl*, Element*>::iterator iterator;
854 if (!m_duplicateIds.contains(elementId.impl())) {
855 // Fast path. The ID is not already in m_duplicateIds, so we assume that it's
856 // also not already in m_elementsById and do an add. If that add succeeds, we're done.
857 pair<iterator, bool> addResult = m_elementsById.add(elementId.impl(), element);
858 if (addResult.second)
860 // The add failed, so this ID was already cached in m_elementsById.
861 // There are multiple elements with this ID. Remove the m_elementsById
862 // cache for this ID so getElementById searches for it next time it is called.
863 m_elementsById.remove(addResult.first);
864 m_duplicateIds.add(elementId.impl());
866 // There are multiple elements with this ID. If it exists, remove the m_elementsById
867 // cache for this ID so getElementById searches for it next time it is called.
868 iterator cachedItem = m_elementsById.find(elementId.impl());
869 if (cachedItem != m_elementsById.end()) {
870 m_elementsById.remove(cachedItem);
871 m_duplicateIds.add(elementId.impl());
874 m_duplicateIds.add(elementId.impl());
877 void Document::removeElementById(const AtomicString& elementId, Element* element)
879 if (m_elementsById.get(elementId.impl()) == element)
880 m_elementsById.remove(elementId.impl());
882 m_duplicateIds.remove(elementId.impl());
885 Element* Document::getElementByAccessKey(const String& key) const
889 if (!m_accessKeyMapValid) {
890 for (Node* n = firstChild(); n; n = n->traverseNextNode()) {
891 if (!n->isElementNode())
893 Element* element = static_cast<Element*>(n);
894 const AtomicString& accessKey = element->getAttribute(accesskeyAttr);
895 if (!accessKey.isEmpty())
896 m_elementsByAccessKey.set(accessKey.impl(), element);
898 m_accessKeyMapValid = true;
900 return m_elementsByAccessKey.get(key.impl());
903 void Document::updateTitle()
905 if (Frame* f = frame())
906 f->loader()->setTitle(m_title);
909 void Document::setTitle(const String& title, Element* titleElement)
912 // Title set by JavaScript -- overrides any title elements.
913 m_titleSetExplicitly = true;
914 if (!isHTMLDocument())
916 else if (!m_titleElement) {
917 if (HTMLElement* headElement = head()) {
918 ExceptionCode ec = 0;
919 m_titleElement = createElement("title", ec);
921 headElement->appendChild(m_titleElement, ec);
925 } else if (titleElement != m_titleElement) {
926 if (m_titleElement || m_titleSetExplicitly)
927 // Only allow the first title element to change the title -- others have no effect.
929 m_titleElement = titleElement;
932 if (m_title == title)
938 if (m_titleSetExplicitly && m_titleElement && m_titleElement->hasTagName(titleTag))
939 static_cast<HTMLTitleElement*>(m_titleElement.get())->setText(m_title);
942 void Document::removeTitle(Element* titleElement)
944 if (m_titleElement != titleElement)
948 m_titleSetExplicitly = false;
950 // Update title based on first title element in the head, if one exists.
951 if (HTMLElement* headElement = head()) {
952 for (Node* e = headElement->firstChild(); e; e = e->nextSibling())
953 if (e->hasTagName(titleTag)) {
954 HTMLTitleElement* titleElement = static_cast<HTMLTitleElement*>(e);
955 setTitle(titleElement->text(), titleElement);
960 if (!m_titleElement && !m_title.isEmpty()) {
966 String Document::nodeName() const
971 Node::NodeType Document::nodeType() const
973 return DOCUMENT_NODE;
976 FrameView* Document::view() const
978 return m_frame ? m_frame->view() : 0;
981 Page* Document::page() const
983 return m_frame ? m_frame->page() : 0;
986 Settings* Document::settings() const
988 return m_frame ? m_frame->settings() : 0;
991 PassRefPtr<Range> Document::createRange()
993 return new Range(this);
996 PassRefPtr<NodeIterator> Document::createNodeIterator(Node* root, unsigned whatToShow,
997 NodeFilter* filter, bool expandEntityReferences, ExceptionCode& ec)
1000 ec = NOT_SUPPORTED_ERR;
1003 return new NodeIterator(root, whatToShow, filter, expandEntityReferences);
1006 PassRefPtr<TreeWalker> Document::createTreeWalker(Node *root, unsigned whatToShow,
1007 NodeFilter* filter, bool expandEntityReferences, ExceptionCode& ec)
1010 ec = NOT_SUPPORTED_ERR;
1013 return new TreeWalker(root, whatToShow, filter, expandEntityReferences);
1016 void Document::setDocumentChanged(bool b)
1019 if (!m_docChanged) {
1020 if (!changedDocuments)
1021 changedDocuments = new DeprecatedPtrList<Document>;
1022 changedDocuments->append(this);
1024 if (m_accessKeyMapValid) {
1025 m_accessKeyMapValid = false;
1026 m_elementsByAccessKey.clear();
1029 if (m_docChanged && changedDocuments)
1030 changedDocuments->remove(this);
1036 void Document::recalcStyle(StyleChange change)
1038 // we should not enter style recalc while painting
1039 if (frame() && frame()->isPainting()) {
1040 ASSERT(!frame()->isPainting());
1044 if (m_inStyleRecalc)
1045 return; // Guard against re-entrancy. -dwh
1047 m_inStyleRecalc = true;
1048 suspendPostAttachCallbacks();
1050 ASSERT(!renderer() || renderArena());
1051 if (!renderer() || !renderArena())
1054 if (change == Force) {
1055 // style selector may set this again during recalc
1056 m_hasNodesWithPlaceholderStyle = false;
1058 RenderStyle* oldStyle = renderer()->style();
1061 RenderStyle* _style = new (m_renderArena) RenderStyle();
1063 _style->setDisplay(BLOCK);
1064 _style->setVisuallyOrdered(visuallyOrdered);
1065 // ### make the font stuff _really_ work!!!!
1067 FontDescription fontDescription;
1068 fontDescription.setUsePrinterFont(printing());
1069 if (Settings* settings = this->settings()) {
1070 fontDescription.setRenderingMode(settings->fontRenderingMode());
1071 if (printing() && !settings->shouldPrintBackgrounds())
1072 _style->setForceBackgroundsToWhite(true);
1073 const AtomicString& stdfont = settings->standardFontFamily();
1074 if (!stdfont.isEmpty()) {
1075 fontDescription.firstFamily().setFamily(stdfont);
1076 fontDescription.firstFamily().appendFamily(0);
1078 fontDescription.setKeywordSize(CSS_VAL_MEDIUM - CSS_VAL_XX_SMALL + 1);
1079 m_styleSelector->setFontSize(fontDescription, m_styleSelector->fontSizeForKeyword(CSS_VAL_MEDIUM, inCompatMode(), false));
1082 _style->setFontDescription(fontDescription);
1083 _style->font().update(m_styleSelector->fontSelector());
1085 _style->setHtmlHacks(true); // enable html specific rendering tricks
1087 StyleChange ch = diff(_style, oldStyle);
1088 if (renderer() && ch != NoChange)
1089 renderer()->setStyle(_style);
1090 if (change != Force)
1093 _style->deref(m_renderArena);
1095 oldStyle->deref(m_renderArena);
1098 for (Node* n = firstChild(); n; n = n->nextSibling())
1099 if (change >= Inherit || n->hasChangedChild() || n->changed())
1100 n->recalcStyle(change);
1102 if (changed() && view())
1106 setChanged(NoStyleChange);
1107 setHasChangedChild(false);
1108 setDocumentChanged(false);
1110 resumePostAttachCallbacks();
1111 m_inStyleRecalc = false;
1113 // If we wanted to call implicitClose() during recalcStyle, do so now that we're finished.
1114 if (m_closeAfterStyleRecalc) {
1115 m_closeAfterStyleRecalc = false;
1120 void Document::updateRendering()
1122 if (hasChangedChild())
1123 recalcStyle(NoChange);
1126 void Document::updateDocumentsRendering()
1128 if (!changedDocuments)
1131 while (Document* doc = changedDocuments->take()) {
1132 doc->m_docChanged = false;
1133 doc->updateRendering();
1137 void Document::updateLayout()
1139 if (Element* oe = ownerElement())
1140 oe->document()->updateLayout();
1142 // FIXME: Dave Hyatt's pretty sure we can remove this because layout calls recalcStyle as needed.
1145 // Only do a layout if changes have occurred that make it necessary.
1146 FrameView* v = view();
1147 if (v && renderer() && (v->layoutPending() || renderer()->needsLayout()))
1151 // FIXME: This is a bad idea and needs to be removed eventually.
1152 // Other browsers load stylesheets before they continue parsing the web page.
1153 // Since we don't, we can run JavaScript code that needs answers before the
1154 // stylesheets are loaded. Doing a layout ignoring the pending stylesheets
1155 // lets us get reasonable answers. The long term solution to this problem is
1156 // to instead suspend JavaScript execution.
1157 void Document::updateLayoutIgnorePendingStylesheets()
1159 bool oldIgnore = m_ignorePendingStylesheets;
1161 if (!haveStylesheetsLoaded()) {
1162 m_ignorePendingStylesheets = true;
1163 // FIXME: We are willing to attempt to suppress painting with outdated style info only once. Our assumption is that it would be
1164 // dangerous to try to stop it a second time, after page content has already been loaded and displayed
1165 // with accurate style information. (Our suppression involves blanking the whole page at the
1166 // moment. If it were more refined, we might be able to do something better.)
1167 // It's worth noting though that this entire method is a hack, since what we really want to do is
1168 // suspend JS instead of doing a layout with inaccurate information.
1169 if (body() && !body()->renderer() && m_pendingSheetLayout == NoLayoutWithPendingSheets) {
1170 m_pendingSheetLayout = DidLayoutWithPendingSheets;
1171 updateStyleSelector();
1172 } else if (m_hasNodesWithPlaceholderStyle)
1173 // If new nodes have been added or style recalc has been done with style sheets still pending, some nodes
1174 // may not have had their real style calculated yet. Normally this gets cleaned when style sheets arrive
1175 // but here we need up-to-date style immediatly.
1181 m_ignorePendingStylesheets = oldIgnore;
1184 void Document::attach()
1186 ASSERT(!attached());
1187 ASSERT(!m_inPageCache);
1190 m_renderArena = new RenderArena();
1192 // Create the rendering tree
1193 setRenderer(new (m_renderArena) RenderView(this, view()));
1197 RenderObject* render = renderer();
1200 ContainerNode::attach();
1202 setRenderer(render);
1205 void Document::detach()
1208 ASSERT(!m_inPageCache);
1210 RenderObject* render = renderer();
1212 // indicate destruction mode, i.e. attached() but renderer == 0
1215 // Empty out these lists as a performance optimization, since detaching
1216 // all the individual render objects will cause all the RenderImage
1217 // objects to remove themselves from the lists.
1218 m_imageLoadEventDispatchSoonList.clear();
1219 m_imageLoadEventDispatchingList.clear();
1225 ContainerNode::detach();
1230 // FIXME: is this needed or desirable?
1233 if (m_renderArena) {
1234 delete m_renderArena;
1239 void Document::removeAllEventListenersFromAllNodes()
1241 m_windowEventListeners.clear();
1242 removeAllDisconnectedNodeEventListeners();
1243 for (Node *n = this; n; n = n->traverseNextNode()) {
1244 if (!n->isEventTargetNode())
1246 EventTargetNodeCast(n)->removeAllEventListeners();
1250 void Document::registerDisconnectedNodeWithEventListeners(Node* node)
1252 m_disconnectedNodesWithEventListeners.add(node);
1255 void Document::unregisterDisconnectedNodeWithEventListeners(Node* node)
1257 m_disconnectedNodesWithEventListeners.remove(node);
1260 void Document::removeAllDisconnectedNodeEventListeners()
1262 HashSet<Node*>::iterator end = m_disconnectedNodesWithEventListeners.end();
1263 for (HashSet<Node*>::iterator i = m_disconnectedNodesWithEventListeners.begin(); i != end; ++i)
1264 EventTargetNodeCast(*i)->removeAllEventListeners();
1265 m_disconnectedNodesWithEventListeners.clear();
1268 AXObjectCache* Document::axObjectCache() const
1270 // The only document that actually has a AXObjectCache is the top-level
1271 // document. This is because we need to be able to get from any WebCoreAXObject
1272 // to any other WebCoreAXObject on the same page. Using a single cache allows
1273 // lookups across nested webareas (i.e. multiple documents).
1275 if (m_axObjectCache) {
1276 // return already known top-level cache
1277 if (!ownerElement())
1278 return m_axObjectCache;
1280 // In some pages with frames, the cache is created before the sub-webarea is
1281 // inserted into the tree. Here, we catch that case and just toss the old
1282 // cache and start over.
1283 delete m_axObjectCache;
1284 m_axObjectCache = 0;
1287 // ask the top-level document for its cache
1288 Document* doc = topDocument();
1290 return doc->axObjectCache();
1292 // this is the top-level document, so install a new cache
1293 m_axObjectCache = new AXObjectCache;
1294 return m_axObjectCache;
1297 void Document::setVisuallyOrdered()
1299 visuallyOrdered = true;
1301 renderer()->style()->setVisuallyOrdered(true);
1304 Tokenizer* Document::createTokenizer()
1306 // FIXME: this should probably pass the frame instead
1307 return new XMLTokenizer(this, view());
1310 void Document::open()
1312 // This is work that we should probably do in clear(), but we can't have it
1313 // happen when implicitOpen() is called unless we reorganize Frame code.
1314 if (Document *parent = parentDocument()) {
1315 if (m_url.isEmpty() || m_url == "about:blank")
1316 setURL(parent->baseURL());
1317 if (m_baseURL.isEmpty() || m_baseURL == "about:blank")
1318 setBaseURL(parent->baseURL());
1322 if (m_frame->loader()->isLoadingMainResource() || (tokenizer() && tokenizer()->executingScript()))
1325 if (m_frame->loader()->state() == FrameStateProvisional)
1326 m_frame->loader()->stopAllLoaders();
1332 m_frame->loader()->didExplicitOpen();
1335 void Document::cancelParsing()
1338 // We have to clear the tokenizer to avoid possibly triggering
1339 // the onload handler when closing as a side effect of a cancel-style
1340 // change, such as opening a new document or closing the window while
1348 void Document::implicitOpen()
1353 m_tokenizer = createTokenizer();
1357 HTMLElement* Document::body()
1359 Node* de = documentElement();
1363 // try to prefer a FRAMESET element over BODY
1365 for (Node* i = de->firstChild(); i; i = i->nextSibling()) {
1366 if (i->hasTagName(framesetTag))
1367 return static_cast<HTMLElement*>(i);
1369 if (i->hasTagName(bodyTag))
1372 return static_cast<HTMLElement*>(body);
1375 void Document::setBody(PassRefPtr<HTMLElement> newBody, ExceptionCode& ec)
1378 ec = HIERARCHY_REQUEST_ERR;
1382 HTMLElement* b = body();
1384 documentElement()->appendChild(newBody, ec);
1386 documentElement()->replaceChild(newBody, b, ec);
1389 HTMLHeadElement* Document::head()
1391 Node* de = documentElement();
1395 for (Node* e = de->firstChild(); e; e = e->nextSibling())
1396 if (e->hasTagName(headTag))
1397 return static_cast<HTMLHeadElement*>(e);
1402 void Document::close()
1404 Frame* frame = this->frame();
1406 // This code calls implicitClose() if all loading has completed.
1407 FrameLoader* frameLoader = frame->loader();
1408 frameLoader->endIfNotLoadingMainResource();
1409 frameLoader->checkCompleted();
1411 // Because we have no frame, we don't know if all loading has completed,
1412 // so we just call implicitClose() immediately. FIXME: This might fire
1413 // the load event prematurely <http://bugs.webkit.org/show_bug.cgi?id=14568>.
1418 void Document::implicitClose()
1420 // 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.
1421 if (m_inStyleRecalc) {
1422 m_closeAfterStyleRecalc = true;
1426 bool wasLocationChangePending = frame() && frame()->loader()->isScheduledLocationChangePending();
1427 bool doload = !parsing() && m_tokenizer && !m_processingLoadEvent && !wasLocationChangePending;
1432 m_processingLoadEvent = true;
1434 m_wellFormed = m_tokenizer && m_tokenizer->wellFormed();
1436 // We have to clear the tokenizer, in case someone document.write()s from the
1437 // onLoad event handler, as in Radar 3206524.
1441 // Create a body element if we don't already have one. See Radar 3758785.
1442 if (!this->body() && isHTMLDocument()) {
1443 if (Node* documentElement = this->documentElement()) {
1444 ExceptionCode ec = 0;
1445 documentElement->appendChild(new HTMLBodyElement(this), ec);
1450 dispatchImageLoadEventsNow();
1451 this->dispatchWindowEvent(loadEvent, false, false);
1452 if (Frame* f = frame())
1453 f->loader()->handledOnloadEvents();
1454 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1455 if (!ownerElement())
1456 printf("onload fired at %d\n", elapsedTime());
1459 m_processingLoadEvent = false;
1461 // An event handler may have removed the frame
1465 // Make sure both the initial layout and reflow happen after the onload
1466 // fires. This will improve onload scores, and other browsers do it.
1467 // If they wanna cheat, we can too. -dwh
1469 if (frame()->loader()->isScheduledLocationChangePending() && elapsedTime() < cLayoutScheduleThreshold) {
1470 // Just bail out. Before or during the onload we were shifted to another page.
1471 // The old i-Bench suite does this. When this happens don't bother painting or laying out.
1472 view()->unscheduleRelayout();
1476 frame()->loader()->checkCallImplicitClose();
1478 // Now do our painting/layout, but only if we aren't in a subframe or if we're in a subframe
1479 // that has been sized already. Otherwise, our view size would be incorrect, so doing any
1480 // layout/painting now would be pointless.
1481 if (!ownerElement() || (ownerElement()->renderer() && !ownerElement()->renderer()->needsLayout())) {
1484 // Always do a layout after loading if needed.
1485 if (view() && renderer() && (!renderer()->firstChild() || renderer()->needsLayout()))
1488 // Paint immediately after the document is ready. We do this to ensure that any timers set by the
1489 // onload don't have a chance to fire before we would have painted. To avoid over-flushing we only
1490 // worry about this for the top-level document.
1492 // FIXME: This causes a timing issue with the dispatchDidFinishLoad delegate callback.
1493 // See <rdar://problem/5092361>
1494 if (view() && !ownerElement())
1500 if (renderer() && AXObjectCache::accessibilityEnabled())
1501 axObjectCache()->postNotificationToElement(renderer(), "AXLoadComplete");
1505 // FIXME: Officially, time 0 is when the outermost <svg> receives its
1506 // SVGLoad event, but we don't implement those yet. This is close enough
1507 // for now. In some cases we should have fired earlier.
1508 if (svgExtensions())
1509 accessSVGExtensions()->startAnimations();
1513 void Document::setParsing(bool b)
1516 if (!m_bParsing && view())
1517 view()->scheduleRelayout();
1519 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1520 if (!ownerElement() && !m_bParsing)
1521 printf("Parsing finished at %d\n", elapsedTime());
1525 bool Document::shouldScheduleLayout()
1527 // We can update layout if:
1528 // (a) we actually need a layout
1529 // (b) our stylesheets are all loaded
1530 // (c) we have a <body>
1531 return (renderer() && renderer()->needsLayout() && haveStylesheetsLoaded() &&
1532 documentElement() && documentElement()->renderer() &&
1533 (!documentElement()->hasTagName(htmlTag) || body()));
1536 int Document::minimumLayoutDelay()
1538 if (m_overMinimumLayoutThreshold)
1541 int elapsed = elapsedTime();
1542 m_overMinimumLayoutThreshold = elapsed > cLayoutScheduleThreshold;
1544 // We'll want to schedule the timer to fire at the minimum layout threshold.
1545 return max(0, cLayoutScheduleThreshold - elapsed);
1548 int Document::elapsedTime() const
1550 return static_cast<int>((currentTime() - m_startTime) * 1000);
1553 void Document::write(const DeprecatedString& text)
1555 write(String(text));
1558 void Document::write(const String& text)
1560 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1561 if (!ownerElement())
1562 printf("Beginning a document.write at %d\n", elapsedTime());
1567 ASSERT(m_tokenizer);
1570 write(DeprecatedString("<html>"));
1572 m_tokenizer->write(text, false);
1574 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1575 if (!ownerElement())
1576 printf("Ending a document.write at %d\n", elapsedTime());
1580 void Document::writeln(const String &text)
1583 write(String("\n"));
1586 void Document::finishParsing()
1588 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1589 if (!ownerElement())
1590 printf("Received all data at %d\n", elapsedTime());
1593 // Let the tokenizer go through as much data as it can. There will be three possible outcomes after
1594 // finish() is called:
1595 // (1) All remaining data is parsed, document isn't loaded yet
1596 // (2) All remaining data is parsed, document is loaded, tokenizer gets deleted
1597 // (3) Data is still remaining to be parsed.
1599 m_tokenizer->finish();
1602 void Document::clear()
1609 m_windowEventListeners.clear();
1612 void Document::setURL(const DeprecatedString& url)
1618 if (m_styleSelector)
1619 m_styleSelector->setEncodedURL(m_url);
1621 m_isAllowedToLoadLocalResources = shouldBeAllowedToLoadLocalResources();
1624 bool Document::shouldBeAllowedToLoadLocalResources() const
1626 if (FrameLoader::shouldTreatURLAsLocal(m_url))
1629 Frame* frame = this->frame();
1633 DocumentLoader* documentLoader = frame->loader()->documentLoader();
1634 if (!documentLoader)
1637 if (m_url == "about:blank" && frame->loader()->opener() && frame->loader()->opener()->document()->isAllowedToLoadLocalResources())
1640 return documentLoader->substituteData().isValid();
1643 void Document::setBaseURL(const DeprecatedString& baseURL)
1645 m_baseURL = baseURL;
1647 m_elemSheet->setHref(m_baseURL);
1650 void Document::setCSSStyleSheet(const String &url, const String& charset, const String &sheet)
1652 m_sheet = new CSSStyleSheet(this, url, charset);
1653 m_sheet->parseString(sheet);
1655 updateStyleSelector();
1658 void Document::setUserStyleSheet(const String& sheet)
1660 if (m_usersheet != sheet) {
1661 m_usersheet = sheet;
1662 updateStyleSelector();
1666 CSSStyleSheet* Document::elementSheet()
1669 m_elemSheet = new CSSStyleSheet(this, baseURL());
1670 return m_elemSheet.get();
1673 CSSStyleSheet* Document::mappedElementSheet()
1675 if (!m_mappedElementSheet)
1676 m_mappedElementSheet = new CSSStyleSheet(this, baseURL());
1677 return m_mappedElementSheet.get();
1680 void Document::determineParseMode(const String&)
1682 // For XML documents use strict parse mode.
1683 // HTML overrides this method to determine the parse mode.
1688 static Node* nextNodeWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent* event)
1690 // Search is inclusive of start
1691 for (Node* n = start; n; n = n->traverseNextNode())
1692 if (n->isKeyboardFocusable(event) && n->tabIndex() == tabIndex)
1698 static Node* previousNodeWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent* event)
1700 // Search is inclusive of start
1701 for (Node* n = start; n; n = n->traversePreviousNode())
1702 if (n->isKeyboardFocusable(event) && n->tabIndex() == tabIndex)
1708 static Node* nextNodeWithGreaterTabIndex(Node* start, int tabIndex, KeyboardEvent* event)
1710 // Search is inclusive of start
1711 int winningTabIndex = SHRT_MAX + 1;
1713 for (Node* n = start; n; n = n->traverseNextNode())
1714 if (n->isKeyboardFocusable(event) && n->tabIndex() > tabIndex && n->tabIndex() < winningTabIndex) {
1716 winningTabIndex = n->tabIndex();
1722 static Node* previousNodeWithLowerTabIndex(Node* start, int tabIndex, KeyboardEvent* event)
1724 // Search is inclusive of start
1725 int winningTabIndex = 0;
1727 for (Node* n = start; n; n = n->traversePreviousNode())
1728 if (n->isKeyboardFocusable(event) && n->tabIndex() < tabIndex && n->tabIndex() > winningTabIndex) {
1730 winningTabIndex = n->tabIndex();
1736 Node* Document::nextFocusableNode(Node* start, KeyboardEvent* event)
1739 // First try to find a node with the same tabindex as start that comes after start in the document.
1740 if (Node* winner = nextNodeWithExactTabIndex(start->traverseNextNode(), start->tabIndex(), event))
1743 if (start->tabIndex() == 0)
1744 // We've reached the last node in the document with a tabindex of 0. This is the end of the tabbing order.
1748 // Look for the first node in the document that:
1749 // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if start is null), and
1750 // 2) comes first in the document, if there's a tie.
1751 if (Node* winner = nextNodeWithGreaterTabIndex(this, start ? start->tabIndex() : 0, event))
1754 // There are no nodes with a tabindex greater than start's tabindex,
1755 // so find the first node with a tabindex of 0.
1756 return nextNodeWithExactTabIndex(this, 0, event);
1759 Node* Document::previousFocusableNode(Node* start, KeyboardEvent* event)
1762 for (last = this; last->lastChild(); last = last->lastChild())
1765 // First try to find the last node in the document that comes before start and has the same tabindex as start.
1766 // If start is null, find the last node in the document with a tabindex of 0.
1768 int startingTabIndex;
1770 startingNode = start->traversePreviousNode();
1771 startingTabIndex = start->tabIndex();
1773 startingNode = last;
1774 startingTabIndex = 0;
1777 if (Node* winner = previousNodeWithExactTabIndex(startingNode, startingTabIndex, event))
1780 // There are no nodes before start with the same tabindex as start, so look for a node that:
1781 // 1) has the highest non-zero tabindex (that is less than start's tabindex), and
1782 // 2) comes last in the document, if there's a tie.
1783 startingTabIndex = (start && start->tabIndex()) ? start->tabIndex() : SHRT_MAX;
1784 return previousNodeWithLowerTabIndex(last, startingTabIndex, event);
1787 int Document::nodeAbsIndex(Node *node)
1789 ASSERT(node->document() == this);
1792 for (Node *n = node; n && n != this; n = n->traversePreviousNode())
1797 Node *Document::nodeWithAbsIndex(int absIndex)
1800 for (int i = 0; n && (i < absIndex); i++) {
1801 n = n->traverseNextNode();
1806 void Document::processHttpEquiv(const String &equiv, const String &content)
1808 ASSERT(!equiv.isNull() && !content.isNull());
1810 Frame *frame = this->frame();
1812 if (equalIgnoringCase(equiv, "default-style")) {
1813 // The preferred style set has been overridden as per section
1814 // 14.3.2 of the HTML4.0 specification. We need to update the
1815 // sheet used variable and then update our style selector.
1816 // For more info, see the test at:
1817 // http://www.hixie.ch/tests/evil/css/import/main/preferred.html
1819 m_selectedStylesheetSet = content;
1820 m_preferredStylesheetSet = content;
1821 updateStyleSelector();
1822 } else if (equalIgnoringCase(equiv, "refresh")) {
1825 if (frame && parseHTTPRefresh(content, true, delay, url)) {
1827 url = frame->loader()->url().string();
1829 url = completeURL(url);
1830 frame->loader()->scheduleHTTPRedirection(delay, url);
1832 } else if (equalIgnoringCase(equiv, "set-cookie")) {
1833 // FIXME: make setCookie work on XML documents too; e.g. in case of <html:meta .....>
1834 if (isHTMLDocument())
1835 static_cast<HTMLDocument*>(this)->setCookie(content);
1839 MouseEventWithHitTestResults Document::prepareMouseEvent(const HitTestRequest& request, const IntPoint& documentPoint, const PlatformMouseEvent& event)
1841 ASSERT(!renderer() || renderer()->isRenderView());
1844 return MouseEventWithHitTestResults(event, HitTestResult(IntPoint()));
1846 HitTestResult result(documentPoint);
1847 renderer()->layer()->hitTest(request, result);
1849 if (!request.readonly)
1852 return MouseEventWithHitTestResults(event, result);
1855 // DOM Section 1.1.1
1856 bool Document::childTypeAllowed(NodeType type)
1859 case ATTRIBUTE_NODE:
1860 case CDATA_SECTION_NODE:
1861 case DOCUMENT_FRAGMENT_NODE:
1864 case ENTITY_REFERENCE_NODE:
1867 case XPATH_NAMESPACE_NODE:
1870 case PROCESSING_INSTRUCTION_NODE:
1872 case DOCUMENT_TYPE_NODE:
1874 // Documents may contain no more than one of each of these.
1875 // (One Element and one DocumentType.)
1876 for (Node* c = firstChild(); c; c = c->nextSibling())
1877 if (c->nodeType() == type)
1884 bool Document::canReplaceChild(Node* newChild, Node* oldChild)
1887 // ContainerNode::replaceChild will raise a NOT_FOUND_ERR.
1890 if (oldChild->nodeType() == newChild->nodeType())
1893 int numDoctypes = 0;
1894 int numElements = 0;
1896 // First, check how many doctypes and elements we have, not counting
1897 // the child we're about to remove.
1898 for (Node* c = firstChild(); c; c = c->nextSibling()) {
1902 switch (c->nodeType()) {
1903 case DOCUMENT_TYPE_NODE:
1914 // Then, see how many doctypes and elements might be added by the new child.
1915 if (newChild->nodeType() == DOCUMENT_FRAGMENT_NODE) {
1916 for (Node* c = firstChild(); c; c = c->nextSibling()) {
1917 switch (c->nodeType()) {
1918 case ATTRIBUTE_NODE:
1919 case CDATA_SECTION_NODE:
1920 case DOCUMENT_FRAGMENT_NODE:
1923 case ENTITY_REFERENCE_NODE:
1926 case XPATH_NAMESPACE_NODE:
1929 case PROCESSING_INSTRUCTION_NODE:
1931 case DOCUMENT_TYPE_NODE:
1940 switch (newChild->nodeType()) {
1941 case ATTRIBUTE_NODE:
1942 case CDATA_SECTION_NODE:
1943 case DOCUMENT_FRAGMENT_NODE:
1946 case ENTITY_REFERENCE_NODE:
1949 case XPATH_NAMESPACE_NODE:
1952 case PROCESSING_INSTRUCTION_NODE:
1954 case DOCUMENT_TYPE_NODE:
1963 if (numElements > 1 || numDoctypes > 1)
1969 PassRefPtr<Node> Document::cloneNode(bool /*deep*/)
1971 // Spec says cloning Document nodes is "implementation dependent"
1972 // so we do not support it...
1976 StyleSheetList* Document::styleSheets()
1978 return m_styleSheets.get();
1981 String Document::preferredStylesheetSet() const
1983 return m_preferredStylesheetSet;
1986 String Document::selectedStylesheetSet() const
1988 return m_selectedStylesheetSet;
1991 void Document::setSelectedStylesheetSet(const String& aString)
1993 m_selectedStylesheetSet = aString;
1994 updateStyleSelector();
1996 renderer()->repaint();
1999 // This method is called whenever a top-level stylesheet has finished loading.
2000 void Document::removePendingSheet()
2002 // Make sure we knew this sheet was pending, and that our count isn't out of sync.
2003 ASSERT(m_pendingStylesheets > 0);
2005 m_pendingStylesheets--;
2007 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2008 if (!ownerElement())
2009 printf("Stylesheet loaded at time %d. %d stylesheets still remain.\n", elapsedTime(), m_pendingStylesheets);
2012 updateStyleSelector();
2014 if (!m_pendingStylesheets && m_tokenizer)
2015 m_tokenizer->executeScriptsWaitingForStylesheets();
2017 if (!m_pendingStylesheets && m_gotoAnchorNeededAfterStylesheetsLoad && m_frame)
2018 m_frame->loader()->gotoAnchor();
2021 void Document::updateStyleSelector()
2023 // Don't bother updating, since we haven't loaded all our style info yet
2024 // and haven't calculated the style selector for the first time.
2025 if (!m_didCalculateStyleSelector && !haveStylesheetsLoaded())
2028 if (didLayoutWithPendingStylesheets() && m_pendingStylesheets <= 0) {
2029 m_pendingSheetLayout = IgnoreLayoutWithPendingSheets;
2031 renderer()->repaint();
2034 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2035 if (!ownerElement())
2036 printf("Beginning update of style selector at time %d.\n", elapsedTime());
2039 recalcStyleSelector();
2042 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2043 if (!ownerElement())
2044 printf("Finished update of style selector at time %d\n", elapsedTime());
2048 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
2050 view()->scheduleRelayout();
2054 void Document::recalcStyleSelector()
2056 if (!renderer() || !attached())
2059 DeprecatedPtrList<StyleSheet> oldStyleSheets = m_styleSheets->styleSheets;
2060 m_styleSheets->styleSheets.clear();
2062 bool matchAuthorAndUserStyles = true;
2063 if (Settings* settings = this->settings())
2064 matchAuthorAndUserStyles = settings->authorAndUserStylesEnabled();
2066 Node* n = matchAuthorAndUserStyles ? this : 0;
2067 for ( ; n; n = n->traverseNextNode()) {
2068 StyleSheet* sheet = 0;
2070 if (n->nodeType() == PROCESSING_INSTRUCTION_NODE) {
2071 // Processing instruction (XML documents only)
2072 ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(n);
2073 sheet = pi->sheet();
2075 // Don't apply XSL transforms to already transformed documents -- <rdar://problem/4132806>
2076 if (pi->isXSL() && !transformSourceDocument()) {
2077 // Don't apply XSL transforms until loading is finished.
2079 applyXSLTransform(pi);
2083 if (!sheet && !pi->localHref().isEmpty()) {
2084 // Processing instruction with reference to an element in this document - e.g.
2085 // <?xml-stylesheet href="#mystyle">, with the element
2086 // <foo id="mystyle">heading { color: red; }</foo> at some location in
2088 Element* elem = getElementById(pi->localHref().impl());
2090 String sheetText("");
2091 for (Node* c = elem->firstChild(); c; c = c->nextSibling()) {
2092 if (c->nodeType() == TEXT_NODE || c->nodeType() == CDATA_SECTION_NODE)
2093 sheetText += c->nodeValue();
2096 CSSStyleSheet* cssSheet = new CSSStyleSheet(this);
2097 cssSheet->parseString(sheetText);
2098 pi->setCSSStyleSheet(cssSheet);
2102 } else if (n->isHTMLElement() && (n->hasTagName(linkTag) || n->hasTagName(styleTag))
2104 || (n->isSVGElement() && n->hasTagName(SVGNames::styleTag))
2107 Element* e = static_cast<Element*>(n);
2108 DeprecatedString title = e->getAttribute(titleAttr).deprecatedString();
2109 bool enabledViaScript = false;
2110 if (e->hasLocalName(linkTag)) {
2112 HTMLLinkElement* l = static_cast<HTMLLinkElement*>(n);
2113 if (l->isDisabled())
2115 enabledViaScript = l->isEnabledViaScript();
2116 if (l->isLoading()) {
2117 // it is loading but we should still decide which style sheet set to use
2118 if (!enabledViaScript && !title.isEmpty() && m_preferredStylesheetSet.isEmpty()) {
2119 const AtomicString& rel = e->getAttribute(relAttr);
2120 if (!rel.domString().contains("alternate")) {
2121 m_preferredStylesheetSet = title;
2122 m_selectedStylesheetSet = title;
2128 title = DeprecatedString::null;
2131 // Get the current preferred styleset. This is the
2132 // set of sheets that will be enabled.
2134 if (n->isSVGElement() && n->hasTagName(SVGNames::styleTag))
2135 sheet = static_cast<SVGStyleElement*>(n)->sheet();
2138 if (e->hasLocalName(linkTag))
2139 sheet = static_cast<HTMLLinkElement*>(n)->sheet();
2142 sheet = static_cast<HTMLStyleElement*>(n)->sheet();
2144 // Check to see if this sheet belongs to a styleset
2145 // (thus making it PREFERRED or ALTERNATE rather than
2147 if (!enabledViaScript && !title.isEmpty()) {
2148 // Yes, we have a title.
2149 if (m_preferredStylesheetSet.isEmpty()) {
2150 // No preferred set has been established. If
2151 // we are NOT an alternate sheet, then establish
2152 // us as the preferred set. Otherwise, just ignore
2154 DeprecatedString rel = e->getAttribute(relAttr).deprecatedString();
2155 if (e->hasLocalName(styleTag) || !rel.contains("alternate"))
2156 m_preferredStylesheetSet = m_selectedStylesheetSet = title;
2159 if (title != m_preferredStylesheetSet)
2163 if (!n->isHTMLElement())
2164 title = title.replace('&', "&&");
2171 m_styleSheets->styleSheets.append(sheet);
2174 // For HTML documents, stylesheets are not allowed within/after the <BODY> tag. So we
2175 // can stop searching here.
2176 if (isHTMLDocument() && n->hasTagName(bodyTag))
2180 // De-reference all the stylesheets in the old list
2181 DeprecatedPtrListIterator<StyleSheet> it(oldStyleSheets);
2182 for (; it.current(); ++it)
2183 it.current()->deref();
2185 // Create a new style selector
2186 delete m_styleSelector;
2187 String usersheet = m_usersheet;
2188 if (view() && view()->mediaType() == "print")
2189 usersheet += m_printSheet;
2190 m_styleSelector = new CSSStyleSelector(this, usersheet, m_styleSheets.get(), m_mappedElementSheet.get(), !inCompatMode(), matchAuthorAndUserStyles);
2191 m_styleSelector->setEncodedURL(m_url);
2192 m_didCalculateStyleSelector = true;
2195 void Document::setHoverNode(PassRefPtr<Node> newHoverNode)
2197 m_hoverNode = newHoverNode;
2200 void Document::setActiveNode(PassRefPtr<Node> newActiveNode)
2202 m_activeNode = newActiveNode;
2205 void Document::focusedNodeRemoved()
2210 void Document::removeFocusedNodeOfSubtree(Node* node, bool amongChildrenOnly)
2212 if (!m_focusedNode || this->inPageCache()) // If the document is in the page cache, then we don't need to clear out the focused node.
2215 bool nodeInSubtree = false;
2216 if (amongChildrenOnly)
2217 nodeInSubtree = m_focusedNode->isDescendantOf(node);
2219 nodeInSubtree = (m_focusedNode == node) || m_focusedNode->isDescendantOf(node);
2222 document()->focusedNodeRemoved();
2225 void Document::hoveredNodeDetached(Node* node)
2227 if (!m_hoverNode || (node != m_hoverNode && (!m_hoverNode->isTextNode() || node != m_hoverNode->parent())))
2230 m_hoverNode = node->parent();
2231 while (m_hoverNode && !m_hoverNode->renderer())
2232 m_hoverNode = m_hoverNode->parent();
2234 frame()->eventHandler()->scheduleHoverStateUpdate();
2237 void Document::activeChainNodeDetached(Node* node)
2239 if (!m_activeNode || (node != m_activeNode && (!m_activeNode->isTextNode() || node != m_activeNode->parent())))
2242 m_activeNode = node->parent();
2243 while (m_activeNode && !m_activeNode->renderer())
2244 m_activeNode = m_activeNode->parent();
2247 const Vector<DashboardRegionValue>& Document::dashboardRegions() const
2249 return m_dashboardRegions;
2252 void Document::setDashboardRegions(const Vector<DashboardRegionValue>& regions)
2254 m_dashboardRegions = regions;
2255 setDashboardRegionsDirty(false);
2258 bool Document::setFocusedNode(PassRefPtr<Node> newFocusedNode)
2260 // Make sure newFocusedNode is actually in this document
2261 if (newFocusedNode && (newFocusedNode->document() != this))
2264 if (m_focusedNode == newFocusedNode)
2267 bool focusChangeBlocked = false;
2268 RefPtr<Node> oldFocusedNode = m_focusedNode;
2271 // Remove focus from the existing focus node (if any)
2272 if (oldFocusedNode && !oldFocusedNode->m_inDetach) {
2273 if (oldFocusedNode->active())
2274 oldFocusedNode->setActive(false);
2276 oldFocusedNode->setFocus(false);
2278 // Dispatch a change event for text fields or textareas that have been edited
2279 RenderObject *r = static_cast<RenderObject*>(oldFocusedNode.get()->renderer());
2280 if (r && (r->isTextArea() || r->isTextField()) && r->isEdited()) {
2281 EventTargetNodeCast(oldFocusedNode.get())->dispatchHTMLEvent(changeEvent, true, false);
2282 if ((r = static_cast<RenderObject*>(oldFocusedNode.get()->renderer())))
2283 r->setEdited(false);
2286 // Dispatch the blur event and let the node do any other blur related activities (important for text fields)
2287 EventTargetNodeCast(oldFocusedNode.get())->dispatchBlurEvent();
2289 if (m_focusedNode) {
2290 // handler shifted focus
2291 focusChangeBlocked = true;
2294 EventTargetNodeCast(oldFocusedNode.get())->dispatchUIEvent(DOMFocusOutEvent);
2295 if (m_focusedNode) {
2296 // handler shifted focus
2297 focusChangeBlocked = true;
2300 if ((oldFocusedNode.get() == this) && oldFocusedNode->hasOneRef())
2303 if (oldFocusedNode.get() == oldFocusedNode->rootEditableElement())
2304 frame()->editor()->didEndEditing();
2307 if (newFocusedNode) {
2308 if (newFocusedNode == newFocusedNode->rootEditableElement() && !acceptsEditingFocus(newFocusedNode.get())) {
2309 // delegate blocks focus change
2310 focusChangeBlocked = true;
2311 goto SetFocusedNodeDone;
2313 // Set focus on the new node
2314 m_focusedNode = newFocusedNode.get();
2316 // Dispatch the focus event and let the node do any other focus related activities (important for text fields)
2317 EventTargetNodeCast(m_focusedNode.get())->dispatchFocusEvent();
2319 if (m_focusedNode != newFocusedNode) {
2320 // handler shifted focus
2321 focusChangeBlocked = true;
2322 goto SetFocusedNodeDone;
2324 EventTargetNodeCast(m_focusedNode.get())->dispatchUIEvent(DOMFocusInEvent);
2325 if (m_focusedNode != newFocusedNode) {
2326 // handler shifted focus
2327 focusChangeBlocked = true;
2328 goto SetFocusedNodeDone;
2330 m_focusedNode->setFocus();
2332 if (m_focusedNode.get() == m_focusedNode->rootEditableElement())
2333 frame()->editor()->didBeginEditing();
2335 // eww, I suck. set the qt focus correctly
2336 // ### find a better place in the code for this
2338 Widget *focusWidget = widgetForNode(m_focusedNode.get());
2340 // Make sure a widget has the right size before giving it focus.
2341 // Otherwise, we are testing edge cases of the Widget code.
2342 // Specifically, in WebCore this does not work well for text fields.
2344 // Re-get the widget in case updating the layout changed things.
2345 focusWidget = widgetForNode(m_focusedNode.get());
2348 focusWidget->setFocus();
2355 if (!focusChangeBlocked && m_focusedNode && AXObjectCache::accessibilityEnabled())
2356 axObjectCache()->handleFocusedUIElementChanged();
2361 return !focusChangeBlocked;
2364 void Document::setCSSTarget(Node* n)
2367 m_cssTarget->setChanged();
2373 Node* Document::getCSSTarget() const
2378 void Document::attachNodeIterator(NodeIterator *ni)
2380 m_nodeIterators.add(ni);
2383 void Document::detachNodeIterator(NodeIterator *ni)
2385 m_nodeIterators.remove(ni);
2388 void Document::notifyBeforeNodeRemoval(Node *n)
2390 if (Frame* f = frame()) {
2391 f->selectionController()->nodeWillBeRemoved(n);
2392 f->dragCaretController()->nodeWillBeRemoved(n);
2395 HashSet<NodeIterator*>::const_iterator end = m_nodeIterators.end();
2396 for (HashSet<NodeIterator*>::const_iterator it = m_nodeIterators.begin(); it != end; ++it)
2397 (*it)->notifyBeforeNodeRemoval(n);
2400 DOMWindow* Document::defaultView() const
2405 return frame()->domWindow();
2408 PassRefPtr<Event> Document::createEvent(const String &eventType, ExceptionCode& ec)
2410 if (eventType == "UIEvents" || eventType == "UIEvent")
2412 if (eventType == "MouseEvents" || eventType == "MouseEvent")
2413 return new MouseEvent;
2414 if (eventType == "MutationEvents" || eventType == "MutationEvent")
2415 return new MutationEvent;
2416 if (eventType == "KeyboardEvents" || eventType == "KeyboardEvent")
2417 return new KeyboardEvent;
2418 if (eventType == "HTMLEvents" || eventType == "Event" || eventType == "Events")
2420 if (eventType == "ProgressEvent")
2421 return new ProgressEvent;
2422 if (eventType == "TextEvent")
2423 return new TextEvent;
2424 if (eventType == "OverflowEvent")
2425 return new OverflowEvent;
2426 if (eventType == "WheelEvent")
2427 return new WheelEvent;
2429 if (eventType == "SVGEvents")
2431 if (eventType == "SVGZoomEvents")
2432 return new SVGZoomEvent;
2434 ec = NOT_SUPPORTED_ERR;
2438 CSSStyleDeclaration *Document::getOverrideStyle(Element */*elt*/, const String &/*pseudoElt*/)
2443 void Document::handleWindowEvent(Event *evt, bool useCapture)
2445 if (m_windowEventListeners.isEmpty())
2448 // if any html event listeners are registered on the window, then dispatch them here
2449 RegisteredEventListenerList listenersCopy = m_windowEventListeners;
2450 RegisteredEventListenerList::iterator it = listenersCopy.begin();
2452 for (; it != listenersCopy.end(); ++it)
2453 if ((*it)->eventType() == evt->type() && (*it)->useCapture() == useCapture && !(*it)->removed())
2454 (*it)->listener()->handleEvent(evt, true);
2457 void Document::setHTMLWindowEventListener(const AtomicString &eventType, PassRefPtr<EventListener> listener)
2459 // If we already have it we don't want removeWindowEventListener to delete it
2460 removeHTMLWindowEventListener(eventType);
2462 addWindowEventListener(eventType, listener, false);
2465 EventListener *Document::getHTMLWindowEventListener(const AtomicString &eventType)
2467 RegisteredEventListenerList::iterator it = m_windowEventListeners.begin();
2468 for (; it != m_windowEventListeners.end(); ++it)
2469 if ( (*it)->eventType() == eventType && (*it)->listener()->isHTMLEventListener())
2470 return (*it)->listener();
2474 void Document::removeHTMLWindowEventListener(const AtomicString &eventType)
2476 RegisteredEventListenerList::iterator it = m_windowEventListeners.begin();
2477 for (; it != m_windowEventListeners.end(); ++it)
2478 if ( (*it)->eventType() == eventType && (*it)->listener()->isHTMLEventListener()) {
2479 m_windowEventListeners.remove(it);
2484 void Document::addWindowEventListener(const AtomicString &eventType, PassRefPtr<EventListener> listener, bool useCapture)
2486 // Remove existing identical listener set with identical arguments.
2487 // The DOM 2 spec says that "duplicate instances are discarded" in this case.
2488 removeWindowEventListener(eventType, listener.get(), useCapture);
2489 m_windowEventListeners.append(new RegisteredEventListener(eventType, listener, useCapture));
2492 void Document::removeWindowEventListener(const AtomicString &eventType, EventListener *listener, bool useCapture)
2494 RegisteredEventListener rl(eventType, listener, useCapture);
2495 RegisteredEventListenerList::iterator it = m_windowEventListeners.begin();
2496 for (; it != m_windowEventListeners.end(); ++it)
2498 m_windowEventListeners.remove(it);
2503 bool Document::hasWindowEventListener(const AtomicString &eventType)
2505 RegisteredEventListenerList::iterator it = m_windowEventListeners.begin();
2506 for (; it != m_windowEventListeners.end(); ++it)
2507 if ((*it)->eventType() == eventType) {
2513 PassRefPtr<EventListener> Document::createHTMLEventListener(const String& functionName, const String& code, Node *node)
2515 if (Frame* frm = frame())
2516 if (KJSProxy* proxy = frm->scriptProxy())
2517 return proxy->createHTMLEventHandler(functionName, code, node);
2521 void Document::setHTMLWindowEventListener(const AtomicString& eventType, Attribute* attr)
2523 setHTMLWindowEventListener(eventType,
2524 createHTMLEventListener(attr->localName().domString(), attr->value(), 0));
2527 void Document::dispatchImageLoadEventSoon(HTMLImageLoader *image)
2529 m_imageLoadEventDispatchSoonList.append(image);
2530 if (!m_imageLoadEventTimer.isActive())
2531 m_imageLoadEventTimer.startOneShot(0);
2534 void Document::removeImage(HTMLImageLoader* image)
2536 // Remove instances of this image from both lists.
2537 // Use loops because we allow multiple instances to get into the lists.
2538 while (m_imageLoadEventDispatchSoonList.removeRef(image)) { }
2539 while (m_imageLoadEventDispatchingList.removeRef(image)) { }
2540 if (m_imageLoadEventDispatchSoonList.isEmpty())
2541 m_imageLoadEventTimer.stop();
2544 void Document::dispatchImageLoadEventsNow()
2546 // need to avoid re-entering this function; if new dispatches are
2547 // scheduled before the parent finishes processing the list, they
2548 // will set a timer and eventually be processed
2549 if (!m_imageLoadEventDispatchingList.isEmpty()) {
2553 m_imageLoadEventTimer.stop();
2555 m_imageLoadEventDispatchingList = m_imageLoadEventDispatchSoonList;
2556 m_imageLoadEventDispatchSoonList.clear();
2557 for (DeprecatedPtrListIterator<HTMLImageLoader> it(m_imageLoadEventDispatchingList); it.current();) {
2558 HTMLImageLoader* image = it.current();
2559 // Must advance iterator *before* dispatching call.
2560 // Otherwise, it might be advanced automatically if dispatching the call had a side effect
2561 // of destroying the current HTMLImageLoader, and then we would advance past the *next* item,
2562 // missing one altogether.
2564 image->dispatchLoadEvent();
2566 m_imageLoadEventDispatchingList.clear();
2569 void Document::imageLoadEventTimerFired(Timer<Document>*)
2571 dispatchImageLoadEventsNow();
2574 Element* Document::ownerElement() const
2578 return frame()->ownerElement();
2581 String Document::cookie() const
2583 return cookies(url());
2586 void Document::setCookie(const String& value)
2588 setCookies(url(), policyBaseURL().deprecatedString(), value);
2591 String Document::referrer() const
2594 return frame()->loader()->referrer();
2598 String Document::domain() const
2600 return m_securityOrigin->domain();
2603 void Document::setDomain(const String& newDomain)
2605 // Both NS and IE specify that changing the domain is only allowed when
2606 // the new domain is a suffix of the old domain.
2608 // FIXME: We should add logging indicating why a domain was not allowed.
2610 // If the new domain is the same as the old domain, still call
2611 // m_securityOrigin.setDomainForDOM. This will change the
2612 // security check behavior. For example, if a page loaded on port 8000
2613 // assigns its current domain using document.domain, the page will
2614 // allow other pages loaded on different ports in the same domain that
2615 // have also assigned to access this page.
2616 if (equalIgnoringCase(domain(), newDomain)) {
2617 m_securityOrigin->setDomainFromDOM(newDomain);
2621 int oldLength = domain().length();
2622 int newLength = newDomain.length();
2623 // e.g. newDomain = webkit.org (10) and domain() = www.webkit.org (14)
2624 if (newLength >= oldLength)
2627 String test = domain().copy();
2628 // Check that it's a subdomain, not e.g. "ebkit.org"
2629 if (test[oldLength - newLength - 1] != '.')
2632 // Now test is "webkit.org" from domain()
2633 // and we check that it's the same thing as newDomain
2634 test.remove(0, oldLength - newLength);
2635 if (test != newDomain)
2638 m_securityOrigin->setDomainFromDOM(newDomain);
2641 String Document::lastModified() const
2646 DocumentLoader* loader = f->loader()->documentLoader();
2649 return loader->response().httpHeaderField("Last-Modified");
2652 bool Document::isValidName(const String &name)
2654 const UChar* s = reinterpret_cast<const UChar*>(name.characters());
2655 unsigned length = name.length();
2663 U16_NEXT(s, i, length, c)
2664 if (!isValidNameStart(c))
2667 while (i < length) {
2668 U16_NEXT(s, i, length, c)
2669 if (!isValidNamePart(c))
2676 bool Document::parseQualifiedName(const String &qualifiedName, String &prefix, String &localName)
2678 unsigned length = qualifiedName.length();
2683 bool nameStart = true;
2684 bool sawColon = false;
2687 const UChar* s = reinterpret_cast<const UChar*>(qualifiedName.characters());
2688 for (unsigned i = 0; i < length;) {
2690 U16_NEXT(s, i, length, c)
2693 return false; // multiple colons: not allowed
2697 } else if (nameStart) {
2698 if (!isValidNameStart(c))
2702 if (!isValidNamePart(c))
2709 localName = qualifiedName.copy();
2711 prefix = qualifiedName.substring(0, colonPos);
2712 localName = qualifiedName.substring(colonPos + 1, length - (colonPos + 1));
2718 void Document::addImageMap(HTMLMapElement* imageMap)
2720 const AtomicString& name = imageMap->getName();
2724 // Add the image map, unless there's already another with that name.
2725 // "First map wins" is the rule other browsers seem to implement.
2726 m_imageMapsByName.add(name.impl(), imageMap);
2729 void Document::removeImageMap(HTMLMapElement* imageMap)
2731 // Remove the image map by name.
2732 // But don't remove some other image map that just happens to have the same name.
2733 // FIXME: Use a HashCountedSet as we do for IDs to find the first remaining map
2734 // once a map has been removed.
2735 const AtomicString& name = imageMap->getName();
2739 ImageMapsByName::iterator it = m_imageMapsByName.find(name.impl());
2740 if (it != m_imageMapsByName.end() && it->second == imageMap)
2741 m_imageMapsByName.remove(it);
2744 HTMLMapElement *Document::getImageMap(const String& url) const
2748 int hashPos = url.find('#');
2749 String name = (hashPos < 0 ? url : url.substring(hashPos + 1)).impl();
2750 AtomicString mapName = hMode == XHtml ? name : name.lower();
2751 return m_imageMapsByName.get(mapName.impl());
2754 void Document::setDecoder(TextResourceDecoder *decoder)
2756 m_decoder = decoder;
2759 UChar Document::backslashAsCurrencySymbol() const
2763 return m_decoder->encoding().backslashAsCurrencySymbol();
2766 DeprecatedString Document::completeURL(const DeprecatedString& url)
2768 // FIXME: This treats null URLs the same as empty URLs, unlike the String function below.
2770 // If both the URL and base URL are empty, like they are for documents
2771 // created using DOMImplementation::createDocument, just return the passed in URL.
2772 // (We do this because url() returns "about:blank" for empty URLs.
2773 if (m_url.isEmpty() && m_baseURL.isEmpty())
2776 return KURL(baseURL(), url).deprecatedString();
2777 return KURL(baseURL(), url, m_decoder->encoding()).deprecatedString();
2780 String Document::completeURL(const String& url)
2782 // FIXME: This always returns null when passed a null URL, unlike the String function above.
2785 return completeURL(url.deprecatedString());
2788 bool Document::inPageCache()
2790 return m_inPageCache;
2793 void Document::setInPageCache(bool flag)
2795 if (m_inPageCache == flag)
2798 m_inPageCache = flag;
2800 ASSERT(m_savedRenderer == 0);
2801 m_savedRenderer = renderer();
2802 if (FrameView* v = view())
2803 v->resetScrollbars();
2805 ASSERT(renderer() == 0 || renderer() == m_savedRenderer);
2806 ASSERT(m_renderArena);
2807 setRenderer(m_savedRenderer);
2808 m_savedRenderer = 0;
2812 void Document::willSaveToCache()
2814 HashSet<Element*>::iterator end = m_pageCacheCallbackElements.end();
2815 for (HashSet<Element*>::iterator i = m_pageCacheCallbackElements.begin(); i != end; ++i)
2816 (*i)->willSaveToCache();
2819 void Document::didRestoreFromCache()
2821 HashSet<Element*>::iterator end = m_pageCacheCallbackElements.end();
2822 for (HashSet<Element*>::iterator i = m_pageCacheCallbackElements.begin(); i != end; ++i)
2823 (*i)->didRestoreFromCache();
2826 void Document::registerForCacheCallbacks(Element* e)
2828 m_pageCacheCallbackElements.add(e);
2831 void Document::unregisterForCacheCallbacks(Element* e)
2833 m_pageCacheCallbackElements.remove(e);
2836 void Document::setShouldCreateRenderers(bool f)
2838 m_createRenderers = f;
2841 bool Document::shouldCreateRenderers()
2843 return m_createRenderers;
2846 String Document::toString() const
2850 for (Node *child = firstChild(); child != NULL; child = child->nextSibling()) {
2851 result += child->toString();
2857 // Support for Javascript execCommand, and related methods
2859 static Editor::Command command(Document* document, const String& commandName, bool userInterface = false)
2861 Frame* frame = document->frame();
2862 if (!frame || frame->document() != document)
2863 return Editor::Command();
2864 return frame->editor()->command(commandName,
2865 userInterface ? CommandFromDOMWithUserInterface : CommandFromDOM);
2868 bool Document::execCommand(const String& commandName, bool userInterface, const String& value)
2870 return command(this, commandName, userInterface).execute(value);
2873 bool Document::queryCommandEnabled(const String& commandName)
2875 return command(this, commandName).isEnabled();
2878 bool Document::queryCommandIndeterm(const String& commandName)
2880 return command(this, commandName).state() == MixedTriState;
2883 bool Document::queryCommandState(const String& commandName)
2885 return command(this, commandName).state() != FalseTriState;
2888 bool Document::queryCommandSupported(const String& commandName)
2890 return command(this, commandName).isSupported();
2893 String Document::queryCommandValue(const String& commandName)
2895 return command(this, commandName).value();
2898 static IntRect placeholderRectForMarker()
2900 return IntRect(-1, -1, -1, -1);
2903 void Document::addMarker(Range *range, DocumentMarker::MarkerType type, String description)
2905 // Use a TextIterator to visit the potentially multiple nodes the range covers.
2906 for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) {
2907 RefPtr<Range> textPiece = markedText.range();
2909 DocumentMarker marker = {type, textPiece->startOffset(exception), textPiece->endOffset(exception), description};
2910 addMarker(textPiece->startContainer(exception), marker);
2914 void Document::removeMarkers(Range* range, DocumentMarker::MarkerType markerType)
2916 if (m_markers.isEmpty())
2919 ExceptionCode ec = 0;
2920 Node* startContainer = range->startContainer(ec);
2921 Node* endContainer = range->endContainer(ec);
2923 Node* pastEndNode = range->pastEndNode();
2924 for (Node* node = range->startNode(); node != pastEndNode; node = node->traverseNextNode()) {
2925 int startOffset = node == startContainer ? range->startOffset(ec) : 0;
2926 int endOffset = node == endContainer ? range->endOffset(ec) : INT_MAX;
2927 int length = endOffset - startOffset;
2928 removeMarkers(node, startOffset, length, markerType);
2932 // Markers are stored in order sorted by their location.
2933 // They do not overlap each other, as currently required by the drawing code in RenderText.cpp.
2935 void Document::addMarker(Node *node, DocumentMarker newMarker)
2937 ASSERT(newMarker.endOffset >= newMarker.startOffset);
2938 if (newMarker.endOffset == newMarker.startOffset)
2941 MarkerMapVectorPair* vectorPair = m_markers.get(node);
2944 vectorPair = new MarkerMapVectorPair;
2945 vectorPair->first.append(newMarker);
2946 vectorPair->second.append(placeholderRectForMarker());
2947 m_markers.set(node, vectorPair);
2949 Vector<DocumentMarker>& markers = vectorPair->first;
2950 Vector<IntRect>& rects = vectorPair->second;
2951 ASSERT(markers.size() == rects.size());
2953 for (i = 0; i != markers.size();) {
2954 DocumentMarker marker = markers[i];
2956 if (newMarker.endOffset < marker.startOffset+1) {
2957 // This is the first marker that is completely after newMarker, and disjoint from it.
2958 // We found our insertion point.
2960 } else if (newMarker.startOffset > marker.endOffset) {
2961 // maker is before newMarker, and disjoint from it. Keep scanning.
2963 } else if (newMarker == marker) {
2964 // already have this one, NOP
2967 // marker and newMarker intersect or touch - merge them into newMarker
2968 newMarker.startOffset = min(newMarker.startOffset, marker.startOffset);
2969 newMarker.endOffset = max(newMarker.endOffset, marker.endOffset);
2970 // remove old one, we'll add newMarker later
2973 // it points to the next marker to consider
2976 // at this point i points to the node before which we want to insert
2977 markers.insert(i, newMarker);
2978 rects.insert(i, placeholderRectForMarker());
2981 // repaint the affected node
2982 if (node->renderer())
2983 node->renderer()->repaint();
2986 // copies markers from srcNode to dstNode, applying the specified shift delta to the copies. The shift is
2987 // useful if, e.g., the caller has created the dstNode from a non-prefix substring of the srcNode.
2988 void Document::copyMarkers(Node *srcNode, unsigned startOffset, int length, Node *dstNode, int delta, DocumentMarker::MarkerType markerType)
2993 MarkerMapVectorPair* vectorPair = m_markers.get(srcNode);
2997 ASSERT(vectorPair->first.size() == vectorPair->second.size());
2999 bool docDirty = false;
3000 unsigned endOffset = startOffset + length - 1;
3001 Vector<DocumentMarker>& markers = vectorPair->first;
3002 for (size_t i = 0; i != markers.size(); ++i) {
3003 DocumentMarker marker = markers[i];
3005 // stop if we are now past the specified range
3006 if (marker.startOffset > endOffset)
3009 // skip marker that is before the specified range or is the wrong type
3010 if (marker.endOffset < startOffset || (marker.type != markerType && markerType != DocumentMarker::AllMarkers))
3013 // pin the marker to the specified range and apply the shift delta
3015 if (marker.startOffset < startOffset)
3016 marker.startOffset = startOffset;
3017 if (marker.endOffset > endOffset)
3018 marker.endOffset = endOffset;
3019 marker.startOffset += delta;
3020 marker.endOffset += delta;
3022 addMarker(dstNode, marker);
3025 // repaint the affected node
3026 if (docDirty && dstNode->renderer())
3027 dstNode->renderer()->repaint();
3030 void Document::removeMarkers(Node* node, unsigned startOffset, int length, DocumentMarker::MarkerType markerType)
3035 MarkerMapVectorPair* vectorPair = m_markers.get(node);
3039 Vector<DocumentMarker>& markers = vectorPair->first;
3040 Vector<IntRect>& rects = vectorPair->second;
3041 ASSERT(markers.size() == rects.size());
3042 bool docDirty = false;
3043 unsigned endOffset = startOffset + length;
3044 for (size_t i = 0; i < markers.size();) {
3045 DocumentMarker marker = markers[i];
3047 // markers are returned in order, so stop if we are now past the specified range
3048 if (marker.startOffset >= endOffset)
3051 // skip marker that is wrong type or before target
3052 if (marker.endOffset < startOffset || (marker.type != markerType && markerType != DocumentMarker::AllMarkers)) {
3057 // at this point we know that marker and target intersect in some way
3060 // pitch the old marker and any associated rect
3064 // add either of the resulting slices that are left after removing target
3065 if (startOffset > marker.startOffset) {
3066 DocumentMarker newLeft = marker;
3067 newLeft.endOffset = startOffset;
3068 markers.insert(i, newLeft);
3069 rects.insert(i, placeholderRectForMarker());
3070 // i now points to the newly-inserted node, but we want to skip that one
3073 if (marker.endOffset > endOffset) {
3074 DocumentMarker newRight = marker;
3075 newRight.startOffset = endOffset;
3076 markers.insert(i, newRight);
3077 rects.insert(i, placeholderRectForMarker());
3078 // i now points to the newly-inserted node, but we want to skip that one
3083 if (markers.isEmpty()) {
3084 ASSERT(rects.isEmpty());
3085 m_markers.remove(node);
3089 // repaint the affected node
3090 if (docDirty && node->renderer())
3091 node->renderer()->repaint();
3094 DocumentMarker* Document::markerContainingPoint(const IntPoint& point, DocumentMarker::MarkerType markerType)
3096 // outer loop: process each node that contains any markers
3097 MarkerMap::iterator end = m_markers.end();
3098 for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
3099 // inner loop; process each marker in this node
3100 MarkerMapVectorPair* vectorPair = nodeIterator->second;
3101 Vector<DocumentMarker>& markers = vectorPair->first;
3102 Vector<IntRect>& rects = vectorPair->second;
3103 ASSERT(markers.size() == rects.size());
3104 unsigned markerCount = markers.size();
3105 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
3106 DocumentMarker& marker = markers[markerIndex];
3108 // skip marker that is wrong type
3109 if (marker.type != markerType && markerType != DocumentMarker::AllMarkers)
3112 IntRect& r = rects[markerIndex];
3114 // skip placeholder rects
3115 if (r == placeholderRectForMarker())
3118 if (r.contains(point))
3126 Vector<DocumentMarker> Document::markersForNode(Node* node)
3128 MarkerMapVectorPair* vectorPair = m_markers.get(node);
3130 return vectorPair->first;
3131 return Vector<DocumentMarker>();
3134 Vector<IntRect> Document::renderedRectsForMarkers(DocumentMarker::MarkerType markerType)
3136 Vector<IntRect> result;
3138 // outer loop: process each node
3139 MarkerMap::iterator end = m_markers.end();
3140 for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
3141 // inner loop; process each marker in this node
3142 MarkerMapVectorPair* vectorPair = nodeIterator->second;
3143 Vector<DocumentMarker>& markers = vectorPair->first;
3144 Vector<IntRect>& rects = vectorPair->second;
3145 ASSERT(markers.size() == rects.size());
3146 unsigned markerCount = markers.size();
3147 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
3148 DocumentMarker marker = markers[markerIndex];
3150 // skip marker that is wrong type
3151 if (marker.type != markerType && markerType != DocumentMarker::AllMarkers)
3154 IntRect r = rects[markerIndex];
3155 // skip placeholder rects
3156 if (r == placeholderRectForMarker())
3166 void Document::removeMarkers(Node* node)
3168 MarkerMap::iterator i = m_markers.find(node);
3169 if (i != m_markers.end()) {
3171 m_markers.remove(i);
3172 if (RenderObject* renderer = node->renderer())
3173 renderer->repaint();
3177 void Document::removeMarkers(DocumentMarker::MarkerType markerType)
3179 // outer loop: process each markered node in the document
3180 MarkerMap markerMapCopy = m_markers;
3181 MarkerMap::iterator end = markerMapCopy.end();
3182 for (MarkerMap::iterator i = markerMapCopy.begin(); i != end; ++i) {
3183 Node* node = i->first.get();
3184 bool nodeNeedsRepaint = false;
3186 // inner loop: process each marker in the current node
3187 MarkerMapVectorPair* vectorPair = i->second;
3188 Vector<DocumentMarker>& markers = vectorPair->first;
3189 Vector<IntRect>& rects = vectorPair->second;
3190 ASSERT(markers.size() == rects.size());
3191 for (size_t i = 0; i != markers.size();) {
3192 DocumentMarker marker = markers[i];
3194 // skip nodes that are not of the specified type
3195 if (marker.type != markerType && markerType != DocumentMarker::AllMarkers) {
3200 // pitch the old marker
3203 nodeNeedsRepaint = true;
3204 // markerIterator now points to the next node
3207 // Redraw the node if it changed. Do this before the node is removed from m_markers, since
3208 // m_markers might contain the last reference to the node.
3209 if (nodeNeedsRepaint) {
3210 RenderObject* renderer = node->renderer();
3212 renderer->repaint();
3215 // delete the node's list if it is now empty
3216 if (markers.isEmpty()) {
3217 ASSERT(rects.isEmpty());
3218 m_markers.remove(node);
3224 void Document::repaintMarkers(DocumentMarker::MarkerType markerType)
3226 // outer loop: process each markered node in the document
3227 MarkerMap::iterator end = m_markers.end();
3228 for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
3229 Node* node = i->first.get();
3231 // inner loop: process each marker in the current node
3232 MarkerMapVectorPair* vectorPair = i->second;
3233 Vector<DocumentMarker>& markers = vectorPair->first;
3234 bool nodeNeedsRepaint = false;
3235 for (size_t i = 0; i != markers.size(); ++i) {
3236 DocumentMarker marker = markers[i];
3238 // skip nodes that are not of the specified type
3239 if (marker.type == markerType || markerType == DocumentMarker::AllMarkers) {
3240 nodeNeedsRepaint = true;
3245 if (!nodeNeedsRepaint)
3248 // cause the node to be redrawn
3249 if (RenderObject* renderer = node->renderer())
3250 renderer->repaint();
3254 void Document::setRenderedRectForMarker(Node* node, DocumentMarker marker, const IntRect& r)
3256 MarkerMapVectorPair* vectorPair = m_markers.get(node);
3258 ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marker we don't already know about
3262 Vector<DocumentMarker>& markers = vectorPair->first;
3263 ASSERT(markers.size() == vectorPair->second.size());
3264 unsigned markerCount = markers.size();
3265 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
3266 DocumentMarker m = markers[markerIndex];
3268 vectorPair->second[markerIndex] = r;
3273 ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marker we don't already know about
3276 void Document::invalidateRenderedRectsForMarkersInRect(const IntRect& r)
3278 // outer loop: process each markered node in the document
3279 MarkerMap::iterator end = m_markers.end();
3280 for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
3282 // inner loop: process each rect in the current node
3283 MarkerMapVectorPair* vectorPair = i->second;
3284 Vector<IntRect>& rects = vectorPair->second;
3286 unsigned rectCount = rects.size();
3287 for (unsigned rectIndex = 0; rectIndex < rectCount; ++rectIndex)
3288 if (rects[rectIndex].intersects(r))
3289 rects[rectIndex] = placeholderRectForMarker();
3293 void Document::shiftMarkers(Node *node, unsigned startOffset, int delta, DocumentMarker::MarkerType markerType)
3295 MarkerMapVectorPair* vectorPair = m_markers.get(node);
3299 Vector<DocumentMarker>& markers = vectorPair->first;
3300 Vector<IntRect>& rects = vectorPair->second;
3301 ASSERT(markers.size() == rects.size());
3303 bool docDirty = false;
3304 for (size_t i = 0; i != markers.size(); ++i) {
3305 DocumentMarker &marker = markers[i];
3306 if (marker.startOffset >= startOffset && (markerType == DocumentMarker::AllMarkers || marker.type == markerType)) {
3307 ASSERT((int)marker.startOffset + delta >= 0);
3308 marker.startOffset += delta;
3309 marker.endOffset += delta;
3312 // Marker moved, so previously-computed rendered rectangle is now invalid
3313 rects[i] = placeholderRectForMarker();
3317 // repaint the affected node
3318 if (docDirty && node->renderer())
3319 node->renderer()->repaint();
3324 void Document::applyXSLTransform(ProcessingInstruction* pi)
3326 RefPtr<XSLTProcessor> processor = new XSLTProcessor;
3327 processor->setXSLStylesheet(static_cast<XSLStyleSheet*>(pi->sheet()));
3329 String resultMIMEType;
3331 String resultEncoding;
3332 if (!processor->transformToString(this, resultMIMEType, newSource, resultEncoding))
3334 // FIXME: If the transform failed we should probably report an error (like Mozilla does).
3335 processor->createDocumentFromSource(newSource, resultEncoding, resultMIMEType, this, frame());
3338 void Document::setTransformSource(void* doc)
3340 if (doc == m_transformSource)
3343 xmlFreeDoc((xmlDocPtr)m_transformSource);
3344 m_transformSource = doc;
3349 void Document::setDesignMode(InheritedBool value)
3351 m_designMode = value;
3354 Document::InheritedBool Document::getDesignMode() const
3356 return m_designMode;
3359 bool Document::inDesignMode() const
3361 for (const Document* d = this; d; d = d->parentDocument()) {
3362 if (d->m_designMode != inherit)
3363 return d->m_designMode;
3368 Document *Document::parentDocument() const
3370 Frame *childPart = frame();
3373 Frame *parent = childPart->tree()->parent();
3376 return parent->document();
3379 Document *Document::topDocument() const
3381 Document *doc = const_cast<Document *>(this);
3383 while ((element = doc->ownerElement()))
3384 doc = element->document();
3389 PassRefPtr<Attr> Document::createAttributeNS(const String &namespaceURI, const String &qualifiedName, ExceptionCode& ec)
3391 if (qualifiedName.isNull()) {
3396 String localName = qualifiedName;
3399 if ((colonpos = qualifiedName.find(':')) >= 0) {
3400 prefix = qualifiedName.copy();
3401 localName = qualifiedName.copy();
3402 prefix.truncate(colonpos);
3403 localName.remove(0, colonpos+1);
3406 if (!isValidName(localName)) {
3407 ec = INVALID_CHARACTER_ERR;
3411 // FIXME: Assume this is a mapped attribute, since createAttribute isn't namespace-aware. There's no harm to XML
3412 // documents if we're wrong.
3413 return new Attr(0, this, new MappedAttribute(QualifiedName(prefix, localName, namespaceURI), StringImpl::empty()));
3417 const SVGDocumentExtensions* Document::svgExtensions()
3419 return m_svgExtensions;
3422 SVGDocumentExtensions* Document::accessSVGExtensions()
3424 if (!m_svgExtensions)
3425 m_svgExtensions = new SVGDocumentExtensions(this);
3426 return m_svgExtensions;
3430 PassRefPtr<HTMLCollection> Document::images()
3432 return new HTMLCollection(this, HTMLCollection::DocImages);
3435 PassRefPtr<HTMLCollection> Document::applets()
3437 return new HTMLCollection(this, HTMLCollection::DocApplets);
3440 PassRefPtr<HTMLCollection> Document::embeds()
3442 return new HTMLCollection(this, HTMLCollection::DocEmbeds);
3445 PassRefPtr<HTMLCollection> Document::plugins()
3447 // This is an alias for embeds() required for the JS DOM bindings.
3448 return new HTMLCollection(this, HTMLCollection::DocEmbeds);
3451 PassRefPtr<HTMLCollection> Document::objects()
3453 return new HTMLCollection(this, HTMLCollection::DocObjects);
3456 PassRefPtr<HTMLCollection> Document::scripts()
3458 return new HTMLCollection(this, HTMLCollection::DocScripts);
3461 PassRefPtr<HTMLCollection> Document::links()
3463 return new HTMLCollection(this, HTMLCollection::DocLinks);
3466 PassRefPtr<HTMLCollection> Document::forms()
3468 return new HTMLCollection(this, HTMLCollection::DocForms);
3471 PassRefPtr<HTMLCollection> Document::anchors()
3473 return new HTMLCollection(this, HTMLCollection::DocAnchors);
3476 PassRefPtr<HTMLCollection> Document::all()
3478 return new HTMLCollection(this, HTMLCollection::DocAll);
3481 PassRefPtr<HTMLCollection> Document::windowNamedItems(const String &name)
3483 return new HTMLNameCollection(this, HTMLCollection::WindowNamedItems, name);
3486 PassRefPtr<HTMLCollection> Document::documentNamedItems(const String &name)
3488 return new HTMLNameCollection(this, HTMLCollection::DocumentNamedItems, name);
3491 HTMLCollection::CollectionInfo* Document::nameCollectionInfo(HTMLCollection::Type type, const AtomicString& name)
3493 ASSERT(type >= HTMLCollection::FirstNamedDocumentCachedType);
3494 unsigned index = type - HTMLCollection::FirstNamedDocumentCachedType;
3495 ASSERT(index < HTMLCollection::NumNamedDocumentCachedTypes);
3497 NamedCollectionMap& map = m_nameCollectionInfo[index];
3498 NamedCollectionMap::iterator iter = map.find(name.impl());
3499 if (iter == map.end())
3500 iter = map.add(name.impl(), new HTMLCollection::CollectionInfo).first;
3501 return iter->second;
3504 void Document::finishedParsing()
3508 ExceptionCode ec = 0;
3509 dispatchEvent(new Event(DOMContentLoadedEvent, true, false), ec);
3511 if (Frame* f = frame())
3512 f->loader()->finishedParsing();
3515 Vector<String> Document::formElementsState() const
3517 Vector<String> stateVector;
3518 stateVector.reserveCapacity(m_formElementsWithState.size() * 3);
3519 typedef ListHashSet<HTMLFormControlElementWithState*>::const_iterator Iterator;
3520 Iterator end = m_formElementsWithState.end();
3521 for (Iterator it = m_formElementsWithState.begin(); it != end; ++it) {
3522 HTMLFormControlElementWithState* e = *it;
3524 if (e->saveState(value)) {
3525 stateVector.append(e->name().domString());
3526 stateVector.append(e->type().domString());
3527 stateVector.append(value);
3535 PassRefPtr<XPathExpression> Document::createExpression(const String& expression,
3536 XPathNSResolver* resolver,
3539 if (!m_xpathEvaluator)
3540 m_xpathEvaluator = new XPathEvaluator;
3541 return m_xpathEvaluator->createExpression(expression, resolver, ec);
3544 PassRefPtr<XPathNSResolver> Document::createNSResolver(Node* nodeResolver)
3546 if (!m_xpathEvaluator)
3547 m_xpathEvaluator = new XPathEvaluator;
3548 return m_xpathEvaluator->createNSResolver(nodeResolver);
3551 PassRefPtr<XPathResult> Document::evaluate(const String& expression,
3553 XPathNSResolver* resolver,
3554 unsigned short type,
3555 XPathResult* result,
3558 if (!m_xpathEvaluator)
3559 m_xpathEvaluator = new XPathEvaluator;
3560 return m_xpathEvaluator->evaluate(expression, contextNode, resolver, type, result, ec);
3563 #endif // ENABLE(XPATH)
3565 void Document::setStateForNewFormElements(const Vector<String>& stateVector)
3567 // Walk the state vector backwards so that the value to use for each
3568 // name/type pair first is the one at the end of each individual vector
3569 // in the FormElementStateMap. We're using them like stacks.
3570 typedef FormElementStateMap::iterator Iterator;
3571 m_formElementsWithState.clear();
3572 for (size_t i = stateVector.size() / 3 * 3; i; i -= 3) {
3573 AtomicString a = stateVector[i - 3];
3574 AtomicString b = stateVector[i - 2];
3575 const String& c = stateVector[i - 1];
3576 FormElementKey key(a.impl(), b.impl());
3577 Iterator it = m_stateForNewFormElements.find(key);
3578 if (it != m_stateForNewFormElements.end())
3579 it->second.append(c);
3581 Vector<String> v(1);
3583 m_stateForNewFormElements.set(key, v);
3588 bool Document::hasStateForNewFormElements() const
3590 return !m_stateForNewFormElements.isEmpty();
3593 bool Document::takeStateForFormElement(AtomicStringImpl* name, AtomicStringImpl* type, String& state)
3595 typedef FormElementStateMap::iterator Iterator;
3596 Iterator it = m_stateForNewFormElements.find(FormElementKey(name, type));
3597 if (it == m_stateForNewFormElements.end())
3599 ASSERT(it->second.size());
3600 state = it->second.last();
3601 if (it->second.size() > 1)
3602 it->second.removeLast();
3604 m_stateForNewFormElements.remove(it);
3608 FormElementKey::FormElementKey(AtomicStringImpl* name, AtomicStringImpl* type)
3609 : m_name(name), m_type(type)
3614 FormElementKey::~FormElementKey()
3619 FormElementKey::FormElementKey(const FormElementKey& other)
3620 : m_name(other.name()), m_type(other.type())
3625 FormElementKey& FormElementKey::operator=(const FormElementKey& other)
3629 m_name = other.name();
3630 m_type = other.type();
3634 void FormElementKey::ref() const
3636 if (name() && name() != HashTraits<AtomicStringImpl*>::deletedValue())
3642 void FormElementKey::deref() const
3644 if (name() && name() != HashTraits<AtomicStringImpl*>::deletedValue())
3650 unsigned FormElementKeyHash::hash(const FormElementKey& k)
3652 ASSERT(sizeof(k) % (sizeof(uint16_t) * 2) == 0);
3654 unsigned l = sizeof(k) / (sizeof(uint16_t) * 2);
3655 const uint16_t* s = reinterpret_cast<const uint16_t*>(&k);
3656 uint32_t hash = PHI;
3659 for (; l > 0; l--) {
3661 uint32_t tmp = (s[1] << 11) ^ hash;
3662 hash = (hash << 16) ^ tmp;
3667 // Force "avalanching" of final 127 bits
3674 // this avoids ever returning a hash code of 0, since that is used to
3675 // signal "hash not computed yet", using a value that is likely to be
3676 // effectively the same as 0 when the low bits are masked
3683 FormElementKey FormElementKeyHashTraits::deletedValue()
3685 return HashTraits<AtomicStringImpl*>::deletedValue();
3689 String Document::iconURL()
3694 void Document::setIconURL(const String& iconURL, const String& type)
3696 // FIXME - <rdar://problem/4727645> - At some point in the future, we might actually honor the "type"