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