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., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, 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"
34 #include "DOMImplementation.h"
35 #include "DocLoader.h"
36 #include "DocumentFragment.h"
37 #include "DocumentLoader.h"
38 #include "DocumentType.h"
39 #include "EditingText.h"
41 #include "EditorClient.h"
42 #include "EntityReference.h"
44 #include "EventHandler.h"
45 #include "EventListener.h"
46 #include "EventNames.h"
47 #include "ExceptionCode.h"
48 #include "FocusController.h"
50 #include "FrameLoader.h"
51 #include "FrameTree.h"
52 #include "FrameView.h"
53 #include "HTMLBodyElement.h"
54 #include "HTMLDocument.h"
55 #include "HTMLElementFactory.h"
56 #include "HTMLFrameOwnerElement.h"
57 #include "HTMLHeadElement.h"
58 #include "HTMLImageLoader.h"
59 #include "HTMLInputElement.h"
60 #include "HTMLLinkElement.h"
61 #include "HTMLMapElement.h"
62 #include "HTMLNameCollection.h"
63 #include "HTMLNames.h"
64 #include "HTMLStyleElement.h"
65 #include "HTMLTitleElement.h"
66 #include "HTTPParsers.h"
67 #include "HitTestRequest.h"
68 #include "HitTestResult.h"
70 #include "KeyboardEvent.h"
72 #include "MouseEvent.h"
73 #include "MouseEventWithHitTestResults.h"
74 #include "MutationEvent.h"
75 #include "NameNodeList.h"
76 #include "NodeFilter.h"
77 #include "NodeIterator.h"
78 #include "OverflowEvent.h"
80 #include "PlatformKeyboardEvent.h"
81 #include "ProcessingInstruction.h"
82 #include "RegisteredEventListener.h"
83 #include "RegularExpression.h"
84 #include "RenderArena.h"
85 #include "RenderView.h"
86 #include "RenderWidget.h"
87 #include "SegmentedString.h"
88 #include "SelectionController.h"
90 #include "StringHash.h"
91 #include "StyleSheetList.h"
92 #include "SystemTime.h"
93 #include "TextEvent.h"
94 #include "TextIterator.h"
95 #include "TextResourceDecoder.h"
96 #include "TreeWalker.h"
98 #include "WheelEvent.h"
99 #include "XMLHttpRequest.h"
100 #include "XMLTokenizer.h"
101 #include "kjs_binding.h"
102 #include "kjs_proxy.h"
105 #include "XPathEvaluator.h"
106 #include "XPathExpression.h"
107 #include "XPathNSResolver.h"
108 #include "XPathResult.h"
112 #include "XSLTProcessor.h"
116 #include "XBLBindingManager.h"
120 #include "SVGDocumentExtensions.h"
121 #include "SVGElementFactory.h"
122 #include "SVGZoomEvent.h"
123 #include "SVGStyleElement.h"
124 #include "TimeScheduler.h"
129 using namespace Unicode;
133 using namespace EventNames;
134 using namespace HTMLNames;
136 // #define INSTRUMENT_LAYOUT_SCHEDULING 1
138 // This amount of time must have elapsed before we will even consider scheduling a layout without a delay.
139 // FIXME: For faster machines this value can really be lowered to 200. 250 is adequate, but a little high
141 static const int cLayoutScheduleThreshold = 250;
143 // Use 1 to represent the document's default form.
144 static HTMLFormElement* const defaultForm = reinterpret_cast<HTMLFormElement*>(1);
146 // Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's
147 static const unsigned PHI = 0x9e3779b9U;
149 // DOM Level 2 says (letters added):
151 // a) Name start characters must have one of the categories Ll, Lu, Lo, Lt, Nl.
152 // b) Name characters other than Name-start characters must have one of the categories Mc, Me, Mn, Lm, or Nd.
153 // c) Characters in the compatibility area (i.e. with character code greater than #xF900 and less than #xFFFE) are not allowed in XML names.
154 // 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.
155 // 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.
156 // f) Characters #x20DD-#x20E0 are excluded (in accordance with Unicode, section 5.14).
157 // g) Character #x00B7 is classified as an extender, because the property list so identifies it.
158 // h) Character #x0387 is added as a name character, because #x00B7 is its canonical equivalent.
159 // i) Characters ':' and '_' are allowed as name-start characters.
160 // j) Characters '-' and '.' are allowed as name characters.
162 // It also contains complete tables. If we decide it's better, we could include those instead of the following code.
164 static inline bool isValidNameStart(UChar32 c)
167 if ((c >= 0x02BB && c <= 0x02C1) || c == 0x559 || c == 0x6E5 || c == 0x6E6)
171 if (c == ':' || c == '_')
174 // rules (a) and (f) above
175 const uint32_t nameStartMask = Letter_Lowercase | Letter_Uppercase | Letter_Other | Letter_Titlecase | Number_Letter;
176 if (!(Unicode::category(c) & nameStartMask))
180 if (c >= 0xF900 && c < 0xFFFE)
184 DecompositionType decompType = decompositionType(c);
185 if (decompType == DecompositionFont || decompType == DecompositionCompat)
191 static inline bool isValidNamePart(UChar32 c)
193 // rules (a), (e), and (i) above
194 if (isValidNameStart(c))
197 // rules (g) and (h) above
198 if (c == 0x00B7 || c == 0x0387)
202 if (c == '-' || c == '.')
205 // rules (b) and (f) above
206 const uint32_t otherNamePartMask = Mark_NonSpacing | Mark_Enclosing | Mark_SpacingCombining | Letter_Modifier | Number_DecimalDigit;
207 if (!(Unicode::category(c) & otherNamePartMask))
211 if (c >= 0xF900 && c < 0xFFFE)
215 DecompositionType decompType = decompositionType(c);
216 if (decompType == DecompositionFont || decompType == DecompositionCompat)
222 static Widget* widgetForNode(Node* focusedNode)
226 RenderObject* renderer = focusedNode->renderer();
227 if (!renderer || !renderer->isWidget())
229 return static_cast<RenderWidget*>(renderer)->widget();
232 static bool acceptsEditingFocus(Node *node)
235 ASSERT(node->isContentEditable());
237 Node *root = node->rootEditableElement();
238 Frame* frame = node->document()->frame();
242 return frame->editor()->shouldBeginEditing(rangeOfContents(root).get());
245 DeprecatedPtrList<Document>* Document::changedDocuments = 0;
247 // FrameView might be 0
248 Document::Document(DOMImplementation* impl, Frame* frame, bool isXHTML)
250 , m_implementation(impl)
251 , m_domtree_version(0)
252 , m_styleSheets(new StyleSheetList)
254 , m_titleSetExplicitly(false)
255 , m_imageLoadEventTimer(this, &Document::imageLoadEventTimerFired)
256 , m_updateFocusAppearanceTimer(this, &Document::updateFocusAppearanceTimerFired)
258 , m_transformSource(0)
260 , m_xmlVersion("1.0")
261 , m_xmlStandalone(false)
263 , m_bindingManager(new XBLBindingManager(this))
265 , m_domainWasSetInDOM(false)
268 , m_designMode(inherit)
269 , m_selfOnlyRefCount(0)
273 , m_hasDashboardRegions(false)
274 , m_dashboardRegionsDirty(false)
275 , m_accessKeyMapValid(false)
276 , m_createRenderers(true)
277 , m_inPageCache(false)
278 , m_isAllowedToLoadLocalResources(false)
279 , m_useSecureKeyboardEntryWhenActive(false)
280 #if USE(LOW_BANDWIDTH_DISPLAY)
281 , m_inLowBandwidthDisplay(false)
286 m_document.resetSkippingRef(this);
295 // FIXME: DocLoader probably no longer needs the frame argument
296 m_docLoader = new DocLoader(frame, this);
298 visuallyOrdered = false;
300 m_docChanged = false;
302 m_wellFormed = false;
306 m_textColor = Color::black;
309 m_inStyleRecalc = false;
310 m_closeAfterStyleRecalc = false;
311 m_usesDescendantRules = false;
312 m_usesSiblingRules = false;
313 m_usesFirstLineRules = false;
314 m_usesFirstLetterRules = false;
315 m_gotoAnchorNeededAfterStylesheetsLoad = false;
317 m_styleSelector = new CSSStyleSelector(this, m_usersheet, m_styleSheets.get(), !inCompatMode());
318 m_didCalculateStyleSelector = false;
319 m_pendingStylesheets = 0;
320 m_ignorePendingStylesheets = false;
321 m_hasNodesWithPlaceholderStyle = false;
322 m_pendingSheetLayout = NoLayoutWithPendingSheets;
327 resetVisitedLinkColor();
328 resetActiveLinkColor();
330 m_processingLoadEvent = false;
331 m_startTime = currentTime();
332 m_overMinimumLayoutThreshold = false;
336 initSecurityPolicyURL();
338 static int docID = 0;
342 void Document::removedLastRef()
344 if (m_selfOnlyRefCount) {
345 // if removing a child removes the last self-only ref, we don't
346 // want the document to be destructed until after
347 // removeAllChildren returns, so we guard ourselves with an
348 // extra self-only ref
350 DocPtr<Document> guard(this);
352 // we must make sure not to be retaining any of our children through
353 // these extra pointers or we will create a reference cycle
359 m_documentElement = 0;
363 deleteAllValues(m_markers);
372 Document::~Document()
375 ASSERT(!m_inPageCache);
376 ASSERT(!m_savedRenderer);
378 removeAllEventListeners();
381 delete m_svgExtensions;
384 XMLHttpRequest::detachRequests(this);
387 KJS::ScriptInterpreter::forgetAllDOMNodesForDocument(this);
390 if (m_docChanged && changedDocuments)
391 changedDocuments->remove(this);
393 m_document.resetSkippingRef(0);
394 delete m_styleSelector;
398 delete m_renderArena;
403 xmlFreeDoc((xmlDocPtr)m_transformSource);
407 delete m_bindingManager;
410 deleteAllValues(m_markers);
412 if (m_axObjectCache) {
413 delete m_axObjectCache;
423 unsigned count = sizeof(m_nameCollectionInfo) / sizeof(m_nameCollectionInfo[0]);
424 for (unsigned i = 0; i < count; i++)
425 deleteAllValues(m_nameCollectionInfo[i]);
428 void Document::resetLinkColor()
430 m_linkColor = Color(0, 0, 238);
433 void Document::resetVisitedLinkColor()
435 m_visitedLinkColor = Color(85, 26, 139);
438 void Document::resetActiveLinkColor()
440 m_activeLinkColor.setNamedColor("red");
443 void Document::setDocType(PassRefPtr<DocumentType> docType)
448 DocumentType *Document::doctype() const
450 return m_docType.get();
453 DOMImplementation* Document::implementation() const
455 return m_implementation.get();
458 void Document::childrenChanged()
460 // invalidate the document element we have cached in case it was replaced
461 m_documentElement = 0;
464 Element* Document::documentElement() const
466 if (!m_documentElement) {
467 Node* n = firstChild();
468 while (n && !n->isElementNode())
469 n = n->nextSibling();
470 m_documentElement = static_cast<Element*>(n);
473 return m_documentElement.get();
476 PassRefPtr<Element> Document::createElement(const String &name, ExceptionCode& ec)
479 if (!isValidName(name)) {
480 ec = INVALID_CHARACTER_ERR;
484 return HTMLElementFactory::createHTMLElement(AtomicString(name), this, 0, false);
486 return createElementNS(nullAtom, name, ec);
489 PassRefPtr<DocumentFragment> Document::createDocumentFragment()
491 return new DocumentFragment(document());
494 PassRefPtr<Text> Document::createTextNode(const String &data)
496 return new Text(this, data);
499 PassRefPtr<Comment> Document::createComment (const String &data)
501 return new Comment(this, data);
504 PassRefPtr<CDATASection> Document::createCDATASection(const String &data, ExceptionCode& ec)
506 if (isHTMLDocument()) {
507 ec = NOT_SUPPORTED_ERR;
510 return new CDATASection(this, data);
513 PassRefPtr<ProcessingInstruction> Document::createProcessingInstruction(const String &target, const String &data, ExceptionCode& ec)
515 if (!isValidName(target)) {
516 ec = INVALID_CHARACTER_ERR;
519 if (isHTMLDocument()) {
520 ec = NOT_SUPPORTED_ERR;
523 return new ProcessingInstruction(this, target, data);
526 PassRefPtr<EntityReference> Document::createEntityReference(const String &name, ExceptionCode& ec)
528 if (!isValidName(name)) {
529 ec = INVALID_CHARACTER_ERR;
532 if (isHTMLDocument()) {
533 ec = NOT_SUPPORTED_ERR;
536 return new EntityReference(this, name);
539 PassRefPtr<EditingText> Document::createEditingTextNode(const String &text)
541 return new EditingText(this, text);
544 PassRefPtr<CSSStyleDeclaration> Document::createCSSStyleDeclaration()
546 return new CSSMutableStyleDeclaration;
549 PassRefPtr<Node> Document::importNode(Node* importedNode, bool deep, ExceptionCode& ec)
555 || (importedNode->isSVGElement() && page() && page()->settings()->usesDashboardBackwardCompatibilityMode())
558 ec = NOT_SUPPORTED_ERR;
562 switch (importedNode->nodeType()) {
564 return createTextNode(importedNode->nodeValue());
565 case CDATA_SECTION_NODE:
566 return createCDATASection(importedNode->nodeValue(), ec);
567 case ENTITY_REFERENCE_NODE:
568 return createEntityReference(importedNode->nodeName(), ec);
569 case PROCESSING_INSTRUCTION_NODE:
570 return createProcessingInstruction(importedNode->nodeName(), importedNode->nodeValue(), ec);
572 return createComment(importedNode->nodeValue());
574 Element *oldElement = static_cast<Element *>(importedNode);
575 RefPtr<Element> newElement = createElementNS(oldElement->namespaceURI(), oldElement->tagQName().toString(), ec);
580 NamedAttrMap* attrs = oldElement->attributes(true);
582 unsigned length = attrs->length();
583 for (unsigned i = 0; i < length; i++) {
584 Attribute* attr = attrs->attributeItem(i);
585 newElement->setAttribute(attr->name(), attr->value().impl(), ec);
591 newElement->copyNonAttributeProperties(oldElement);
594 for (Node* oldChild = oldElement->firstChild(); oldChild; oldChild = oldChild->nextSibling()) {
595 RefPtr<Node> newChild = importNode(oldChild, true, ec);
598 newElement->appendChild(newChild.release(), ec);
604 return newElement.release();
609 case DOCUMENT_TYPE_NODE:
610 case DOCUMENT_FRAGMENT_NODE:
612 case XPATH_NAMESPACE_NODE:
616 ec = NOT_SUPPORTED_ERR;
621 PassRefPtr<Node> Document::adoptNode(PassRefPtr<Node> source, ExceptionCode& ec)
624 ec = NOT_SUPPORTED_ERR;
628 switch (source->nodeType()) {
632 case DOCUMENT_TYPE_NODE:
633 case XPATH_NAMESPACE_NODE:
634 ec = NOT_SUPPORTED_ERR;
636 case ATTRIBUTE_NODE: {
637 Attr* attr = static_cast<Attr*>(source.get());
638 if (attr->ownerElement())
639 attr->ownerElement()->removeAttributeNode(attr, ec);
640 attr->m_attrWasSpecifiedOrElementHasRareData = true;
644 if (source->parentNode())
645 source->parentNode()->removeChild(source.get(), ec);
648 for (Node* node = source.get(); node; node = node->traverseNextNode(source.get()))
649 node->setDocument(this);
654 // FIXME: This should really be in a possible ElementFactory class
655 PassRefPtr<Element> Document::createElement(const QualifiedName& qName, bool createdByParser, ExceptionCode& ec)
659 // FIXME: Use registered namespaces and look up in a hash to find the right factory.
660 if (qName.namespaceURI() == xhtmlNamespaceURI)
661 e = HTMLElementFactory::createHTMLElement(qName.localName(), this, 0, createdByParser);
663 else if (qName.namespaceURI() == SVGNames::svgNamespaceURI)
664 e = SVGElementFactory::createSVGElement(qName, this, createdByParser);
668 e = new Element(qName, document());
670 if (e && !qName.prefix().isNull()) {
671 e->setPrefix(qName.prefix(), ec);
679 PassRefPtr<Element> Document::createElementNS(const String &_namespaceURI, const String &qualifiedName, ExceptionCode& ec)
681 String prefix, localName;
682 if (!parseQualifiedName(qualifiedName, prefix, localName)) {
683 ec = INVALID_CHARACTER_ERR;
688 QualifiedName qName = QualifiedName(AtomicString(prefix), AtomicString(localName), AtomicString(_namespaceURI));
690 return createElement(qName, false, ec);
693 Element *Document::getElementById(const AtomicString& elementId) const
695 if (elementId.length() == 0)
698 Element *element = m_elementsById.get(elementId.impl());
702 if (m_duplicateIds.contains(elementId.impl())) {
703 for (Node *n = traverseNextNode(); n != 0; n = n->traverseNextNode()) {
704 if (n->isElementNode()) {
705 element = static_cast<Element*>(n);
706 if (element->hasID() && element->getAttribute(idAttr) == elementId) {
707 m_duplicateIds.remove(elementId.impl());
708 m_elementsById.set(elementId.impl(), element);
717 String Document::readyState() const
719 if (Frame* f = frame()) {
720 if (f->loader()->isComplete())
725 // FIXME: What does "interactive" mean?
726 // FIXME: Missing support for "uninitialized".
731 String Document::inputEncoding() const
733 if (TextResourceDecoder* d = decoder())
734 return d->encoding().name();
738 String Document::defaultCharset() const
740 if (Settings* settings = this->settings())
741 return settings->defaultTextEncodingName();
745 void Document::setCharset(const String& charset)
749 decoder()->setEncoding(charset, TextResourceDecoder::UserChosenEncoding);
752 void Document::setXMLVersion(const String& version, ExceptionCode& ec)
754 // FIXME: also raise NOT_SUPPORTED_ERR if the version is set to a value that is not supported by this Document.
755 if (!implementation()->hasFeature("XML", String())) {
756 ec = NOT_SUPPORTED_ERR;
760 m_xmlVersion = version;
763 void Document::setXMLStandalone(bool standalone, ExceptionCode& ec)
765 if (!implementation()->hasFeature("XML", String())) {
766 ec = NOT_SUPPORTED_ERR;
770 m_xmlStandalone = standalone;
773 String Document::documentURI() const
778 void Document::setDocumentURI(const String &uri)
780 m_baseURL = uri.deprecatedString();
783 String Document::baseURI() const
785 return documentURI();
788 Element* Document::elementFromPoint(int x, int y) const
793 HitTestRequest request(true, true);
794 HitTestResult result(IntPoint(x, y));
795 renderer()->layer()->hitTest(request, result);
797 Node* n = result.innerNode();
798 while (n && !n->isElementNode())
801 n = n->shadowAncestorNode();
802 return static_cast<Element*>(n);
805 void Document::addElementById(const AtomicString& elementId, Element* element)
807 if (!m_elementsById.contains(elementId.impl()))
808 m_elementsById.set(elementId.impl(), element);
810 m_duplicateIds.add(elementId.impl());
813 void Document::removeElementById(const AtomicString& elementId, Element* element)
815 if (m_elementsById.get(elementId.impl()) == element)
816 m_elementsById.remove(elementId.impl());
818 m_duplicateIds.remove(elementId.impl());
821 Element* Document::getElementByAccessKey(const String& key) const
825 if (!m_accessKeyMapValid) {
826 for (Node* n = firstChild(); n; n = n->traverseNextNode()) {
827 if (!n->isElementNode())
829 Element* element = static_cast<Element*>(n);
830 const AtomicString& accessKey = element->getAttribute(accesskeyAttr);
831 if (!accessKey.isEmpty())
832 m_elementsByAccessKey.set(accessKey.impl(), element);
834 m_accessKeyMapValid = true;
836 return m_elementsByAccessKey.get(key.impl());
839 void Document::updateTitle()
841 if (Frame* f = frame())
842 f->loader()->setTitle(m_title);
845 void Document::setTitle(const String& title, Element* titleElement)
848 // Title set by JavaScript -- overrides any title elements.
849 m_titleSetExplicitly = true;
850 if (!isHTMLDocument())
852 else if (!m_titleElement) {
853 if (HTMLElement* headElement = head()) {
854 ExceptionCode ec = 0;
855 m_titleElement = createElement("title", ec);
857 headElement->appendChild(m_titleElement, ec);
861 } else if (titleElement != m_titleElement) {
862 if (m_titleElement || m_titleSetExplicitly)
863 // Only allow the first title element to change the title -- others have no effect.
865 m_titleElement = titleElement;
868 if (m_title == title)
874 if (m_titleSetExplicitly && m_titleElement && m_titleElement->hasTagName(titleTag))
875 static_cast<HTMLTitleElement*>(m_titleElement.get())->setText(m_title);
878 void Document::removeTitle(Element* titleElement)
880 if (m_titleElement != titleElement)
884 m_titleSetExplicitly = false;
886 // Update title based on first title element in the head, if one exists.
887 if (HTMLElement* headElement = head()) {
888 for (Node* e = headElement->firstChild(); e; e = e->nextSibling())
889 if (e->hasTagName(titleTag)) {
890 HTMLTitleElement* titleElement = static_cast<HTMLTitleElement*>(e);
891 setTitle(titleElement->text(), titleElement);
896 if (!m_titleElement && !m_title.isEmpty()) {
902 String Document::nodeName() const
907 Node::NodeType Document::nodeType() const
909 return DOCUMENT_NODE;
912 FrameView* Document::view() const
914 return m_frame ? m_frame->view() : 0;
917 Page* Document::page() const
919 return m_frame ? m_frame->page() : 0;
922 Settings* Document::settings() const
924 return m_frame ? m_frame->settings() : 0;
927 PassRefPtr<Range> Document::createRange()
929 return new Range(this);
932 PassRefPtr<NodeIterator> Document::createNodeIterator(Node* root, unsigned whatToShow,
933 NodeFilter* filter, bool expandEntityReferences, ExceptionCode& ec)
936 ec = NOT_SUPPORTED_ERR;
939 return new NodeIterator(root, whatToShow, filter, expandEntityReferences);
942 PassRefPtr<TreeWalker> Document::createTreeWalker(Node *root, unsigned whatToShow,
943 NodeFilter* filter, bool expandEntityReferences, ExceptionCode& ec)
946 ec = NOT_SUPPORTED_ERR;
949 return new TreeWalker(root, whatToShow, filter, expandEntityReferences);
952 void Document::setDocumentChanged(bool b)
956 if (!changedDocuments)
957 changedDocuments = new DeprecatedPtrList<Document>;
958 changedDocuments->append(this);
960 if (m_accessKeyMapValid) {
961 m_accessKeyMapValid = false;
962 m_elementsByAccessKey.clear();
965 if (m_docChanged && changedDocuments)
966 changedDocuments->remove(this);
972 void Document::recalcStyle(StyleChange change)
974 // we should not enter style recalc while painting
975 if (frame() && frame()->isPainting()) {
976 ASSERT(!frame()->isPainting());
981 return; // Guard against re-entrancy. -dwh
983 m_inStyleRecalc = true;
985 ASSERT(!renderer() || renderArena());
986 if (!renderer() || !renderArena())
989 if (change == Force) {
990 // style selector may set this again during recalc
991 m_hasNodesWithPlaceholderStyle = false;
993 RenderStyle* oldStyle = renderer()->style();
996 RenderStyle* _style = new (m_renderArena) RenderStyle();
998 _style->setDisplay(BLOCK);
999 _style->setVisuallyOrdered(visuallyOrdered);
1000 // ### make the font stuff _really_ work!!!!
1002 FontDescription fontDescription;
1003 fontDescription.setUsePrinterFont(printing());
1004 if (Settings* settings = this->settings()) {
1005 if (printing() && !settings->shouldPrintBackgrounds())
1006 _style->setForceBackgroundsToWhite(true);
1007 const AtomicString& stdfont = settings->standardFontFamily();
1008 if (!stdfont.isEmpty()) {
1009 fontDescription.firstFamily().setFamily(stdfont);
1010 fontDescription.firstFamily().appendFamily(0);
1012 fontDescription.setKeywordSize(CSS_VAL_MEDIUM - CSS_VAL_XX_SMALL + 1);
1013 m_styleSelector->setFontSize(fontDescription, m_styleSelector->fontSizeForKeyword(CSS_VAL_MEDIUM, inCompatMode(), false));
1016 _style->setFontDescription(fontDescription);
1017 _style->font().update();
1019 _style->setHtmlHacks(true); // enable html specific rendering tricks
1021 StyleChange ch = diff(_style, oldStyle);
1022 if (renderer() && ch != NoChange)
1023 renderer()->setStyle(_style);
1024 if (change != Force)
1027 _style->deref(m_renderArena);
1029 oldStyle->deref(m_renderArena);
1032 for (Node* n = firstChild(); n; n = n->nextSibling())
1033 if (change >= Inherit || n->hasChangedChild() || n->changed())
1034 n->recalcStyle(change);
1036 if (changed() && view())
1040 setChanged(NoStyleChange);
1041 setHasChangedChild(false);
1042 setDocumentChanged(false);
1044 m_inStyleRecalc = false;
1046 // If we wanted to call implicitClose() during recalcStyle, do so now that we're finished.
1047 if (m_closeAfterStyleRecalc) {
1048 m_closeAfterStyleRecalc = false;
1053 void Document::updateRendering()
1055 if (hasChangedChild())
1056 recalcStyle(NoChange);
1059 void Document::updateDocumentsRendering()
1061 if (!changedDocuments)
1064 while (Document* doc = changedDocuments->take()) {
1065 doc->m_docChanged = false;
1066 doc->updateRendering();
1070 void Document::updateLayout()
1072 if (Element* oe = ownerElement())
1073 oe->document()->updateLayout();
1075 // FIXME: Dave Hyatt's pretty sure we can remove this because layout calls recalcStyle as needed.
1078 // Only do a layout if changes have occurred that make it necessary.
1079 FrameView* v = view();
1080 if (v && renderer() && (v->layoutPending() || renderer()->needsLayout()))
1084 // FIXME: This is a bad idea and needs to be removed eventually.
1085 // Other browsers load stylesheets before they continue parsing the web page.
1086 // Since we don't, we can run JavaScript code that needs answers before the
1087 // stylesheets are loaded. Doing a layout ignoring the pending stylesheets
1088 // lets us get reasonable answers. The long term solution to this problem is
1089 // to instead suspend JavaScript execution.
1090 void Document::updateLayoutIgnorePendingStylesheets()
1092 bool oldIgnore = m_ignorePendingStylesheets;
1094 if (!haveStylesheetsLoaded()) {
1095 m_ignorePendingStylesheets = true;
1096 // FIXME: We are willing to attempt to suppress painting with outdated style info only once. Our assumption is that it would be
1097 // dangerous to try to stop it a second time, after page content has already been loaded and displayed
1098 // with accurate style information. (Our suppression involves blanking the whole page at the
1099 // moment. If it were more refined, we might be able to do something better.)
1100 // It's worth noting though that this entire method is a hack, since what we really want to do is
1101 // suspend JS instead of doing a layout with inaccurate information.
1102 if (body() && !body()->renderer() && m_pendingSheetLayout == NoLayoutWithPendingSheets) {
1103 m_pendingSheetLayout = DidLayoutWithPendingSheets;
1104 updateStyleSelector();
1105 } else if (m_hasNodesWithPlaceholderStyle)
1106 // If new nodes have been added or style recalc has been done with style sheets still pending, some nodes
1107 // may not have had their real style calculated yet. Normally this gets cleaned when style sheets arrive
1108 // but here we need up-to-date style immediatly.
1114 m_ignorePendingStylesheets = oldIgnore;
1117 void Document::attach()
1119 ASSERT(!attached());
1120 ASSERT(!m_inPageCache);
1123 m_renderArena = new RenderArena();
1125 // Create the rendering tree
1126 setRenderer(new (m_renderArena) RenderView(this, view()));
1130 RenderObject* render = renderer();
1133 ContainerNode::attach();
1135 setRenderer(render);
1138 void Document::detach()
1141 ASSERT(!m_inPageCache);
1143 RenderObject* render = renderer();
1145 // indicate destruction mode, i.e. attached() but renderer == 0
1148 // Empty out these lists as a performance optimization, since detaching
1149 // all the individual render objects will cause all the RenderImage
1150 // objects to remove themselves from the lists.
1151 m_imageLoadEventDispatchSoonList.clear();
1152 m_imageLoadEventDispatchingList.clear();
1158 ContainerNode::detach();
1163 // FIXME: is this needed or desirable?
1166 if (m_renderArena) {
1167 delete m_renderArena;
1172 void Document::removeAllEventListenersFromAllNodes()
1174 m_windowEventListeners.clear();
1175 removeAllDisconnectedNodeEventListeners();
1176 for (Node *n = this; n; n = n->traverseNextNode()) {
1177 if (!n->isEventTargetNode())
1179 EventTargetNodeCast(n)->removeAllEventListeners();
1183 void Document::registerDisconnectedNodeWithEventListeners(Node* node)
1185 m_disconnectedNodesWithEventListeners.add(node);
1188 void Document::unregisterDisconnectedNodeWithEventListeners(Node* node)
1190 m_disconnectedNodesWithEventListeners.remove(node);
1193 void Document::removeAllDisconnectedNodeEventListeners()
1195 HashSet<Node*>::iterator end = m_disconnectedNodesWithEventListeners.end();
1196 for (HashSet<Node*>::iterator i = m_disconnectedNodesWithEventListeners.begin(); i != end; ++i)
1197 EventTargetNodeCast(*i)->removeAllEventListeners();
1198 m_disconnectedNodesWithEventListeners.clear();
1201 AXObjectCache* Document::axObjectCache() const
1203 // The only document that actually has a AXObjectCache is the top-level
1204 // document. This is because we need to be able to get from any WebCoreAXObject
1205 // to any other WebCoreAXObject on the same page. Using a single cache allows
1206 // lookups across nested webareas (i.e. multiple documents).
1208 if (m_axObjectCache) {
1209 // return already known top-level cache
1210 if (!ownerElement())
1211 return m_axObjectCache;
1213 // In some pages with frames, the cache is created before the sub-webarea is
1214 // inserted into the tree. Here, we catch that case and just toss the old
1215 // cache and start over.
1216 delete m_axObjectCache;
1217 m_axObjectCache = 0;
1220 // ask the top-level document for its cache
1221 Document* doc = topDocument();
1223 return doc->axObjectCache();
1225 // this is the top-level document, so install a new cache
1226 m_axObjectCache = new AXObjectCache;
1227 return m_axObjectCache;
1230 void Document::setVisuallyOrdered()
1232 visuallyOrdered = true;
1234 renderer()->style()->setVisuallyOrdered(true);
1237 void Document::updateSelection()
1242 RenderView *canvas = static_cast<RenderView*>(renderer());
1243 Selection selection = frame()->selectionController()->selection();
1245 if (!selection.isRange())
1246 canvas->clearSelection();
1248 // Use the rightmost candidate for the start of the selection, and the leftmost candidate for the end of the selection.
1249 // Example: foo <a>bar</a>. Imagine that a line wrap occurs after 'foo', and that 'bar' is selected. If we pass [foo, 3]
1250 // as the start of the selection, the selection painting code will think that content on the line containing 'foo' is selected
1251 // and will fill the gap before 'bar'.
1252 Position startPos = selection.visibleStart().deepEquivalent();
1253 if (startPos.downstream().isCandidate())
1254 startPos = startPos.downstream();
1255 Position endPos = selection.visibleEnd().deepEquivalent();
1256 if (endPos.upstream().isCandidate())
1257 endPos = endPos.upstream();
1259 // We can get into a state where the selection endpoints map to the same VisiblePosition when a selection is deleted
1260 // because we don't yet notify the SelectionController of text removal.
1261 if (startPos.isNotNull() && endPos.isNotNull() && selection.visibleStart() != selection.visibleEnd()) {
1262 RenderObject *startRenderer = startPos.node()->renderer();
1263 RenderObject *endRenderer = endPos.node()->renderer();
1264 static_cast<RenderView*>(renderer())->setSelection(startRenderer, startPos.offset(), endRenderer, endPos.offset());
1269 Tokenizer* Document::createTokenizer()
1271 // FIXME: this should probably pass the frame instead
1272 return new XMLTokenizer(this, view());
1275 void Document::open()
1277 // This is work that we should probably do in clear(), but we can't have it
1278 // happen when implicitOpen() is called unless we reorganize Frame code.
1279 if (Document *parent = parentDocument()) {
1280 if (m_url.isEmpty() || m_url == "about:blank")
1281 setURL(parent->baseURL());
1282 if (m_baseURL.isEmpty() || m_baseURL == "about:blank")
1283 setBaseURL(parent->baseURL());
1287 if (m_frame->loader()->isLoadingMainResource() || (tokenizer() && tokenizer()->executingScript()))
1290 if (m_frame->loader()->state() == FrameStateProvisional)
1291 m_frame->loader()->stopAllLoaders();
1297 m_frame->loader()->didExplicitOpen();
1300 void Document::cancelParsing()
1303 // We have to clear the tokenizer to avoid possibly triggering
1304 // the onload handler when closing as a side effect of a cancel-style
1305 // change, such as opening a new document or closing the window while
1313 void Document::implicitOpen()
1318 m_tokenizer = createTokenizer();
1322 HTMLElement* Document::body()
1324 Node* de = documentElement();
1328 // try to prefer a FRAMESET element over BODY
1330 for (Node* i = de->firstChild(); i; i = i->nextSibling()) {
1331 if (i->hasTagName(framesetTag))
1332 return static_cast<HTMLElement*>(i);
1334 if (i->hasTagName(bodyTag))
1337 return static_cast<HTMLElement*>(body);
1340 HTMLHeadElement* Document::head()
1342 Node* de = documentElement();
1346 for (Node* e = de->firstChild(); e; e = e->nextSibling())
1347 if (e->hasTagName(headTag))
1348 return static_cast<HTMLHeadElement*>(e);
1353 void Document::close()
1355 Frame* frame = this->frame();
1357 // This code calls implicitClose() if all loading has completed.
1358 FrameLoader* frameLoader = frame->loader();
1359 frameLoader->endIfNotLoadingMainResource();
1360 frameLoader->checkCompleted();
1362 // Because we have no frame, we don't know if all loading has completed,
1363 // so we just call implicitClose() immediately. FIXME: This might fire
1364 // the load event prematurely <http://bugs.webkit.org/show_bug.cgi?id=14568>.
1369 void Document::implicitClose()
1371 // 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.
1372 if (m_inStyleRecalc) {
1373 m_closeAfterStyleRecalc = true;
1377 bool wasLocationChangePending = frame() && frame()->loader()->isScheduledLocationChangePending();
1378 bool doload = !parsing() && m_tokenizer && !m_processingLoadEvent && !wasLocationChangePending;
1383 m_processingLoadEvent = true;
1385 m_wellFormed = m_tokenizer && m_tokenizer->wellFormed();
1387 // We have to clear the tokenizer, in case someone document.write()s from the
1388 // onLoad event handler, as in Radar 3206524.
1392 // Create a body element if we don't already have one. See Radar 3758785.
1393 if (!this->body() && isHTMLDocument()) {
1394 if (Node* documentElement = this->documentElement()) {
1395 ExceptionCode ec = 0;
1396 documentElement->appendChild(new HTMLBodyElement(this), ec);
1401 dispatchImageLoadEventsNow();
1402 this->dispatchWindowEvent(loadEvent, false, false);
1403 if (Frame* f = frame())
1404 f->loader()->handledOnloadEvents();
1405 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1406 if (!ownerElement())
1407 printf("onload fired at %d\n", elapsedTime());
1410 m_processingLoadEvent = false;
1412 // An event handler may have removed the frame
1416 // Make sure both the initial layout and reflow happen after the onload
1417 // fires. This will improve onload scores, and other browsers do it.
1418 // If they wanna cheat, we can too. -dwh
1420 if (frame()->loader()->isScheduledLocationChangePending() && elapsedTime() < cLayoutScheduleThreshold) {
1421 // Just bail out. Before or during the onload we were shifted to another page.
1422 // The old i-Bench suite does this. When this happens don't bother painting or laying out.
1423 view()->unscheduleRelayout();
1427 frame()->loader()->checkCallImplicitClose();
1429 // Now do our painting/layout, but only if we aren't in a subframe or if we're in a subframe
1430 // that has been sized already. Otherwise, our view size would be incorrect, so doing any
1431 // layout/painting now would be pointless.
1432 if (!ownerElement() || (ownerElement()->renderer() && !ownerElement()->renderer()->needsLayout())) {
1435 // Always do a layout after loading if needed.
1436 if (view() && renderer() && (!renderer()->firstChild() || renderer()->needsLayout()))
1439 // Paint immediately after the document is ready. We do this to ensure that any timers set by the
1440 // onload don't have a chance to fire before we would have painted. To avoid over-flushing we only
1441 // worry about this for the top-level document.
1443 // FIXME: This causes a timing issue with the dispatchDidFinishLoad delegate callback.
1444 // See <rdar://problem/5092361>
1445 if (view() && !ownerElement())
1451 if (renderer() && AXObjectCache::accessibilityEnabled())
1452 axObjectCache()->postNotificationToElement(renderer(), "AXLoadComplete");
1456 // FIXME: Officially, time 0 is when the outermost <svg> receives its
1457 // SVGLoad event, but we don't implement those yet. This is close enough
1458 // for now. In some cases we should have fired earlier.
1459 if (svgExtensions())
1460 accessSVGExtensions()->startAnimations();
1464 void Document::setParsing(bool b)
1467 if (!m_bParsing && view())
1468 view()->scheduleRelayout();
1470 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1471 if (!ownerElement() && !m_bParsing)
1472 printf("Parsing finished at %d\n", elapsedTime());
1476 bool Document::shouldScheduleLayout()
1478 // We can update layout if:
1479 // (a) we actually need a layout
1480 // (b) our stylesheets are all loaded
1481 // (c) we have a <body>
1482 return (renderer() && renderer()->needsLayout() && haveStylesheetsLoaded() &&
1483 documentElement() && documentElement()->renderer() &&
1484 (!documentElement()->hasTagName(htmlTag) || body()));
1487 int Document::minimumLayoutDelay()
1489 if (m_overMinimumLayoutThreshold)
1492 int elapsed = elapsedTime();
1493 m_overMinimumLayoutThreshold = elapsed > cLayoutScheduleThreshold;
1495 // We'll want to schedule the timer to fire at the minimum layout threshold.
1496 return max(0, cLayoutScheduleThreshold - elapsed);
1499 int Document::elapsedTime() const
1501 return static_cast<int>((currentTime() - m_startTime) * 1000);
1504 void Document::write(const DeprecatedString& text)
1506 write(String(text));
1509 void Document::write(const String& text)
1511 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1512 if (!ownerElement())
1513 printf("Beginning a document.write at %d\n", elapsedTime());
1518 ASSERT(m_tokenizer);
1521 write(DeprecatedString("<html>"));
1523 m_tokenizer->write(text, false);
1525 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1526 if (!ownerElement())
1527 printf("Ending a document.write at %d\n", elapsedTime());
1531 void Document::writeln(const String &text)
1534 write(String("\n"));
1537 void Document::finishParsing()
1539 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1540 if (!ownerElement())
1541 printf("Received all data at %d\n", elapsedTime());
1544 // Let the tokenizer go through as much data as it can. There will be three possible outcomes after
1545 // finish() is called:
1546 // (1) All remaining data is parsed, document isn't loaded yet
1547 // (2) All remaining data is parsed, document is loaded, tokenizer gets deleted
1548 // (3) Data is still remaining to be parsed.
1550 m_tokenizer->finish();
1553 void Document::clear()
1560 m_windowEventListeners.clear();
1563 void Document::setURL(const DeprecatedString& url)
1569 if (m_styleSelector)
1570 m_styleSelector->setEncodedURL(m_url);
1572 m_isAllowedToLoadLocalResources = shouldBeAllowedToLoadLocalResources();
1575 bool Document::shouldBeAllowedToLoadLocalResources() const
1577 if (FrameLoader::shouldTreatURLAsLocal(m_url))
1580 Frame* frame = this->frame();
1584 DocumentLoader* documentLoader = frame->loader()->documentLoader();
1585 if (!documentLoader)
1588 if (m_url == "about:blank" && frame->loader()->opener() && frame->loader()->opener()->document()->isAllowedToLoadLocalResources())
1591 return documentLoader->substituteData().isValid();
1594 void Document::setBaseURL(const DeprecatedString& baseURL)
1596 m_baseURL = baseURL;
1598 m_elemSheet->setHref(m_baseURL);
1601 void Document::setCSSStyleSheet(const String &url, const String& charset, const String &sheet)
1603 m_sheet = new CSSStyleSheet(this, url, charset);
1604 m_sheet->parseString(sheet);
1606 updateStyleSelector();
1609 void Document::setUserStyleSheet(const String& sheet)
1611 if (m_usersheet != sheet) {
1612 m_usersheet = sheet;
1613 updateStyleSelector();
1617 CSSStyleSheet* Document::elementSheet()
1620 m_elemSheet = new CSSStyleSheet(this, baseURL());
1621 return m_elemSheet.get();
1624 void Document::determineParseMode(const String&)
1626 // For XML documents use strict parse mode.
1627 // HTML overrides this method to determine the parse mode.
1632 static Node* nextNodeWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent* event)
1634 // Search is inclusive of start
1635 for (Node* n = start; n; n = n->traverseNextNode())
1636 if (n->isKeyboardFocusable(event) && n->tabIndex() == tabIndex)
1642 static Node* previousNodeWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent* event)
1644 // Search is inclusive of start
1645 for (Node* n = start; n; n = n->traversePreviousNode())
1646 if (n->isKeyboardFocusable(event) && n->tabIndex() == tabIndex)
1652 static Node* nextNodeWithGreaterTabIndex(Node* start, int tabIndex, KeyboardEvent* event)
1654 // Search is inclusive of start
1655 int winningTabIndex = SHRT_MAX + 1;
1657 for (Node* n = start; n; n = n->traverseNextNode())
1658 if (n->isKeyboardFocusable(event) && n->tabIndex() > tabIndex && n->tabIndex() < winningTabIndex) {
1660 winningTabIndex = n->tabIndex();
1666 static Node* previousNodeWithLowerTabIndex(Node* start, int tabIndex, KeyboardEvent* event)
1668 // Search is inclusive of start
1669 int winningTabIndex = 0;
1671 for (Node* n = start; n; n = n->traversePreviousNode())
1672 if (n->isKeyboardFocusable(event) && n->tabIndex() < tabIndex && n->tabIndex() > winningTabIndex) {
1674 winningTabIndex = n->tabIndex();
1680 Node* Document::nextFocusableNode(Node* start, KeyboardEvent* event)
1683 // First try to find a node with the same tabindex as start that comes after start in the document.
1684 if (Node* winner = nextNodeWithExactTabIndex(start->traverseNextNode(), start->tabIndex(), event))
1687 if (start->tabIndex() == 0)
1688 // We've reached the last node in the document with a tabindex of 0. This is the end of the tabbing order.
1692 // Look for the first node in the document that:
1693 // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if start is null), and
1694 // 2) comes first in the document, if there's a tie.
1695 if (Node* winner = nextNodeWithGreaterTabIndex(this, start ? start->tabIndex() : 0, event))
1698 // There are no nodes with a tabindex greater than start's tabindex,
1699 // so find the first node with a tabindex of 0.
1700 return nextNodeWithExactTabIndex(this, 0, event);
1703 Node* Document::previousFocusableNode(Node* start, KeyboardEvent* event)
1706 for (last = this; last->lastChild(); last = last->lastChild())
1709 // First try to find the last node in the document that comes before start and has the same tabindex as start.
1710 // If start is null, find the last node in the document with a tabindex of 0.
1712 int startingTabIndex;
1714 startingNode = start->traversePreviousNode();
1715 startingTabIndex = start->tabIndex();
1717 startingNode = last;
1718 startingTabIndex = 0;
1721 if (Node* winner = previousNodeWithExactTabIndex(startingNode, startingTabIndex, event))
1724 // There are no nodes before start with the same tabindex as start, so look for a node that:
1725 // 1) has the highest non-zero tabindex (that is less than start's tabindex), and
1726 // 2) comes last in the document, if there's a tie.
1727 startingTabIndex = (start && start->tabIndex()) ? start->tabIndex() : SHRT_MAX;
1728 return previousNodeWithLowerTabIndex(last, startingTabIndex, event);
1731 int Document::nodeAbsIndex(Node *node)
1733 ASSERT(node->document() == this);
1736 for (Node *n = node; n && n != this; n = n->traversePreviousNode())
1741 Node *Document::nodeWithAbsIndex(int absIndex)
1744 for (int i = 0; n && (i < absIndex); i++) {
1745 n = n->traverseNextNode();
1750 void Document::processHttpEquiv(const String &equiv, const String &content)
1752 ASSERT(!equiv.isNull() && !content.isNull());
1754 Frame *frame = this->frame();
1756 if (equalIgnoringCase(equiv, "default-style")) {
1757 // The preferred style set has been overridden as per section
1758 // 14.3.2 of the HTML4.0 specification. We need to update the
1759 // sheet used variable and then update our style selector.
1760 // For more info, see the test at:
1761 // http://www.hixie.ch/tests/evil/css/import/main/preferred.html
1763 m_selectedStylesheetSet = content;
1764 m_preferredStylesheetSet = content;
1765 updateStyleSelector();
1766 } else if (equalIgnoringCase(equiv, "refresh")) {
1769 if (frame && parseHTTPRefresh(content, true, delay, url)) {
1771 url = frame->loader()->url().url();
1773 url = completeURL(url);
1774 frame->loader()->scheduleHTTPRedirection(delay, url);
1776 } else if (equalIgnoringCase(equiv, "set-cookie")) {
1777 // FIXME: make setCookie work on XML documents too; e.g. in case of <html:meta .....>
1778 if (isHTMLDocument())
1779 static_cast<HTMLDocument*>(this)->setCookie(content);
1783 MouseEventWithHitTestResults Document::prepareMouseEvent(const HitTestRequest& request, const IntPoint& documentPoint, const PlatformMouseEvent& event)
1785 ASSERT(!renderer() || renderer()->isRenderView());
1788 return MouseEventWithHitTestResults(event, HitTestResult(IntPoint()));
1790 HitTestResult result(documentPoint);
1791 renderer()->layer()->hitTest(request, result);
1793 if (!request.readonly)
1796 return MouseEventWithHitTestResults(event, result);
1799 // DOM Section 1.1.1
1800 bool Document::childTypeAllowed(NodeType type)
1803 case ATTRIBUTE_NODE:
1804 case CDATA_SECTION_NODE:
1805 case DOCUMENT_FRAGMENT_NODE:
1808 case ENTITY_REFERENCE_NODE:
1811 case XPATH_NAMESPACE_NODE:
1814 case PROCESSING_INSTRUCTION_NODE:
1816 case DOCUMENT_TYPE_NODE:
1818 // Documents may contain no more than one of each of these.
1819 // (One Element and one DocumentType.)
1820 for (Node* c = firstChild(); c; c = c->nextSibling())
1821 if (c->nodeType() == type)
1828 bool Document::canReplaceChild(Node* newChild, Node* oldChild)
1830 if (oldChild->nodeType() == newChild->nodeType())
1833 int numDoctypes = 0;
1834 int numElements = 0;
1836 // First, check how many doctypes and elements we have, not counting
1837 // the child we're about to remove.
1838 for (Node* c = firstChild(); c; c = c->nextSibling()) {
1842 switch (c->nodeType()) {
1843 case DOCUMENT_TYPE_NODE:
1854 // Then, see how many doctypes and elements might be added by the new child.
1855 if (newChild->nodeType() == DOCUMENT_FRAGMENT_NODE) {
1856 for (Node* c = firstChild(); c; c = c->nextSibling()) {
1857 switch (c->nodeType()) {
1858 case ATTRIBUTE_NODE:
1859 case CDATA_SECTION_NODE:
1860 case DOCUMENT_FRAGMENT_NODE:
1863 case ENTITY_REFERENCE_NODE:
1866 case XPATH_NAMESPACE_NODE:
1869 case PROCESSING_INSTRUCTION_NODE:
1871 case DOCUMENT_TYPE_NODE:
1880 switch (newChild->nodeType()) {
1881 case ATTRIBUTE_NODE:
1882 case CDATA_SECTION_NODE:
1883 case DOCUMENT_FRAGMENT_NODE:
1886 case ENTITY_REFERENCE_NODE:
1889 case XPATH_NAMESPACE_NODE:
1892 case PROCESSING_INSTRUCTION_NODE:
1894 case DOCUMENT_TYPE_NODE:
1903 if (numElements > 1 || numDoctypes > 1)
1909 PassRefPtr<Node> Document::cloneNode(bool /*deep*/)
1911 // Spec says cloning Document nodes is "implementation dependent"
1912 // so we do not support it...
1916 StyleSheetList* Document::styleSheets()
1918 return m_styleSheets.get();
1921 String Document::preferredStylesheetSet() const
1923 return m_preferredStylesheetSet;
1926 String Document::selectedStylesheetSet() const
1928 return m_selectedStylesheetSet;
1931 void Document::setSelectedStylesheetSet(const String& aString)
1933 m_selectedStylesheetSet = aString;
1934 updateStyleSelector();
1936 renderer()->repaint();
1939 // This method is called whenever a top-level stylesheet has finished loading.
1940 void Document::removePendingSheet()
1942 // Make sure we knew this sheet was pending, and that our count isn't out of sync.
1943 ASSERT(m_pendingStylesheets > 0);
1945 m_pendingStylesheets--;
1947 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1948 if (!ownerElement())
1949 printf("Stylesheet loaded at time %d. %d stylesheets still remain.\n", elapsedTime(), m_pendingStylesheets);
1952 updateStyleSelector();
1954 if (!m_pendingStylesheets && m_gotoAnchorNeededAfterStylesheetsLoad && m_frame)
1955 m_frame->loader()->gotoAnchor();
1958 void Document::updateStyleSelector()
1960 // Don't bother updating, since we haven't loaded all our style info yet
1961 // and haven't calculated the style selector for the first time.
1962 if (!m_didCalculateStyleSelector && !haveStylesheetsLoaded())
1965 if (didLayoutWithPendingStylesheets() && m_pendingStylesheets <= 0) {
1966 m_pendingSheetLayout = IgnoreLayoutWithPendingSheets;
1968 renderer()->repaint();
1971 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1972 if (!ownerElement())
1973 printf("Beginning update of style selector at time %d.\n", elapsedTime());
1976 recalcStyleSelector();
1979 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1980 if (!ownerElement())
1981 printf("Finished update of style selector at time %d\n", elapsedTime());
1985 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
1987 view()->scheduleRelayout();
1991 void Document::recalcStyleSelector()
1993 if (!renderer() || !attached())
1996 DeprecatedPtrList<StyleSheet> oldStyleSheets = m_styleSheets->styleSheets;
1997 m_styleSheets->styleSheets.clear();
1999 for (n = this; n; n = n->traverseNextNode()) {
2000 StyleSheet *sheet = 0;
2002 if (n->nodeType() == PROCESSING_INSTRUCTION_NODE)
2004 // Processing instruction (XML documents only)
2005 ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(n);
2006 sheet = pi->sheet();
2008 // Don't apply XSL transforms to already transformed documents -- <rdar://problem/4132806>
2009 if (pi->isXSL() && !transformSourceDocument()) {
2010 // Don't apply XSL transforms until loading is finished.
2012 applyXSLTransform(pi);
2016 if (!sheet && !pi->localHref().isEmpty())
2018 // Processing instruction with reference to an element in this document - e.g.
2019 // <?xml-stylesheet href="#mystyle">, with the element
2020 // <foo id="mystyle">heading { color: red; }</foo> at some location in
2022 Element* elem = getElementById(pi->localHref().impl());
2024 String sheetText("");
2026 for (c = elem->firstChild(); c; c = c->nextSibling()) {
2027 if (c->nodeType() == TEXT_NODE || c->nodeType() == CDATA_SECTION_NODE)
2028 sheetText += c->nodeValue();
2031 CSSStyleSheet *cssSheet = new CSSStyleSheet(this);
2032 cssSheet->parseString(sheetText);
2033 pi->setCSSStyleSheet(cssSheet);
2038 } else if (n->isHTMLElement() && (n->hasTagName(linkTag) || n->hasTagName(styleTag))
2040 || (n->isSVGElement() && n->hasTagName(SVGNames::styleTag))
2043 Element* e = static_cast<Element*>(n);
2044 DeprecatedString title = e->getAttribute(titleAttr).deprecatedString();
2045 bool enabledViaScript = false;
2046 if (e->hasLocalName(linkTag)) {
2048 HTMLLinkElement* l = static_cast<HTMLLinkElement*>(n);
2049 if (l->isDisabled())
2051 enabledViaScript = l->isEnabledViaScript();
2052 if (l->isLoading()) {
2053 // it is loading but we should still decide which style sheet set to use
2054 if (!enabledViaScript && !title.isEmpty() && m_preferredStylesheetSet.isEmpty()) {
2055 const AtomicString& rel = e->getAttribute(relAttr);
2056 if (!rel.domString().contains("alternate")) {
2057 m_preferredStylesheetSet = title;
2058 m_selectedStylesheetSet = title;
2064 title = DeprecatedString::null;
2067 // Get the current preferred styleset. This is the
2068 // set of sheets that will be enabled.
2070 if (n->isSVGElement() && n->hasTagName(SVGNames::styleTag))
2071 sheet = static_cast<SVGStyleElement*>(n)->sheet();
2074 if (e->hasLocalName(linkTag))
2075 sheet = static_cast<HTMLLinkElement*>(n)->sheet();
2078 sheet = static_cast<HTMLStyleElement*>(n)->sheet();
2080 // Check to see if this sheet belongs to a styleset
2081 // (thus making it PREFERRED or ALTERNATE rather than
2083 if (!enabledViaScript && !title.isEmpty()) {
2084 // Yes, we have a title.
2085 if (m_preferredStylesheetSet.isEmpty()) {
2086 // No preferred set has been established. If
2087 // we are NOT an alternate sheet, then establish
2088 // us as the preferred set. Otherwise, just ignore
2090 DeprecatedString rel = e->getAttribute(relAttr).deprecatedString();
2091 if (e->hasLocalName(styleTag) || !rel.contains("alternate"))
2092 m_preferredStylesheetSet = m_selectedStylesheetSet = title;
2095 if (title != m_preferredStylesheetSet)
2099 if (!n->isHTMLElement())
2100 title = title.replace('&', "&&");
2107 m_styleSheets->styleSheets.append(sheet);
2110 // For HTML documents, stylesheets are not allowed within/after the <BODY> tag. So we
2111 // can stop searching here.
2112 if (isHTMLDocument() && n->hasTagName(bodyTag))
2116 // De-reference all the stylesheets in the old list
2117 DeprecatedPtrListIterator<StyleSheet> it(oldStyleSheets);
2118 for (; it.current(); ++it)
2119 it.current()->deref();
2121 // Create a new style selector
2122 delete m_styleSelector;
2123 String usersheet = m_usersheet;
2124 if (view() && view()->mediaType() == "print")
2125 usersheet += m_printSheet;
2126 m_styleSelector = new CSSStyleSelector(this, usersheet, m_styleSheets.get(), !inCompatMode());
2127 m_styleSelector->setEncodedURL(m_url);
2128 m_didCalculateStyleSelector = true;
2131 void Document::setHoverNode(PassRefPtr<Node> newHoverNode)
2133 m_hoverNode = newHoverNode;
2136 void Document::setActiveNode(PassRefPtr<Node> newActiveNode)
2138 m_activeNode = newActiveNode;
2141 void Document::focusedNodeRemoved(Node* node)
2146 void Document::hoveredNodeDetached(Node* node)
2148 if (!m_hoverNode || (node != m_hoverNode && (!m_hoverNode->isTextNode() || node != m_hoverNode->parent())))
2151 m_hoverNode = node->parent();
2152 while (m_hoverNode && !m_hoverNode->renderer())
2153 m_hoverNode = m_hoverNode->parent();
2155 frame()->eventHandler()->scheduleHoverStateUpdate();
2158 void Document::activeChainNodeDetached(Node* node)
2160 if (!m_activeNode || (node != m_activeNode && (!m_activeNode->isTextNode() || node != m_activeNode->parent())))
2163 m_activeNode = node->parent();
2164 while (m_activeNode && !m_activeNode->renderer())
2165 m_activeNode = m_activeNode->parent();
2168 const Vector<DashboardRegionValue>& Document::dashboardRegions() const
2170 return m_dashboardRegions;
2173 void Document::setDashboardRegions(const Vector<DashboardRegionValue>& regions)
2175 m_dashboardRegions = regions;
2176 setDashboardRegionsDirty(false);
2179 bool Document::setFocusedNode(PassRefPtr<Node> newFocusedNode)
2181 // Make sure newFocusedNode is actually in this document
2182 if (newFocusedNode && (newFocusedNode->document() != this))
2185 if (m_focusedNode == newFocusedNode)
2188 bool focusChangeBlocked = false;
2189 RefPtr<Node> oldFocusedNode = m_focusedNode;
2192 // Remove focus from the existing focus node (if any)
2193 if (oldFocusedNode && !oldFocusedNode->m_inDetach) {
2194 if (oldFocusedNode->active())
2195 oldFocusedNode->setActive(false);
2197 oldFocusedNode->setFocus(false);
2199 // Dispatch a change event for text fields or textareas that have been edited
2200 RenderObject *r = static_cast<RenderObject*>(oldFocusedNode.get()->renderer());
2201 if (r && (r->isTextArea() || r->isTextField()) && r->isEdited()) {
2202 EventTargetNodeCast(oldFocusedNode.get())->dispatchHTMLEvent(changeEvent, true, false);
2203 if ((r = static_cast<RenderObject*>(oldFocusedNode.get()->renderer())))
2204 r->setEdited(false);
2207 // Dispatch the blur event and let the node do any other blur related activities (important for text fields)
2208 EventTargetNodeCast(oldFocusedNode.get())->dispatchBlurEvent();
2210 if (m_focusedNode) {
2211 // handler shifted focus
2212 focusChangeBlocked = true;
2215 EventTargetNodeCast(oldFocusedNode.get())->dispatchUIEvent(DOMFocusOutEvent);
2216 if (m_focusedNode) {
2217 // handler shifted focus
2218 focusChangeBlocked = true;
2221 if ((oldFocusedNode.get() == this) && oldFocusedNode->hasOneRef())
2224 if (oldFocusedNode.get() == oldFocusedNode->rootEditableElement())
2225 frame()->editor()->didEndEditing();
2228 if (newFocusedNode) {
2229 if (newFocusedNode == newFocusedNode->rootEditableElement() && !acceptsEditingFocus(newFocusedNode.get())) {
2230 // delegate blocks focus change
2231 focusChangeBlocked = true;
2232 goto SetFocusedNodeDone;
2234 // Set focus on the new node
2235 m_focusedNode = newFocusedNode.get();
2237 // Dispatch the focus event and let the node do any other focus related activities (important for text fields)
2238 EventTargetNodeCast(m_focusedNode.get())->dispatchFocusEvent();
2240 if (m_focusedNode != newFocusedNode) {
2241 // handler shifted focus
2242 focusChangeBlocked = true;
2243 goto SetFocusedNodeDone;
2245 EventTargetNodeCast(m_focusedNode.get())->dispatchUIEvent(DOMFocusInEvent);
2246 if (m_focusedNode != newFocusedNode) {
2247 // handler shifted focus
2248 focusChangeBlocked = true;
2249 goto SetFocusedNodeDone;
2251 m_focusedNode->setFocus();
2253 if (m_focusedNode.get() == m_focusedNode->rootEditableElement())
2254 frame()->editor()->didBeginEditing();
2256 // eww, I suck. set the qt focus correctly
2257 // ### find a better place in the code for this
2259 Widget *focusWidget = widgetForNode(m_focusedNode.get());
2261 // Make sure a widget has the right size before giving it focus.
2262 // Otherwise, we are testing edge cases of the Widget code.
2263 // Specifically, in WebCore this does not work well for text fields.
2265 // Re-get the widget in case updating the layout changed things.
2266 focusWidget = widgetForNode(m_focusedNode.get());
2269 focusWidget->setFocus();
2276 if (!focusChangeBlocked && m_focusedNode && AXObjectCache::accessibilityEnabled())
2277 axObjectCache()->handleFocusedUIElementChanged();
2282 return !focusChangeBlocked;
2285 void Document::setCSSTarget(Node* n)
2288 m_cssTarget->setChanged();
2294 Node* Document::getCSSTarget() const
2299 void Document::attachNodeIterator(NodeIterator *ni)
2301 m_nodeIterators.add(ni);
2304 void Document::detachNodeIterator(NodeIterator *ni)
2306 m_nodeIterators.remove(ni);
2309 void Document::notifyBeforeNodeRemoval(Node *n)
2311 if (Frame* f = frame()) {
2312 f->selectionController()->nodeWillBeRemoved(n);
2313 f->dragCaretController()->nodeWillBeRemoved(n);
2316 HashSet<NodeIterator*>::const_iterator end = m_nodeIterators.end();
2317 for (HashSet<NodeIterator*>::const_iterator it = m_nodeIterators.begin(); it != end; ++it)
2318 (*it)->notifyBeforeNodeRemoval(n);
2321 DOMWindow* Document::defaultView() const
2326 return frame()->domWindow();
2329 PassRefPtr<Event> Document::createEvent(const String &eventType, ExceptionCode& ec)
2331 if (eventType == "UIEvents" || eventType == "UIEvent")
2333 if (eventType == "MouseEvents" || eventType == "MouseEvent")
2334 return new MouseEvent;
2335 if (eventType == "MutationEvents" || eventType == "MutationEvent")
2336 return new MutationEvent;
2337 if (eventType == "KeyboardEvents" || eventType == "KeyboardEvent")
2338 return new KeyboardEvent;
2339 if (eventType == "HTMLEvents" || eventType == "Event" || eventType == "Events")
2341 if (eventType == "TextEvent")
2342 return new TextEvent;
2343 if (eventType == "OverflowEvent")
2344 return new OverflowEvent;
2345 if (eventType == "WheelEvent")
2346 return new WheelEvent;
2348 if (eventType == "SVGEvents")
2350 if (eventType == "SVGZoomEvents")
2351 return new SVGZoomEvent;
2353 ec = NOT_SUPPORTED_ERR;
2357 CSSStyleDeclaration *Document::getOverrideStyle(Element */*elt*/, const String &/*pseudoElt*/)
2362 void Document::handleWindowEvent(Event *evt, bool useCapture)
2364 if (m_windowEventListeners.isEmpty())
2367 // if any html event listeners are registered on the window, then dispatch them here
2368 RegisteredEventListenerList listenersCopy = m_windowEventListeners;
2369 RegisteredEventListenerList::iterator it = listenersCopy.begin();
2371 for (; it != listenersCopy.end(); ++it)
2372 if ((*it)->eventType() == evt->type() && (*it)->useCapture() == useCapture && !(*it)->removed())
2373 (*it)->listener()->handleEvent(evt, true);
2377 void Document::defaultEventHandler(Event *evt)
2380 if (evt->type() == keydownEvent) {
2381 KeyboardEvent* kevt = static_cast<KeyboardEvent *>(evt);
2382 if (kevt->ctrlKey()) {
2383 const PlatformKeyboardEvent* ev = kevt->keyEvent();
2384 String key = (ev ? ev->unmodifiedText() : kevt->keyIdentifier()).lower();
2385 Element* elem = getElementByAccessKey(key);
2387 elem->accessKeyAction(false);
2388 evt->setDefaultHandled();
2394 ContainerNode::defaultEventHandler(evt);
2397 void Document::setHTMLWindowEventListener(const AtomicString &eventType, PassRefPtr<EventListener> listener)
2399 // If we already have it we don't want removeWindowEventListener to delete it
2400 removeHTMLWindowEventListener(eventType);
2402 addWindowEventListener(eventType, listener, false);
2405 EventListener *Document::getHTMLWindowEventListener(const AtomicString &eventType)
2407 RegisteredEventListenerList::iterator it = m_windowEventListeners.begin();
2408 for (; it != m_windowEventListeners.end(); ++it)
2409 if ( (*it)->eventType() == eventType && (*it)->listener()->isHTMLEventListener())
2410 return (*it)->listener();
2414 void Document::removeHTMLWindowEventListener(const AtomicString &eventType)
2416 RegisteredEventListenerList::iterator it = m_windowEventListeners.begin();
2417 for (; it != m_windowEventListeners.end(); ++it)
2418 if ( (*it)->eventType() == eventType && (*it)->listener()->isHTMLEventListener()) {
2419 m_windowEventListeners.remove(it);
2424 void Document::addWindowEventListener(const AtomicString &eventType, PassRefPtr<EventListener> listener, bool useCapture)
2426 // Remove existing identical listener set with identical arguments.
2427 // The DOM 2 spec says that "duplicate instances are discarded" in this case.
2428 removeWindowEventListener(eventType, listener.get(), useCapture);
2429 m_windowEventListeners.append(new RegisteredEventListener(eventType, listener, useCapture));
2432 void Document::removeWindowEventListener(const AtomicString &eventType, EventListener *listener, bool useCapture)
2434 RegisteredEventListener rl(eventType, listener, useCapture);
2435 RegisteredEventListenerList::iterator it = m_windowEventListeners.begin();
2436 for (; it != m_windowEventListeners.end(); ++it)
2438 m_windowEventListeners.remove(it);
2443 bool Document::hasWindowEventListener(const AtomicString &eventType)
2445 RegisteredEventListenerList::iterator it = m_windowEventListeners.begin();
2446 for (; it != m_windowEventListeners.end(); ++it)
2447 if ((*it)->eventType() == eventType) {
2453 PassRefPtr<EventListener> Document::createHTMLEventListener(const String& functionName, const String& code, Node *node)
2455 if (Frame* frm = frame())
2456 if (KJSProxy* proxy = frm->scriptProxy())
2457 return proxy->createHTMLEventHandler(functionName, code, node);
2461 void Document::setHTMLWindowEventListener(const AtomicString& eventType, Attribute* attr)
2463 setHTMLWindowEventListener(eventType,
2464 createHTMLEventListener(attr->localName().domString(), attr->value(), 0));
2467 void Document::dispatchImageLoadEventSoon(HTMLImageLoader *image)
2469 m_imageLoadEventDispatchSoonList.append(image);
2470 if (!m_imageLoadEventTimer.isActive())
2471 m_imageLoadEventTimer.startOneShot(0);
2474 void Document::removeImage(HTMLImageLoader* image)
2476 // Remove instances of this image from both lists.
2477 // Use loops because we allow multiple instances to get into the lists.
2478 while (m_imageLoadEventDispatchSoonList.removeRef(image)) { }
2479 while (m_imageLoadEventDispatchingList.removeRef(image)) { }
2480 if (m_imageLoadEventDispatchSoonList.isEmpty())
2481 m_imageLoadEventTimer.stop();
2484 void Document::dispatchImageLoadEventsNow()
2486 // need to avoid re-entering this function; if new dispatches are
2487 // scheduled before the parent finishes processing the list, they
2488 // will set a timer and eventually be processed
2489 if (!m_imageLoadEventDispatchingList.isEmpty()) {
2493 m_imageLoadEventTimer.stop();
2495 m_imageLoadEventDispatchingList = m_imageLoadEventDispatchSoonList;
2496 m_imageLoadEventDispatchSoonList.clear();
2497 for (DeprecatedPtrListIterator<HTMLImageLoader> it(m_imageLoadEventDispatchingList); it.current();) {
2498 HTMLImageLoader* image = it.current();
2499 // Must advance iterator *before* dispatching call.
2500 // Otherwise, it might be advanced automatically if dispatching the call had a side effect
2501 // of destroying the current HTMLImageLoader, and then we would advance past the *next* item,
2502 // missing one altogether.
2504 image->dispatchLoadEvent();
2506 m_imageLoadEventDispatchingList.clear();
2509 void Document::imageLoadEventTimerFired(Timer<Document>*)
2511 dispatchImageLoadEventsNow();
2514 Element* Document::ownerElement() const
2518 return frame()->ownerElement();
2521 String Document::referrer() const
2524 return frame()->loader()->referrer();
2528 String Document::domain() const
2530 if (m_domain.isEmpty()) // not set yet (we set it on demand to save time and space)
2531 m_domain = KURL(URL()).host(); // Initially set to the host
2535 void Document::setDomain(const String& newDomain)
2537 m_domainWasSetInDOM = true;
2539 // Not set yet (we set it on demand to save time and space)
2540 // Initially set to the host
2541 if (m_domain.isEmpty())
2542 m_domain = KURL(URL()).host();
2544 // Both NS and IE specify that changing the domain is only allowed when
2545 // the new domain is a suffix of the old domain.
2547 // FIXME: We should add logging indicating why a domain was not allowed.
2549 int oldLength = m_domain.length();
2550 int newLength = newDomain.length();
2551 // e.g. newDomain=kde.org (7) and m_domain=www.kde.org (11)
2552 if (newLength < oldLength) {
2553 String test = m_domain.copy();
2554 // Check that it's a subdomain, not e.g. "de.org"
2555 if (test[oldLength - newLength - 1] == '.') {
2556 // Now test is "kde.org" from m_domain
2557 // and we check that it's the same thing as newDomain
2558 test.remove(0, oldLength - newLength);
2559 if (test == newDomain)
2560 m_domain = newDomain;
2565 void Document::setDomainInternal(const String& newDomain)
2567 m_domainWasSetInDOM = false;
2568 m_domain = newDomain;
2571 bool Document::isValidName(const String &name)
2573 const UChar* s = reinterpret_cast<const UChar*>(name.characters());
2574 unsigned length = name.length();
2582 U16_NEXT(s, i, length, c)
2583 if (!isValidNameStart(c))
2586 while (i < length) {
2587 U16_NEXT(s, i, length, c)
2588 if (!isValidNamePart(c))
2595 bool Document::parseQualifiedName(const String &qualifiedName, String &prefix, String &localName)
2597 unsigned length = qualifiedName.length();
2602 bool nameStart = true;
2603 bool sawColon = false;
2606 const UChar* s = reinterpret_cast<const UChar*>(qualifiedName.characters());
2607 for (unsigned i = 0; i < length;) {
2609 U16_NEXT(s, i, length, c)
2612 return false; // multiple colons: not allowed
2616 } else if (nameStart) {
2617 if (!isValidNameStart(c))
2621 if (!isValidNamePart(c))
2628 localName = qualifiedName.copy();
2630 prefix = qualifiedName.substring(0, colonPos);
2631 localName = qualifiedName.substring(colonPos + 1, length - (colonPos + 1));
2637 void Document::addImageMap(HTMLMapElement* imageMap)
2639 // Add the image map, unless there's already another with that name.
2640 // "First map wins" is the rule other browsers seem to implement.
2641 m_imageMapsByName.add(imageMap->getName().impl(), imageMap);
2644 void Document::removeImageMap(HTMLMapElement* imageMap)
2646 // Remove the image map by name.
2647 // But don't remove some other image map that just happens to have the same name.
2648 // FIXME: Use a HashCountedSet as we do for IDs to find the first remaining map
2649 // once a map has been removed.
2650 const AtomicString& name = imageMap->getName();
2651 ImageMapsByName::iterator it = m_imageMapsByName.find(name.impl());
2652 if (it != m_imageMapsByName.end() && it->second == imageMap)
2653 m_imageMapsByName.remove(it);
2656 HTMLMapElement *Document::getImageMap(const String& URL) const
2660 int hashPos = URL.find('#');
2661 String name = (hashPos < 0 ? URL : URL.substring(hashPos + 1)).impl();
2662 AtomicString mapName = hMode == XHtml ? name : name.lower();
2663 return m_imageMapsByName.get(mapName.impl());
2666 void Document::setDecoder(TextResourceDecoder *decoder)
2668 m_decoder = decoder;
2671 UChar Document::backslashAsCurrencySymbol() const
2675 return m_decoder->encoding().backslashAsCurrencySymbol();
2678 DeprecatedString Document::completeURL(const DeprecatedString& URL)
2680 // FIXME: This treats null URLs the same as empty URLs, unlike the String function below.
2682 // If both the URL and base URL are empty, like they are for documents
2683 // created using DOMImplementation::createDocument, just return the passed in URL.
2684 // (We do this because URL() returns "about:blank" for empty URLs.
2685 if (m_url.isEmpty() && m_baseURL.isEmpty())
2688 return KURL(baseURL(), URL).url();
2689 return KURL(baseURL(), URL, m_decoder->encoding()).url();
2692 String Document::completeURL(const String &URL)
2694 // FIXME: This always returns null when passed a null URL, unlike the String function above.
2697 return completeURL(URL.deprecatedString());
2700 bool Document::inPageCache()
2702 return m_inPageCache;
2705 void Document::setInPageCache(bool flag)
2707 if (m_inPageCache == flag)
2710 m_inPageCache = flag;
2712 ASSERT(m_savedRenderer == 0);
2713 m_savedRenderer = renderer();
2714 if (FrameView* v = view())
2715 v->resetScrollbars();
2717 ASSERT(renderer() == 0 || renderer() == m_savedRenderer);
2718 ASSERT(m_renderArena);
2719 setRenderer(m_savedRenderer);
2720 m_savedRenderer = 0;
2724 void Document::registerForDidRestoreFromCacheCallback(Element* e)
2726 m_didRestorePageCallbackSet.add(e);
2729 void Document::unregisterForDidRestoreFromCacheCallback(Element* e)
2731 m_didRestorePageCallbackSet.remove(e);
2734 void Document::didRestoreFromCache()
2736 HashSet<Element*>::iterator it = m_didRestorePageCallbackSet.begin();
2737 for (; it != m_didRestorePageCallbackSet.end(); ++it)
2738 (*it)->didRestoreFromCache();
2741 void Document::setShouldCreateRenderers(bool f)
2743 m_createRenderers = f;
2746 bool Document::shouldCreateRenderers()
2748 return m_createRenderers;
2751 String Document::toString() const
2755 for (Node *child = firstChild(); child != NULL; child = child->nextSibling()) {
2756 result += child->toString();
2762 // Support for Javascript execCommand, and related methods
2764 JSEditor *Document::jsEditor()
2767 m_jsEditor = new JSEditor(this);
2771 bool Document::execCommand(const String &command, bool userInterface, const String &value)
2773 return jsEditor()->execCommand(command, userInterface, value);
2776 bool Document::queryCommandEnabled(const String &command)
2778 return jsEditor()->queryCommandEnabled(command);
2781 bool Document::queryCommandIndeterm(const String &command)
2783 return jsEditor()->queryCommandIndeterm(command);
2786 bool Document::queryCommandState(const String &command)
2788 return jsEditor()->queryCommandState(command);
2791 bool Document::queryCommandSupported(const String &command)
2793 return jsEditor()->queryCommandSupported(command);
2796 String Document::queryCommandValue(const String &command)
2798 return jsEditor()->queryCommandValue(command);
2801 static IntRect placeholderRectForMarker(void)
2803 return IntRect(-1,-1,-1,-1);
2806 void Document::addMarker(Range *range, DocumentMarker::MarkerType type, String description)
2808 // Use a TextIterator to visit the potentially multiple nodes the range covers.
2809 for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) {
2810 RefPtr<Range> textPiece = markedText.range();
2812 DocumentMarker marker = {type, textPiece->startOffset(exception), textPiece->endOffset(exception), description};
2813 addMarker(textPiece->startContainer(exception), marker);
2817 void Document::removeMarkers(Range* range, DocumentMarker::MarkerType markerType)
2819 if (m_markers.isEmpty())
2822 ExceptionCode ec = 0;
2823 Node* startContainer = range->startContainer(ec);
2824 Node* endContainer = range->endContainer(ec);
2826 Node* pastEndNode = range->pastEndNode();
2827 for (Node* node = range->startNode(); node != pastEndNode; node = node->traverseNextNode()) {
2828 int startOffset = node == startContainer ? range->startOffset(ec) : 0;
2829 int endOffset = node == endContainer ? range->endOffset(ec) : INT_MAX;
2830 int length = endOffset - startOffset;
2831 removeMarkers(node, startOffset, length, markerType);
2835 // Markers are stored in order sorted by their location.
2836 // They do not overlap each other, as currently required by the drawing code in RenderText.cpp.
2838 void Document::addMarker(Node *node, DocumentMarker newMarker)
2840 ASSERT(newMarker.endOffset >= newMarker.startOffset);
2841 if (newMarker.endOffset == newMarker.startOffset)
2844 MarkerMapVectorPair* vectorPair = m_markers.get(node);
2847 vectorPair = new MarkerMapVectorPair;
2848 vectorPair->first.append(newMarker);
2849 vectorPair->second.append(placeholderRectForMarker());
2850 m_markers.set(node, vectorPair);
2852 Vector<DocumentMarker>& markers = vectorPair->first;
2853 Vector<IntRect>& rects = vectorPair->second;
2854 ASSERT(markers.size() == rects.size());
2856 for (i = 0; i != markers.size();) {
2857 DocumentMarker marker = markers[i];
2859 if (newMarker.endOffset < marker.startOffset+1) {
2860 // This is the first marker that is completely after newMarker, and disjoint from it.
2861 // We found our insertion point.
2863 } else if (newMarker.startOffset > marker.endOffset) {
2864 // maker is before newMarker, and disjoint from it. Keep scanning.
2866 } else if (newMarker == marker) {
2867 // already have this one, NOP
2870 // marker and newMarker intersect or touch - merge them into newMarker
2871 newMarker.startOffset = min(newMarker.startOffset, marker.startOffset);
2872 newMarker.endOffset = max(newMarker.endOffset, marker.endOffset);
2873 // remove old one, we'll add newMarker later
2876 // it points to the next marker to consider
2879 // at this point i points to the node before which we want to insert
2880 markers.insert(i, newMarker);
2881 rects.insert(i, placeholderRectForMarker());
2884 // repaint the affected node
2885 if (node->renderer())
2886 node->renderer()->repaint();
2889 // copies markers from srcNode to dstNode, applying the specified shift delta to the copies. The shift is
2890 // useful if, e.g., the caller has created the dstNode from a non-prefix substring of the srcNode.
2891 void Document::copyMarkers(Node *srcNode, unsigned startOffset, int length, Node *dstNode, int delta, DocumentMarker::MarkerType markerType)
2896 MarkerMapVectorPair* vectorPair = m_markers.get(srcNode);
2900 ASSERT(vectorPair->first.size() == vectorPair->second.size());
2902 bool docDirty = false;
2903 unsigned endOffset = startOffset + length - 1;
2904 Vector<DocumentMarker>& markers = vectorPair->first;
2905 for (size_t i = 0; i != markers.size(); ++i) {
2906 DocumentMarker marker = markers[i];
2908 // stop if we are now past the specified range
2909 if (marker.startOffset > endOffset)
2912 // skip marker that is before the specified range or is the wrong type
2913 if (marker.endOffset < startOffset || (marker.type != markerType && markerType != DocumentMarker::AllMarkers))
2916 // pin the marker to the specified range and apply the shift delta
2918 if (marker.startOffset < startOffset)
2919 marker.startOffset = startOffset;
2920 if (marker.endOffset > endOffset)
2921 marker.endOffset = endOffset;
2922 marker.startOffset += delta;
2923 marker.endOffset += delta;
2925 addMarker(dstNode, marker);
2928 // repaint the affected node
2929 if (docDirty && dstNode->renderer())
2930 dstNode->renderer()->repaint();
2933 void Document::removeMarkers(Node* node, unsigned startOffset, int length, DocumentMarker::MarkerType markerType)
2938 MarkerMapVectorPair* vectorPair = m_markers.get(node);
2942 Vector<DocumentMarker>& markers = vectorPair->first;
2943 Vector<IntRect>& rects = vectorPair->second;
2944 ASSERT(markers.size() == rects.size());
2945 bool docDirty = false;
2946 unsigned endOffset = startOffset + length;
2947 for (size_t i = 0; i < markers.size();) {
2948 DocumentMarker marker = markers[i];
2950 // markers are returned in order, so stop if we are now past the specified range
2951 if (marker.startOffset >= endOffset)
2954 // skip marker that is wrong type or before target
2955 if (marker.endOffset < startOffset || (marker.type != markerType && markerType != DocumentMarker::AllMarkers)) {
2960 // at this point we know that marker and target intersect in some way
2963 // pitch the old marker and any associated rect
2967 // add either of the resulting slices that are left after removing target
2968 if (startOffset > marker.startOffset) {
2969 DocumentMarker newLeft = marker;
2970 newLeft.endOffset = startOffset;
2971 markers.insert(i, newLeft);
2972 rects.insert(i, placeholderRectForMarker());
2973 // i now points to the newly-inserted node, but we want to skip that one
2976 if (marker.endOffset > endOffset) {
2977 DocumentMarker newRight = marker;
2978 newRight.startOffset = endOffset;
2979 markers.insert(i, newRight);
2980 rects.insert(i, placeholderRectForMarker());
2981 // i now points to the newly-inserted node, but we want to skip that one
2986 if (markers.isEmpty()) {
2987 ASSERT(rects.isEmpty());
2988 m_markers.remove(node);
2992 // repaint the affected node
2993 if (docDirty && node->renderer())
2994 node->renderer()->repaint();
2997 DocumentMarker* Document::markerContainingPoint(const IntPoint& point, DocumentMarker::MarkerType markerType)
2999 // outer loop: process each node that contains any markers
3000 MarkerMap::iterator end = m_markers.end();
3001 for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
3002 // inner loop; process each marker in this node
3003 MarkerMapVectorPair* vectorPair = nodeIterator->second;
3004 Vector<DocumentMarker>& markers = vectorPair->first;
3005 Vector<IntRect>& rects = vectorPair->second;
3006 ASSERT(markers.size() == rects.size());
3007 unsigned markerCount = markers.size();
3008 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
3009 DocumentMarker& marker = markers[markerIndex];
3011 // skip marker that is wrong type
3012 if (marker.type != markerType && markerType != DocumentMarker::AllMarkers)
3015 IntRect& r = rects[markerIndex];
3017 // skip placeholder rects
3018 if (r == placeholderRectForMarker())
3021 if (r.contains(point))
3029 Vector<DocumentMarker> Document::markersForNode(Node* node)
3031 MarkerMapVectorPair* vectorPair = m_markers.get(node);
3033 return vectorPair->first;
3034 return Vector<DocumentMarker>();
3037 Vector<IntRect> Document::renderedRectsForMarkers(DocumentMarker::MarkerType markerType)
3039 Vector<IntRect> result;
3041 // outer loop: process each node
3042 MarkerMap::iterator end = m_markers.end();
3043 for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
3044 // inner loop; process each marker in this node
3045 MarkerMapVectorPair* vectorPair = nodeIterator->second;
3046 Vector<DocumentMarker>& markers = vectorPair->first;
3047 Vector<IntRect>& rects = vectorPair->second;
3048 ASSERT(markers.size() == rects.size());
3049 unsigned markerCount = markers.size();
3050 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
3051 DocumentMarker marker = markers[markerIndex];
3053 // skip marker that is wrong type
3054 if (marker.type != markerType && markerType != DocumentMarker::AllMarkers)
3057 IntRect r = rects[markerIndex];
3058 // skip placeholder rects
3059 if (r == placeholderRectForMarker())
3069 void Document::removeMarkers(Node* node)
3071 MarkerMap::iterator i = m_markers.find(node);
3072 if (i != m_markers.end()) {
3074 m_markers.remove(i);
3075 if (RenderObject* renderer = node->renderer())
3076 renderer->repaint();
3080 void Document::removeMarkers(DocumentMarker::MarkerType markerType)
3082 // outer loop: process each markered node in the document
3083 MarkerMap markerMapCopy = m_markers;
3084 MarkerMap::iterator end = markerMapCopy.end();
3085 for (MarkerMap::iterator i = markerMapCopy.begin(); i != end; ++i) {
3086 Node* node = i->first.get();
3087 bool nodeNeedsRepaint = false;
3089 // inner loop: process each marker in the current node
3090 MarkerMapVectorPair* vectorPair = i->second;
3091 Vector<DocumentMarker>& markers = vectorPair->first;
3092 Vector<IntRect>& rects = vectorPair->second;
3093 ASSERT(markers.size() == rects.size());
3094 for (size_t i = 0; i != markers.size();) {
3095 DocumentMarker marker = markers[i];
3097 // skip nodes that are not of the specified type
3098 if (marker.type != markerType && markerType != DocumentMarker::AllMarkers) {
3103 // pitch the old marker
3106 nodeNeedsRepaint = true;
3107 // markerIterator now points to the next node
3110 // Redraw the node if it changed. Do this before the node is removed from m_markers, since
3111 // m_markers might contain the last reference to the node.
3112 if (nodeNeedsRepaint) {
3113 RenderObject* renderer = node->renderer();
3115 renderer->repaint();
3118 // delete the node's list if it is now empty
3119 if (markers.isEmpty()) {
3120 ASSERT(rects.isEmpty());
3121 m_markers.remove(node);
3127 void Document::repaintMarkers(DocumentMarker::MarkerType markerType)
3129 // outer loop: process each markered node in the document
3130 MarkerMap::iterator end = m_markers.end();
3131 for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
3132 Node* node = i->first.get();
3134 // inner loop: process each marker in the current node
3135 MarkerMapVectorPair* vectorPair = i->second;
3136 Vector<DocumentMarker>& markers = vectorPair->first;
3137 bool nodeNeedsRepaint = false;
3138 for (size_t i = 0; i != markers.size(); ++i) {
3139 DocumentMarker marker = markers[i];
3141 // skip nodes that are not of the specified type
3142 if (marker.type == markerType || markerType == DocumentMarker::AllMarkers) {
3143 nodeNeedsRepaint = true;
3148 if (!nodeNeedsRepaint)
3151 // cause the node to be redrawn
3152 if (RenderObject* renderer = node->renderer())
3153 renderer->repaint();
3157 void Document::setRenderedRectForMarker(Node* node, DocumentMarker marker, const IntRect& r)
3159 MarkerMapVectorPair* vectorPair = m_markers.get(node);
3161 ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marker we don't already know about
3165 Vector<DocumentMarker>& markers = vectorPair->first;
3166 ASSERT(markers.size() == vectorPair->second.size());
3167 unsigned markerCount = markers.size();
3168 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
3169 DocumentMarker m = markers[markerIndex];
3171 vectorPair->second[markerIndex] = r;
3176 ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marker we don't already know about
3179 void Document::invalidateRenderedRectsForMarkersInRect(const IntRect& r)
3181 // outer loop: process each markered node in the document
3182 MarkerMap::iterator end = m_markers.end();
3183 for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
3185 // inner loop: process each rect in the current node
3186 MarkerMapVectorPair* vectorPair = i->second;
3187 Vector<IntRect>& rects = vectorPair->second;
3189 unsigned rectCount = rects.size();
3190 for (unsigned rectIndex = 0; rectIndex < rectCount; ++rectIndex)
3191 if (rects[rectIndex].intersects(r))
3192 rects[rectIndex] = placeholderRectForMarker();
3196 void Document::shiftMarkers(Node *node, unsigned startOffset, int delta, DocumentMarker::MarkerType markerType)
3198 MarkerMapVectorPair* vectorPair = m_markers.get(node);
3202 Vector<DocumentMarker>& markers = vectorPair->first;
3203 Vector<IntRect>& rects = vectorPair->second;
3204 ASSERT(markers.size() == rects.size());
3206 bool docDirty = false;
3207 for (size_t i = 0; i != markers.size(); ++i) {
3208 DocumentMarker &marker = markers[i];
3209 if (marker.startOffset >= startOffset && (markerType == DocumentMarker::AllMarkers || marker.type == markerType)) {
3210 ASSERT((int)marker.startOffset + delta >= 0);
3211 marker.startOffset += delta;
3212 marker.endOffset += delta;
3215 // Marker moved, so previously-computed rendered rectangle is now invalid
3216 rects[i] = placeholderRectForMarker();
3220 // repaint the affected node
3221 if (docDirty && node->renderer())
3222 node->renderer()->repaint();
3227 void Document::applyXSLTransform(ProcessingInstruction* pi)
3229 RefPtr<XSLTProcessor> processor = new XSLTProcessor;
3230 processor->setXSLStylesheet(static_cast<XSLStyleSheet*>(pi->sheet()));
3232 DeprecatedString resultMIMEType;
3233 DeprecatedString newSource;
3234 DeprecatedString resultEncoding;
3235 if (!processor->transformToString(this, resultMIMEType, newSource, resultEncoding))
3237 // FIXME: If the transform failed we should probably report an error (like Mozilla does).
3238 processor->createDocumentFromSource(newSource, resultEncoding, resultMIMEType, this, frame());
3241 void Document::setTransformSource(void* doc)
3243 if (doc == m_transformSource)
3246 xmlFreeDoc((xmlDocPtr)m_transformSource);
3247 m_transformSource = doc;
3252 void Document::setDesignMode(InheritedBool value)
3254 m_designMode = value;
3257 Document::InheritedBool Document::getDesignMode() const
3259 return m_designMode;
3262 bool Document::inDesignMode() const
3264 for (const Document* d = this; d; d = d->parentDocument()) {
3265 if (d->m_designMode != inherit)
3266 return d->m_designMode;
3271 Document *Document::parentDocument() const
3273 Frame *childPart = frame();
3276 Frame *parent = childPart->tree()->parent();
3279 return parent->document();
3282 Document *Document::topDocument() const
3284 Document *doc = const_cast<Document *>(this);
3286 while ((element = doc->ownerElement()))
3287 doc = element->document();
3292 PassRefPtr<Attr> Document::createAttributeNS(const String &namespaceURI, const String &qualifiedName, ExceptionCode& ec)
3294 if (qualifiedName.isNull()) {
3299 String localName = qualifiedName;
3302 if ((colonpos = qualifiedName.find(':')) >= 0) {
3303 prefix = qualifiedName.copy();
3304 localName = qualifiedName.copy();
3305 prefix.truncate(colonpos);
3306 localName.remove(0, colonpos+1);
3309 if (!isValidName(localName)) {
3310 ec = INVALID_CHARACTER_ERR;
3314 // FIXME: Assume this is a mapped attribute, since createAttribute isn't namespace-aware. There's no harm to XML
3315 // documents if we're wrong.
3316 return new Attr(0, this, new MappedAttribute(QualifiedName(prefix, localName, namespaceURI), StringImpl::empty()));
3320 const SVGDocumentExtensions* Document::svgExtensions()
3322 return m_svgExtensions;
3325 SVGDocumentExtensions* Document::accessSVGExtensions()
3327 if (!m_svgExtensions)
3328 m_svgExtensions = new SVGDocumentExtensions(this);
3329 return m_svgExtensions;
3333 PassRefPtr<HTMLCollection> Document::images()
3335 return new HTMLCollection(this, HTMLCollection::DocImages);
3338 PassRefPtr<HTMLCollection> Document::applets()
3340 return new HTMLCollection(this, HTMLCollection::DocApplets);
3343 PassRefPtr<HTMLCollection> Document::embeds()
3345 return new HTMLCollection(this, HTMLCollection::DocEmbeds);
3348 PassRefPtr<HTMLCollection> Document::plugins()
3350 // This is an alias for embeds() required for the JS DOM bindings.
3351 return new HTMLCollection(this, HTMLCollection::DocEmbeds);
3354 PassRefPtr<HTMLCollection> Document::objects()
3356 return new HTMLCollection(this, HTMLCollection::DocObjects);
3359 PassRefPtr<HTMLCollection> Document::scripts()
3361 return new HTMLCollection(this, HTMLCollection::DocScripts);
3364 PassRefPtr<HTMLCollection> Document::links()
3366 return new HTMLCollection(this, HTMLCollection::DocLinks);
3369 PassRefPtr<HTMLCollection> Document::forms()
3371 return new HTMLCollection(this, HTMLCollection::DocForms);
3374 PassRefPtr<HTMLCollection> Document::anchors()
3376 return new HTMLCollection(this, HTMLCollection::DocAnchors);
3379 PassRefPtr<HTMLCollection> Document::all()
3381 return new HTMLCollection(this, HTMLCollection::DocAll);
3384 PassRefPtr<HTMLCollection> Document::windowNamedItems(const String &name)
3386 return new HTMLNameCollection(this, HTMLCollection::WindowNamedItems, name);
3389 PassRefPtr<HTMLCollection> Document::documentNamedItems(const String &name)
3391 return new HTMLNameCollection(this, HTMLCollection::DocumentNamedItems, name);
3394 HTMLCollection::CollectionInfo* Document::nameCollectionInfo(HTMLCollection::Type type, const String& name)
3396 HashMap<AtomicStringImpl*, HTMLCollection::CollectionInfo*>& map = m_nameCollectionInfo[type - HTMLCollection::UnnamedCollectionTypes];
3398 AtomicString atomicName(name);
3400 HashMap<AtomicStringImpl*, HTMLCollection::CollectionInfo*>::iterator iter = map.find(atomicName.impl());
3401 if (iter == map.end())
3402 iter = map.add(atomicName.impl(), new HTMLCollection::CollectionInfo).first;
3404 return iter->second;
3407 PassRefPtr<NameNodeList> Document::getElementsByName(const String &elementName)
3409 return new NameNodeList(this, elementName);
3412 void Document::finishedParsing()
3415 if (Frame* f = frame())
3416 f->loader()->finishedParsing();
3419 Vector<String> Document::formElementsState() const
3421 Vector<String> stateVector;
3422 stateVector.reserveCapacity(m_formElementsWithState.size() * 3);
3423 typedef ListHashSet<HTMLFormControlElementWithState*>::const_iterator Iterator;
3424 Iterator end = m_formElementsWithState.end();
3425 for (Iterator it = m_formElementsWithState.begin(); it != end; ++it) {
3426 HTMLFormControlElementWithState* e = *it;
3428 if (e->saveState(value)) {
3429 stateVector.append(e->name().domString());
3430 stateVector.append(e->type().domString());
3431 stateVector.append(value);
3439 PassRefPtr<XPathExpression> Document::createExpression(const String& expression,
3440 XPathNSResolver* resolver,
3443 if (!m_xpathEvaluator)
3444 m_xpathEvaluator = new XPathEvaluator;
3445 return m_xpathEvaluator->createExpression(expression, resolver, ec);
3448 PassRefPtr<XPathNSResolver> Document::createNSResolver(Node* nodeResolver)
3450 if (!m_xpathEvaluator)
3451 m_xpathEvaluator = new XPathEvaluator;
3452 return m_xpathEvaluator->createNSResolver(nodeResolver);
3455 PassRefPtr<XPathResult> Document::evaluate(const String& expression,
3457 XPathNSResolver* resolver,
3458 unsigned short type,
3459 XPathResult* result,
3462 if (!m_xpathEvaluator)
3463 m_xpathEvaluator = new XPathEvaluator;
3464 return m_xpathEvaluator->evaluate(expression, contextNode, resolver, type, result, ec);
3467 #endif // ENABLE(XPATH)
3469 void Document::setStateForNewFormElements(const Vector<String>& stateVector)
3471 // Walk the state vector backwards so that the value to use for each
3472 // name/type pair first is the one at the end of each individual vector
3473 // in the FormElementStateMap. We're using them like stacks.
3474 typedef FormElementStateMap::iterator Iterator;
3475 m_formElementsWithState.clear();
3476 for (size_t i = stateVector.size() / 3 * 3; i; i -= 3) {
3477 AtomicString a = stateVector[i - 3];
3478 AtomicString b = stateVector[i - 2];
3479 const String& c = stateVector[i - 1];
3480 FormElementKey key(a.impl(), b.impl());
3481 Iterator it = m_stateForNewFormElements.find(key);
3482 if (it != m_stateForNewFormElements.end())
3483 it->second.append(c);
3485 Vector<String> v(1);
3487 m_stateForNewFormElements.set(key, v);
3492 bool Document::hasStateForNewFormElements() const
3494 return !m_stateForNewFormElements.isEmpty();
3497 bool Document::takeStateForFormElement(AtomicStringImpl* name, AtomicStringImpl* type, String& state)
3499 typedef FormElementStateMap::iterator Iterator;
3500 Iterator it = m_stateForNewFormElements.find(FormElementKey(name, type));
3501 if (it == m_stateForNewFormElements.end())
3503 ASSERT(it->second.size());
3504 state = it->second.last();
3505 if (it->second.size() > 1)
3506 it->second.removeLast();
3508 m_stateForNewFormElements.remove(it);
3512 FormElementKey::FormElementKey(AtomicStringImpl* name, AtomicStringImpl* type)
3513 : m_name(name), m_type(type)
3518 FormElementKey::~FormElementKey()
3523 FormElementKey::FormElementKey(const FormElementKey& other)
3524 : m_name(other.name()), m_type(other.type())
3529 FormElementKey& FormElementKey::operator=(const FormElementKey& other)
3533 m_name = other.name();
3534 m_type = other.type();
3538 void FormElementKey::ref() const
3540 if (name() && name() != HashTraits<AtomicStringImpl*>::deletedValue())
3546 void FormElementKey::deref() const
3548 if (name() && name() != HashTraits<AtomicStringImpl*>::deletedValue())
3554 unsigned FormElementKeyHash::hash(const FormElementKey& k)
3556 ASSERT(sizeof(k) % (sizeof(uint16_t) * 2) == 0);
3558 unsigned l = sizeof(k) / (sizeof(uint16_t) * 2);
3559 const uint16_t* s = reinterpret_cast<const uint16_t*>(&k);
3560 uint32_t hash = PHI;
3563 for (; l > 0; l--) {
3565 uint32_t tmp = (s[1] << 11) ^ hash;
3566 hash = (hash << 16) ^ tmp;
3571 // Force "avalanching" of final 127 bits
3578 // this avoids ever returning a hash code of 0, since that is used to
3579 // signal "hash not computed yet", using a value that is likely to be
3580 // effectively the same as 0 when the low bits are masked
3587 FormElementKey FormElementKeyHashTraits::deletedValue()
3589 return HashTraits<AtomicStringImpl*>::deletedValue();
3593 String Document::iconURL()
3598 void Document::setIconURL(const String& iconURL, const String& type)
3600 // FIXME - <rdar://problem/4727645> - At some point in the future, we might actually honor the "type"
3601 if (m_iconURL.isEmpty())
3602 m_iconURL = iconURL;
3603 else if (!type.isEmpty())
3604 m_iconURL = iconURL;
3607 void Document::setUseSecureKeyboardEntryWhenActive(bool usesSecureKeyboard)
3609 if (m_useSecureKeyboardEntryWhenActive == usesSecureKeyboard)
3612 m_useSecureKeyboardEntryWhenActive = usesSecureKeyboard;
3613 m_frame->updateSecureKeyboardEntryIfActive();
3616 bool Document::useSecureKeyboardEntryWhenActive() const
3618 return m_useSecureKeyboardEntryWhenActive;
3621 void Document::initSecurityPolicyURL()
3626 FrameLoader* loader = m_frame->loader();
3627 m_securityPolicyURL = loader->url();
3629 // javascript: URLs create document using the "about" protocol
3630 if (!m_securityPolicyURL.isEmpty() && !equalIgnoringCase(m_securityPolicyURL.protocol(), "about"))
3633 Frame* openerFrame = 0;
3634 if (m_frame->tree()->parent())
3635 openerFrame = m_frame->tree()->parent();
3636 else if (loader->opener())
3637 openerFrame = loader->opener();
3642 Document* openerDocument = openerFrame->document();
3643 if (!openerDocument)
3646 m_securityPolicyURL = openerDocument->securityPolicyURL();
3649 void Document::updateFocusAppearanceSoon()
3651 if (!m_updateFocusAppearanceTimer.isActive())
3652 m_updateFocusAppearanceTimer.startOneShot(0);
3655 void Document::cancelFocusAppearanceUpdate()
3657 m_updateFocusAppearanceTimer.stop();
3660 void Document::updateFocusAppearanceTimerFired(Timer<Document>*)
3662 Node* node = focusedNode();
3665 if (!node->isElementNode())
3670 Element* element = static_cast<Element*>(node);
3671 if (element->isFocusable())
3672 element->updateFocusAppearance(false);
3675 } // namespace WebCore