Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(294)

Side by Side Diff: webkit/pending/Document.cpp

Issue 6500: Cleaning up the unfork (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 12 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/pending/Document.h ('k') | webkit/pending/DragController.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * (C) 2006 Alexey Proskuryakov (ap@webkit.org)
6 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
7 *
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.
12 *
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.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24 #include "config.h"
25 #include "Document.h"
26
27 #include "AnimationController.h"
28 #include "AXObjectCache.h"
29 #include "CDATASection.h"
30 #include "CSSHelper.h"
31 #include "CSSStyleSelector.h"
32 #include "CSSStyleSheet.h"
33 #include "CSSValueKeywords.h"
34 #include "CString.h"
35 #include "CachedCSSStyleSheet.h"
36 #include "Comment.h"
37 #include "CookieJar.h"
38 #include "DOMImplementation.h"
39 #include "DOMWindow.h"
40 #include "DocLoader.h"
41 #include "DocumentFragment.h"
42 #include "DocumentLoader.h"
43 #include "DocumentType.h"
44 #include "EditingText.h"
45 #include "Editor.h"
46 #include "EntityReference.h"
47 #include "Event.h"
48 #include "EventHandler.h"
49 #include "EventListener.h"
50 #include "EventNames.h"
51 #include "ExceptionCode.h"
52 #include "FocusController.h"
53 #include "FontCache.h"
54 #include "Frame.h"
55 #include "FrameLoader.h"
56 #include "FrameTree.h"
57 #include "FrameView.h"
58 #include "HTMLBodyElement.h"
59 #include "HTMLCanvasElement.h"
60 #include "HTMLDocument.h"
61 #include "HTMLElementFactory.h"
62 #include "HTMLFrameOwnerElement.h"
63 #include "HTMLHeadElement.h"
64 #include "HTMLImageLoader.h"
65 #include "HTMLInputElement.h"
66 #include "HTMLLinkElement.h"
67 #include "HTMLMapElement.h"
68 #include "HTMLNameCollection.h"
69 #include "HTMLNames.h"
70 #include "HTMLStyleElement.h"
71 #include "HTMLTitleElement.h"
72 #include "HTTPParsers.h"
73 #include "HistoryItem.h"
74 #include "HitTestRequest.h"
75 #include "HitTestResult.h"
76 #include "KeyboardEvent.h"
77 #include "Logging.h"
78 #include "MessageEvent.h"
79 #include "MouseEvent.h"
80 #include "MouseEventWithHitTestResults.h"
81 #include "MutationEvent.h"
82 #include "NameNodeList.h"
83 #include "NodeFilter.h"
84 #include "NodeIterator.h"
85 #include "NodeWithIndex.h"
86 #include "OverflowEvent.h"
87 #include "Page.h"
88 #include "PlatformKeyboardEvent.h"
89 #include "ProcessingInstruction.h"
90 #include "ProgressEvent.h"
91 #include "RegisteredEventListener.h"
92 #include "RegularExpression.h"
93 #include "RenderArena.h"
94 #include "RenderView.h"
95 #include "RenderWidget.h"
96 #include "SecurityOrigin.h"
97 #include "SegmentedString.h"
98 #include "SelectionController.h"
99 #include "Settings.h"
100 #include "StringHash.h"
101 #include "StyleSheetList.h"
102 #include "SystemTime.h"
103 #include "TextEvent.h"
104 #include "TextIterator.h"
105 #include "TextResourceDecoder.h"
106 #include "TreeWalker.h"
107 #include "UIEvent.h"
108 #include "WheelEvent.h"
109 #include "XMLHttpRequest.h"
110 #include "XMLNames.h"
111 #include "XMLTokenizer.h"
112 #include "ScriptController.h"
113
114 #if USE(JSC)
115 #include <kjs/JSLock.h>
116 #include "JSDOMBinding.h"
117 #endif
118
119 #if ENABLE(DATABASE)
120 #include "Database.h"
121 #include "DatabaseThread.h"
122 #endif
123
124 #if ENABLE(XPATH)
125 #include "XPathEvaluator.h"
126 #include "XPathExpression.h"
127 #include "XPathNSResolver.h"
128 #include "XPathResult.h"
129 #endif
130
131 #if ENABLE(XSLT)
132 #include "XSLTProcessor.h"
133 #endif
134
135 #if ENABLE(XBL)
136 #include "XBLBindingManager.h"
137 #endif
138
139 #if ENABLE(SVG)
140 #include "SVGDocumentExtensions.h"
141 #include "SVGElementFactory.h"
142 #include "SVGZoomEvent.h"
143 #include "SVGStyleElement.h"
144 #endif
145
146 #if defined(__APPLE__)
147 // we need to be PLATFORM(CHROMIUM) for this file, even if we're not building
148 // that particular target, for the a11y ifdefs.
149 #define WTF_PLATFORM_CHROMIUM 1
150 #endif
151
152 using namespace std;
153 using namespace WTF;
154 using namespace Unicode;
155
156 namespace WebCore {
157
158 using namespace EventNames;
159 using namespace HTMLNames;
160
161 // #define INSTRUMENT_LAYOUT_SCHEDULING 1
162
163 // This amount of time must have elapsed before we will even consider scheduling a layout without a delay.
164 // FIXME: For faster machines this value can really be lowered to 200. 250 is a dequate, but a little high
165 // for dual G5s. :)
166 static const int cLayoutScheduleThreshold = 250;
167
168 // Use 1 to represent the document's default form.
169 static HTMLFormElement* const defaultForm = reinterpret_cast<HTMLFormElement*>(1 );
170
171 // Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's
172 static const unsigned PHI = 0x9e3779b9U;
173
174 // DOM Level 2 says (letters added):
175 //
176 // a) Name start characters must have one of the categories Ll, Lu, Lo, Lt, Nl.
177 // b) Name characters other than Name-start characters must have one of the cate gories Mc, Me, Mn, Lm, or Nd.
178 // c) Characters in the compatibility area (i.e. with character code greater tha n #xF900 and less than #xFFFE) are not allowed in XML names.
179 // d) Characters which have a font or compatibility decomposition (i.e. those wi th a "compatibility formatting tag" in field 5 of the database -- marked by fiel d 5 beginning with a "<") are not allowed.
180 // e) The following characters are treated as name-start characters rather than name characters, because the property file classifies them as Alphabetic: [#x02B B-#x02C1], #x0559, #x06E5, #x06E6.
181 // f) Characters #x20DD-#x20E0 are excluded (in accordance with Unicode, section 5.14).
182 // g) Character #x00B7 is classified as an extender, because the property list s o identifies it.
183 // h) Character #x0387 is added as a name character, because #x00B7 is its canon ical equivalent.
184 // i) Characters ':' and '_' are allowed as name-start characters.
185 // j) Characters '-' and '.' are allowed as name characters.
186 //
187 // It also contains complete tables. If we decide it's better, we could include those instead of the following code.
188
189 static inline bool isValidNameStart(UChar32 c)
190 {
191 // rule (e) above
192 if ((c >= 0x02BB && c <= 0x02C1) || c == 0x559 || c == 0x6E5 || c == 0x6E6)
193 return true;
194
195 // rule (i) above
196 if (c == ':' || c == '_')
197 return true;
198
199 // rules (a) and (f) above
200 const uint32_t nameStartMask = Letter_Lowercase | Letter_Uppercase | Letter_ Other | Letter_Titlecase | Number_Letter;
201 if (!(Unicode::category(c) & nameStartMask))
202 return false;
203
204 // rule (c) above
205 if (c >= 0xF900 && c < 0xFFFE)
206 return false;
207
208 // rule (d) above
209 DecompositionType decompType = decompositionType(c);
210 if (decompType == DecompositionFont || decompType == DecompositionCompat)
211 return false;
212
213 return true;
214 }
215
216 static inline bool isValidNamePart(UChar32 c)
217 {
218 // rules (a), (e), and (i) above
219 if (isValidNameStart(c))
220 return true;
221
222 // rules (g) and (h) above
223 if (c == 0x00B7 || c == 0x0387)
224 return true;
225
226 // rule (j) above
227 if (c == '-' || c == '.')
228 return true;
229
230 // rules (b) and (f) above
231 const uint32_t otherNamePartMask = Mark_NonSpacing | Mark_Enclosing | Mark_S pacingCombining | Letter_Modifier | Number_DecimalDigit;
232 if (!(Unicode::category(c) & otherNamePartMask))
233 return false;
234
235 // rule (c) above
236 if (c >= 0xF900 && c < 0xFFFE)
237 return false;
238
239 // rule (d) above
240 DecompositionType decompType = decompositionType(c);
241 if (decompType == DecompositionFont || decompType == DecompositionCompat)
242 return false;
243
244 return true;
245 }
246
247 static Widget* widgetForNode(Node* focusedNode)
248 {
249 if (!focusedNode)
250 return 0;
251 RenderObject* renderer = focusedNode->renderer();
252 if (!renderer || !renderer->isWidget())
253 return 0;
254 return static_cast<RenderWidget*>(renderer)->widget();
255 }
256
257 static bool acceptsEditingFocus(Node *node)
258 {
259 ASSERT(node);
260 ASSERT(node->isContentEditable());
261
262 Node *root = node->rootEditableElement();
263 Frame* frame = node->document()->frame();
264 if (!frame || !root)
265 return false;
266
267 return frame->editor()->shouldBeginEditing(rangeOfContents(root).get());
268 }
269
270 static HashSet<Document*>* changedDocuments = 0;
271
272 Document::Document(Frame* frame, bool isXHTML)
273 : ContainerNode(0)
274 , m_domtree_version(0)
275 , m_styleSheets(StyleSheetList::create(this))
276 , m_title("")
277 , m_titleSetExplicitly(false)
278 , m_imageLoadEventTimer(this, &Document::imageLoadEventTimerFired)
279 , m_updateFocusAppearanceTimer(this, &Document::updateFocusAppearanceTimerFi red)
280 #if ENABLE(XSLT)
281 , m_transformSource(0)
282 #endif
283 , m_xmlVersion("1.0")
284 , m_xmlStandalone(false)
285 , m_dominantScript(USCRIPT_INVALID_CODE)
286 #if ENABLE(XBL)
287 , m_bindingManager(new XBLBindingManager(this))
288 #endif
289 , m_savedRenderer(0)
290 , m_secureForms(0)
291 , m_designMode(inherit)
292 , m_selfOnlyRefCount(0)
293 #if ENABLE(SVG)
294 , m_svgExtensions(0)
295 #endif
296 #if ENABLE(DASHBOARD_SUPPORT)
297 , m_hasDashboardRegions(false)
298 , m_dashboardRegionsDirty(false)
299 #endif
300 , m_accessKeyMapValid(false)
301 , m_createRenderers(true)
302 , m_inPageCache(false)
303 , m_useSecureKeyboardEntryWhenActive(false)
304 , m_isXHTML(isXHTML)
305 , m_numNodeListCaches(0)
306 #if ENABLE(DATABASE)
307 , m_hasOpenDatabases(false)
308 #endif
309 #if USE(LOW_BANDWIDTH_DISPLAY)
310 , m_inLowBandwidthDisplay(false)
311 #endif
312 {
313 m_document.resetSkippingRef(this);
314
315 m_printing = false;
316
317 m_ignoreAutofocus = false;
318
319 m_frame = frame;
320 m_renderArena = 0;
321
322 m_axObjectCache = 0;
323
324 m_docLoader = new DocLoader(this);
325
326 visuallyOrdered = false;
327 m_bParsing = false;
328 m_docChanged = false;
329 m_tokenizer = 0;
330 m_wellFormed = false;
331
332 setParseMode(Strict);
333
334 m_textColor = Color::black;
335 m_listenerTypes = 0;
336 m_inDocument = true;
337 m_inStyleRecalc = false;
338 m_closeAfterStyleRecalc = false;
339 m_usesDescendantRules = false;
340 m_usesSiblingRules = false;
341 m_usesFirstLineRules = false;
342 m_usesFirstLetterRules = false;
343 m_gotoAnchorNeededAfterStylesheetsLoad = false;
344
345 m_styleSelector = 0;
346 m_didCalculateStyleSelector = false;
347 m_pendingStylesheets = 0;
348 m_ignorePendingStylesheets = false;
349 m_hasNodesWithPlaceholderStyle = false;
350 m_pendingSheetLayout = NoLayoutWithPendingSheets;
351
352 m_cssTarget = 0;
353
354 resetLinkColor();
355 resetVisitedLinkColor();
356 resetActiveLinkColor();
357
358 m_processingLoadEvent = false;
359 m_startTime = currentTime();
360 m_overMinimumLayoutThreshold = false;
361
362 initSecurityContext();
363 initDNSPrefetchEnabled();
364
365 static int docID = 0;
366 m_docID = docID++;
367 }
368
369 void Document::removedLastRef()
370 {
371 ASSERT(!m_deletionHasBegun);
372 if (m_selfOnlyRefCount) {
373 // If removing a child removes the last self-only ref, we don't
374 // want the document to be destructed until after
375 // removeAllChildren returns, so we guard ourselves with an
376 // extra self-only ref.
377
378 DocPtr<Document> guard(this);
379
380 // We must make sure not to be retaining any of our children through
381 // these extra pointers or we will create a reference cycle.
382 m_docType = 0;
383 m_focusedNode = 0;
384 m_hoverNode = 0;
385 m_activeNode = 0;
386 m_titleElement = 0;
387 m_documentElement = 0;
388
389 removeAllChildren();
390
391 deleteAllValues(m_markers);
392 m_markers.clear();
393
394 delete m_tokenizer;
395 m_tokenizer = 0;
396
397 #ifndef NDEBUG
398 m_inRemovedLastRefFunction = false;
399 #endif
400 } else {
401 #ifndef NDEBUG
402 m_deletionHasBegun = true;
403 #endif
404 delete this;
405 }
406 }
407
408 Document::~Document()
409 {
410 ASSERT(!renderer());
411 ASSERT(!m_inPageCache);
412 ASSERT(!m_savedRenderer);
413 ASSERT(m_ranges.isEmpty());
414
415 removeAllEventListeners();
416
417 #if ENABLE(SVG)
418 delete m_svgExtensions;
419 #endif
420
421 XMLHttpRequest::detachRequests(this);
422 #if USE(JSC)
423 {
424 KJS::JSLock lock(false);
425 ScriptInterpreter::forgetAllDOMNodesForDocument(this);
426 }
427 #endif
428
429 if (m_docChanged && changedDocuments)
430 changedDocuments->remove(this);
431 delete m_tokenizer;
432 m_document.resetSkippingRef(0);
433 delete m_styleSelector;
434 delete m_docLoader;
435
436 if (m_renderArena) {
437 delete m_renderArena;
438 m_renderArena = 0;
439 }
440
441 #if ENABLE(XSLT)
442 xmlFreeDoc((xmlDocPtr)m_transformSource);
443 #endif
444
445 #if ENABLE(XBL)
446 delete m_bindingManager;
447 #endif
448
449 deleteAllValues(m_markers);
450
451 clearAXObjectCache();
452
453 m_decoder = 0;
454
455 unsigned count = sizeof(m_nameCollectionInfo) / sizeof(m_nameCollectionInfo[ 0]);
456 for (unsigned i = 0; i < count; i++)
457 deleteAllValues(m_nameCollectionInfo[i]);
458
459 #if ENABLE(DATABASE)
460 if (m_databaseThread) {
461 ASSERT(m_databaseThread->terminationRequested());
462 m_databaseThread = 0;
463 }
464 #endif
465
466 if (m_styleSheets)
467 m_styleSheets->documentDestroyed();
468
469 m_document = 0;
470 }
471
472 void Document::resetLinkColor()
473 {
474 m_linkColor = Color(0, 0, 238);
475 }
476
477 void Document::resetVisitedLinkColor()
478 {
479 m_visitedLinkColor = Color(85, 26, 139);
480 }
481
482 void Document::resetActiveLinkColor()
483 {
484 m_activeLinkColor.setNamedColor("red");
485 }
486
487 void Document::setDocType(PassRefPtr<DocumentType> docType)
488 {
489 // This should never be called more than once.
490 // Note: This is not a public DOM method and can only be called by the parse r.
491 ASSERT(!m_docType || !docType);
492 if (m_docType && docType)
493 return;
494 m_docType = docType;
495 if (m_docType)
496 m_docType->setDocument(this);
497 determineParseMode();
498 }
499
500 DOMImplementation* Document::implementation() const
501 {
502 if (!m_implementation)
503 m_implementation = DOMImplementation::create();
504 return m_implementation.get();
505 }
506
507 void Document::childrenChanged(bool changedByParser, Node* beforeChange, Node* a fterChange, int childCountDelta)
508 {
509 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, c hildCountDelta);
510
511 // Invalidate the document element we have cached in case it was replaced.
512 m_documentElement = 0;
513 }
514
515 Element* Document::documentElement() const
516 {
517 if (!m_documentElement) {
518 Node* n = firstChild();
519 while (n && !n->isElementNode())
520 n = n->nextSibling();
521 m_documentElement = static_cast<Element*>(n);
522 }
523
524 return m_documentElement.get();
525 }
526
527 PassRefPtr<Element> Document::createElement(const AtomicString& name, ExceptionC ode& ec)
528 {
529 if (!isValidName(name)) {
530 ec = INVALID_CHARACTER_ERR;
531 return 0;
532 }
533
534 if (m_isXHTML)
535 return HTMLElementFactory::createHTMLElement(name, this, 0, false);
536
537 return createElement(QualifiedName(nullAtom, name, nullAtom), false, ec);
538 }
539
540 PassRefPtr<DocumentFragment> Document::createDocumentFragment()
541 {
542 return new DocumentFragment(document());
543 }
544
545 PassRefPtr<Text> Document::createTextNode(const String& data)
546 {
547 return new Text(this, data);
548 }
549
550 PassRefPtr<Comment> Document::createComment(const String& data)
551 {
552 return new Comment(this, data);
553 }
554
555 PassRefPtr<CDATASection> Document::createCDATASection(const String& data, Except ionCode& ec)
556 {
557 if (isHTMLDocument()) {
558 ec = NOT_SUPPORTED_ERR;
559 return 0;
560 }
561 return new CDATASection(this, data);
562 }
563
564 PassRefPtr<ProcessingInstruction> Document::createProcessingInstruction(const St ring& target, const String& data, ExceptionCode& ec)
565 {
566 if (!isValidName(target)) {
567 ec = INVALID_CHARACTER_ERR;
568 return 0;
569 }
570 if (isHTMLDocument()) {
571 ec = NOT_SUPPORTED_ERR;
572 return 0;
573 }
574 return new ProcessingInstruction(this, target, data);
575 }
576
577 PassRefPtr<EntityReference> Document::createEntityReference(const String& name, ExceptionCode& ec)
578 {
579 if (!isValidName(name)) {
580 ec = INVALID_CHARACTER_ERR;
581 return 0;
582 }
583 if (isHTMLDocument()) {
584 ec = NOT_SUPPORTED_ERR;
585 return 0;
586 }
587 return new EntityReference(this, name);
588 }
589
590 PassRefPtr<EditingText> Document::createEditingTextNode(const String& text)
591 {
592 return new EditingText(this, text);
593 }
594
595 PassRefPtr<CSSStyleDeclaration> Document::createCSSStyleDeclaration()
596 {
597 return CSSMutableStyleDeclaration::create();
598 }
599
600 PassRefPtr<Node> Document::importNode(Node* importedNode, bool deep, ExceptionCo de& ec)
601 {
602 ec = 0;
603
604 if (!importedNode
605 #if ENABLE(SVG) && ENABLE(DASHBOARD_SUPPORT)
606 || (importedNode->isSVGElement() && page() && page()->settings()->usesDa shboardBackwardCompatibilityMode())
607 #endif
608 ) {
609 ec = NOT_SUPPORTED_ERR;
610 return 0;
611 }
612
613 switch (importedNode->nodeType()) {
614 case TEXT_NODE:
615 return createTextNode(importedNode->nodeValue());
616 case CDATA_SECTION_NODE:
617 return createCDATASection(importedNode->nodeValue(), ec);
618 case ENTITY_REFERENCE_NODE:
619 return createEntityReference(importedNode->nodeName(), ec);
620 case PROCESSING_INSTRUCTION_NODE:
621 return createProcessingInstruction(importedNode->nodeName(), importe dNode->nodeValue(), ec);
622 case COMMENT_NODE:
623 return createComment(importedNode->nodeValue());
624 case ELEMENT_NODE: {
625 Element* oldElement = static_cast<Element*>(importedNode);
626 RefPtr<Element> newElement = createElementNS(oldElement->namespaceUR I(), oldElement->tagQName().toString(), ec);
627
628 if (ec)
629 return 0;
630
631 NamedAttrMap* attrs = oldElement->attributes(true);
632 if (attrs) {
633 unsigned length = attrs->length();
634 for (unsigned i = 0; i < length; i++) {
635 Attribute* attr = attrs->attributeItem(i);
636 newElement->setAttribute(attr->name(), attr->value().impl(), ec);
637 if (ec)
638 return 0;
639 }
640 }
641
642 newElement->copyNonAttributeProperties(oldElement);
643
644 if (deep) {
645 for (Node* oldChild = oldElement->firstChild(); oldChild; oldChi ld = oldChild->nextSibling()) {
646 RefPtr<Node> newChild = importNode(oldChild, true, ec);
647 if (ec)
648 return 0;
649 newElement->appendChild(newChild.release(), ec);
650 if (ec)
651 return 0;
652 }
653 }
654
655 return newElement.release();
656 }
657 case ATTRIBUTE_NODE: {
658 RefPtr<Attr> newAttr = new Attr(0, this, static_cast<Attr*>(imported Node)->attr()->clone());
659 newAttr->createTextChild();
660 return newAttr.release();
661 }
662 case DOCUMENT_FRAGMENT_NODE: {
663 DocumentFragment* oldFragment = static_cast<DocumentFragment*>(impor tedNode);
664 RefPtr<DocumentFragment> newFragment = createDocumentFragment();
665 if (deep) {
666 for (Node* oldChild = oldFragment->firstChild(); oldChild; oldCh ild = oldChild->nextSibling()) {
667 RefPtr<Node> newChild = importNode(oldChild, true, ec);
668 if (ec)
669 return 0;
670 newFragment->appendChild(newChild.release(), ec);
671 if (ec)
672 return 0;
673 }
674 }
675
676 return newFragment.release();
677 }
678 case ENTITY_NODE:
679 case NOTATION_NODE:
680 // FIXME: It should be possible to import these node types, however in DOM3 the DocumentType is readonly, so there isn't much sense in doing that.
681 // Ability to add these imported nodes to a DocumentType will be con sidered for addition to a future release of the DOM.
682 case DOCUMENT_NODE:
683 case DOCUMENT_TYPE_NODE:
684 case XPATH_NAMESPACE_NODE:
685 break;
686 }
687
688 ec = NOT_SUPPORTED_ERR;
689 return 0;
690 }
691
692
693 PassRefPtr<Node> Document::adoptNode(PassRefPtr<Node> source, ExceptionCode& ec)
694 {
695 if (!source) {
696 ec = NOT_SUPPORTED_ERR;
697 return 0;
698 }
699
700 if (source->isReadOnlyNode()) {
701 ec = NO_MODIFICATION_ALLOWED_ERR;
702 return 0;
703 }
704
705 switch (source->nodeType()) {
706 case ENTITY_NODE:
707 case NOTATION_NODE:
708 case DOCUMENT_NODE:
709 case DOCUMENT_TYPE_NODE:
710 case XPATH_NAMESPACE_NODE:
711 ec = NOT_SUPPORTED_ERR;
712 return 0;
713 case ATTRIBUTE_NODE: {
714 Attr* attr = static_cast<Attr*>(source.get());
715 if (attr->ownerElement())
716 attr->ownerElement()->removeAttributeNode(attr, ec);
717 attr->setSpecified(true);
718 break;
719 }
720 default:
721 if (source->parentNode())
722 source->parentNode()->removeChild(source.get(), ec);
723 }
724
725 for (Node* node = source.get(); node; node = node->traverseNextNode(source.g et()))
726 node->setDocument(this);
727
728 return source;
729 }
730
731 bool Document::hasPrefixNamespaceMismatch(const QualifiedName& qName)
732 {
733 static const AtomicString xmlnsNamespaceURI("http://www.w3.org/2000/xmlns/") ;
734 static const AtomicString xmlns("xmlns");
735 static const AtomicString xml("xml");
736
737 // These checks are from DOM Core Level 2, createElementNS
738 // http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-DocCrElNS
739 if (!qName.prefix().isEmpty() && qName.namespaceURI().isNull()) // createEle mentNS(null, "html:div")
740 return true;
741 if (qName.prefix() == xml && qName.namespaceURI() != XMLNames::xmlNamespaceU RI) // createElementNS("http://www.example.com", "xml:lang")
742 return true;
743
744 // Required by DOM Level 3 Core and unspecified by DOM Level 2 Core:
745 // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-DocC rElNS
746 // createElementNS("http://www.w3.org/2000/xmlns/", "foo:bar"), createElemen tNS(null, "xmlns:bar")
747 if ((qName.prefix() == xmlns && qName.namespaceURI() != xmlnsNamespaceURI) | | (qName.prefix() != xmlns && qName.namespaceURI() == xmlnsNamespaceURI))
748 return true;
749
750 return false;
751 }
752
753 // FIXME: This should really be in a possible ElementFactory class
754 PassRefPtr<Element> Document::createElement(const QualifiedName& qName, bool cre atedByParser, ExceptionCode& ec)
755 {
756 RefPtr<Element> e;
757
758 // FIXME: Use registered namespaces and look up in a hash to find the right factory.
759 if (qName.namespaceURI() == xhtmlNamespaceURI)
760 e = HTMLElementFactory::createHTMLElement(qName.localName(), this, 0, cr eatedByParser);
761 #if ENABLE(SVG)
762 else if (qName.namespaceURI() == SVGNames::svgNamespaceURI)
763 e = SVGElementFactory::createSVGElement(qName, this, createdByParser);
764 #endif
765
766 if (!e)
767 e = new Element(qName, document());
768
769 // FIXME: The element factories should be fixed to not ignore qName.prefix()
770 // Instead they should pass the entire qName into element creation so we don 't
771 // need to manually set the prefix after creation.
772 // Then this code can become ASSERT(qName == e.qname());
773 // and Document::createElement can stop taking ExceptionCode& as well.
774 if (e && !qName.prefix().isNull()) {
775 ec = 0;
776 e->setPrefix(qName.prefix(), ec);
777 if (ec)
778 return 0;
779 }
780
781 return e.release();
782 }
783
784 PassRefPtr<Element> Document::createElementNS(const String& namespaceURI, const String& qualifiedName, ExceptionCode& ec)
785 {
786 String prefix, localName;
787 if (!parseQualifiedName(qualifiedName, prefix, localName, ec))
788 return 0;
789
790 QualifiedName qName(prefix, localName, namespaceURI);
791 if (hasPrefixNamespaceMismatch(qName)) {
792 ec = NAMESPACE_ERR;
793 return 0;
794 }
795
796 return createElement(qName, false, ec);
797 }
798
799 Element* Document::getElementById(const AtomicString& elementId) const
800 {
801 if (elementId.isEmpty())
802 return 0;
803
804 Element* element = m_elementsById.get(elementId.impl());
805 if (element)
806 return element;
807
808 if (m_duplicateIds.contains(elementId.impl())) {
809 // We know there's at least one node with this id, but we don't know wha t the first one is.
810 for (Node *n = traverseNextNode(); n != 0; n = n->traverseNextNode()) {
811 if (n->isElementNode()) {
812 element = static_cast<Element*>(n);
813 if (element->hasID() && element->getAttribute(idAttr) == element Id) {
814 m_duplicateIds.remove(elementId.impl());
815 m_elementsById.set(elementId.impl(), element);
816 return element;
817 }
818 }
819 }
820 ASSERT_NOT_REACHED();
821 }
822 return 0;
823 }
824
825 String Document::readyState() const
826 {
827 if (Frame* f = frame()) {
828 if (f->loader()->isComplete())
829 return "complete";
830 if (parsing())
831 return "loading";
832 return "loaded";
833 // FIXME: What does "interactive" mean?
834 // FIXME: Missing support for "uninitialized".
835 }
836 return String();
837 }
838
839 String Document::inputEncoding() const
840 {
841 if (TextResourceDecoder* d = decoder())
842 return d->encoding().name();
843 return String();
844 }
845
846 String Document::defaultCharset() const
847 {
848 if (Settings* settings = this->settings())
849 return settings->defaultTextEncodingName();
850 return String();
851 }
852
853 void Document::setCharset(const String& charset)
854 {
855 if (!decoder())
856 return;
857 decoder()->setEncoding(charset, TextResourceDecoder::UserChosenEncoding);
858 }
859
860 UScriptCode Document::dominantScript() const
861 {
862 struct EncodingScript {
863 const char* encoding;
864 UScriptCode script;
865 };
866
867 // inputEncoding() always returns a canonical name. We use
868 // MIME names and IANA names (if the former is not available).
869 static const EncodingScript encodingScriptList[] = {
870 { "GB2312", USCRIPT_SIMPLIFIED_HAN },
871 { "GBK", USCRIPT_SIMPLIFIED_HAN },
872 { "GB18030", USCRIPT_SIMPLIFIED_HAN },
873 { "Big5", USCRIPT_TRADITIONAL_HAN },
874 { "Big5-HKSCS", USCRIPT_TRADITIONAL_HAN },
875 { "Shift_JIS", USCRIPT_HIRAGANA},
876 { "EUC-JP", USCRIPT_HIRAGANA }, // Japanese (USCRIPT_JAPANESE)
877 { "ISO-2022-KR", USCRIPT_HIRAGANA },
878 { "EUC-KR", USCRIPT_HANGUL }, // Korean (USCRIPT_KOREAN)
879 { "TIS-620", USCRIPT_THAI },
880 { "ISO-8859-1", USCRIPT_LATIN },
881 { "ISO-8859-15", USCRIPT_LATIN },
882 { "windows-1252", USCRIPT_LATIN },
883 { "ISO-8859-2", USCRIPT_LATIN },
884 { "windows-1250", USCRIPT_LATIN },
885 { "ISO-8859-3", USCRIPT_LATIN },
886 { "ISO-8859-4", USCRIPT_LATIN },
887 { "ISO-8859-13", USCRIPT_LATIN },
888 { "windows-1257", USCRIPT_LATIN },
889 { "ISO-8859-5", USCRIPT_CYRILLIC },
890 { "windows-1251", USCRIPT_CYRILLIC },
891 { "KOI8-R", USCRIPT_CYRILLIC },
892 { "KOI8-U", USCRIPT_CYRILLIC },
893 { "ISO-8859-6", USCRIPT_ARABIC },
894 { "windows-1256", USCRIPT_ARABIC },
895 { "ISO-8859-7", USCRIPT_GREEK },
896 { "windows-1253", USCRIPT_GREEK },
897 { "ISO-8859-8", USCRIPT_HEBREW },
898 { "windows-1255", USCRIPT_HEBREW },
899 { "ISO-8859-9", USCRIPT_LATIN }, // Turkish
900 { "windows-1254", USCRIPT_LATIN },
901 { "ISO-8859-10", USCRIPT_LATIN }, // Nordic
902 { "ISO-8859-14", USCRIPT_LATIN }, // Celtic
903 { "ISO-8859-16", USCRIPT_LATIN }, // Romanian
904 { "windows-1258", USCRIPT_LATIN }, // Vietnamese
905 };
906
907 static HashMap<String, UScriptCode> encodingScriptMap;
908
909 if (encodingScriptMap.isEmpty()) {
910 for (unsigned i = 0; i < sizeof(encodingScriptList) / sizeof(encodingScr iptList[0]); ++i)
911 encodingScriptMap.set(encodingScriptList[i].encoding,
912 encodingScriptList[i].script);
913 }
914
915 if (m_dominantScript != USCRIPT_INVALID_CODE)
916 return m_dominantScript;
917 String encoding = inputEncoding();
918 if (encoding.isEmpty())
919 return m_dominantScript;
920
921 HashMap<String, UScriptCode>::iterator it = encodingScriptMap.find(encoding) ;
922 if (it != encodingScriptMap.end())
923 m_dominantScript = it->second;
924 else
925 // TODO(jungshik) : should return a script corresponding to the locale.
926 m_dominantScript = USCRIPT_COMMON;
927 return m_dominantScript;
928 }
929
930 void Document::setXMLVersion(const String& version, ExceptionCode& ec)
931 {
932 if (!implementation()->hasFeature("XML", String())) {
933 ec = NOT_SUPPORTED_ERR;
934 return;
935 }
936
937 // FIXME: Also raise NOT_SUPPORTED_ERR if the version is set to a value that is not supported by this Document.
938
939 m_xmlVersion = version;
940 }
941
942 void Document::setXMLStandalone(bool standalone, ExceptionCode& ec)
943 {
944 if (!implementation()->hasFeature("XML", String())) {
945 ec = NOT_SUPPORTED_ERR;
946 return;
947 }
948
949 m_xmlStandalone = standalone;
950 }
951
952 void Document::setDocumentURI(const String& uri)
953 {
954 m_documentURI = uri;
955 updateBaseURL();
956 }
957
958 KURL Document::baseURI() const
959 {
960 return m_baseURL;
961 }
962
963 Element* Document::elementFromPoint(int x, int y) const
964 {
965 if (!renderer())
966 return 0;
967
968 HitTestRequest request(true, true);
969 HitTestResult result(IntPoint(x, y));
970 renderer()->layer()->hitTest(request, result);
971
972 Node* n = result.innerNode();
973 while (n && !n->isElementNode())
974 n = n->parentNode();
975 if (n)
976 n = n->shadowAncestorNode();
977 return static_cast<Element*>(n);
978 }
979
980 void Document::addElementById(const AtomicString& elementId, Element* element)
981 {
982 typedef HashMap<AtomicStringImpl*, Element*>::iterator iterator;
983 if (!m_duplicateIds.contains(elementId.impl())) {
984 // Fast path. The ID is not already in m_duplicateIds, so we assume that it's
985 // also not already in m_elementsById and do an add. If that add succeed s, we're done.
986 pair<iterator, bool> addResult = m_elementsById.add(elementId.impl(), el ement);
987 if (addResult.second)
988 return;
989 // The add failed, so this ID was already cached in m_elementsById.
990 // There are multiple elements with this ID. Remove the m_elementsById
991 // cache for this ID so getElementById searches for it next time it is c alled.
992 m_elementsById.remove(addResult.first);
993 m_duplicateIds.add(elementId.impl());
994 } else {
995 // There are multiple elements with this ID. If it exists, remove the m_ elementsById
996 // cache for this ID so getElementById searches for it next time it is c alled.
997 iterator cachedItem = m_elementsById.find(elementId.impl());
998 if (cachedItem != m_elementsById.end()) {
999 m_elementsById.remove(cachedItem);
1000 m_duplicateIds.add(elementId.impl());
1001 }
1002 }
1003 m_duplicateIds.add(elementId.impl());
1004 }
1005
1006 void Document::removeElementById(const AtomicString& elementId, Element* element )
1007 {
1008 if (m_elementsById.get(elementId.impl()) == element)
1009 m_elementsById.remove(elementId.impl());
1010 else
1011 m_duplicateIds.remove(elementId.impl());
1012 }
1013
1014 Element* Document::getElementByAccessKey(const String& key) const
1015 {
1016 if (key.isEmpty())
1017 return 0;
1018 if (!m_accessKeyMapValid) {
1019 for (Node* n = firstChild(); n; n = n->traverseNextNode()) {
1020 if (!n->isElementNode())
1021 continue;
1022 Element* element = static_cast<Element*>(n);
1023 const AtomicString& accessKey = element->getAttribute(accesskeyAttr) ;
1024 if (!accessKey.isEmpty())
1025 m_elementsByAccessKey.set(accessKey.impl(), element);
1026 }
1027 m_accessKeyMapValid = true;
1028 }
1029 return m_elementsByAccessKey.get(key.impl());
1030 }
1031
1032 void Document::updateTitle()
1033 {
1034 if (Frame* f = frame())
1035 f->loader()->setTitle(m_title);
1036 }
1037
1038 void Document::setTitle(const String& title, Element* titleElement)
1039 {
1040 if (!titleElement) {
1041 // Title set by JavaScript -- overrides any title elements.
1042 m_titleSetExplicitly = true;
1043 if (!isHTMLDocument())
1044 m_titleElement = 0;
1045 else if (!m_titleElement) {
1046 if (HTMLElement* headElement = head()) {
1047 ExceptionCode ec = 0;
1048 m_titleElement = createElement("title", ec);
1049 ASSERT(!ec);
1050 headElement->appendChild(m_titleElement, ec);
1051 ASSERT(!ec);
1052 }
1053 }
1054 } else if (titleElement != m_titleElement) {
1055 if (m_titleElement || m_titleSetExplicitly)
1056 // Only allow the first title element to change the title -- others have no effect.
1057 return;
1058 m_titleElement = titleElement;
1059 }
1060
1061 if (m_title == title)
1062 return;
1063
1064 m_title = title;
1065 updateTitle();
1066
1067 if (m_titleSetExplicitly && m_titleElement && m_titleElement->hasTagName(tit leTag))
1068 static_cast<HTMLTitleElement*>(m_titleElement.get())->setText(m_title);
1069 }
1070
1071 void Document::removeTitle(Element* titleElement)
1072 {
1073 if (m_titleElement != titleElement)
1074 return;
1075
1076 m_titleElement = 0;
1077 m_titleSetExplicitly = false;
1078
1079 // Update title based on first title element in the head, if one exists.
1080 if (HTMLElement* headElement = head()) {
1081 for (Node* e = headElement->firstChild(); e; e = e->nextSibling())
1082 if (e->hasTagName(titleTag)) {
1083 HTMLTitleElement* titleElement = static_cast<HTMLTitleElement*>( e);
1084 setTitle(titleElement->text(), titleElement);
1085 break;
1086 }
1087 }
1088
1089 if (!m_titleElement && !m_title.isEmpty()) {
1090 m_title = "";
1091 updateTitle();
1092 }
1093 }
1094
1095 String Document::nodeName() const
1096 {
1097 return "#document";
1098 }
1099
1100 Node::NodeType Document::nodeType() const
1101 {
1102 return DOCUMENT_NODE;
1103 }
1104
1105 FrameView* Document::view() const
1106 {
1107 return m_frame ? m_frame->view() : 0;
1108 }
1109
1110 Page* Document::page() const
1111 {
1112 return m_frame ? m_frame->page() : 0;
1113 }
1114
1115 Settings* Document::settings() const
1116 {
1117 return m_frame ? m_frame->settings() : 0;
1118 }
1119
1120 PassRefPtr<Range> Document::createRange()
1121 {
1122 return Range::create(this);
1123 }
1124
1125 PassRefPtr<NodeIterator> Document::createNodeIterator(Node* root, unsigned whatT oShow,
1126 PassRefPtr<NodeFilter> filter, bool expandEntityReferences, ExceptionCode& e c)
1127 {
1128 if (!root) {
1129 ec = NOT_SUPPORTED_ERR;
1130 return 0;
1131 }
1132 return NodeIterator::create(root, whatToShow, filter, expandEntityReferences );
1133 }
1134
1135 PassRefPtr<TreeWalker> Document::createTreeWalker(Node *root, unsigned whatToSho w,
1136 PassRefPtr<NodeFilter> filter, bool expandEntityReferences, ExceptionCode& e c)
1137 {
1138 if (!root) {
1139 ec = NOT_SUPPORTED_ERR;
1140 return 0;
1141 }
1142 return TreeWalker::create(root, whatToShow, filter, expandEntityReferences);
1143 }
1144
1145 void Document::setDocumentChanged(bool b)
1146 {
1147 if (b) {
1148 if (!m_docChanged) {
1149 if (!changedDocuments)
1150 changedDocuments = new HashSet<Document*>;
1151 changedDocuments->add(this);
1152 }
1153 if (m_accessKeyMapValid) {
1154 m_accessKeyMapValid = false;
1155 m_elementsByAccessKey.clear();
1156 }
1157 } else {
1158 if (m_docChanged && changedDocuments)
1159 changedDocuments->remove(this);
1160 }
1161
1162 m_docChanged = b;
1163 }
1164
1165 void Document::recalcStyle(StyleChange change)
1166 {
1167 // we should not enter style recalc while painting
1168 if (frame() && frame()->isPainting()) {
1169 ASSERT(!frame()->isPainting());
1170 return;
1171 }
1172
1173 if (m_inStyleRecalc)
1174 return; // Guard against re-entrancy. -dwh
1175
1176 m_inStyleRecalc = true;
1177 suspendPostAttachCallbacks();
1178
1179 ASSERT(!renderer() || renderArena());
1180 if (!renderer() || !renderArena())
1181 goto bail_out;
1182
1183 if (change == Force) {
1184 // style selector may set this again during recalc
1185 m_hasNodesWithPlaceholderStyle = false;
1186
1187 RenderStyle* oldStyle = renderer()->style();
1188 if (oldStyle)
1189 oldStyle->ref();
1190 RenderStyle* _style = new (m_renderArena) RenderStyle();
1191 _style->ref();
1192 _style->setDisplay(BLOCK);
1193 _style->setVisuallyOrdered(visuallyOrdered);
1194 _style->setZoom(frame()->pageZoomFactor());
1195 m_styleSelector->setStyle(_style);
1196
1197 FontDescription fontDescription;
1198 fontDescription.setUsePrinterFont(printing());
1199 // TODO(jungshik): Eventually, we need to derive the dominant script
1200 // for the current node based on 'xml:lang' and 'lang' specified for
1201 // it or inherited from its parent rather than using the document-wide
1202 // value (inferred from charset). Note also that it does not work
1203 // for 'script-agnostic' charsets like UTF-8. In that case, Firefox
1204 // uses the script corresponding to the application locale.
1205 // While a document is loaded, this function is called multiple
1206 // times. At the beginning, the document charset is not known and
1207 // dominantScript remains invalid. Only when it's determined, we
1208 // change the font accordingly.
1209 // See http://bugs.webkit.org/show_bug.cgi?id=10874 and
1210 // https://bugs.webkit.org/show_bug.cgi?id=18085
1211 UScriptCode script = dominantScript();
1212 if (script != USCRIPT_INVALID_CODE)
1213 fontDescription.setDominantScript(script);
1214 if (Settings* settings = this->settings()) {
1215 fontDescription.setRenderingMode(settings->fontRenderingMode());
1216 if (printing() && !settings->shouldPrintBackgrounds())
1217 _style->setForceBackgroundsToWhite(true);
1218 const AtomicString& stdfont = settings->standardFontFamily();
1219 if (!stdfont.isEmpty()) {
1220 fontDescription.firstFamily().setFamily(stdfont);
1221 FontFamily& currFamily = fontDescription.firstFamily();
1222 if (script != USCRIPT_INVALID_CODE) {
1223 // TODO(jungshik) : I might as well modify |genericFamily| of
1224 // |fontDescription| here, but I'm wary of a potential breakag e.
1225 // For now, just use a temporary variable.
1226 FontDescription tmpDescription;
1227 tmpDescription.setGenericFamily(FontDescription::StandardFamil y);
1228 AtomicString docFont = FontCache::getGenericFontForScript(
1229 script, tmpDescription);
1230 if (!docFont.isEmpty()) {
1231 RefPtr<SharedFontFamily> newFamily(SharedFontFamily::creat e());
1232 newFamily->setFamily(docFont);
1233 currFamily.appendFamily(newFamily);
1234 currFamily = *newFamily;
1235 }
1236 }
1237 currFamily.appendFamily(0);
1238 }
1239 fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1) ;
1240 m_styleSelector->setFontSize(fontDescription, m_styleSelector->fontS izeForKeyword(CSSValueMedium, inCompatMode(), false));
1241 }
1242
1243 _style->setFontDescription(fontDescription);
1244 _style->font().update(m_styleSelector->fontSelector());
1245 if (inCompatMode())
1246 _style->setHtmlHacks(true); // enable html specific rendering tricks
1247
1248 StyleChange ch = diff(_style, oldStyle);
1249 if (renderer() && ch != NoChange)
1250 renderer()->setStyle(_style);
1251 if (change != Force)
1252 change = ch;
1253
1254 _style->deref(m_renderArena);
1255 if (oldStyle)
1256 oldStyle->deref(m_renderArena);
1257 }
1258
1259 for (Node* n = firstChild(); n; n = n->nextSibling())
1260 if (change >= Inherit || n->hasChangedChild() || n->changed())
1261 n->recalcStyle(change);
1262
1263 if (changed() && view())
1264 view()->layout();
1265
1266 bail_out:
1267 setChanged(NoStyleChange);
1268 setHasChangedChild(false);
1269 setDocumentChanged(false);
1270
1271 resumePostAttachCallbacks();
1272 m_inStyleRecalc = false;
1273
1274 // If we wanted to call implicitClose() during recalcStyle, do so now that w e're finished.
1275 if (m_closeAfterStyleRecalc) {
1276 m_closeAfterStyleRecalc = false;
1277 implicitClose();
1278 }
1279 }
1280
1281 void Document::updateRendering()
1282 {
1283 if (hasChangedChild() && !inPageCache())
1284 recalcStyle(NoChange);
1285
1286 // Tell the animation controller that the style is available and it can star t animations
1287 if (m_frame)
1288 m_frame->animation()->styleAvailable();
1289 }
1290
1291 void Document::updateDocumentsRendering()
1292 {
1293 if (!changedDocuments)
1294 return;
1295
1296 while (changedDocuments->size()) {
1297 HashSet<Document*>::iterator it = changedDocuments->begin();
1298 Document* doc = *it;
1299 changedDocuments->remove(it);
1300
1301 doc->m_docChanged = false;
1302 doc->updateRendering();
1303 }
1304 }
1305
1306 void Document::updateLayout()
1307 {
1308 if (Element* oe = ownerElement())
1309 oe->document()->updateLayout();
1310
1311 // FIXME: Dave Hyatt's pretty sure we can remove this because layout calls r ecalcStyle as needed.
1312 updateRendering();
1313
1314 // Only do a layout if changes have occurred that make it necessary.
1315 FrameView* v = view();
1316 if (v && renderer() && (v->layoutPending() || renderer()->needsLayout()))
1317 v->layout();
1318 }
1319
1320 // FIXME: This is a bad idea and needs to be removed eventually.
1321 // Other browsers load stylesheets before they continue parsing the web page.
1322 // Since we don't, we can run JavaScript code that needs answers before the
1323 // stylesheets are loaded. Doing a layout ignoring the pending stylesheets
1324 // lets us get reasonable answers. The long term solution to this problem is
1325 // to instead suspend JavaScript execution.
1326 void Document::updateLayoutIgnorePendingStylesheets()
1327 {
1328 bool oldIgnore = m_ignorePendingStylesheets;
1329
1330 if (!haveStylesheetsLoaded()) {
1331 m_ignorePendingStylesheets = true;
1332 // FIXME: We are willing to attempt to suppress painting with outdated s tyle info only once. Our assumption is that it would be
1333 // dangerous to try to stop it a second time, after page content has alr eady been loaded and displayed
1334 // with accurate style information. (Our suppression involves blanking the whole page at the
1335 // moment. If it were more refined, we might be able to do something be tter.)
1336 // It's worth noting though that this entire method is a hack, since wha t we really want to do is
1337 // suspend JS instead of doing a layout with inaccurate information.
1338 if (body() && !body()->renderer() && m_pendingSheetLayout == NoLayoutWit hPendingSheets) {
1339 m_pendingSheetLayout = DidLayoutWithPendingSheets;
1340 updateStyleSelector();
1341 } else if (m_hasNodesWithPlaceholderStyle)
1342 // If new nodes have been added or style recalc has been done with s tyle sheets still pending, some nodes
1343 // may not have had their real style calculated yet. Normally this g ets cleaned when style sheets arrive
1344 // but here we need up-to-date style immediatly.
1345 recalcStyle(Force);
1346 }
1347
1348 updateLayout();
1349
1350 m_ignorePendingStylesheets = oldIgnore;
1351 }
1352
1353 void Document::attach()
1354 {
1355 ASSERT(!attached());
1356 ASSERT(!m_inPageCache);
1357 ASSERT(!m_axObjectCache);
1358
1359 if (!m_renderArena)
1360 m_renderArena = new RenderArena();
1361
1362 // Create the rendering tree
1363 setRenderer(new (m_renderArena) RenderView(this, view()));
1364
1365 if (!m_styleSelector) {
1366 bool matchAuthorAndUserStyles = true;
1367 if (Settings* docSettings = settings())
1368 matchAuthorAndUserStyles = docSettings->authorAndUserStylesEnabled() ;
1369 m_styleSelector = new CSSStyleSelector(this, userStyleSheet(), m_styleSh eets.get(), m_mappedElementSheet.get(), !inCompatMode(), matchAuthorAndUserStyle s);
1370 }
1371
1372 recalcStyle(Force);
1373
1374 RenderObject* render = renderer();
1375 setRenderer(0);
1376
1377 ContainerNode::attach();
1378
1379 setRenderer(render);
1380 }
1381
1382 void Document::detach()
1383 {
1384 ASSERT(attached());
1385 ASSERT(!m_inPageCache);
1386
1387 clearAXObjectCache();
1388
1389 RenderObject* render = renderer();
1390
1391 // indicate destruction mode, i.e. attached() but renderer == 0
1392 setRenderer(0);
1393
1394 // Empty out these lists as a performance optimization, since detaching
1395 // all the individual render objects will cause all the RenderImage
1396 // objects to remove themselves from the lists.
1397 m_imageLoadEventDispatchSoonList.clear();
1398 m_imageLoadEventDispatchingList.clear();
1399
1400 m_hoverNode = 0;
1401 m_focusedNode = 0;
1402 m_activeNode = 0;
1403
1404 ContainerNode::detach();
1405
1406 if (render)
1407 render->destroy();
1408
1409 // This is required, as our Frame might delete itself as soon as it detaches
1410 // us. However, this violates Node::detach() symantics, as it's never
1411 // possible to re-attach. Eventually Document::detach() should be renamed
1412 // or this call made explicit in each of the callers of Document::detach().
1413 clearFramePointer();
1414
1415 if (m_renderArena) {
1416 delete m_renderArena;
1417 m_renderArena = 0;
1418 }
1419 }
1420
1421 void Document::clearFramePointer()
1422 {
1423 m_frame = 0;
1424 }
1425
1426 void Document::removeAllEventListenersFromAllNodes()
1427 {
1428 m_windowEventListeners.clear();
1429 removeAllDisconnectedNodeEventListeners();
1430 for (Node *n = this; n; n = n->traverseNextNode()) {
1431 if (!n->isEventTargetNode())
1432 continue;
1433 EventTargetNodeCast(n)->removeAllEventListeners();
1434 }
1435 }
1436
1437 void Document::registerDisconnectedNodeWithEventListeners(Node* node)
1438 {
1439 m_disconnectedNodesWithEventListeners.add(node);
1440 }
1441
1442 void Document::unregisterDisconnectedNodeWithEventListeners(Node* node)
1443 {
1444 m_disconnectedNodesWithEventListeners.remove(node);
1445 }
1446
1447 void Document::removeAllDisconnectedNodeEventListeners()
1448 {
1449 HashSet<Node*>::iterator end = m_disconnectedNodesWithEventListeners.end();
1450 for (HashSet<Node*>::iterator i = m_disconnectedNodesWithEventListeners.begi n(); i != end; ++i)
1451 EventTargetNodeCast(*i)->removeAllEventListeners();
1452 m_disconnectedNodesWithEventListeners.clear();
1453 }
1454
1455 void Document::clearAXObjectCache()
1456 {
1457 // clear cache in top document
1458 if (m_axObjectCache) {
1459 delete m_axObjectCache;
1460 m_axObjectCache = 0;
1461 return;
1462 }
1463
1464 // ask the top-level document to clear its cache
1465 Document* doc = topDocument();
1466 if (doc != this)
1467 doc->clearAXObjectCache();
1468 }
1469
1470 AXObjectCache* Document::axObjectCache() const
1471 {
1472 // The only document that actually has a AXObjectCache is the top-level
1473 // document. This is because we need to be able to get from any WebCoreAXOb ject
1474 // to any other WebCoreAXObject on the same page. Using a single cache allo ws
1475 // lookups across nested webareas (i.e. multiple documents).
1476
1477 if (m_axObjectCache) {
1478 // return already known top-level cache
1479 if (!ownerElement())
1480 return m_axObjectCache;
1481
1482 // In some pages with frames, the cache is created before the sub-webare a is
1483 // inserted into the tree. Here, we catch that case and just toss the o ld
1484 // cache and start over.
1485 // NOTE: This recovery may no longer be needed. I have been unable to tr igger
1486 // it again. See rdar://5794454
1487 // FIXME: Can this be fixed when inserting the subframe instead of now?
1488 // FIXME: If this function was called to get the cache in order to remov e
1489 // an AXObject, we are now deleting the cache as a whole and returning a
1490 // new empty cache that does not contain the AXObject! That should actua lly
1491 // be OK. I am concerned about other cases like this where accessing the
1492 // cache blows away the AXObject being operated on.
1493 delete m_axObjectCache;
1494 m_axObjectCache = 0;
1495 }
1496
1497 // ask the top-level document for its cache
1498 Document* doc = topDocument();
1499 if (doc != this)
1500 return doc->axObjectCache();
1501
1502 // this is the top-level document, so install a new cache
1503 m_axObjectCache = new AXObjectCache;
1504 return m_axObjectCache;
1505 }
1506
1507 void Document::setVisuallyOrdered()
1508 {
1509 visuallyOrdered = true;
1510 if (renderer())
1511 renderer()->style()->setVisuallyOrdered(true);
1512 }
1513
1514 Tokenizer* Document::createTokenizer()
1515 {
1516 // FIXME: this should probably pass the frame instead
1517 return new XMLTokenizer(this, view());
1518 }
1519
1520 void Document::open(Document* ownerDocument)
1521 {
1522 if (ownerDocument) {
1523 setURL(ownerDocument->url());
1524 m_cookieURL = ownerDocument->cookieURL();
1525 m_securityOrigin = ownerDocument->securityOrigin();
1526 }
1527
1528 if (m_frame) {
1529 if (m_frame->loader()->isLoadingMainResource() || (tokenizer() && tokeni zer()->executingScript()))
1530 return;
1531
1532 if (m_frame->loader()->state() == FrameStateProvisional)
1533 m_frame->loader()->stopAllLoaders();
1534 }
1535
1536 implicitOpen();
1537
1538 if (m_frame)
1539 m_frame->loader()->didExplicitOpen();
1540 }
1541
1542 void Document::cancelParsing()
1543 {
1544 if (m_tokenizer) {
1545 // We have to clear the tokenizer to avoid possibly triggering
1546 // the onload handler when closing as a side effect of a cancel-style
1547 // change, such as opening a new document or closing the window while
1548 // still parsing
1549 delete m_tokenizer;
1550 m_tokenizer = 0;
1551 close();
1552 }
1553 }
1554
1555 void Document::implicitOpen()
1556 {
1557 cancelParsing();
1558
1559 clear();
1560 m_tokenizer = createTokenizer();
1561 setParsing(true);
1562 }
1563
1564 HTMLElement* Document::body()
1565 {
1566 Node* de = documentElement();
1567 if (!de)
1568 return 0;
1569
1570 // try to prefer a FRAMESET element over BODY
1571 Node* body = 0;
1572 for (Node* i = de->firstChild(); i; i = i->nextSibling()) {
1573 if (i->hasTagName(framesetTag))
1574 return static_cast<HTMLElement*>(i);
1575
1576 if (i->hasTagName(bodyTag))
1577 body = i;
1578 }
1579 return static_cast<HTMLElement*>(body);
1580 }
1581
1582 void Document::setBody(PassRefPtr<HTMLElement> newBody, ExceptionCode& ec)
1583 {
1584 if (!newBody || !documentElement()) {
1585 ec = HIERARCHY_REQUEST_ERR;
1586 return;
1587 }
1588
1589 HTMLElement* b = body();
1590 if (!b)
1591 documentElement()->appendChild(newBody, ec);
1592 else
1593 documentElement()->replaceChild(newBody, b, ec);
1594 }
1595
1596 HTMLHeadElement* Document::head()
1597 {
1598 Node* de = documentElement();
1599 if (!de)
1600 return 0;
1601
1602 for (Node* e = de->firstChild(); e; e = e->nextSibling())
1603 if (e->hasTagName(headTag))
1604 return static_cast<HTMLHeadElement*>(e);
1605
1606 return 0;
1607 }
1608
1609 void Document::close()
1610 {
1611 Frame* frame = this->frame();
1612 if (frame) {
1613 // This code calls implicitClose() if all loading has completed.
1614 FrameLoader* frameLoader = frame->loader();
1615 frameLoader->endIfNotLoadingMainResource();
1616 frameLoader->checkCompleted();
1617 } else {
1618 // Because we have no frame, we don't know if all loading has completed,
1619 // so we just call implicitClose() immediately. FIXME: This might fire
1620 // the load event prematurely <http://bugs.webkit.org/show_bug.cgi?id=14 568>.
1621 implicitClose();
1622 }
1623 }
1624
1625 void Document::implicitClose()
1626 {
1627 // If we're in the middle of recalcStyle, we need to defer the close until t he style information is accurate and all elements are re-attached.
1628 if (m_inStyleRecalc) {
1629 m_closeAfterStyleRecalc = true;
1630 return;
1631 }
1632
1633 bool wasLocationChangePending = frame() && frame()->loader()->isScheduledLoc ationChangePending();
1634 bool doload = !parsing() && m_tokenizer && !m_processingLoadEvent && !wasLoc ationChangePending;
1635
1636 if (!doload)
1637 return;
1638
1639 m_processingLoadEvent = true;
1640
1641 m_wellFormed = m_tokenizer && m_tokenizer->wellFormed();
1642
1643 // We have to clear the tokenizer, in case someone document.write()s from th e
1644 // onLoad event handler, as in Radar 3206524.
1645 delete m_tokenizer;
1646 m_tokenizer = 0;
1647
1648 // Parser should have picked up all preloads by now
1649 m_docLoader->clearPreloads();
1650
1651 // Create a body element if we don't already have one. See Radar 3758785.
1652 if (!this->body() && isHTMLDocument()) {
1653 if (Node* documentElement = this->documentElement()) {
1654 ExceptionCode ec = 0;
1655 documentElement->appendChild(new HTMLBodyElement(this), ec);
1656 ASSERT(!ec);
1657 }
1658 }
1659
1660 // FIXME: We kick off the icon loader when the Document is done parsing.
1661 // There are earlier opportunities we could start it:
1662 // -When the <head> finishes parsing
1663 // -When any new HTMLLinkElement is inserted into the document
1664 // But those add a dynamic component to the favicon that has UI
1665 // ramifications, and we need to decide what is the Right Thing To Do(tm)
1666 Frame* f = frame();
1667 if (f)
1668 f->loader()->startIconLoader();
1669
1670 // Resume the animations (or start them)
1671 if (f)
1672 f->animation()->resumeAnimations(this);
1673
1674 dispatchImageLoadEventsNow();
1675 this->dispatchWindowEvent(loadEvent, false, false);
1676 if (f)
1677 f->loader()->handledOnloadEvents();
1678 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1679 if (!ownerElement())
1680 printf("onload fired at %d\n", elapsedTime());
1681 #endif
1682
1683 m_processingLoadEvent = false;
1684
1685 // An event handler may have removed the frame
1686 if (!frame())
1687 return;
1688
1689 // Make sure both the initial layout and reflow happen after the onload
1690 // fires. This will improve onload scores, and other browsers do it.
1691 // If they wanna cheat, we can too. -dwh
1692
1693 if (frame()->loader()->isScheduledLocationChangePending() && elapsedTime() < cLayoutScheduleThreshold) {
1694 // Just bail out. Before or during the onload we were shifted to another page.
1695 // The old i-Bench suite does this. When this happens don't bother paint ing or laying out.
1696 view()->unscheduleRelayout();
1697 return;
1698 }
1699
1700 frame()->loader()->checkCallImplicitClose();
1701
1702 // Now do our painting/layout, but only if we aren't in a subframe or if we' re in a subframe
1703 // that has been sized already. Otherwise, our view size would be incorrect , so doing any
1704 // layout/painting now would be pointless.
1705 if (!ownerElement() || (ownerElement()->renderer() && !ownerElement()->rende rer()->needsLayout())) {
1706 updateRendering();
1707
1708 // Always do a layout after loading if needed.
1709 if (view() && renderer() && (!renderer()->firstChild() || renderer()->ne edsLayout()))
1710 view()->layout();
1711
1712 // Paint immediately after the document is ready. We do this to ensure that any timers set by the
1713 // onload don't have a chance to fire before we would have painted. To avoid over-flushing we only
1714 // worry about this for the top-level document.
1715 #if !PLATFORM(MAC)
1716 // FIXME: This causes a timing issue with the dispatchDidFinishLoad dele gate callback.
1717 // See <rdar://problem/5092361>
1718 if (view() && !ownerElement())
1719 view()->update();
1720 #endif
1721 }
1722
1723 #if PLATFORM(MAC)
1724 if (renderer() && AXObjectCache::accessibilityEnabled())
1725 axObjectCache()->postNotificationToElement(renderer(), "AXLoadComplete") ;
1726 #endif
1727
1728 #if ENABLE(SVG)
1729 // FIXME: Officially, time 0 is when the outermost <svg> receives its
1730 // SVGLoad event, but we don't implement those yet. This is close enough
1731 // for now. In some cases we should have fired earlier.
1732 if (svgExtensions())
1733 accessSVGExtensions()->startAnimations();
1734 #endif
1735 }
1736
1737 void Document::setParsing(bool b)
1738 {
1739 m_bParsing = b;
1740 if (!m_bParsing && view())
1741 view()->scheduleRelayout();
1742
1743 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1744 if (!ownerElement() && !m_bParsing)
1745 printf("Parsing finished at %d\n", elapsedTime());
1746 #endif
1747 }
1748
1749 bool Document::shouldScheduleLayout()
1750 {
1751 // We can update layout if:
1752 // (a) we actually need a layout
1753 // (b) our stylesheets are all loaded
1754 // (c) we have a <body>
1755 return (renderer() && renderer()->needsLayout() && haveStylesheetsLoaded() & &
1756 documentElement() && documentElement()->renderer() &&
1757 (!documentElement()->hasTagName(htmlTag) || body()));
1758 }
1759
1760 int Document::minimumLayoutDelay()
1761 {
1762 if (m_overMinimumLayoutThreshold)
1763 return 0;
1764
1765 int elapsed = elapsedTime();
1766 m_overMinimumLayoutThreshold = elapsed > cLayoutScheduleThreshold;
1767
1768 // We'll want to schedule the timer to fire at the minimum layout threshold.
1769 return max(0, cLayoutScheduleThreshold - elapsed);
1770 }
1771
1772 int Document::elapsedTime() const
1773 {
1774 return static_cast<int>((currentTime() - m_startTime) * 1000);
1775 }
1776
1777 void Document::write(const String& text, Document* ownerDocument)
1778 {
1779 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1780 if (!ownerElement())
1781 printf("Beginning a document.write at %d\n", elapsedTime());
1782 #endif
1783
1784 if (!m_tokenizer) {
1785 open(ownerDocument);
1786 ASSERT(m_tokenizer);
1787 if (!m_tokenizer)
1788 return;
1789 write("<html>", ownerDocument);
1790 }
1791 m_tokenizer->write(text, false);
1792
1793 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1794 if (!ownerElement())
1795 printf("Ending a document.write at %d\n", elapsedTime());
1796 #endif
1797 }
1798
1799 void Document::writeln(const String& text, Document* ownerDocument)
1800 {
1801 write(text, ownerDocument);
1802 write("\n", ownerDocument);
1803 }
1804
1805 void Document::finishParsing()
1806 {
1807 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1808 if (!ownerElement())
1809 printf("Received all data at %d\n", elapsedTime());
1810 #endif
1811
1812 // Let the tokenizer go through as much data as it can. There will be three possible outcomes after
1813 // finish() is called:
1814 // (1) All remaining data is parsed, document isn't loaded yet
1815 // (2) All remaining data is parsed, document is loaded, tokenizer gets dele ted
1816 // (3) Data is still remaining to be parsed.
1817 if (m_tokenizer)
1818 m_tokenizer->finish();
1819 }
1820
1821 void Document::clear()
1822 {
1823 delete m_tokenizer;
1824 m_tokenizer = 0;
1825
1826 removeChildren();
1827
1828 m_windowEventListeners.clear();
1829 }
1830
1831 void Document::setURL(const KURL& url)
1832 {
1833 const KURL& newURL = url.isEmpty() ? blankURL() : url;
1834 if (newURL == m_url)
1835 return;
1836
1837 m_url = newURL;
1838 m_documentURI = m_url.string();
1839 updateBaseURL();
1840 }
1841
1842 void Document::setBaseElementURL(const KURL& baseElementURL)
1843 {
1844 m_baseElementURL = baseElementURL;
1845 updateBaseURL();
1846 }
1847
1848 void Document::updateBaseURL()
1849 {
1850 m_baseURL = m_baseElementURL.isEmpty() ? KURL(documentURI()) : m_baseElement URL;
1851 if (!m_baseURL.isValid())
1852 m_baseURL = KURL();
1853
1854 if (m_elemSheet)
1855 m_elemSheet->setHref(m_baseURL.string());
1856 if (m_mappedElementSheet)
1857 m_mappedElementSheet->setHref(m_baseURL.string());
1858 }
1859
1860 void Document::setCSSStyleSheet(const String& url, const String& charset, const CachedCSSStyleSheet* sheet)
1861 {
1862 m_sheet = CSSStyleSheet::create(this, url, charset);
1863 m_sheet->parseString(sheet->sheetText());
1864
1865 updateStyleSelector();
1866 }
1867
1868 #if FRAME_LOADS_USER_STYLESHEET
1869 void Document::setUserStyleSheet(const String& sheet)
1870 {
1871 if (m_usersheet != sheet) {
1872 m_usersheet = sheet;
1873 updateStyleSelector();
1874 }
1875 }
1876 #endif
1877
1878 String Document::userStyleSheet() const
1879 {
1880 #if FRAME_LOADS_USER_STYLESHEET
1881 return m_usersheet;
1882 #else
1883 Page* page = this->page();
1884 if (!page)
1885 return String();
1886 return page->userStyleSheet();
1887 #endif
1888 }
1889
1890 CSSStyleSheet* Document::elementSheet()
1891 {
1892 if (!m_elemSheet)
1893 m_elemSheet = CSSStyleSheet::create(this, m_baseURL.string());
1894 return m_elemSheet.get();
1895 }
1896
1897 CSSStyleSheet* Document::mappedElementSheet()
1898 {
1899 if (!m_mappedElementSheet)
1900 m_mappedElementSheet = CSSStyleSheet::create(this, m_baseURL.string());
1901 return m_mappedElementSheet.get();
1902 }
1903
1904 static Node* nextNodeWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent* event)
1905 {
1906 // Search is inclusive of start
1907 for (Node* n = start; n; n = n->traverseNextNode())
1908 if (n->isKeyboardFocusable(event) && n->tabIndex() == tabIndex)
1909 return n;
1910
1911 return 0;
1912 }
1913
1914 static Node* previousNodeWithExactTabIndex(Node* start, int tabIndex, KeyboardEv ent* event)
1915 {
1916 // Search is inclusive of start
1917 for (Node* n = start; n; n = n->traversePreviousNode())
1918 if (n->isKeyboardFocusable(event) && n->tabIndex() == tabIndex)
1919 return n;
1920
1921 return 0;
1922 }
1923
1924 static Node* nextNodeWithGreaterTabIndex(Node* start, int tabIndex, KeyboardEven t* event)
1925 {
1926 // Search is inclusive of start
1927 int winningTabIndex = SHRT_MAX + 1;
1928 Node* winner = 0;
1929 for (Node* n = start; n; n = n->traverseNextNode())
1930 if (n->isKeyboardFocusable(event) && n->tabIndex() > tabIndex && n->tabI ndex() < winningTabIndex) {
1931 winner = n;
1932 winningTabIndex = n->tabIndex();
1933 }
1934
1935 return winner;
1936 }
1937
1938 static Node* previousNodeWithLowerTabIndex(Node* start, int tabIndex, KeyboardEv ent* event)
1939 {
1940 // Search is inclusive of start
1941 int winningTabIndex = 0;
1942 Node* winner = 0;
1943 for (Node* n = start; n; n = n->traversePreviousNode())
1944 if (n->isKeyboardFocusable(event) && n->tabIndex() < tabIndex && n->tabI ndex() > winningTabIndex) {
1945 winner = n;
1946 winningTabIndex = n->tabIndex();
1947 }
1948
1949 return winner;
1950 }
1951
1952 Node* Document::nextFocusableNode(Node* start, KeyboardEvent* event)
1953 {
1954 if (start) {
1955 // If a node is excluded from the normal tabbing cycle, the next focusab le node is determined by tree order
1956 if (start->tabIndex() < 0) {
1957 for (Node* n = start->traverseNextNode(); n; n = n->traverseNextNode ())
1958 if (n->isKeyboardFocusable(event) && n->tabIndex() >= 0)
1959 return n;
1960 }
1961
1962 // First try to find a node with the same tabindex as start that comes a fter start in the document.
1963 if (Node* winner = nextNodeWithExactTabIndex(start->traverseNextNode(), start->tabIndex(), event))
1964 return winner;
1965
1966 if (start->tabIndex() == 0)
1967 // We've reached the last node in the document with a tabindex of 0. This is the end of the tabbing order.
1968 return 0;
1969 }
1970
1971 // Look for the first node in the document that:
1972 // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if start is null), and
1973 // 2) comes first in the document, if there's a tie.
1974 if (Node* winner = nextNodeWithGreaterTabIndex(this, start ? start->tabIndex () : 0, event))
1975 return winner;
1976
1977 // There are no nodes with a tabindex greater than start's tabindex,
1978 // so find the first node with a tabindex of 0.
1979 return nextNodeWithExactTabIndex(this, 0, event);
1980 }
1981
1982 Node* Document::previousFocusableNode(Node* start, KeyboardEvent* event)
1983 {
1984 Node* last;
1985 for (last = this; last->lastChild(); last = last->lastChild())
1986 ; // Empty loop.
1987
1988 // First try to find the last node in the document that comes before start a nd has the same tabindex as start.
1989 // If start is null, find the last node in the document with a tabindex of 0 .
1990 Node* startingNode;
1991 int startingTabIndex;
1992 if (start) {
1993 startingNode = start->traversePreviousNode();
1994 startingTabIndex = start->tabIndex();
1995 } else {
1996 startingNode = last;
1997 startingTabIndex = 0;
1998 }
1999
2000 // However, if a node is excluded from the normal tabbing cycle, the previou s focusable node is determined by tree order
2001 if (startingTabIndex < 0) {
2002 for (Node* n = startingNode; n; n = n->traversePreviousNode())
2003 if (n->isKeyboardFocusable(event) && n->tabIndex() >= 0)
2004 return n;
2005 }
2006
2007 if (Node* winner = previousNodeWithExactTabIndex(startingNode, startingTabIn dex, event))
2008 return winner;
2009
2010 // There are no nodes before start with the same tabindex as start, so look for a node that:
2011 // 1) has the highest non-zero tabindex (that is less than start's tabindex) , and
2012 // 2) comes last in the document, if there's a tie.
2013 startingTabIndex = (start && start->tabIndex()) ? start->tabIndex() : SHRT_M AX;
2014 return previousNodeWithLowerTabIndex(last, startingTabIndex, event);
2015 }
2016
2017 int Document::nodeAbsIndex(Node *node)
2018 {
2019 ASSERT(node->document() == this);
2020
2021 int absIndex = 0;
2022 for (Node *n = node; n && n != this; n = n->traversePreviousNode())
2023 absIndex++;
2024 return absIndex;
2025 }
2026
2027 Node *Document::nodeWithAbsIndex(int absIndex)
2028 {
2029 Node *n = this;
2030 for (int i = 0; n && (i < absIndex); i++) {
2031 n = n->traverseNextNode();
2032 }
2033 return n;
2034 }
2035
2036 void Document::processHttpEquiv(const String &equiv, const String &content)
2037 {
2038 ASSERT(!equiv.isNull() && !content.isNull());
2039
2040 Frame *frame = this->frame();
2041
2042 if (equalIgnoringCase(equiv, "default-style")) {
2043 // The preferred style set has been overridden as per section
2044 // 14.3.2 of the HTML4.0 specification. We need to update the
2045 // sheet used variable and then update our style selector.
2046 // For more info, see the test at:
2047 // http://www.hixie.ch/tests/evil/css/import/main/preferred.html
2048 // -dwh
2049 m_selectedStylesheetSet = content;
2050 m_preferredStylesheetSet = content;
2051 updateStyleSelector();
2052 } else if (equalIgnoringCase(equiv, "refresh")) {
2053 double delay;
2054 String url;
2055 if (frame && parseHTTPRefresh(content, true, delay, url)) {
2056 if (url.isEmpty())
2057 url = frame->loader()->url().string();
2058 else
2059 url = completeURL(url).string();
2060 frame->loader()->scheduleHTTPRedirection(delay, url);
2061 }
2062 } else if (equalIgnoringCase(equiv, "set-cookie")) {
2063 // FIXME: make setCookie work on XML documents too; e.g. in case of <htm l:meta .....>
2064 if (isHTMLDocument())
2065 static_cast<HTMLDocument*>(this)->setCookie(content);
2066 } else if (equalIgnoringCase(equiv, "content-language"))
2067 setContentLanguage(content);
2068 else if (equalIgnoringCase(equiv, "x-dns-prefetch-control"))
2069 setDNSPrefetchControl(content);
2070 }
2071
2072 MouseEventWithHitTestResults Document::prepareMouseEvent(const HitTestRequest& r equest, const IntPoint& documentPoint, const PlatformMouseEvent& event)
2073 {
2074 ASSERT(!renderer() || renderer()->isRenderView());
2075
2076 if (!renderer())
2077 return MouseEventWithHitTestResults(event, HitTestResult(IntPoint()));
2078
2079 HitTestResult result(documentPoint);
2080 renderer()->layer()->hitTest(request, result);
2081
2082 if (!request.readonly)
2083 updateRendering();
2084
2085 return MouseEventWithHitTestResults(event, result);
2086 }
2087
2088 // DOM Section 1.1.1
2089 bool Document::childTypeAllowed(NodeType type)
2090 {
2091 switch (type) {
2092 case ATTRIBUTE_NODE:
2093 case CDATA_SECTION_NODE:
2094 case DOCUMENT_FRAGMENT_NODE:
2095 case DOCUMENT_NODE:
2096 case ENTITY_NODE:
2097 case ENTITY_REFERENCE_NODE:
2098 case NOTATION_NODE:
2099 case TEXT_NODE:
2100 case XPATH_NAMESPACE_NODE:
2101 return false;
2102 case COMMENT_NODE:
2103 case PROCESSING_INSTRUCTION_NODE:
2104 return true;
2105 case DOCUMENT_TYPE_NODE:
2106 case ELEMENT_NODE:
2107 // Documents may contain no more than one of each of these.
2108 // (One Element and one DocumentType.)
2109 for (Node* c = firstChild(); c; c = c->nextSibling())
2110 if (c->nodeType() == type)
2111 return false;
2112 return true;
2113 }
2114 return false;
2115 }
2116
2117 bool Document::canReplaceChild(Node* newChild, Node* oldChild)
2118 {
2119 if (!oldChild)
2120 // ContainerNode::replaceChild will raise a NOT_FOUND_ERR.
2121 return true;
2122
2123 if (oldChild->nodeType() == newChild->nodeType())
2124 return true;
2125
2126 int numDoctypes = 0;
2127 int numElements = 0;
2128
2129 // First, check how many doctypes and elements we have, not counting
2130 // the child we're about to remove.
2131 for (Node* c = firstChild(); c; c = c->nextSibling()) {
2132 if (c == oldChild)
2133 continue;
2134
2135 switch (c->nodeType()) {
2136 case DOCUMENT_TYPE_NODE:
2137 numDoctypes++;
2138 break;
2139 case ELEMENT_NODE:
2140 numElements++;
2141 break;
2142 default:
2143 break;
2144 }
2145 }
2146
2147 // Then, see how many doctypes and elements might be added by the new child.
2148 if (newChild->nodeType() == DOCUMENT_FRAGMENT_NODE) {
2149 for (Node* c = firstChild(); c; c = c->nextSibling()) {
2150 switch (c->nodeType()) {
2151 case ATTRIBUTE_NODE:
2152 case CDATA_SECTION_NODE:
2153 case DOCUMENT_FRAGMENT_NODE:
2154 case DOCUMENT_NODE:
2155 case ENTITY_NODE:
2156 case ENTITY_REFERENCE_NODE:
2157 case NOTATION_NODE:
2158 case TEXT_NODE:
2159 case XPATH_NAMESPACE_NODE:
2160 return false;
2161 case COMMENT_NODE:
2162 case PROCESSING_INSTRUCTION_NODE:
2163 break;
2164 case DOCUMENT_TYPE_NODE:
2165 numDoctypes++;
2166 break;
2167 case ELEMENT_NODE:
2168 numElements++;
2169 break;
2170 }
2171 }
2172 } else {
2173 switch (newChild->nodeType()) {
2174 case ATTRIBUTE_NODE:
2175 case CDATA_SECTION_NODE:
2176 case DOCUMENT_FRAGMENT_NODE:
2177 case DOCUMENT_NODE:
2178 case ENTITY_NODE:
2179 case ENTITY_REFERENCE_NODE:
2180 case NOTATION_NODE:
2181 case TEXT_NODE:
2182 case XPATH_NAMESPACE_NODE:
2183 return false;
2184 case COMMENT_NODE:
2185 case PROCESSING_INSTRUCTION_NODE:
2186 return true;
2187 case DOCUMENT_TYPE_NODE:
2188 numDoctypes++;
2189 break;
2190 case ELEMENT_NODE:
2191 numElements++;
2192 break;
2193 }
2194 }
2195
2196 if (numElements > 1 || numDoctypes > 1)
2197 return false;
2198
2199 return true;
2200 }
2201
2202 PassRefPtr<Node> Document::cloneNode(bool /*deep*/)
2203 {
2204 // Spec says cloning Document nodes is "implementation dependent"
2205 // so we do not support it...
2206 return 0;
2207 }
2208
2209 StyleSheetList* Document::styleSheets()
2210 {
2211 return m_styleSheets.get();
2212 }
2213
2214 String Document::preferredStylesheetSet() const
2215 {
2216 return m_preferredStylesheetSet;
2217 }
2218
2219 String Document::selectedStylesheetSet() const
2220 {
2221 return m_selectedStylesheetSet;
2222 }
2223
2224 void Document::setSelectedStylesheetSet(const String& aString)
2225 {
2226 m_selectedStylesheetSet = aString;
2227 updateStyleSelector();
2228 if (renderer())
2229 renderer()->repaint();
2230 }
2231
2232 // This method is called whenever a top-level stylesheet has finished loading.
2233 void Document::removePendingSheet()
2234 {
2235 // Make sure we knew this sheet was pending, and that our count isn't out of sync.
2236 ASSERT(m_pendingStylesheets > 0);
2237
2238 m_pendingStylesheets--;
2239
2240 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2241 if (!ownerElement())
2242 printf("Stylesheet loaded at time %d. %d stylesheets still remain.\n", e lapsedTime(), m_pendingStylesheets);
2243 #endif
2244
2245 updateStyleSelector();
2246
2247 if (!m_pendingStylesheets && m_tokenizer)
2248 m_tokenizer->executeScriptsWaitingForStylesheets();
2249
2250 if (!m_pendingStylesheets && m_gotoAnchorNeededAfterStylesheetsLoad && m_fra me)
2251 m_frame->loader()->gotoAnchor();
2252 }
2253
2254 void Document::updateStyleSelector()
2255 {
2256 // Don't bother updating, since we haven't loaded all our style info yet
2257 // and haven't calculated the style selector for the first time.
2258 if (!m_didCalculateStyleSelector && !haveStylesheetsLoaded())
2259 return;
2260
2261 if (didLayoutWithPendingStylesheets() && m_pendingStylesheets <= 0) {
2262 m_pendingSheetLayout = IgnoreLayoutWithPendingSheets;
2263 if (renderer())
2264 renderer()->repaint();
2265 }
2266
2267 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2268 if (!ownerElement())
2269 printf("Beginning update of style selector at time %d.\n", elapsedTime() );
2270 #endif
2271
2272 recalcStyleSelector();
2273 recalcStyle(Force);
2274
2275 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2276 if (!ownerElement())
2277 printf("Finished update of style selector at time %d\n", elapsedTime());
2278 #endif
2279
2280 if (renderer()) {
2281 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
2282 if (view())
2283 view()->scheduleRelayout();
2284 }
2285 }
2286
2287 void Document::addStyleSheetCandidateNode(Node* node, bool createdByParser)
2288 {
2289 // Until the <body> exists, we have no choice but to compare document positi ons,
2290 // since styles outside of the body and head continue to be shunted into the head
2291 // (and thus can shift to end up before dynamically added DOM content that i s also
2292 // outside the body).
2293 if ((createdByParser && body()) || m_styleSheetCandidateNodes.isEmpty()) {
2294 m_styleSheetCandidateNodes.add(node);
2295 return;
2296 }
2297
2298 // Determine an appropriate insertion point.
2299 ListHashSet<Node*>::iterator begin = m_styleSheetCandidateNodes.begin();
2300 ListHashSet<Node*>::iterator end = m_styleSheetCandidateNodes.end();
2301 ListHashSet<Node*>::iterator it = end;
2302 Node* followingNode = 0;
2303 do {
2304 --it;
2305 Node* n = *it;
2306 unsigned short position = n->compareDocumentPosition(node);
2307 if (position == DOCUMENT_POSITION_FOLLOWING) {
2308 m_styleSheetCandidateNodes.insertBefore(followingNode, node);
2309 return;
2310 }
2311 followingNode = n;
2312 } while (it != begin);
2313
2314 m_styleSheetCandidateNodes.insertBefore(followingNode, node);
2315 }
2316
2317 void Document::removeStyleSheetCandidateNode(Node* node)
2318 {
2319 m_styleSheetCandidateNodes.remove(node);
2320 }
2321
2322 void Document::recalcStyleSelector()
2323 {
2324 if (!renderer() || !attached())
2325 return;
2326
2327 StyleSheetVector sheets;
2328
2329 bool matchAuthorAndUserStyles = true;
2330 if (Settings* settings = this->settings())
2331 matchAuthorAndUserStyles = settings->authorAndUserStylesEnabled();
2332
2333 ListHashSet<Node*>::iterator begin = m_styleSheetCandidateNodes.begin();
2334 ListHashSet<Node*>::iterator end = m_styleSheetCandidateNodes.end();
2335 if (!matchAuthorAndUserStyles)
2336 end = begin;
2337 for (ListHashSet<Node*>::iterator it = begin; it != end; ++it) {
2338 Node* n = *it;
2339
2340 StyleSheet* sheet = 0;
2341
2342 if (n->nodeType() == PROCESSING_INSTRUCTION_NODE) {
2343 // Processing instruction (XML documents only)
2344 ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(n);
2345 sheet = pi->sheet();
2346 #if ENABLE(XSLT)
2347 // Don't apply XSL transforms to already transformed documents -- <r dar://problem/4132806>
2348 if (pi->isXSL() && !transformSourceDocument()) {
2349 // Don't apply XSL transforms until loading is finished.
2350 if (!parsing())
2351 applyXSLTransform(pi);
2352 return;
2353 }
2354 #endif
2355 if (!sheet && !pi->localHref().isEmpty()) {
2356 // Processing instruction with reference to an element in this d ocument - e.g.
2357 // <?xml-stylesheet href="#mystyle">, with the element
2358 // <foo id="mystyle">heading { color: red; }</foo> at some locat ion in
2359 // the document
2360 Element* elem = getElementById(pi->localHref().impl());
2361 if (elem) {
2362 String sheetText("");
2363 for (Node* c = elem->firstChild(); c; c = c->nextSibling()) {
2364 if (c->nodeType() == TEXT_NODE || c->nodeType() == CDATA _SECTION_NODE)
2365 sheetText += c->nodeValue();
2366 }
2367
2368 RefPtr<CSSStyleSheet> cssSheet = CSSStyleSheet::create(this) ;
2369 cssSheet->parseString(sheetText);
2370 pi->setCSSStyleSheet(cssSheet);
2371 sheet = cssSheet.get();
2372 }
2373 }
2374 } else if (n->isHTMLElement() && (n->hasTagName(linkTag) || n->hasTagNam e(styleTag))
2375 #if ENABLE(SVG)
2376 || (n->isSVGElement() && n->hasTagName(SVGNames::styleTag))
2377 #endif
2378 ) {
2379 Element* e = static_cast<Element*>(n);
2380 AtomicString title = e->getAttribute(titleAttr);
2381 bool enabledViaScript = false;
2382 if (e->hasLocalName(linkTag)) {
2383 // <LINK> element
2384 HTMLLinkElement* l = static_cast<HTMLLinkElement*>(n);
2385 if (l->isDisabled())
2386 continue;
2387 enabledViaScript = l->isEnabledViaScript();
2388 if (l->isLoading()) {
2389 // it is loading but we should still decide which style shee t set to use
2390 if (!enabledViaScript && !title.isEmpty() && m_preferredStyl esheetSet.isEmpty()) {
2391 const AtomicString& rel = e->getAttribute(relAttr);
2392 if (!rel.contains("alternate")) {
2393 m_preferredStylesheetSet = title;
2394 m_selectedStylesheetSet = title;
2395 }
2396 }
2397 continue;
2398 }
2399 if (!l->sheet())
2400 title = nullAtom;
2401 }
2402
2403 // Get the current preferred styleset. This is the
2404 // set of sheets that will be enabled.
2405 #if ENABLE(SVG)
2406 if (n->isSVGElement() && n->hasTagName(SVGNames::styleTag))
2407 sheet = static_cast<SVGStyleElement*>(n)->sheet();
2408 else
2409 #endif
2410 if (e->hasLocalName(linkTag))
2411 sheet = static_cast<HTMLLinkElement*>(n)->sheet();
2412 else
2413 // <STYLE> element
2414 sheet = static_cast<HTMLStyleElement*>(n)->sheet();
2415
2416 // Check to see if this sheet belongs to a styleset
2417 // (thus making it PREFERRED or ALTERNATE rather than
2418 // PERSISTENT).
2419 if (!enabledViaScript && !title.isEmpty()) {
2420 // Yes, we have a title.
2421 if (m_preferredStylesheetSet.isEmpty()) {
2422 // No preferred set has been established. If
2423 // we are NOT an alternate sheet, then establish
2424 // us as the preferred set. Otherwise, just ignore
2425 // this sheet.
2426 AtomicString rel = e->getAttribute(relAttr);
2427 if (e->hasLocalName(styleTag) || !rel.contains("alternate"))
2428 m_preferredStylesheetSet = m_selectedStylesheetSet = tit le;
2429 }
2430
2431 if (title != m_preferredStylesheetSet)
2432 sheet = 0;
2433 }
2434 }
2435
2436 if (sheet)
2437 sheets.append(sheet);
2438 }
2439
2440 m_styleSheets->swap(sheets);
2441
2442 // Create a new style selector
2443 delete m_styleSelector;
2444 m_styleSelector = new CSSStyleSelector(this, userStyleSheet(), m_styleSheets .get(), m_mappedElementSheet.get(), !inCompatMode(), matchAuthorAndUserStyles);
2445 m_didCalculateStyleSelector = true;
2446 }
2447
2448 void Document::setHoverNode(PassRefPtr<Node> newHoverNode)
2449 {
2450 m_hoverNode = newHoverNode;
2451 }
2452
2453 void Document::setActiveNode(PassRefPtr<Node> newActiveNode)
2454 {
2455 m_activeNode = newActiveNode;
2456 }
2457
2458 void Document::focusedNodeRemoved()
2459 {
2460 setFocusedNode(0);
2461 }
2462
2463 void Document::removeFocusedNodeOfSubtree(Node* node, bool amongChildrenOnly)
2464 {
2465 if (!m_focusedNode || this->inPageCache()) // If the document is in the page cache, then we don't need to clear out the focused node.
2466 return;
2467
2468 bool nodeInSubtree = false;
2469 if (amongChildrenOnly)
2470 nodeInSubtree = m_focusedNode->isDescendantOf(node);
2471 else
2472 nodeInSubtree = (m_focusedNode == node) || m_focusedNode->isDescendantOf (node);
2473
2474 if (nodeInSubtree)
2475 document()->focusedNodeRemoved();
2476 }
2477
2478 void Document::hoveredNodeDetached(Node* node)
2479 {
2480 if (!m_hoverNode || (node != m_hoverNode && (!m_hoverNode->isTextNode() || n ode != m_hoverNode->parent())))
2481 return;
2482
2483 m_hoverNode = node->parent();
2484 while (m_hoverNode && !m_hoverNode->renderer())
2485 m_hoverNode = m_hoverNode->parent();
2486 if (frame())
2487 frame()->eventHandler()->scheduleHoverStateUpdate();
2488 }
2489
2490 void Document::activeChainNodeDetached(Node* node)
2491 {
2492 if (!m_activeNode || (node != m_activeNode && (!m_activeNode->isTextNode() | | node != m_activeNode->parent())))
2493 return;
2494
2495 m_activeNode = node->parent();
2496 while (m_activeNode && !m_activeNode->renderer())
2497 m_activeNode = m_activeNode->parent();
2498 }
2499
2500 #if ENABLE(DASHBOARD_SUPPORT)
2501 const Vector<DashboardRegionValue>& Document::dashboardRegions() const
2502 {
2503 return m_dashboardRegions;
2504 }
2505
2506 void Document::setDashboardRegions(const Vector<DashboardRegionValue>& regions)
2507 {
2508 m_dashboardRegions = regions;
2509 setDashboardRegionsDirty(false);
2510 }
2511 #endif
2512
2513 bool Document::setFocusedNode(PassRefPtr<Node> newFocusedNode)
2514 {
2515 // Make sure newFocusedNode is actually in this document
2516 if (newFocusedNode && (newFocusedNode->document() != this))
2517 return true;
2518
2519 if (m_focusedNode == newFocusedNode)
2520 return true;
2521
2522 if (m_inPageCache)
2523 return false;
2524
2525 bool focusChangeBlocked = false;
2526 RefPtr<Node> oldFocusedNode = m_focusedNode;
2527 m_focusedNode = 0;
2528
2529 // Remove focus from the existing focus node (if any)
2530 if (oldFocusedNode && !oldFocusedNode->m_inDetach) {
2531 if (oldFocusedNode->active())
2532 oldFocusedNode->setActive(false);
2533
2534 oldFocusedNode->setFocus(false);
2535
2536 // Dispatch a change event for text fields or textareas that have been e dited
2537 RenderObject *r = static_cast<RenderObject*>(oldFocusedNode.get()->rende rer());
2538 if (r && (r->isTextArea() || r->isTextField()) && r->isEdited()) {
2539 EventTargetNodeCast(oldFocusedNode.get())->dispatchHTMLEvent(changeE vent, true, false);
2540 if ((r = static_cast<RenderObject*>(oldFocusedNode.get()->renderer() )))
2541 r->setEdited(false);
2542 }
2543
2544 // Dispatch the blur event and let the node do any other blur related ac tivities (important for text fields)
2545 EventTargetNodeCast(oldFocusedNode.get())->dispatchBlurEvent();
2546
2547 if (m_focusedNode) {
2548 // handler shifted focus
2549 focusChangeBlocked = true;
2550 newFocusedNode = 0;
2551 }
2552 EventTargetNodeCast(oldFocusedNode.get())->dispatchUIEvent(DOMFocusOutEv ent);
2553 if (m_focusedNode) {
2554 // handler shifted focus
2555 focusChangeBlocked = true;
2556 newFocusedNode = 0;
2557 }
2558 if ((oldFocusedNode.get() == this) && oldFocusedNode->hasOneRef())
2559 return true;
2560
2561 if (oldFocusedNode.get() == oldFocusedNode->rootEditableElement())
2562 frame()->editor()->didEndEditing();
2563 }
2564
2565 if (newFocusedNode) {
2566 if (newFocusedNode == newFocusedNode->rootEditableElement() && !acceptsE ditingFocus(newFocusedNode.get())) {
2567 // delegate blocks focus change
2568 focusChangeBlocked = true;
2569 goto SetFocusedNodeDone;
2570 }
2571 // Set focus on the new node
2572 m_focusedNode = newFocusedNode.get();
2573
2574 // Dispatch the focus event and let the node do any other focus related activities (important for text fields)
2575 EventTargetNodeCast(m_focusedNode.get())->dispatchFocusEvent();
2576
2577 if (m_focusedNode != newFocusedNode) {
2578 // handler shifted focus
2579 focusChangeBlocked = true;
2580 goto SetFocusedNodeDone;
2581 }
2582 EventTargetNodeCast(m_focusedNode.get())->dispatchUIEvent(DOMFocusInEven t);
2583 if (m_focusedNode != newFocusedNode) {
2584 // handler shifted focus
2585 focusChangeBlocked = true;
2586 goto SetFocusedNodeDone;
2587 }
2588 m_focusedNode->setFocus();
2589
2590 if (m_focusedNode.get() == m_focusedNode->rootEditableElement())
2591 frame()->editor()->didBeginEditing();
2592
2593 // eww, I suck. set the qt focus correctly
2594 // ### find a better place in the code for this
2595 if (view()) {
2596 Widget *focusWidget = widgetForNode(m_focusedNode.get());
2597 if (focusWidget) {
2598 // Make sure a widget has the right size before giving it focus.
2599 // Otherwise, we are testing edge cases of the Widget code.
2600 // Specifically, in WebCore this does not work well for text fie lds.
2601 updateLayout();
2602 // Re-get the widget in case updating the layout changed things.
2603 focusWidget = widgetForNode(m_focusedNode.get());
2604 }
2605 if (focusWidget)
2606 focusWidget->setFocus();
2607 else
2608 view()->setFocus();
2609 }
2610 }
2611
2612 #if PLATFORM(MAC) && !PLATFORM(CHROMIUM)
2613 if (!focusChangeBlocked && m_focusedNode && AXObjectCache::accessibilityEnab led())
2614 axObjectCache()->handleFocusedUIElementChanged();
2615 #endif
2616
2617 SetFocusedNodeDone:
2618 updateRendering();
2619 return !focusChangeBlocked;
2620 }
2621
2622 void Document::setCSSTarget(Node* n)
2623 {
2624 if (m_cssTarget)
2625 m_cssTarget->setChanged();
2626 m_cssTarget = n;
2627 if (n)
2628 n->setChanged();
2629 }
2630
2631 Node* Document::getCSSTarget() const
2632 {
2633 return m_cssTarget;
2634 }
2635
2636 void Document::attachNodeIterator(NodeIterator *ni)
2637 {
2638 m_nodeIterators.add(ni);
2639 }
2640
2641 void Document::detachNodeIterator(NodeIterator *ni)
2642 {
2643 m_nodeIterators.remove(ni);
2644 }
2645
2646 void Document::nodeChildrenChanged(ContainerNode* container)
2647 {
2648 if (!page() || !page()->settings()->rangeMutationDisabledForOldAppleMail()) {
2649 HashSet<Range*>::const_iterator end = m_ranges.end();
2650 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; + +it)
2651 (*it)->nodeChildrenChanged(container);
2652 }
2653 }
2654
2655 void Document::nodeWillBeRemoved(Node* n)
2656 {
2657 HashSet<NodeIterator*>::const_iterator nodeIteratorsEnd = m_nodeIterators.en d();
2658 for (HashSet<NodeIterator*>::const_iterator it = m_nodeIterators.begin(); it != nodeIteratorsEnd; ++it)
2659 (*it)->nodeWillBeRemoved(n);
2660
2661 if (!page() || !page()->settings()->rangeMutationDisabledForOldAppleMail()) {
2662 HashSet<Range*>::const_iterator rangesEnd = m_ranges.end();
2663 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != ranges End; ++it)
2664 (*it)->nodeWillBeRemoved(n);
2665 }
2666
2667 if (Frame* frame = this->frame()) {
2668 frame->selection()->nodeWillBeRemoved(n);
2669 frame->dragCaretController()->nodeWillBeRemoved(n);
2670 }
2671 }
2672
2673 void Document::textInserted(Node* text, unsigned offset, unsigned length)
2674 {
2675 if (!page() || !page()->settings()->rangeMutationDisabledForOldAppleMail()) {
2676 HashSet<Range*>::const_iterator end = m_ranges.end();
2677 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; + +it)
2678 (*it)->textInserted(text, offset, length);
2679 }
2680
2681 // Update the markers for spelling and grammar checking.
2682 shiftMarkers(text, offset, length);
2683 }
2684
2685 void Document::textRemoved(Node* text, unsigned offset, unsigned length)
2686 {
2687 if (!page() || !page()->settings()->rangeMutationDisabledForOldAppleMail()) {
2688 HashSet<Range*>::const_iterator end = m_ranges.end();
2689 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; + +it)
2690 (*it)->textRemoved(text, offset, length);
2691 }
2692
2693 // Update the markers for spelling and grammar checking.
2694 removeMarkers(text, offset, length);
2695 shiftMarkers(text, offset + length, 0 - length);
2696 }
2697
2698 void Document::textNodesMerged(Text* oldNode, unsigned offset)
2699 {
2700 if (!page() || !page()->settings()->rangeMutationDisabledForOldAppleMail()) {
2701 NodeWithIndex oldNodeWithIndex(oldNode);
2702 HashSet<Range*>::const_iterator end = m_ranges.end();
2703 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; + +it)
2704 (*it)->textNodesMerged(oldNodeWithIndex, offset);
2705 }
2706
2707 // FIXME: This should update markers for spelling and grammar checking.
2708 }
2709
2710 void Document::textNodeSplit(Text* oldNode)
2711 {
2712 if (!page() || !page()->settings()->rangeMutationDisabledForOldAppleMail()) {
2713 HashSet<Range*>::const_iterator end = m_ranges.end();
2714 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; + +it)
2715 (*it)->textNodeSplit(oldNode);
2716 }
2717
2718 // FIXME: This should update markers for spelling and grammar checking.
2719 }
2720
2721 // FIXME: eventually, this should return a DOMWindow stored in the document.
2722 DOMWindow* Document::domWindow() const
2723 {
2724 if (!frame())
2725 return 0;
2726 return frame()->domWindow();
2727 }
2728
2729 PassRefPtr<Event> Document::createEvent(const String& eventType, ExceptionCode& ec)
2730 {
2731 if (eventType == "UIEvents" || eventType == "UIEvent")
2732 return UIEvent::create();
2733 if (eventType == "MouseEvents" || eventType == "MouseEvent")
2734 return MouseEvent::create();
2735 if (eventType == "MutationEvents" || eventType == "MutationEvent")
2736 return MutationEvent::create();
2737 if (eventType == "KeyboardEvents" || eventType == "KeyboardEvent")
2738 return KeyboardEvent::create();
2739 if (eventType == "HTMLEvents" || eventType == "Event" || eventType == "Event s")
2740 return Event::create();
2741 if (eventType == "ProgressEvent")
2742 return ProgressEvent::create();
2743 if (eventType == "TextEvent")
2744 return TextEvent::create();
2745 if (eventType == "OverflowEvent")
2746 return OverflowEvent::create();
2747 if (eventType == "WheelEvent")
2748 return WheelEvent::create();
2749 #if ENABLE(SVG)
2750 if (eventType == "SVGEvents")
2751 return Event::create();
2752 if (eventType == "SVGZoomEvents")
2753 return SVGZoomEvent::create();
2754 #endif
2755 if (eventType == "MessageEvent")
2756 return MessageEvent::create();
2757 ec = NOT_SUPPORTED_ERR;
2758 return 0;
2759 }
2760
2761 CSSStyleDeclaration* Document::getOverrideStyle(Element*, const String&)
2762 {
2763 return 0;
2764 }
2765
2766 void Document::handleWindowEvent(Event *evt, bool useCapture)
2767 {
2768 if (m_windowEventListeners.isEmpty())
2769 return;
2770
2771 // if any html event listeners are registered on the window, then dispatch t hem here
2772 RegisteredEventListenerList listenersCopy = m_windowEventListeners;
2773 RegisteredEventListenerList::iterator it = listenersCopy.begin();
2774
2775 for (; it != listenersCopy.end(); ++it)
2776 if ((*it)->eventType() == evt->type() && (*it)->useCapture() == useCaptu re && !(*it)->removed())
2777 (*it)->listener()->handleEvent(evt, true);
2778 }
2779
2780 void Document::setHTMLWindowEventListener(const AtomicString &eventType, PassRef Ptr<EventListener> listener)
2781 {
2782 // If we already have it we don't want removeWindowEventListener to delete i t
2783 removeHTMLWindowEventListener(eventType);
2784 if (listener)
2785 addWindowEventListener(eventType, listener, false);
2786 }
2787
2788 EventListener *Document::getHTMLWindowEventListener(const AtomicString& eventTyp e)
2789 {
2790 RegisteredEventListenerList::iterator it = m_windowEventListeners.begin();
2791 for (; it != m_windowEventListeners.end(); ++it) {
2792 if ((*it)->eventType() == eventType && (*it)->listener()->isHTMLEventLis tener())
2793 return (*it)->listener();
2794 }
2795 return 0;
2796 }
2797
2798 void Document::removeHTMLWindowEventListener(const AtomicString& eventType)
2799 {
2800 RegisteredEventListenerList::iterator it = m_windowEventListeners.begin();
2801 for (; it != m_windowEventListeners.end(); ++it) {
2802 if ((*it)->eventType() == eventType && (*it)->listener()->isHTMLEventLis tener()) {
2803 if (eventType == unloadEvent)
2804 removePendingFrameUnloadEventCount();
2805 else if (eventType == beforeunloadEvent)
2806 removePendingFrameBeforeUnloadEventCount();
2807 m_windowEventListeners.remove(it);
2808 return;
2809 }
2810 }
2811 }
2812
2813 void Document::addWindowEventListener(const AtomicString &eventType, PassRefPtr< EventListener> listener, bool useCapture)
2814 {
2815 if (eventType == unloadEvent)
2816 addPendingFrameUnloadEventCount();
2817 else if (eventType == beforeunloadEvent)
2818 addPendingFrameBeforeUnloadEventCount();
2819 // Remove existing identical listener set with identical arguments.
2820 // The DOM 2 spec says that "duplicate instances are discarded" in this case .
2821 removeWindowEventListener(eventType, listener.get(), useCapture);
2822 m_windowEventListeners.append(RegisteredEventListener::create(eventType, lis tener, useCapture));
2823 }
2824
2825 void Document::removeWindowEventListener(const AtomicString& eventType, EventLis tener* listener, bool useCapture)
2826 {
2827 RegisteredEventListenerList::iterator it = m_windowEventListeners.begin();
2828 for (; it != m_windowEventListeners.end(); ++it) {
2829 RegisteredEventListener& r = **it;
2830 if (r.eventType() == eventType && r.listener() == listener && r.useCaptu re() == useCapture) {
2831 if (eventType == unloadEvent)
2832 removePendingFrameUnloadEventCount();
2833 else if (eventType == beforeunloadEvent)
2834 removePendingFrameBeforeUnloadEventCount();
2835 m_windowEventListeners.remove(it);
2836 return;
2837 }
2838 }
2839 }
2840
2841 bool Document::hasWindowEventListener(const AtomicString &eventType)
2842 {
2843 RegisteredEventListenerList::iterator it = m_windowEventListeners.begin();
2844 for (; it != m_windowEventListeners.end(); ++it)
2845 if ((*it)->eventType() == eventType) {
2846 return true;
2847 }
2848 return false;
2849 }
2850
2851 void Document::addPendingFrameUnloadEventCount()
2852 {
2853 if (m_frame)
2854 m_frame->eventHandler()->addPendingFrameUnloadEventCount();
2855 }
2856
2857 void Document::removePendingFrameUnloadEventCount()
2858 {
2859 if (m_frame)
2860 m_frame->eventHandler()->removePendingFrameUnloadEventCount();
2861 }
2862
2863 void Document::addPendingFrameBeforeUnloadEventCount()
2864 {
2865 if (m_frame)
2866 m_frame->eventHandler()->addPendingFrameBeforeUnloadEventCount();
2867 }
2868
2869 void Document::removePendingFrameBeforeUnloadEventCount()
2870 {
2871 if (m_frame)
2872 m_frame->eventHandler()->removePendingFrameBeforeUnloadEventCount();
2873 }
2874
2875 bool Document::hasUnloadEventListener()
2876 {
2877 return (hasWindowEventListener(unloadEvent) ||
2878 hasWindowEventListener(beforeunloadEvent));
2879 }
2880
2881 PassRefPtr<EventListener> Document::createHTMLEventListener(const String& functi onName, const String& code, Node *node)
2882 {
2883 if (Frame* frm = frame())
2884 if (frm->script()->isEnabled())
2885 return frm->script()->createHTMLEventHandler(functionName, code, nod e);
2886 return 0;
2887 }
2888
2889 void Document::setHTMLWindowEventListener(const AtomicString& eventType, Attribu te* attr)
2890 {
2891 setHTMLWindowEventListener(eventType,
2892 createHTMLEventListener(attr->localName().string(), attr->value(), 0));
2893 }
2894
2895 void Document::dispatchImageLoadEventSoon(HTMLImageLoader *image)
2896 {
2897 m_imageLoadEventDispatchSoonList.append(image);
2898 if (!m_imageLoadEventTimer.isActive())
2899 m_imageLoadEventTimer.startOneShot(0);
2900 }
2901
2902 void Document::removeImage(HTMLImageLoader* image)
2903 {
2904 // Remove instances of this image from both lists.
2905 // Use loops because we allow multiple instances to get into the lists.
2906 while (m_imageLoadEventDispatchSoonList.removeRef(image)) { }
2907 while (m_imageLoadEventDispatchingList.removeRef(image)) { }
2908 if (m_imageLoadEventDispatchSoonList.isEmpty())
2909 m_imageLoadEventTimer.stop();
2910 }
2911
2912 void Document::dispatchImageLoadEventsNow()
2913 {
2914 // need to avoid re-entering this function; if new dispatches are
2915 // scheduled before the parent finishes processing the list, they
2916 // will set a timer and eventually be processed
2917 if (!m_imageLoadEventDispatchingList.isEmpty()) {
2918 return;
2919 }
2920
2921 m_imageLoadEventTimer.stop();
2922
2923 m_imageLoadEventDispatchingList = m_imageLoadEventDispatchSoonList;
2924 m_imageLoadEventDispatchSoonList.clear();
2925 for (DeprecatedPtrListIterator<HTMLImageLoader> it(m_imageLoadEventDispatchi ngList); it.current();) {
2926 HTMLImageLoader* image = it.current();
2927 // Must advance iterator *before* dispatching call.
2928 // Otherwise, it might be advanced automatically if dispatching the call had a side effect
2929 // of destroying the current HTMLImageLoader, and then we would advance past the *next* item,
2930 // missing one altogether.
2931 ++it;
2932 image->dispatchLoadEvent();
2933 }
2934 m_imageLoadEventDispatchingList.clear();
2935 }
2936
2937 void Document::imageLoadEventTimerFired(Timer<Document>*)
2938 {
2939 dispatchImageLoadEventsNow();
2940 }
2941
2942 Element* Document::ownerElement() const
2943 {
2944 if (!frame())
2945 return 0;
2946 return frame()->ownerElement();
2947 }
2948
2949 String Document::cookie() const
2950 {
2951 return cookies(this, cookieURL());
2952 }
2953
2954 void Document::setCookie(const String& value)
2955 {
2956 setCookies(this, cookieURL(), policyBaseURL(), value);
2957 }
2958
2959 String Document::referrer() const
2960 {
2961 if (frame())
2962 return frame()->loader()->referrer();
2963 return String();
2964 }
2965
2966 String Document::domain() const
2967 {
2968 return m_securityOrigin->domain();
2969 }
2970
2971 void Document::setDomain(const String& newDomain)
2972 {
2973 // Both NS and IE specify that changing the domain is only allowed when
2974 // the new domain is a suffix of the old domain.
2975
2976 // FIXME: We should add logging indicating why a domain was not allowed.
2977
2978 // If the new domain is the same as the old domain, still call
2979 // m_securityOrigin.setDomainForDOM. This will change the
2980 // security check behavior. For example, if a page loaded on port 8000
2981 // assigns its current domain using document.domain, the page will
2982 // allow other pages loaded on different ports in the same domain that
2983 // have also assigned to access this page.
2984 if (equalIgnoringCase(domain(), newDomain)) {
2985 m_securityOrigin->setDomainFromDOM(newDomain);
2986 return;
2987 }
2988
2989 int oldLength = domain().length();
2990 int newLength = newDomain.length();
2991 // e.g. newDomain = webkit.org (10) and domain() = www.webkit.org (14)
2992 if (newLength >= oldLength)
2993 return;
2994
2995 String test = domain();
2996 // Check that it's a subdomain, not e.g. "ebkit.org"
2997 if (test[oldLength - newLength - 1] != '.')
2998 return;
2999
3000 // Now test is "webkit.org" from domain()
3001 // and we check that it's the same thing as newDomain
3002 test.remove(0, oldLength - newLength);
3003 if (test != newDomain)
3004 return;
3005
3006 m_securityOrigin->setDomainFromDOM(newDomain);
3007 }
3008
3009 String Document::lastModified() const
3010 {
3011 Frame* f = frame();
3012 if (!f)
3013 return String();
3014 DocumentLoader* loader = f->loader()->documentLoader();
3015 if (!loader)
3016 return String();
3017 return loader->response().httpHeaderField("Last-Modified");
3018 }
3019
3020 static bool isValidNameNonASCII(const UChar* characters, unsigned length)
3021 {
3022 unsigned i = 0;
3023
3024 UChar32 c;
3025 U16_NEXT(characters, i, length, c)
3026 if (!isValidNameStart(c))
3027 return false;
3028
3029 while (i < length) {
3030 U16_NEXT(characters, i, length, c)
3031 if (!isValidNamePart(c))
3032 return false;
3033 }
3034
3035 return true;
3036 }
3037
3038 static inline bool isValidNameASCII(const UChar* characters, unsigned length)
3039 {
3040 UChar c = characters[0];
3041 if (!(isASCIIAlpha(c) || c == ':' || c == '_'))
3042 return false;
3043
3044 for (unsigned i = 1; i < length; ++i) {
3045 c = characters[i];
3046 if (!(isASCIIAlphanumeric(c) || c == ':' || c == '_' || c == '-' || c == '.'))
3047 return false;
3048 }
3049
3050 return true;
3051 }
3052
3053 bool Document::isValidName(const String& name)
3054 {
3055 unsigned length = name.length();
3056 if (!length)
3057 return false;
3058
3059 const UChar* characters = name.characters();
3060 return isValidNameASCII(characters, length) || isValidNameNonASCII(character s, length);
3061 }
3062
3063 bool Document::parseQualifiedName(const String& qualifiedName, String& prefix, S tring& localName, ExceptionCode& ec)
3064 {
3065 unsigned length = qualifiedName.length();
3066
3067 if (length == 0) {
3068 ec = INVALID_CHARACTER_ERR;
3069 return false;
3070 }
3071
3072 bool nameStart = true;
3073 bool sawColon = false;
3074 int colonPos = 0;
3075
3076 const UChar* s = qualifiedName.characters();
3077 for (unsigned i = 0; i < length;) {
3078 UChar32 c;
3079 U16_NEXT(s, i, length, c)
3080 if (c == ':') {
3081 if (sawColon) {
3082 ec = NAMESPACE_ERR;
3083 return false; // multiple colons: not allowed
3084 }
3085 nameStart = true;
3086 sawColon = true;
3087 colonPos = i - 1;
3088 } else if (nameStart) {
3089 if (!isValidNameStart(c)) {
3090 ec = INVALID_CHARACTER_ERR;
3091 return false;
3092 }
3093 nameStart = false;
3094 } else {
3095 if (!isValidNamePart(c)) {
3096 ec = INVALID_CHARACTER_ERR;
3097 return false;
3098 }
3099 }
3100 }
3101
3102 if (!sawColon) {
3103 prefix = String();
3104 localName = qualifiedName;
3105 } else {
3106 prefix = qualifiedName.substring(0, colonPos);
3107 if (prefix.isEmpty()) {
3108 ec = NAMESPACE_ERR;
3109 return false;
3110 }
3111 localName = qualifiedName.substring(colonPos + 1);
3112 }
3113
3114 if (localName.isEmpty()) {
3115 ec = NAMESPACE_ERR;
3116 return false;
3117 }
3118
3119 return true;
3120 }
3121
3122 void Document::addImageMap(HTMLMapElement* imageMap)
3123 {
3124 const AtomicString& name = imageMap->getName();
3125 if (!name.impl())
3126 return;
3127
3128 // Add the image map, unless there's already another with that name.
3129 // "First map wins" is the rule other browsers seem to implement.
3130 m_imageMapsByName.add(name.impl(), imageMap);
3131 }
3132
3133 void Document::removeImageMap(HTMLMapElement* imageMap)
3134 {
3135 // Remove the image map by name.
3136 // But don't remove some other image map that just happens to have the same name.
3137 // FIXME: Use a HashCountedSet as we do for IDs to find the first remaining map
3138 // once a map has been removed.
3139 const AtomicString& name = imageMap->getName();
3140 if (!name.impl())
3141 return;
3142
3143 ImageMapsByName::iterator it = m_imageMapsByName.find(name.impl());
3144 if (it != m_imageMapsByName.end() && it->second == imageMap)
3145 m_imageMapsByName.remove(it);
3146 }
3147
3148 HTMLMapElement *Document::getImageMap(const String& url) const
3149 {
3150 if (url.isNull())
3151 return 0;
3152 int hashPos = url.find('#');
3153 String name = (hashPos < 0 ? url : url.substring(hashPos + 1)).impl();
3154 AtomicString mapName = isHTMLDocument() ? name.lower() : name;
3155 return m_imageMapsByName.get(mapName.impl());
3156 }
3157
3158 void Document::setDecoder(PassRefPtr<TextResourceDecoder> decoder)
3159 {
3160 m_decoder = decoder;
3161 }
3162
3163 UChar Document::backslashAsCurrencySymbol() const
3164 {
3165 if (!m_decoder)
3166 return '\\';
3167 return m_decoder->encoding().backslashAsCurrencySymbol();
3168 }
3169
3170 KURL Document::completeURL(const String& url) const
3171 {
3172 // Always return a null URL when passed a null string.
3173 // FIXME: Should we change the KURL constructor to have this behavior?
3174 if (url.isNull())
3175 return KURL();
3176 if (!m_decoder)
3177 return KURL(m_baseURL, url);
3178 return KURL(m_baseURL, url, m_decoder->encoding());
3179 }
3180
3181 bool Document::inPageCache()
3182 {
3183 return m_inPageCache;
3184 }
3185
3186 void Document::setInPageCache(bool flag)
3187 {
3188 if (m_inPageCache == flag)
3189 return;
3190
3191 m_inPageCache = flag;
3192 if (flag) {
3193 ASSERT(m_savedRenderer == 0);
3194 m_savedRenderer = renderer();
3195 if (FrameView* v = view())
3196 v->resetScrollbars();
3197 } else {
3198 ASSERT(renderer() == 0 || renderer() == m_savedRenderer);
3199 ASSERT(m_renderArena);
3200 setRenderer(m_savedRenderer);
3201 m_savedRenderer = 0;
3202 }
3203 }
3204
3205 void Document::willSaveToCache()
3206 {
3207 HashSet<Element*>::iterator end = m_pageCacheCallbackElements.end();
3208 for (HashSet<Element*>::iterator i = m_pageCacheCallbackElements.begin(); i != end; ++i)
3209 (*i)->willSaveToCache();
3210 }
3211
3212 void Document::didRestoreFromCache()
3213 {
3214 HashSet<Element*>::iterator end = m_pageCacheCallbackElements.end();
3215 for (HashSet<Element*>::iterator i = m_pageCacheCallbackElements.begin(); i != end; ++i)
3216 (*i)->didRestoreFromCache();
3217 }
3218
3219 void Document::registerForCacheCallbacks(Element* e)
3220 {
3221 m_pageCacheCallbackElements.add(e);
3222 }
3223
3224 void Document::unregisterForCacheCallbacks(Element* e)
3225 {
3226 m_pageCacheCallbackElements.remove(e);
3227 }
3228
3229 void Document::setShouldCreateRenderers(bool f)
3230 {
3231 m_createRenderers = f;
3232 }
3233
3234 bool Document::shouldCreateRenderers()
3235 {
3236 return m_createRenderers;
3237 }
3238
3239 // Support for Javascript execCommand, and related methods
3240
3241 static Editor::Command command(Document* document, const String& commandName, bo ol userInterface = false)
3242 {
3243 Frame* frame = document->frame();
3244 if (!frame || frame->document() != document)
3245 return Editor::Command();
3246 return frame->editor()->command(commandName,
3247 userInterface ? CommandFromDOMWithUserInterface : CommandFromDOM);
3248 }
3249
3250 bool Document::execCommand(const String& commandName, bool userInterface, const String& value)
3251 {
3252 return command(this, commandName, userInterface).execute(value);
3253 }
3254
3255 bool Document::queryCommandEnabled(const String& commandName)
3256 {
3257 return command(this, commandName).isEnabled();
3258 }
3259
3260 bool Document::queryCommandIndeterm(const String& commandName)
3261 {
3262 return command(this, commandName).state() == MixedTriState;
3263 }
3264
3265 bool Document::queryCommandState(const String& commandName)
3266 {
3267 return command(this, commandName).state() != FalseTriState;
3268 }
3269
3270 bool Document::queryCommandSupported(const String& commandName)
3271 {
3272 return command(this, commandName).isSupported();
3273 }
3274
3275 String Document::queryCommandValue(const String& commandName)
3276 {
3277 return command(this, commandName).value();
3278 }
3279
3280 static IntRect placeholderRectForMarker()
3281 {
3282 return IntRect(-1, -1, -1, -1);
3283 }
3284
3285 void Document::addMarker(Range *range, DocumentMarker::MarkerType type, String d escription)
3286 {
3287 // Use a TextIterator to visit the potentially multiple nodes the range cove rs.
3288 for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance ()) {
3289 RefPtr<Range> textPiece = markedText.range();
3290 int exception = 0;
3291 DocumentMarker marker = {type, textPiece->startOffset(exception), textPi ece->endOffset(exception), description};
3292 addMarker(textPiece->startContainer(exception), marker);
3293 }
3294 }
3295
3296 void Document::removeMarkers(Range* range, DocumentMarker::MarkerType markerType )
3297 {
3298 if (m_markers.isEmpty())
3299 return;
3300
3301 ExceptionCode ec = 0;
3302 Node* startContainer = range->startContainer(ec);
3303 Node* endContainer = range->endContainer(ec);
3304
3305 Node* pastLastNode = range->pastLastNode();
3306 for (Node* node = range->firstNode(); node != pastLastNode; node = node->tra verseNextNode()) {
3307 int startOffset = node == startContainer ? range->startOffset(ec) : 0;
3308 int endOffset = node == endContainer ? range->endOffset(ec) : INT_MAX;
3309 int length = endOffset - startOffset;
3310 removeMarkers(node, startOffset, length, markerType);
3311 }
3312 }
3313
3314 // Markers are stored in order sorted by their start offset.
3315 // Markers of the same type do not overlap each other.
3316
3317 void Document::addMarker(Node* node, DocumentMarker newMarker)
3318 {
3319 ASSERT(newMarker.endOffset >= newMarker.startOffset);
3320 if (newMarker.endOffset == newMarker.startOffset)
3321 return;
3322
3323 MarkerMapVectorPair* vectorPair = m_markers.get(node);
3324
3325 if (!vectorPair) {
3326 vectorPair = new MarkerMapVectorPair;
3327 vectorPair->first.append(newMarker);
3328 vectorPair->second.append(placeholderRectForMarker());
3329 m_markers.set(node, vectorPair);
3330 } else {
3331 Vector<DocumentMarker>& markers = vectorPair->first;
3332 Vector<IntRect>& rects = vectorPair->second;
3333 size_t numMarkers = markers.size();
3334 ASSERT(numMarkers == rects.size());
3335 size_t i;
3336 // Iterate over all markers whose start offset is less than or equal to the new marker's.
3337 // If one of them is of the same type as the new marker and touches it o r intersects with it
3338 // (there is at most one), remove it and adjust the new marker's start o ffset to encompass it.
3339 for (i = 0; i < numMarkers; ++i) {
3340 DocumentMarker marker = markers[i];
3341 if (marker.startOffset > newMarker.startOffset)
3342 break;
3343 if (marker.type == newMarker.type && marker.endOffset >= newMarker.s tartOffset) {
3344 newMarker.startOffset = marker.startOffset;
3345 markers.remove(i);
3346 rects.remove(i);
3347 numMarkers--;
3348 break;
3349 }
3350 }
3351 size_t j = i;
3352 // Iterate over all markers whose end offset is less than or equal to th e new marker's,
3353 // removing markers of the same type as the new marker which touch it or intersect with it,
3354 // adjusting the new marker's end offset to cover them if necessary.
3355 while (j < numMarkers) {
3356 DocumentMarker marker = markers[j];
3357 if (marker.startOffset > newMarker.endOffset)
3358 break;
3359 if (marker.type == newMarker.type) {
3360 markers.remove(j);
3361 rects.remove(j);
3362 if (newMarker.endOffset <= marker.endOffset) {
3363 newMarker.endOffset = marker.endOffset;
3364 break;
3365 }
3366 numMarkers--;
3367 } else
3368 j++;
3369 }
3370 // At this point i points to the node before which we want to insert.
3371 markers.insert(i, newMarker);
3372 rects.insert(i, placeholderRectForMarker());
3373 }
3374
3375 // repaint the affected node
3376 if (node->renderer())
3377 node->renderer()->repaint();
3378 }
3379
3380 // copies markers from srcNode to dstNode, applying the specified shift delta to the copies. The shift is
3381 // useful if, e.g., the caller has created the dstNode from a non-prefix substri ng of the srcNode.
3382 void Document::copyMarkers(Node *srcNode, unsigned startOffset, int length, Node *dstNode, int delta, DocumentMarker::MarkerType markerType)
3383 {
3384 if (length <= 0)
3385 return;
3386
3387 MarkerMapVectorPair* vectorPair = m_markers.get(srcNode);
3388 if (!vectorPair)
3389 return;
3390
3391 ASSERT(vectorPair->first.size() == vectorPair->second.size());
3392
3393 bool docDirty = false;
3394 unsigned endOffset = startOffset + length - 1;
3395 Vector<DocumentMarker>& markers = vectorPair->first;
3396 for (size_t i = 0; i != markers.size(); ++i) {
3397 DocumentMarker marker = markers[i];
3398
3399 // stop if we are now past the specified range
3400 if (marker.startOffset > endOffset)
3401 break;
3402
3403 // skip marker that is before the specified range or is the wrong type
3404 if (marker.endOffset < startOffset || (marker.type != markerType && mark erType != DocumentMarker::AllMarkers))
3405 continue;
3406
3407 // pin the marker to the specified range and apply the shift delta
3408 docDirty = true;
3409 if (marker.startOffset < startOffset)
3410 marker.startOffset = startOffset;
3411 if (marker.endOffset > endOffset)
3412 marker.endOffset = endOffset;
3413 marker.startOffset += delta;
3414 marker.endOffset += delta;
3415
3416 addMarker(dstNode, marker);
3417 }
3418
3419 // repaint the affected node
3420 if (docDirty && dstNode->renderer())
3421 dstNode->renderer()->repaint();
3422 }
3423
3424 void Document::removeMarkers(Node* node, unsigned startOffset, int length, Docum entMarker::MarkerType markerType)
3425 {
3426 if (length <= 0)
3427 return;
3428
3429 MarkerMapVectorPair* vectorPair = m_markers.get(node);
3430 if (!vectorPair)
3431 return;
3432
3433 Vector<DocumentMarker>& markers = vectorPair->first;
3434 Vector<IntRect>& rects = vectorPair->second;
3435 ASSERT(markers.size() == rects.size());
3436 bool docDirty = false;
3437 unsigned endOffset = startOffset + length;
3438 for (size_t i = 0; i < markers.size();) {
3439 DocumentMarker marker = markers[i];
3440
3441 // markers are returned in order, so stop if we are now past the specifi ed range
3442 if (marker.startOffset >= endOffset)
3443 break;
3444
3445 // skip marker that is wrong type or before target
3446 if (marker.endOffset < startOffset || (marker.type != markerType && mark erType != DocumentMarker::AllMarkers)) {
3447 i++;
3448 continue;
3449 }
3450
3451 // at this point we know that marker and target intersect in some way
3452 docDirty = true;
3453
3454 // pitch the old marker and any associated rect
3455 markers.remove(i);
3456 rects.remove(i);
3457
3458 // add either of the resulting slices that are left after removing targe t
3459 if (startOffset > marker.startOffset) {
3460 DocumentMarker newLeft = marker;
3461 newLeft.endOffset = startOffset;
3462 markers.insert(i, newLeft);
3463 rects.insert(i, placeholderRectForMarker());
3464 // i now points to the newly-inserted node, but we want to skip that one
3465 i++;
3466 }
3467 if (marker.endOffset > endOffset) {
3468 DocumentMarker newRight = marker;
3469 newRight.startOffset = endOffset;
3470 markers.insert(i, newRight);
3471 rects.insert(i, placeholderRectForMarker());
3472 // i now points to the newly-inserted node, but we want to skip that one
3473 i++;
3474 }
3475 }
3476
3477 if (markers.isEmpty()) {
3478 ASSERT(rects.isEmpty());
3479 m_markers.remove(node);
3480 delete vectorPair;
3481 }
3482
3483 // repaint the affected node
3484 if (docDirty && node->renderer())
3485 node->renderer()->repaint();
3486 }
3487
3488 DocumentMarker* Document::markerContainingPoint(const IntPoint& point, DocumentM arker::MarkerType markerType)
3489 {
3490 // outer loop: process each node that contains any markers
3491 MarkerMap::iterator end = m_markers.end();
3492 for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != e nd; ++nodeIterator) {
3493 // inner loop; process each marker in this node
3494 MarkerMapVectorPair* vectorPair = nodeIterator->second;
3495 Vector<DocumentMarker>& markers = vectorPair->first;
3496 Vector<IntRect>& rects = vectorPair->second;
3497 ASSERT(markers.size() == rects.size());
3498 unsigned markerCount = markers.size();
3499 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
3500 DocumentMarker& marker = markers[markerIndex];
3501
3502 // skip marker that is wrong type
3503 if (marker.type != markerType && markerType != DocumentMarker::AllMa rkers)
3504 continue;
3505
3506 IntRect& r = rects[markerIndex];
3507
3508 // skip placeholder rects
3509 if (r == placeholderRectForMarker())
3510 continue;
3511
3512 if (r.contains(point))
3513 return &marker;
3514 }
3515 }
3516
3517 return 0;
3518 }
3519
3520 Vector<DocumentMarker> Document::markersForNode(Node* node)
3521 {
3522 MarkerMapVectorPair* vectorPair = m_markers.get(node);
3523 if (vectorPair)
3524 return vectorPair->first;
3525 return Vector<DocumentMarker>();
3526 }
3527
3528 Vector<IntRect> Document::renderedRectsForMarkers(DocumentMarker::MarkerType mar kerType)
3529 {
3530 Vector<IntRect> result;
3531
3532 // outer loop: process each node
3533 MarkerMap::iterator end = m_markers.end();
3534 for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != e nd; ++nodeIterator) {
3535 // inner loop; process each marker in this node
3536 MarkerMapVectorPair* vectorPair = nodeIterator->second;
3537 Vector<DocumentMarker>& markers = vectorPair->first;
3538 Vector<IntRect>& rects = vectorPair->second;
3539 ASSERT(markers.size() == rects.size());
3540 unsigned markerCount = markers.size();
3541 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
3542 DocumentMarker marker = markers[markerIndex];
3543
3544 // skip marker that is wrong type
3545 if (marker.type != markerType && markerType != DocumentMarker::AllMa rkers)
3546 continue;
3547
3548 IntRect r = rects[markerIndex];
3549 // skip placeholder rects
3550 if (r == placeholderRectForMarker())
3551 continue;
3552
3553 result.append(r);
3554 }
3555 }
3556
3557 return result;
3558 }
3559
3560 void Document::removeMarkers(Node* node)
3561 {
3562 MarkerMap::iterator i = m_markers.find(node);
3563 if (i != m_markers.end()) {
3564 delete i->second;
3565 m_markers.remove(i);
3566 if (RenderObject* renderer = node->renderer())
3567 renderer->repaint();
3568 }
3569 }
3570
3571 void Document::removeMarkers(DocumentMarker::MarkerType markerType)
3572 {
3573 // outer loop: process each markered node in the document
3574 MarkerMap markerMapCopy = m_markers;
3575 MarkerMap::iterator end = markerMapCopy.end();
3576 for (MarkerMap::iterator i = markerMapCopy.begin(); i != end; ++i) {
3577 Node* node = i->first.get();
3578 bool nodeNeedsRepaint = false;
3579
3580 // inner loop: process each marker in the current node
3581 MarkerMapVectorPair* vectorPair = i->second;
3582 Vector<DocumentMarker>& markers = vectorPair->first;
3583 Vector<IntRect>& rects = vectorPair->second;
3584 ASSERT(markers.size() == rects.size());
3585 for (size_t i = 0; i != markers.size();) {
3586 DocumentMarker marker = markers[i];
3587
3588 // skip nodes that are not of the specified type
3589 if (marker.type != markerType && markerType != DocumentMarker::AllMa rkers) {
3590 ++i;
3591 continue;
3592 }
3593
3594 // pitch the old marker
3595 markers.remove(i);
3596 rects.remove(i);
3597 nodeNeedsRepaint = true;
3598 // markerIterator now points to the next node
3599 }
3600
3601 // Redraw the node if it changed. Do this before the node is removed fro m m_markers, since
3602 // m_markers might contain the last reference to the node.
3603 if (nodeNeedsRepaint) {
3604 RenderObject* renderer = node->renderer();
3605 if (renderer)
3606 renderer->repaint();
3607 }
3608
3609 // delete the node's list if it is now empty
3610 if (markers.isEmpty()) {
3611 ASSERT(rects.isEmpty());
3612 m_markers.remove(node);
3613 delete vectorPair;
3614 }
3615 }
3616 }
3617
3618 void Document::repaintMarkers(DocumentMarker::MarkerType markerType)
3619 {
3620 // outer loop: process each markered node in the document
3621 MarkerMap::iterator end = m_markers.end();
3622 for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
3623 Node* node = i->first.get();
3624
3625 // inner loop: process each marker in the current node
3626 MarkerMapVectorPair* vectorPair = i->second;
3627 Vector<DocumentMarker>& markers = vectorPair->first;
3628 bool nodeNeedsRepaint = false;
3629 for (size_t i = 0; i != markers.size(); ++i) {
3630 DocumentMarker marker = markers[i];
3631
3632 // skip nodes that are not of the specified type
3633 if (marker.type == markerType || markerType == DocumentMarker::AllMa rkers) {
3634 nodeNeedsRepaint = true;
3635 break;
3636 }
3637 }
3638
3639 if (!nodeNeedsRepaint)
3640 continue;
3641
3642 // cause the node to be redrawn
3643 if (RenderObject* renderer = node->renderer())
3644 renderer->repaint();
3645 }
3646 }
3647
3648 void Document::setRenderedRectForMarker(Node* node, DocumentMarker marker, const IntRect& r)
3649 {
3650 MarkerMapVectorPair* vectorPair = m_markers.get(node);
3651 if (!vectorPair) {
3652 ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marke r we don't already know about
3653 return;
3654 }
3655
3656 Vector<DocumentMarker>& markers = vectorPair->first;
3657 ASSERT(markers.size() == vectorPair->second.size());
3658 unsigned markerCount = markers.size();
3659 for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
3660 DocumentMarker m = markers[markerIndex];
3661 if (m == marker) {
3662 vectorPair->second[markerIndex] = r;
3663 return;
3664 }
3665 }
3666
3667 ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marker we don't already know about
3668 }
3669
3670 void Document::invalidateRenderedRectsForMarkersInRect(const IntRect& r)
3671 {
3672 // outer loop: process each markered node in the document
3673 MarkerMap::iterator end = m_markers.end();
3674 for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
3675
3676 // inner loop: process each rect in the current node
3677 MarkerMapVectorPair* vectorPair = i->second;
3678 Vector<IntRect>& rects = vectorPair->second;
3679
3680 unsigned rectCount = rects.size();
3681 for (unsigned rectIndex = 0; rectIndex < rectCount; ++rectIndex)
3682 if (rects[rectIndex].intersects(r))
3683 rects[rectIndex] = placeholderRectForMarker();
3684 }
3685 }
3686
3687 void Document::shiftMarkers(Node *node, unsigned startOffset, int delta, Documen tMarker::MarkerType markerType)
3688 {
3689 MarkerMapVectorPair* vectorPair = m_markers.get(node);
3690 if (!vectorPair)
3691 return;
3692
3693 Vector<DocumentMarker>& markers = vectorPair->first;
3694 Vector<IntRect>& rects = vectorPair->second;
3695 ASSERT(markers.size() == rects.size());
3696
3697 bool docDirty = false;
3698 for (size_t i = 0; i != markers.size(); ++i) {
3699 DocumentMarker &marker = markers[i];
3700 if (marker.startOffset >= startOffset && (markerType == DocumentMarker:: AllMarkers || marker.type == markerType)) {
3701 ASSERT((int)marker.startOffset + delta >= 0);
3702 marker.startOffset += delta;
3703 marker.endOffset += delta;
3704 docDirty = true;
3705
3706 // Marker moved, so previously-computed rendered rectangle is now in valid
3707 rects[i] = placeholderRectForMarker();
3708 }
3709 }
3710
3711 // repaint the affected node
3712 if (docDirty && node->renderer())
3713 node->renderer()->repaint();
3714 }
3715
3716 #if ENABLE(XSLT)
3717
3718 void Document::applyXSLTransform(ProcessingInstruction* pi)
3719 {
3720 RefPtr<XSLTProcessor> processor = XSLTProcessor::create();
3721 processor->setXSLStyleSheet(static_cast<XSLStyleSheet*>(pi->sheet()));
3722 String resultMIMEType;
3723 String newSource;
3724 String resultEncoding;
3725 if (!processor->transformToString(this, resultMIMEType, newSource, resultEnc oding))
3726 return;
3727 // FIXME: If the transform failed we should probably report an error (like M ozilla does).
3728 processor->createDocumentFromSource(newSource, resultEncoding, resultMIMETyp e, this, frame());
3729 }
3730
3731 void Document::setTransformSource(void* doc)
3732 {
3733 if (doc == m_transformSource)
3734 return;
3735
3736 xmlFreeDoc((xmlDocPtr)m_transformSource);
3737 m_transformSource = doc;
3738 }
3739
3740 #endif
3741
3742 void Document::setDesignMode(InheritedBool value)
3743 {
3744 m_designMode = value;
3745 }
3746
3747 Document::InheritedBool Document::getDesignMode() const
3748 {
3749 return m_designMode;
3750 }
3751
3752 bool Document::inDesignMode() const
3753 {
3754 for (const Document* d = this; d; d = d->parentDocument()) {
3755 if (d->m_designMode != inherit)
3756 return d->m_designMode;
3757 }
3758 return false;
3759 }
3760
3761 Document *Document::parentDocument() const
3762 {
3763 Frame *childPart = frame();
3764 if (!childPart)
3765 return 0;
3766 Frame *parent = childPart->tree()->parent();
3767 if (!parent)
3768 return 0;
3769 return parent->document();
3770 }
3771
3772 Document *Document::topDocument() const
3773 {
3774 Document *doc = const_cast<Document *>(this);
3775 Element *element;
3776 while ((element = doc->ownerElement()))
3777 doc = element->document();
3778
3779 return doc;
3780 }
3781
3782 PassRefPtr<Attr> Document::createAttributeNS(const String& namespaceURI, const S tring& qualifiedName, ExceptionCode& ec, bool shouldIgnoreNamespaceChecks)
3783 {
3784 String prefix, localName;
3785 if (!parseQualifiedName(qualifiedName, prefix, localName, ec))
3786 return 0;
3787
3788 QualifiedName qName(prefix, localName, namespaceURI);
3789 if (!shouldIgnoreNamespaceChecks && hasPrefixNamespaceMismatch(qName)) {
3790 ec = NAMESPACE_ERR;
3791 return 0;
3792 }
3793
3794 // Spec: DOM Level 2 Core: http://www.w3.org/TR/DOM-Level-2-Core/core.html#I D-DocCrAttrNS
3795 if (!shouldIgnoreNamespaceChecks && qName.localName() == "xmlns" && qName.na mespaceURI() != "http://www.w3.org/2000/xmlns/") {
3796 ec = NAMESPACE_ERR;
3797 return 0;
3798 }
3799
3800 // FIXME: Assume this is a mapped attribute, since createAttribute isn't nam espace-aware. There's no harm to XML
3801 // documents if we're wrong.
3802 return new Attr(0, this, MappedAttribute::create(qName, StringImpl::empty()) );
3803 }
3804
3805 #if ENABLE(SVG)
3806 const SVGDocumentExtensions* Document::svgExtensions()
3807 {
3808 return m_svgExtensions;
3809 }
3810
3811 SVGDocumentExtensions* Document::accessSVGExtensions()
3812 {
3813 if (!m_svgExtensions)
3814 m_svgExtensions = new SVGDocumentExtensions(this);
3815 return m_svgExtensions;
3816 }
3817 #endif
3818
3819 PassRefPtr<HTMLCollection> Document::images()
3820 {
3821 return HTMLCollection::create(this, HTMLCollection::DocImages);
3822 }
3823
3824 PassRefPtr<HTMLCollection> Document::applets()
3825 {
3826 return HTMLCollection::create(this, HTMLCollection::DocApplets);
3827 }
3828
3829 PassRefPtr<HTMLCollection> Document::embeds()
3830 {
3831 return HTMLCollection::create(this, HTMLCollection::DocEmbeds);
3832 }
3833
3834 PassRefPtr<HTMLCollection> Document::plugins()
3835 {
3836 // This is an alias for embeds() required for the JS DOM bindings.
3837 return HTMLCollection::create(this, HTMLCollection::DocEmbeds);
3838 }
3839
3840 PassRefPtr<HTMLCollection> Document::objects()
3841 {
3842 return HTMLCollection::create(this, HTMLCollection::DocObjects);
3843 }
3844
3845 PassRefPtr<HTMLCollection> Document::scripts()
3846 {
3847 return HTMLCollection::create(this, HTMLCollection::DocScripts);
3848 }
3849
3850 PassRefPtr<HTMLCollection> Document::links()
3851 {
3852 return HTMLCollection::create(this, HTMLCollection::DocLinks);
3853 }
3854
3855 PassRefPtr<HTMLCollection> Document::forms()
3856 {
3857 return HTMLCollection::create(this, HTMLCollection::DocForms);
3858 }
3859
3860 PassRefPtr<HTMLCollection> Document::anchors()
3861 {
3862 return HTMLCollection::create(this, HTMLCollection::DocAnchors);
3863 }
3864
3865 PassRefPtr<HTMLCollection> Document::all()
3866 {
3867 return HTMLCollection::create(this, HTMLCollection::DocAll);
3868 }
3869
3870 PassRefPtr<HTMLCollection> Document::windowNamedItems(const String &name)
3871 {
3872 return HTMLNameCollection::create(this, HTMLCollection::WindowNamedItems, na me);
3873 }
3874
3875 PassRefPtr<HTMLCollection> Document::documentNamedItems(const String &name)
3876 {
3877 return HTMLNameCollection::create(this, HTMLCollection::DocumentNamedItems, name);
3878 }
3879
3880 HTMLCollection::CollectionInfo* Document::nameCollectionInfo(HTMLCollection::Typ e type, const AtomicString& name)
3881 {
3882 ASSERT(type >= HTMLCollection::FirstNamedDocumentCachedType);
3883 unsigned index = type - HTMLCollection::FirstNamedDocumentCachedType;
3884 ASSERT(index < HTMLCollection::NumNamedDocumentCachedTypes);
3885
3886 NamedCollectionMap& map = m_nameCollectionInfo[index];
3887 NamedCollectionMap::iterator iter = map.find(name.impl());
3888 if (iter == map.end())
3889 iter = map.add(name.impl(), new HTMLCollection::CollectionInfo).first;
3890 return iter->second;
3891 }
3892
3893 void Document::finishedParsing()
3894 {
3895 setParsing(false);
3896
3897 ExceptionCode ec = 0;
3898 dispatchEvent(Event::create(DOMContentLoadedEvent, true, false), ec);
3899
3900 if (Frame* f = frame())
3901 f->loader()->finishedParsing();
3902 }
3903
3904 Vector<String> Document::formElementsState() const
3905 {
3906 Vector<String> stateVector;
3907 stateVector.reserveCapacity(m_formElementsWithState.size() * 3);
3908 typedef ListHashSet<HTMLFormControlElementWithState*>::const_iterator Iterat or;
3909 Iterator end = m_formElementsWithState.end();
3910 for (Iterator it = m_formElementsWithState.begin(); it != end; ++it) {
3911 HTMLFormControlElementWithState* e = *it;
3912 String value;
3913 if (e->saveState(value)) {
3914 stateVector.append(e->name().string());
3915 stateVector.append(e->type().string());
3916 stateVector.append(value);
3917 }
3918 }
3919 return stateVector;
3920 }
3921
3922 #if ENABLE(XPATH)
3923
3924 PassRefPtr<XPathExpression> Document::createExpression(const String& expression,
3925 XPathNSResolver* resolver ,
3926 ExceptionCode& ec)
3927 {
3928 if (!m_xpathEvaluator)
3929 m_xpathEvaluator = XPathEvaluator::create();
3930 return m_xpathEvaluator->createExpression(expression, resolver, ec);
3931 }
3932
3933 PassRefPtr<XPathNSResolver> Document::createNSResolver(Node* nodeResolver)
3934 {
3935 if (!m_xpathEvaluator)
3936 m_xpathEvaluator = XPathEvaluator::create();
3937 return m_xpathEvaluator->createNSResolver(nodeResolver);
3938 }
3939
3940 PassRefPtr<XPathResult> Document::evaluate(const String& expression,
3941 Node* contextNode,
3942 XPathNSResolver* resolver,
3943 unsigned short type,
3944 XPathResult* result,
3945 ExceptionCode& ec)
3946 {
3947 if (!m_xpathEvaluator)
3948 m_xpathEvaluator = XPathEvaluator::create();
3949 return m_xpathEvaluator->evaluate(expression, contextNode, resolver, type, r esult, ec);
3950 }
3951
3952 #endif // ENABLE(XPATH)
3953
3954 void Document::setStateForNewFormElements(const Vector<String>& stateVector)
3955 {
3956 // Walk the state vector backwards so that the value to use for each
3957 // name/type pair first is the one at the end of each individual vector
3958 // in the FormElementStateMap. We're using them like stacks.
3959 typedef FormElementStateMap::iterator Iterator;
3960 m_formElementsWithState.clear();
3961 for (size_t i = stateVector.size() / 3 * 3; i; i -= 3) {
3962 AtomicString a = stateVector[i - 3];
3963 AtomicString b = stateVector[i - 2];
3964 const String& c = stateVector[i - 1];
3965 FormElementKey key(a.impl(), b.impl());
3966 Iterator it = m_stateForNewFormElements.find(key);
3967 if (it != m_stateForNewFormElements.end())
3968 it->second.append(c);
3969 else {
3970 Vector<String> v(1);
3971 v[0] = c;
3972 m_stateForNewFormElements.set(key, v);
3973 }
3974 }
3975 }
3976
3977 bool Document::hasStateForNewFormElements() const
3978 {
3979 return !m_stateForNewFormElements.isEmpty();
3980 }
3981
3982 bool Document::takeStateForFormElement(AtomicStringImpl* name, AtomicStringImpl* type, String& state)
3983 {
3984 typedef FormElementStateMap::iterator Iterator;
3985 Iterator it = m_stateForNewFormElements.find(FormElementKey(name, type));
3986 if (it == m_stateForNewFormElements.end())
3987 return false;
3988 ASSERT(it->second.size());
3989 state = it->second.last();
3990 if (it->second.size() > 1)
3991 it->second.removeLast();
3992 else
3993 m_stateForNewFormElements.remove(it);
3994 return true;
3995 }
3996
3997 FormElementKey::FormElementKey(AtomicStringImpl* name, AtomicStringImpl* type)
3998 : m_name(name), m_type(type)
3999 {
4000 ref();
4001 }
4002
4003 FormElementKey::~FormElementKey()
4004 {
4005 deref();
4006 }
4007
4008 FormElementKey::FormElementKey(const FormElementKey& other)
4009 : m_name(other.name()), m_type(other.type())
4010 {
4011 ref();
4012 }
4013
4014 FormElementKey& FormElementKey::operator=(const FormElementKey& other)
4015 {
4016 other.ref();
4017 deref();
4018 m_name = other.name();
4019 m_type = other.type();
4020 return *this;
4021 }
4022
4023 void FormElementKey::ref() const
4024 {
4025 if (name())
4026 name()->ref();
4027 if (type())
4028 type()->ref();
4029 }
4030
4031 void FormElementKey::deref() const
4032 {
4033 if (name())
4034 name()->deref();
4035 if (type())
4036 type()->deref();
4037 }
4038
4039 unsigned FormElementKeyHash::hash(const FormElementKey& k)
4040 {
4041 ASSERT(sizeof(k) % (sizeof(uint16_t) * 2) == 0);
4042
4043 unsigned l = sizeof(k) / (sizeof(uint16_t) * 2);
4044 const uint16_t* s = reinterpret_cast<const uint16_t*>(&k);
4045 uint32_t hash = PHI;
4046
4047 // Main loop
4048 for (; l > 0; l--) {
4049 hash += s[0];
4050 uint32_t tmp = (s[1] << 11) ^ hash;
4051 hash = (hash << 16) ^ tmp;
4052 s += 2;
4053 hash += hash >> 11;
4054 }
4055
4056 // Force "avalanching" of final 127 bits
4057 hash ^= hash << 3;
4058 hash += hash >> 5;
4059 hash ^= hash << 2;
4060 hash += hash >> 15;
4061 hash ^= hash << 10;
4062
4063 // this avoids ever returning a hash code of 0, since that is used to
4064 // signal "hash not computed yet", using a value that is likely to be
4065 // effectively the same as 0 when the low bits are masked
4066 if (hash == 0)
4067 hash = 0x80000000;
4068
4069 return hash;
4070 }
4071
4072 void Document::setIconURL(const String& iconURL, const String& type)
4073 {
4074 // FIXME - <rdar://problem/4727645> - At some point in the future, we might actually honor the "type"
4075 if (m_iconURL.isEmpty())
4076 m_iconURL = iconURL;
4077 else if (!type.isEmpty())
4078 m_iconURL = iconURL;
4079 }
4080
4081 void Document::setUseSecureKeyboardEntryWhenActive(bool usesSecureKeyboard)
4082 {
4083 if (m_useSecureKeyboardEntryWhenActive == usesSecureKeyboard)
4084 return;
4085
4086 m_useSecureKeyboardEntryWhenActive = usesSecureKeyboard;
4087 m_frame->updateSecureKeyboardEntryIfActive();
4088 }
4089
4090 bool Document::useSecureKeyboardEntryWhenActive() const
4091 {
4092 return m_useSecureKeyboardEntryWhenActive;
4093 }
4094
4095 void Document::initSecurityContext()
4096 {
4097 if (m_securityOrigin && !m_securityOrigin->isEmpty())
4098 return; // m_securityOrigin has already been initialized.
4099
4100 if (!m_frame) {
4101 // No source for a security context.
4102 // This can occur via document.implementation.createDocument().
4103 m_cookieURL = KURL("");
4104 m_securityOrigin = SecurityOrigin::createEmpty();
4105 return;
4106 }
4107
4108 // In the common case, create the security context from the currently
4109 // loading URL.
4110 const KURL& url = m_frame->loader()->url();
4111 m_cookieURL = url;
4112 m_securityOrigin = SecurityOrigin::create(url);
4113
4114 if (FrameLoader::allowSubstituteDataAccessToLocal()) {
4115 // If this document was loaded with substituteData, then the document ca n
4116 // load local resources. See https://bugs.webkit.org/show_bug.cgi?id=16 756
4117 // and https://bugs.webkit.org/show_bug.cgi?id=19760 for further
4118 // discussion.
4119 DocumentLoader* documentLoader = m_frame->loader()->documentLoader();
4120 if (documentLoader && documentLoader->substituteData().isValid())
4121 m_securityOrigin->grantLoadLocalResources();
4122 }
4123
4124 if (!m_securityOrigin->isEmpty())
4125 return;
4126
4127 // If we do not obtain a meaningful origin from the URL, then we try to
4128 // find one via the frame hierarchy.
4129
4130 Frame* ownerFrame = m_frame->tree()->parent();
4131 if (!ownerFrame)
4132 ownerFrame = m_frame->loader()->opener();
4133
4134 if (ownerFrame && ownerFrame->document()) {
4135 m_cookieURL = ownerFrame->document()->cookieURL();
4136 // We alias the SecurityOrigins to match Firefox, see Bug 15313
4137 // https://bugs.webkit.org/show_bug.cgi?id=15313
4138 m_securityOrigin = ownerFrame->document()->securityOrigin();
4139 }
4140 }
4141
4142 void Document::setSecurityOrigin(SecurityOrigin* securityOrigin)
4143 {
4144 m_securityOrigin = securityOrigin;
4145 initDNSPrefetchEnabled();
4146 }
4147
4148 void Document::updateFocusAppearanceSoon()
4149 {
4150 if (!m_updateFocusAppearanceTimer.isActive())
4151 m_updateFocusAppearanceTimer.startOneShot(0);
4152 }
4153
4154 void Document::cancelFocusAppearanceUpdate()
4155 {
4156 m_updateFocusAppearanceTimer.stop();
4157 }
4158
4159 void Document::updateFocusAppearanceTimerFired(Timer<Document>*)
4160 {
4161 Node* node = focusedNode();
4162 if (!node)
4163 return;
4164 if (!node->isElementNode())
4165 return;
4166
4167 updateLayout();
4168
4169 Element* element = static_cast<Element*>(node);
4170 if (element->isFocusable())
4171 element->updateFocusAppearance(false);
4172 }
4173
4174 // FF method for accessing the selection added for compatability.
4175 DOMSelection* Document::getSelection() const
4176 {
4177 return frame() ? frame()->domWindow()->getSelection() : 0;
4178 }
4179
4180 static inline int findSlashDotDotSlash(const UChar* characters, size_t length)
4181 {
4182 if (length < 4)
4183 return -1;
4184 unsigned loopLimit = length - 3;
4185 for (unsigned i = 0; i < loopLimit; ++i) {
4186 if (characters[i] == '/' && characters[i + 1] == '.' && characters[i + 2 ] == '.' && characters[i + 3] == '/')
4187 return i;
4188 }
4189 return -1;
4190 }
4191
4192 static inline int findSlashSlash(const UChar* characters, size_t length, int pos ition)
4193 {
4194 if (length < 2)
4195 return -1;
4196 unsigned loopLimit = length - 1;
4197 for (unsigned i = position; i < loopLimit; ++i) {
4198 if (characters[i] == '/' && characters[i + 1] == '/')
4199 return i;
4200 }
4201 return -1;
4202 }
4203
4204 static inline int findSlashDotSlash(const UChar* characters, size_t length)
4205 {
4206 if (length < 3)
4207 return -1;
4208 unsigned loopLimit = length - 2;
4209 for (unsigned i = 0; i < loopLimit; ++i) {
4210 if (characters[i] == '/' && characters[i + 1] == '.' && characters[i + 2 ] == '/')
4211 return i;
4212 }
4213 return -1;
4214 }
4215
4216 static inline bool containsColonSlashSlash(const UChar* characters, unsigned len gth)
4217 {
4218 if (length < 3)
4219 return false;
4220 unsigned loopLimit = length - 2;
4221 for (unsigned i = 0; i < loopLimit; ++i) {
4222 if (characters[i] == ':' && characters[i + 1] == '/' && characters[i + 2 ] == '/')
4223 return true;
4224 }
4225 return false;
4226 }
4227
4228 static inline void cleanPath(Vector<UChar, 512>& path)
4229 {
4230 // FIXME: Shold not do this in the query or anchor part.
4231 int pos;
4232 while ((pos = findSlashDotDotSlash(path.data(), path.size())) != -1) {
4233 int prev = reverseFind(path.data(), path.size(), '/', pos - 1);
4234 // don't remove the host, i.e. http://foo.org/../foo.html
4235 if (prev < 0 || (prev > 3 && path[prev - 2] == ':' && path[prev - 1] == '/'))
4236 path.remove(pos, 3);
4237 else
4238 path.remove(prev, pos - prev + 3);
4239 }
4240
4241 // FIXME: Shold not do this in the query part.
4242 // Set refPos to -2 to mean "I haven't looked for the anchor yet".
4243 // We don't want to waste a function call on the search for the the anchor
4244 // in the vast majority of cases where there is no "//" in the path.
4245 pos = 0;
4246 int refPos = -2;
4247 while ((pos = findSlashSlash(path.data(), path.size(), pos)) != -1) {
4248 if (refPos == -2)
4249 refPos = find(path.data(), path.size(), '#');
4250 if (refPos > 0 && pos >= refPos)
4251 break;
4252
4253 if (pos == 0 || path[pos - 1] != ':')
4254 path.remove(pos);
4255 else
4256 pos += 2;
4257 }
4258
4259 // FIXME: Shold not do this in the query or anchor part.
4260 while ((pos = findSlashDotSlash(path.data(), path.size())) != -1)
4261 path.remove(pos, 2);
4262 }
4263
4264 static inline bool matchLetter(UChar c, UChar lowercaseLetter)
4265 {
4266 return (c | 0x20) == lowercaseLetter;
4267 }
4268
4269 static inline bool needsTrailingSlash(const UChar* characters, unsigned length)
4270 {
4271 if (length < 6)
4272 return false;
4273 if (!matchLetter(characters[0], 'h')
4274 || !matchLetter(characters[1], 't')
4275 || !matchLetter(characters[2], 't')
4276 || !matchLetter(characters[3], 'p'))
4277 return false;
4278 if (!(characters[4] == ':'
4279 || (matchLetter(characters[4], 's') && characters[5] == ':')))
4280 return false;
4281
4282 unsigned pos = characters[4] == ':' ? 5 : 6;
4283
4284 // Skip initial two slashes if present.
4285 if (pos + 1 < length && characters[pos] == '/' && characters[pos + 1] == '/' )
4286 pos += 2;
4287
4288 // Find next slash.
4289 while (pos < length && characters[pos] != '/')
4290 ++pos;
4291
4292 return pos == length;
4293 }
4294
4295 unsigned Document::visitedLinkHash(const AtomicString& attributeURL) const
4296 {
4297 const UChar* characters = attributeURL.characters();
4298 unsigned length = attributeURL.length();
4299 if (!length)
4300 return 0;
4301
4302 // This is a poor man's completeURL. Faster with less memory allocation.
4303 // FIXME: It's missing a lot of what completeURL does and a lot of what KURL does.
4304 // For example, it does not handle international domain names properly.
4305
4306 // FIXME: It is wrong that we do not do further processing on strings that h ave "://" in them:
4307 // 1) The "://" could be in the query or anchor.
4308 // 2) The URL's path could have a "/./" or a "/../" or a "//" sequence in it.
4309
4310 // FIXME: needsTrailingSlash does not properly return true for a URL that ha s no path, but does
4311 // have a query or anchor.
4312
4313 bool hasColonSlashSlash = containsColonSlashSlash(characters, length);
4314
4315 if (hasColonSlashSlash && !needsTrailingSlash(characters, length))
4316 return AlreadyHashed::avoidDeletedValue(attributeURL.string().impl()->ha sh());
4317
4318 Vector<UChar, 512> buffer;
4319
4320 if (hasColonSlashSlash) {
4321 // FIXME: This is incorrect for URLs that have a query or anchor; the "/ " needs to go at the
4322 // end of the path, *before* the query or anchor.
4323 buffer.append(characters, length);
4324 buffer.append('/');
4325 return AlreadyHashed::avoidDeletedValue(StringImpl::computeHash(buffer.d ata(), buffer.size()));
4326 }
4327
4328 switch (characters[0]) {
4329 case '/':
4330 buffer.append(m_baseURL.string().characters(), m_baseURL.pathStart() );
4331 break;
4332 case '#':
4333 buffer.append(m_baseURL.string().characters(), m_baseURL.pathEnd());
4334 break;
4335 default:
4336 buffer.append(m_baseURL.string().characters(), m_baseURL.pathAfterLa stSlash());
4337 break;
4338 }
4339 buffer.append(characters, length);
4340 cleanPath(buffer);
4341 if (needsTrailingSlash(buffer.data(), buffer.size())) {
4342 // FIXME: This is incorrect for URLs that have a query or anchor; the "/ " needs to go at the
4343 // end of the path, *before* the query or anchor.
4344 buffer.append('/');
4345 }
4346
4347 return AlreadyHashed::avoidDeletedValue(StringImpl::computeHash(buffer.data( ), buffer.size()));
4348 }
4349
4350 #if ENABLE(DATABASE)
4351
4352 void Document::addOpenDatabase(Database* database)
4353 {
4354 if (!m_openDatabaseSet)
4355 m_openDatabaseSet.set(new DatabaseSet);
4356
4357 ASSERT(!m_openDatabaseSet->contains(database));
4358 m_openDatabaseSet->add(database);
4359 }
4360
4361 void Document::removeOpenDatabase(Database* database)
4362 {
4363 ASSERT(m_openDatabaseSet && m_openDatabaseSet->contains(database));
4364 if (!m_openDatabaseSet)
4365 return;
4366
4367 m_openDatabaseSet->remove(database);
4368 }
4369
4370 DatabaseThread* Document::databaseThread()
4371 {
4372 if (!m_databaseThread && !m_hasOpenDatabases) {
4373 // Create the database thread on first request - but not if at least one database was already opened,
4374 // because in that case we already had a database thread and terminated it and should not create another.
4375 m_databaseThread = DatabaseThread::create(this);
4376 if (!m_databaseThread->start())
4377 m_databaseThread = 0;
4378 }
4379
4380 return m_databaseThread.get();
4381 }
4382
4383 void Document::stopDatabases()
4384 {
4385 if (m_openDatabaseSet) {
4386 DatabaseSet::iterator i = m_openDatabaseSet->begin();
4387 DatabaseSet::iterator end = m_openDatabaseSet->end();
4388 for (; i != end; ++i) {
4389 (*i)->stop();
4390 if (m_databaseThread)
4391 m_databaseThread->unscheduleDatabaseTasks(*i);
4392 }
4393 }
4394
4395 if (m_databaseThread)
4396 m_databaseThread->requestTermination();
4397 }
4398
4399 #endif
4400
4401 void Document::attachRange(Range* range)
4402 {
4403 ASSERT(!m_ranges.contains(range));
4404 m_ranges.add(range);
4405 }
4406
4407 void Document::detachRange(Range* range)
4408 {
4409 ASSERT(m_ranges.contains(range));
4410 m_ranges.remove(range);
4411 }
4412
4413 CanvasRenderingContext2D* Document::getCSSCanvasContext(const String& type, cons t String& name, int width, int height)
4414 {
4415 HTMLCanvasElement* result = getCSSCanvasElement(name);
4416 if (!result)
4417 return 0;
4418 result->setSize(IntSize(width, height));
4419 return result->getContext(type);
4420 }
4421
4422 HTMLCanvasElement* Document::getCSSCanvasElement(const String& name)
4423 {
4424 RefPtr<HTMLCanvasElement> result = m_cssCanvasElements.get(name).get();
4425 if (!result) {
4426 result = new HTMLCanvasElement(this);
4427 m_cssCanvasElements.set(name, result);
4428 }
4429 return result.get();
4430 }
4431
4432 void Document::initDNSPrefetchEnabled()
4433 {
4434 m_haveExplicitlyDisabledDNSPrefetch = false;
4435 m_isDNSPrefetchEnabled = (securityOrigin()->protocol() == "http");
4436
4437 // Inherit DNS prefetch opt-out from parent frame
4438 if (Document* parent = parentDocument())
4439 if (!parent->isDNSPrefetchEnabled())
4440 m_isDNSPrefetchEnabled = false;
4441 }
4442
4443 void Document::setDNSPrefetchControl(const String& dnsPrefetchControl)
4444 {
4445 if (equalIgnoringCase(dnsPrefetchControl, "on") &&
4446 !m_haveExplicitlyDisabledDNSPrefetch) {
4447 m_isDNSPrefetchEnabled = true;
4448 return;
4449 }
4450
4451 m_isDNSPrefetchEnabled = false;
4452 m_haveExplicitlyDisabledDNSPrefetch = true;
4453 }
4454
4455 } // namespace WebCore
OLDNEW
« no previous file with comments | « webkit/pending/Document.h ('k') | webkit/pending/DragController.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698