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