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, 2011, 2012 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, 2011, 2012 Google Inc. All rights reserved.
9 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
10 * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved.
11 *
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
16 *
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public License
23 * along with this library; see the file COPYING.LIB. If not, write to
24 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 * Boston, MA 02110-1301, USA.
26 */
27
28 #include "config.h"
29 #include "core/dom/Document.h"
30
31 #include "HTMLElementFactory.h"
32 #include "HTMLNames.h"
33 #include "RuntimeEnabledFeatures.h"
34 #include "SVGElementFactory.h"
35 #include "SVGNames.h"
36 #include "XMLNSNames.h"
37 #include "XMLNames.h"
38 #include "bindings/v8/CustomElementConstructorBuilder.h"
39 #include "bindings/v8/Dictionary.h"
40 #include "bindings/v8/ExceptionMessages.h"
41 #include "bindings/v8/ExceptionState.h"
42 #include "bindings/v8/ExceptionStatePlaceholder.h"
43 #include "bindings/v8/ScriptController.h"
44 #include "core/accessibility/AXObjectCache.h"
45 #include "core/animation/AnimationClock.h"
46 #include "core/animation/DocumentAnimations.h"
47 #include "core/animation/DocumentTimeline.h"
48 #include "core/animation/css/TransitionTimeline.h"
49 #include "core/css/CSSDefaultStyleSheets.h"
50 #include "core/css/CSSFontSelector.h"
51 #include "core/css/CSSStyleDeclaration.h"
52 #include "core/css/CSSStyleSheet.h"
53 #include "core/css/MediaQueryMatcher.h"
54 #include "core/css/StylePropertySet.h"
55 #include "core/css/StyleSheetContents.h"
56 #include "core/css/StyleSheetList.h"
57 #include "core/css/resolver/FontBuilder.h"
58 #include "core/css/resolver/StyleResolver.h"
59 #include "core/css/resolver/StyleResolverStats.h"
60 #include "core/dom/AddConsoleMessageTask.h"
61 #include "core/dom/Attr.h"
62 #include "core/dom/CDATASection.h"
63 #include "core/dom/Comment.h"
64 #include "core/dom/ContextFeatures.h"
65 #include "core/dom/DOMImplementation.h"
66 #include "core/dom/DOMNamedFlowCollection.h"
67 #include "core/dom/DocumentFragment.h"
68 #include "core/dom/DocumentLifecycleNotifier.h"
69 #include "core/dom/DocumentLifecycleObserver.h"
70 #include "core/dom/DocumentMarkerController.h"
71 #include "core/dom/DocumentSharedObjectPool.h"
72 #include "core/dom/DocumentType.h"
73 #include "core/dom/Element.h"
74 #include "core/dom/ElementTraversal.h"
75 #include "core/dom/ExceptionCode.h"
76 #include "core/dom/ExecutionContextTask.h"
77 #include "core/dom/MainThreadTaskRunner.h"
78 #include "core/dom/NamedFlowCollection.h"
79 #include "core/dom/NodeChildRemovalTracker.h"
80 #include "core/dom/NodeFilter.h"
81 #include "core/dom/NodeIterator.h"
82 #include "core/dom/NodeRareData.h"
83 #include "core/dom/NodeRenderStyle.h"
84 #include "core/dom/NodeRenderingTraversal.h"
85 #include "core/dom/NodeTraversal.h"
86 #include "core/dom/NodeWithIndex.h"
87 #include "core/dom/PostAttachCallbacks.h"
88 #include "core/dom/ProcessingInstruction.h"
89 #include "core/dom/RequestAnimationFrameCallback.h"
90 #include "core/dom/ScriptRunner.h"
91 #include "core/dom/ScriptedAnimationController.h"
92 #include "core/dom/SelectorQuery.h"
93 #include "core/dom/StyleEngine.h"
94 #include "core/dom/TouchList.h"
95 #include "core/dom/TransformSource.h"
96 #include "core/dom/TreeWalker.h"
97 #include "core/dom/VisitedLinkState.h"
98 #include "core/dom/custom/CustomElementRegistrationContext.h"
99 #include "core/dom/shadow/ElementShadow.h"
100 #include "core/dom/shadow/ShadowRoot.h"
101 #include "core/editing/Editor.h"
102 #include "core/editing/FrameSelection.h"
103 #include "core/editing/SpellChecker.h"
104 #include "core/events/BeforeUnloadEvent.h"
105 #include "core/events/Event.h"
106 #include "core/events/EventFactory.h"
107 #include "core/events/EventListener.h"
108 #include "core/events/HashChangeEvent.h"
109 #include "core/events/PageTransitionEvent.h"
110 #include "core/events/ScopedEventQueue.h"
111 #include "core/events/ThreadLocalEventNames.h"
112 #include "core/fetch/ResourceFetcher.h"
113 #include "core/fetch/TextResourceDecoder.h"
114 #include "core/frame/ContentSecurityPolicy.h"
115 #include "core/frame/DOMSecurityPolicy.h"
116 #include "core/frame/DOMWindow.h"
117 #include "core/frame/Frame.h"
118 #include "core/frame/FrameView.h"
119 #include "core/frame/History.h"
120 #include "core/frame/animation/AnimationController.h"
121 #include "core/html/HTMLAllCollection.h"
122 #include "core/html/HTMLAnchorElement.h"
123 #include "core/html/HTMLCanvasElement.h"
124 #include "core/html/HTMLCollection.h"
125 #include "core/html/HTMLDialogElement.h"
126 #include "core/html/HTMLDocument.h"
127 #include "core/html/HTMLFrameOwnerElement.h"
128 #include "core/html/HTMLHeadElement.h"
129 #include "core/html/HTMLHtmlElement.h"
130 #include "core/html/HTMLIFrameElement.h"
131 #include "core/html/HTMLImport.h"
132 #include "core/html/HTMLInputElement.h"
133 #include "core/html/HTMLLinkElement.h"
134 #include "core/html/HTMLNameCollection.h"
135 #include "core/html/HTMLScriptElement.h"
136 #include "core/html/HTMLStyleElement.h"
137 #include "core/html/HTMLTitleElement.h"
138 #include "core/html/PluginDocument.h"
139 #include "core/html/forms/FormController.h"
140 #include "core/html/parser/HTMLDocumentParser.h"
141 #include "core/html/parser/HTMLParserIdioms.h"
142 #include "core/html/parser/NestingLevelIncrementer.h"
143 #include "core/inspector/InspectorCounters.h"
144 #include "core/inspector/InspectorInstrumentation.h"
145 #include "core/inspector/ScriptCallStack.h"
146 #include "core/loader/CookieJar.h"
147 #include "core/loader/DocumentLoader.h"
148 #include "core/loader/FrameLoader.h"
149 #include "core/loader/FrameLoaderClient.h"
150 #include "core/loader/ImageLoader.h"
151 #include "core/loader/appcache/ApplicationCacheHost.h"
152 #include "core/page/Chrome.h"
153 #include "core/page/ChromeClient.h"
154 #include "core/page/EventHandler.h"
155 #include "core/page/FrameTree.h"
156 #include "core/page/MouseEventWithHitTestResults.h"
157 #include "core/page/Page.h"
158 #include "core/page/PageConsole.h"
159 #include "core/page/PointerLockController.h"
160 #include "core/frame/Settings.h"
161 #include "core/page/scrolling/ScrollingCoordinator.h"
162 #include "core/rendering/FastTextAutosizer.h"
163 #include "core/rendering/HitTestResult.h"
164 #include "core/rendering/RenderView.h"
165 #include "core/rendering/RenderWidget.h"
166 #include "core/rendering/TextAutosizer.h"
167 #include "core/svg/SVGDocumentExtensions.h"
168 #include "core/svg/SVGFontFaceElement.h"
169 #include "core/svg/SVGStyleElement.h"
170 #include "core/xml/XSLTProcessor.h"
171 #include "core/xml/parser/XMLDocumentParser.h"
172 #include "platform/DateComponents.h"
173 #include "platform/Language.h"
174 #include "platform/TraceEvent.h"
175 #include "platform/network/HTTPParsers.h"
176 #include "platform/scroll/ScrollbarTheme.h"
177 #include "platform/text/PlatformLocale.h"
178 #include "platform/text/SegmentedString.h"
179 #include "platform/weborigin/OriginAccessEntry.h"
180 #include "platform/weborigin/SchemeRegistry.h"
181 #include "platform/weborigin/SecurityOrigin.h"
182 #include "wtf/CurrentTime.h"
183 #include "wtf/HashFunctions.h"
184 #include "wtf/MainThread.h"
185 #include "wtf/StdLibExtras.h"
186 #include "wtf/TemporaryChange.h"
187 #include "wtf/text/StringBuffer.h"
188 #include "wtf/text/TextEncodingRegistry.h"
189
190 using namespace std;
191 using namespace WTF;
192 using namespace Unicode;
193
194 namespace WebCore {
195
196 using namespace HTMLNames;
197
198 static const unsigned cMaxWriteRecursionDepth = 21;
199
200 // This amount of time must have elapsed before we will even consider scheduling a layout without a delay.
201 // FIXME: For faster machines this value can really be lowered to 200. 250 is adequate, but a little high
202 // for dual G5s. :)
203 static const int cLayoutScheduleThreshold = 250;
204
205 // DOM Level 2 says (letters added):
206 //
207 // a) Name start characters must have one of the categories Ll, Lu, Lo, Lt, Nl.
208 // b) Name characters other than Name-start characters must have one of the categories Mc, Me, Mn, Lm, or Nd.
209 // c) Characters in the compatibility area (i.e. with character code greater than #xF900 and less than #xFFFE) are not allowed in XML names.
210 // 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.
211 // 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.
212 // f) Characters #x20DD-#x20E0 are excluded (in accordance with Unicode, section 5.14).
213 // g) Character #x00B7 is classified as an extender, because the property list so identifies it.
214 // h) Character #x0387 is added as a name character, because #x00B7 is its canonical equivalent.
215 // i) Characters ':' and '_' are allowed as name-start characters.
216 // j) Characters '-' and '.' are allowed as name characters.
217 //
218 // It also contains complete tables. If we decide it's better, we could include those instead of the following code.
219
isValidNameStart(UChar32 c)220 static inline bool isValidNameStart(UChar32 c)
221 {
222 // rule (e) above
223 if ((c >= 0x02BB && c <= 0x02C1) || c == 0x559 || c == 0x6E5 || c == 0x6E6)
224 return true;
225
226 // rule (i) above
227 if (c == ':' || c == '_')
228 return true;
229
230 // rules (a) and (f) above
231 const uint32_t nameStartMask = Letter_Lowercase | Letter_Uppercase | Letter_Other | Letter_Titlecase | Number_Letter;
232 if (!(Unicode::category(c) & nameStartMask))
233 return false;
234
235 // rule (c) above
236 if (c >= 0xF900 && c < 0xFFFE)
237 return false;
238
239 // rule (d) above
240 DecompositionType decompType = decompositionType(c);
241 if (decompType == DecompositionFont || decompType == DecompositionCompat)
242 return false;
243
244 return true;
245 }
246
isValidNamePart(UChar32 c)247 static inline bool isValidNamePart(UChar32 c)
248 {
249 // rules (a), (e), and (i) above
250 if (isValidNameStart(c))
251 return true;
252
253 // rules (g) and (h) above
254 if (c == 0x00B7 || c == 0x0387)
255 return true;
256
257 // rule (j) above
258 if (c == '-' || c == '.')
259 return true;
260
261 // rules (b) and (f) above
262 const uint32_t otherNamePartMask = Mark_NonSpacing | Mark_Enclosing | Mark_SpacingCombining | Letter_Modifier | Number_DecimalDigit;
263 if (!(Unicode::category(c) & otherNamePartMask))
264 return false;
265
266 // rule (c) above
267 if (c >= 0xF900 && c < 0xFFFE)
268 return false;
269
270 // rule (d) above
271 DecompositionType decompType = decompositionType(c);
272 if (decompType == DecompositionFont || decompType == DecompositionCompat)
273 return false;
274
275 return true;
276 }
277
shouldInheritSecurityOriginFromOwner(const KURL & url)278 static bool shouldInheritSecurityOriginFromOwner(const KURL& url)
279 {
280 // http://www.whatwg.org/specs/web-apps/current-work/#origin-0
281 //
282 // If a Document has the address "about:blank"
283 // The origin of the Document is the origin it was assigned when its browsing context was created.
284 //
285 // Note: We generalize this to all "blank" URLs and invalid URLs because we
286 // treat all of these URLs as about:blank.
287 //
288 return url.isEmpty() || url.isBlankURL();
289 }
290
widgetForElement(const Element & focusedElement)291 static Widget* widgetForElement(const Element& focusedElement)
292 {
293 RenderObject* renderer = focusedElement.renderer();
294 if (!renderer || !renderer->isWidget())
295 return 0;
296 return toRenderWidget(renderer)->widget();
297 }
298
acceptsEditingFocus(const Element & element)299 static bool acceptsEditingFocus(const Element& element)
300 {
301 ASSERT(element.rendererIsEditable());
302
303 return element.document().frame() && element.rootEditableElement();
304 }
305
canAccessAncestor(const SecurityOrigin & activeSecurityOrigin,Frame * targetFrame)306 static bool canAccessAncestor(const SecurityOrigin& activeSecurityOrigin, Frame* targetFrame)
307 {
308 // targetFrame can be 0 when we're trying to navigate a top-level frame
309 // that has a 0 opener.
310 if (!targetFrame)
311 return false;
312
313 const bool isLocalActiveOrigin = activeSecurityOrigin.isLocal();
314 for (Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ancestorFrame->tree().parent()) {
315 Document* ancestorDocument = ancestorFrame->document();
316 // FIXME: Should be an ASSERT? Frames should alway have documents.
317 if (!ancestorDocument)
318 return true;
319
320 const SecurityOrigin* ancestorSecurityOrigin = ancestorDocument->securityOrigin();
321 if (activeSecurityOrigin.canAccess(ancestorSecurityOrigin))
322 return true;
323
324 // Allow file URL descendant navigation even when allowFileAccessFromFileURLs is false.
325 // FIXME: It's a bit strange to special-case local origins here. Should we be doing
326 // something more general instead?
327 if (isLocalActiveOrigin && ancestorSecurityOrigin->isLocal())
328 return true;
329 }
330
331 return false;
332 }
333
printNavigationErrorMessage(const Frame & frame,const KURL & activeURL,const char * reason)334 static void printNavigationErrorMessage(const Frame& frame, const KURL& activeURL, const char* reason)
335 {
336 String message = "Unsafe JavaScript attempt to initiate navigation for frame with URL '" + frame.document()->url().string() + "' from frame with URL '" + activeURL.string() + "'. " + reason + "\n";
337
338 // FIXME: should we print to the console of the document performing the navigation instead?
339 frame.domWindow()->printErrorMessage(message);
340 }
341
342 uint64_t Document::s_globalTreeVersion = 0;
343
344 // This class should be passed only to Document::postTask.
345 class CheckFocusedElementTask FINAL : public ExecutionContextTask {
346 public:
create()347 static PassOwnPtr<CheckFocusedElementTask> create()
348 {
349 return adoptPtr(new CheckFocusedElementTask());
350 }
~CheckFocusedElementTask()351 virtual ~CheckFocusedElementTask() { }
352
353 private:
CheckFocusedElementTask()354 CheckFocusedElementTask() { }
performTask(ExecutionContext * context)355 virtual void performTask(ExecutionContext* context) OVERRIDE
356 {
357 ASSERT(context->isDocument());
358 Document* document = toDocument(context);
359 document->didRunCheckFocusedElementTask();
360 Element* element = document->focusedElement();
361 if (!element)
362 return;
363 if (document->childNeedsStyleRecalc()) {
364 document->setNeedsFocusedElementCheck();
365 return;
366 }
367 if (element->renderer() && element->renderer()->needsLayout())
368 return;
369 if (!element->isFocusable())
370 document->setFocusedElement(0);
371 }
372 };
373
Document(const DocumentInit & initializer,DocumentClassFlags documentClasses)374 Document::Document(const DocumentInit& initializer, DocumentClassFlags documentClasses)
375 : ContainerNode(0, CreateDocument)
376 , TreeScope(this)
377 , m_hasNodesWithPlaceholderStyle(false)
378 , m_needsNotifyRemoveAllPendingStylesheet(false)
379 , m_evaluateMediaQueriesOnStyleRecalc(false)
380 , m_pendingSheetLayout(NoLayoutWithPendingSheets)
381 , m_frame(initializer.frame())
382 , m_domWindow(m_frame ? m_frame->domWindow() : 0)
383 , m_import(initializer.import())
384 , m_activeParserCount(0)
385 , m_contextFeatures(ContextFeatures::defaultSwitch())
386 , m_wellFormed(false)
387 , m_printing(false)
388 , m_paginatedForScreen(false)
389 , m_compatibilityMode(NoQuirksMode)
390 , m_compatibilityModeLocked(false)
391 , m_didPostCheckFocusedElementTask(false)
392 , m_domTreeVersion(++s_globalTreeVersion)
393 , m_listenerTypes(0)
394 , m_mutationObserverTypes(0)
395 , m_visitedLinkState(VisitedLinkState::create(*this))
396 , m_visuallyOrdered(false)
397 , m_readyState(Complete)
398 , m_bParsing(false)
399 , m_styleRecalcTimer(this, &Document::styleRecalcTimerFired)
400 , m_inStyleRecalc(false)
401 , m_gotoAnchorNeededAfterStylesheetsLoad(false)
402 , m_containsValidityStyleRules(false)
403 , m_updateFocusAppearanceRestoresSelection(false)
404 , m_containsPlugins(false)
405 , m_ignoreDestructiveWriteCount(0)
406 , m_titleSetExplicitly(false)
407 , m_markers(adoptPtr(new DocumentMarkerController))
408 , m_updateFocusAppearanceTimer(this, &Document::updateFocusAppearanceTimerFired)
409 , m_cssTarget(0)
410 , m_loadEventProgress(LoadEventNotRun)
411 , m_startTime(currentTime())
412 , m_overMinimumLayoutThreshold(false)
413 , m_scriptRunner(ScriptRunner::create(this))
414 , m_xmlVersion("1.0")
415 , m_xmlStandalone(StandaloneUnspecified)
416 , m_hasXMLDeclaration(0)
417 , m_designMode(inherit)
418 , m_hasAnnotatedRegions(false)
419 , m_annotatedRegionsDirty(false)
420 , m_useSecureKeyboardEntryWhenActive(false)
421 , m_documentClasses(documentClasses)
422 , m_isViewSource(false)
423 , m_sawElementsInKnownNamespaces(false)
424 , m_isSrcdocDocument(false)
425 , m_isMobileDocument(false)
426 , m_mayDisplaySeamlesslyWithParent(false)
427 , m_renderView(0)
428 , m_weakFactory(this)
429 , m_contextDocument(initializer.contextDocument())
430 , m_idAttributeName(idAttr)
431 , m_hasFullscreenElementStack(false)
432 , m_loadEventDelayCount(0)
433 , m_loadEventDelayTimer(this, &Document::loadEventDelayTimerFired)
434 , m_referrerPolicy(ReferrerPolicyDefault)
435 , m_directionSetOnDocumentElement(false)
436 , m_writingModeSetOnDocumentElement(false)
437 , m_writeRecursionIsTooDeep(false)
438 , m_writeRecursionDepth(0)
439 , m_lastHandledUserGestureTimestamp(0)
440 , m_taskRunner(MainThreadTaskRunner::create(this))
441 , m_registrationContext(initializer.registrationContext(this))
442 , m_sharedObjectPoolClearTimer(this, &Document::sharedObjectPoolClearTimerFired)
443 #ifndef NDEBUG
444 , m_didDispatchViewportPropertiesChanged(false)
445 #endif
446 , m_animationClock(AnimationClock::create())
447 , m_timeline(DocumentTimeline::create(this))
448 , m_transitionTimeline(TransitionTimeline::create(this))
449 , m_templateDocumentHost(0)
450 , m_didAssociateFormControlsTimer(this, &Document::didAssociateFormControlsTimerFired)
451 {
452 setClient(this);
453 ScriptWrappable::init(this);
454
455 if (m_frame) {
456 provideContextFeaturesToDocumentFrom(this, m_frame->page());
457
458 m_fetcher = m_frame->loader().activeDocumentLoader()->fetcher();
459 }
460
461 if (!m_fetcher)
462 m_fetcher = ResourceFetcher::create(0);
463 m_fetcher->setDocument(this);
464
465 // We depend on the url getting immediately set in subframes, but we
466 // also depend on the url NOT getting immediately set in opened windows.
467 // See fast/dom/early-frame-url.html
468 // and fast/dom/location-new-window-no-crash.html, respectively.
469 // FIXME: Can/should we unify this behavior?
470 if (initializer.shouldSetURL())
471 setURL(initializer.url());
472
473 initSecurityContext(initializer);
474 initDNSPrefetch();
475
476 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(m_nodeListCounts); i++)
477 m_nodeListCounts[i] = 0;
478
479 InspectorCounters::incrementCounter(InspectorCounters::DocumentCounter);
480
481 m_lifecyle.advanceTo(DocumentLifecycle::Inactive);
482
483 // Since CSSFontSelector requires Document::m_fetcher and StyleEngine owns
484 // CSSFontSelector, need to initialize m_styleEngine after initializing
485 // m_fetcher.
486 m_styleEngine = StyleEngine::create(*this);
487 }
488
~Document()489 Document::~Document()
490 {
491 ASSERT(!renderView());
492 ASSERT(m_ranges.isEmpty());
493 ASSERT(!m_parentTreeScope);
494 ASSERT(!hasGuardRefCount());
495
496 if (m_templateDocument)
497 m_templateDocument->setTemplateDocumentHost(0); // balanced in templateDocument().
498
499 if (Document* ownerDocument = this->ownerDocument())
500 ownerDocument->didRemoveEventTargetNode(this);
501
502 m_scriptRunner.clear();
503
504 removeAllEventListeners();
505
506 // Currently we believe that Document can never outlive the parser.
507 // Although the Document may be replaced synchronously, DocumentParsers
508 // generally keep at least one reference to an Element which would in turn
509 // has a reference to the Document. If you hit this ASSERT, then that
510 // assumption is wrong. DocumentParser::detach() should ensure that even
511 // if the DocumentParser outlives the Document it won't cause badness.
512 ASSERT(!m_parser || m_parser->refCount() == 1);
513 detachParser();
514
515 if (this == topDocument())
516 clearAXObjectCache();
517
518 if (m_styleSheetList)
519 m_styleSheetList->detachFromDocument();
520
521 if (m_import) {
522 m_import->wasDetachedFromDocument();
523 m_import = 0;
524 }
525
526 m_styleEngine.clear(); // We need to destory CSSFontSelector before destroying m_fetcher.
527
528 if (m_elemSheet)
529 m_elemSheet->clearOwnerNode();
530
531 // It's possible for multiple Documents to end up referencing the same ResourceFetcher (e.g., SVGImages
532 // load the initial empty document and the SVGDocument with the same DocumentLoader).
533 if (m_fetcher->document() == this)
534 m_fetcher->setDocument(0);
535 m_fetcher.clear();
536
537 // We must call clearRareData() here since a Document class inherits TreeScope
538 // as well as Node. See a comment on TreeScope.h for the reason.
539 if (hasRareData())
540 clearRareData();
541
542 ASSERT(!m_listsInvalidatedAtDocument.size());
543
544 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(m_nodeListCounts); i++)
545 ASSERT(!m_nodeListCounts[i]);
546
547 clearDocumentScope();
548 setClient(0);
549
550 InspectorCounters::decrementCounter(InspectorCounters::DocumentCounter);
551 }
552
dispose()553 void Document::dispose()
554 {
555 ASSERT_WITH_SECURITY_IMPLICATION(!m_deletionHasBegun);
556 // We must make sure not to be retaining any of our children through
557 // these extra pointers or we will create a reference cycle.
558 m_docType = 0;
559 m_focusedElement = 0;
560 m_hoverNode = 0;
561 m_activeElement = 0;
562 m_titleElement = 0;
563 m_documentElement = 0;
564 m_contextFeatures = ContextFeatures::defaultSwitch();
565 m_userActionElements.documentDidRemoveLastRef();
566 m_associatedFormControls.clear();
567
568 detachParser();
569
570 m_registrationContext.clear();
571
572 if (m_import) {
573 m_import->wasDetachedFromDocument();
574 m_import = 0;
575 }
576
577 // removeDetachedChildren() doesn't always unregister IDs,
578 // so tear down scope information upfront to avoid having stale references in the map.
579 destroyTreeScopeData();
580 removeDetachedChildren();
581 // removeDetachedChildren() can access FormController.
582 m_formController.clear();
583
584 m_markers->clear();
585
586 m_cssCanvasElements.clear();
587
588 // FIXME: consider using ActiveDOMObject.
589 if (m_scriptedAnimationController)
590 m_scriptedAnimationController->clearDocumentPointer();
591 m_scriptedAnimationController.clear();
592
593 if (svgExtensions())
594 accessSVGExtensions()->pauseAnimations();
595
596 m_lifecyle.advanceTo(DocumentLifecycle::Disposed);
597 lifecycleNotifier().notifyDocumentWasDisposed();
598 }
599
selectorQueryCache()600 SelectorQueryCache& Document::selectorQueryCache()
601 {
602 if (!m_selectorQueryCache)
603 m_selectorQueryCache = adoptPtr(new SelectorQueryCache());
604 return *m_selectorQueryCache;
605 }
606
mediaQueryMatcher()607 MediaQueryMatcher& Document::mediaQueryMatcher()
608 {
609 if (!m_mediaQueryMatcher)
610 m_mediaQueryMatcher = MediaQueryMatcher::create(this);
611 return *m_mediaQueryMatcher;
612 }
613
mediaQueryAffectingValueChanged()614 void Document::mediaQueryAffectingValueChanged()
615 {
616 styleEngine()->clearMediaQueryRuleSetStyleSheets();
617 }
618
setCompatibilityMode(CompatibilityMode mode)619 void Document::setCompatibilityMode(CompatibilityMode mode)
620 {
621 if (m_compatibilityModeLocked || mode == m_compatibilityMode)
622 return;
623 bool wasInQuirksMode = inQuirksMode();
624 m_compatibilityMode = mode;
625 selectorQueryCache().invalidate();
626 if (inQuirksMode() != wasInQuirksMode) {
627 // All injected stylesheets have to reparse using the different mode.
628 m_styleEngine->invalidateInjectedStyleSheetCache();
629 }
630 }
631
compatMode() const632 String Document::compatMode() const
633 {
634 return inQuirksMode() ? "BackCompat" : "CSS1Compat";
635 }
636
setDoctype(PassRefPtr<DocumentType> docType)637 void Document::setDoctype(PassRefPtr<DocumentType> docType)
638 {
639 // This should never be called more than once.
640 ASSERT(!m_docType || !docType);
641 m_docType = docType;
642 if (m_docType) {
643 this->adoptIfNeeded(*m_docType);
644 if (m_docType->publicId().startsWith("-//wapforum//dtd xhtml mobile 1.", /* caseSensitive */ false))
645 m_isMobileDocument = true;
646 }
647 // Doctype affects the interpretation of the stylesheets.
648 clearStyleResolver();
649 }
650
implementation()651 DOMImplementation* Document::implementation()
652 {
653 if (!m_implementation)
654 m_implementation = DOMImplementation::create(*this);
655 return m_implementation.get();
656 }
657
hasManifest() const658 bool Document::hasManifest() const
659 {
660 return documentElement() && isHTMLHtmlElement(documentElement()) && documentElement()->hasAttribute(manifestAttr);
661 }
662
location() const663 Location* Document::location() const
664 {
665 if (!frame())
666 return 0;
667
668 return domWindow()->location();
669 }
670
childrenChanged(bool changedByParser,Node * beforeChange,Node * afterChange,int childCountDelta)671 void Document::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
672 {
673 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
674
675 Element* newDocumentElement = ElementTraversal::firstWithin(*this);
676 if (newDocumentElement == m_documentElement)
677 return;
678 m_documentElement = newDocumentElement;
679 // The root style used for media query matching depends on the document element.
680 clearStyleResolver();
681 }
682
createElement(const AtomicString & name,ExceptionState & exceptionState)683 PassRefPtr<Element> Document::createElement(const AtomicString& name, ExceptionState& exceptionState)
684 {
685 if (!isValidName(name)) {
686 exceptionState.throwUninformativeAndGenericDOMException(InvalidCharacterError);
687 return 0;
688 }
689
690 if (isXHTMLDocument() || isHTMLDocument())
691 return HTMLElementFactory::createHTMLElement(isHTMLDocument() ? name.lower() : name, document(), 0, false);
692
693 return createElement(QualifiedName(nullAtom, name, nullAtom), false);
694 }
695
createElement(const AtomicString & localName,const AtomicString & typeExtension,ExceptionState & exceptionState)696 PassRefPtr<Element> Document::createElement(const AtomicString& localName, const AtomicString& typeExtension, ExceptionState& exceptionState)
697 {
698 if (!isValidName(localName)) {
699 exceptionState.throwUninformativeAndGenericDOMException(InvalidCharacterError);
700 return 0;
701 }
702
703 RefPtr<Element> element;
704
705 if (RuntimeEnabledFeatures::customElementsEnabled() && CustomElement::isValidName(localName) && registrationContext())
706 element = registrationContext()->createCustomTagElement(*this, QualifiedName(nullAtom, localName, xhtmlNamespaceURI));
707 else
708 element = createElement(localName, exceptionState);
709
710 if (RuntimeEnabledFeatures::customElementsEnabled() && !typeExtension.isNull() && !typeExtension.isEmpty())
711 CustomElementRegistrationContext::setIsAttributeAndTypeExtension(element.get(), typeExtension);
712
713 return element;
714 }
715
createElementNS(const AtomicString & namespaceURI,const AtomicString & qualifiedName,const AtomicString & typeExtension,ExceptionState & exceptionState)716 PassRefPtr<Element> Document::createElementNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& typeExtension, ExceptionState& exceptionState)
717 {
718 AtomicString prefix, localName;
719 if (!parseQualifiedName(qualifiedName, prefix, localName, exceptionState))
720 return 0;
721
722 QualifiedName qName(prefix, localName, namespaceURI);
723 if (!hasValidNamespaceForElements(qName)) {
724 exceptionState.throwUninformativeAndGenericDOMException(NamespaceError);
725 return 0;
726 }
727
728 RefPtr<Element> element;
729 if (CustomElement::isValidName(qName.localName()) && registrationContext())
730 element = registrationContext()->createCustomTagElement(*this, qName);
731 else
732 element = createElementNS(namespaceURI, qualifiedName, exceptionState);
733
734 if (!typeExtension.isNull() && !typeExtension.isEmpty())
735 CustomElementRegistrationContext::setIsAttributeAndTypeExtension(element.get(), typeExtension);
736
737 return element;
738 }
739
registerElement(WebCore::ScriptState * state,const AtomicString & name,ExceptionState & exceptionState)740 ScriptValue Document::registerElement(WebCore::ScriptState* state, const AtomicString& name, ExceptionState& exceptionState)
741 {
742 return registerElement(state, name, Dictionary(), exceptionState);
743 }
744
registerElement(WebCore::ScriptState * state,const AtomicString & name,const Dictionary & options,ExceptionState & exceptionState,CustomElement::NameSet validNames)745 ScriptValue Document::registerElement(WebCore::ScriptState* state, const AtomicString& name, const Dictionary& options, ExceptionState& exceptionState, CustomElement::NameSet validNames)
746 {
747 if (!registrationContext()) {
748 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
749 return ScriptValue();
750 }
751
752 CustomElementConstructorBuilder constructorBuilder(state, &options);
753 registrationContext()->registerElement(this, &constructorBuilder, name, validNames, exceptionState);
754 return constructorBuilder.bindingsReturnValue();
755 }
756
setImport(HTMLImport * import)757 void Document::setImport(HTMLImport* import)
758 {
759 ASSERT(!m_import || !import);
760 m_import = import;
761 }
762
didLoadAllImports()763 void Document::didLoadAllImports()
764 {
765 executeScriptsWaitingForResourcesIfNeeded();
766 }
767
haveImportsLoaded() const768 bool Document::haveImportsLoaded() const
769 {
770 return !m_import || !m_import->isBlocked();
771 }
772
createDocumentFragment()773 PassRefPtr<DocumentFragment> Document::createDocumentFragment()
774 {
775 return DocumentFragment::create(document());
776 }
777
createTextNode(const String & data)778 PassRefPtr<Text> Document::createTextNode(const String& data)
779 {
780 return Text::create(*this, data);
781 }
782
createComment(const String & data)783 PassRefPtr<Comment> Document::createComment(const String& data)
784 {
785 return Comment::create(*this, data);
786 }
787
createCDATASection(const String & data,ExceptionState & exceptionState)788 PassRefPtr<CDATASection> Document::createCDATASection(const String& data, ExceptionState& exceptionState)
789 {
790 if (isHTMLDocument()) {
791 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
792 return 0;
793 }
794 if (data.contains("]]>")) {
795 exceptionState.throwDOMException(InvalidCharacterError, "String cannot contain ']]>' since that is the end delimiter of a CData section.");
796 return 0;
797 }
798 return CDATASection::create(*this, data);
799 }
800
createProcessingInstruction(const String & target,const String & data,ExceptionState & exceptionState)801 PassRefPtr<ProcessingInstruction> Document::createProcessingInstruction(const String& target, const String& data, ExceptionState& exceptionState)
802 {
803 if (!isValidName(target)) {
804 exceptionState.throwDOMException(InvalidCharacterError, "The target provided ('" + target + "') is not a valid name.");
805 return 0;
806 }
807 if (data.contains("?>")) {
808 exceptionState.throwDOMException(InvalidCharacterError, "The data provided ('" + data + "') contains '?>'.");
809 return 0;
810 }
811 return ProcessingInstruction::create(*this, target, data);
812 }
813
createEditingTextNode(const String & text)814 PassRefPtr<Text> Document::createEditingTextNode(const String& text)
815 {
816 return Text::createEditingText(*this, text);
817 }
818
createCSSStyleDeclaration()819 PassRefPtr<CSSStyleDeclaration> Document::createCSSStyleDeclaration()
820 {
821 return MutableStylePropertySet::create()->ensureCSSStyleDeclaration();
822 }
823
importNode(Node * importedNode,bool deep,ExceptionState & exceptionState)824 PassRefPtr<Node> Document::importNode(Node* importedNode, bool deep, ExceptionState& exceptionState)
825 {
826 if (!importedNode) {
827 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
828 return 0;
829 }
830
831 switch (importedNode->nodeType()) {
832 case TEXT_NODE:
833 return createTextNode(importedNode->nodeValue());
834 case CDATA_SECTION_NODE:
835 return createCDATASection(importedNode->nodeValue(), exceptionState);
836 case PROCESSING_INSTRUCTION_NODE:
837 return createProcessingInstruction(importedNode->nodeName(), importedNode->nodeValue(), exceptionState);
838 case COMMENT_NODE:
839 return createComment(importedNode->nodeValue());
840 case ELEMENT_NODE: {
841 Element* oldElement = toElement(importedNode);
842 // FIXME: The following check might be unnecessary. Is it possible that
843 // oldElement has mismatched prefix/namespace?
844 if (!hasValidNamespaceForElements(oldElement->tagQName())) {
845 exceptionState.throwUninformativeAndGenericDOMException(NamespaceError);
846 return 0;
847 }
848 RefPtr<Element> newElement = createElement(oldElement->tagQName(), false);
849
850 newElement->cloneDataFromElement(*oldElement);
851
852 if (deep) {
853 for (Node* oldChild = oldElement->firstChild(); oldChild; oldChild = oldChild->nextSibling()) {
854 RefPtr<Node> newChild = importNode(oldChild, true, exceptionState);
855 if (exceptionState.hadException())
856 return 0;
857 newElement->appendChild(newChild.release(), exceptionState);
858 if (exceptionState.hadException())
859 return 0;
860 }
861 }
862
863 return newElement.release();
864 }
865 case ATTRIBUTE_NODE:
866 return Attr::create(*this, QualifiedName(nullAtom, toAttr(importedNode)->name(), nullAtom), toAttr(importedNode)->value());
867 case DOCUMENT_FRAGMENT_NODE: {
868 if (importedNode->isShadowRoot()) {
869 // ShadowRoot nodes should not be explicitly importable.
870 // Either they are imported along with their host node, or created implicitly.
871 break;
872 }
873 DocumentFragment* oldFragment = toDocumentFragment(importedNode);
874 RefPtr<DocumentFragment> newFragment = createDocumentFragment();
875 if (deep) {
876 for (Node* oldChild = oldFragment->firstChild(); oldChild; oldChild = oldChild->nextSibling()) {
877 RefPtr<Node> newChild = importNode(oldChild, true, exceptionState);
878 if (exceptionState.hadException())
879 return 0;
880 newFragment->appendChild(newChild.release(), exceptionState);
881 if (exceptionState.hadException())
882 return 0;
883 }
884 }
885
886 return newFragment.release();
887 }
888 case ENTITY_NODE:
889 case NOTATION_NODE:
890 // 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.
891 // Ability to add these imported nodes to a DocumentType will be considered for addition to a future release of the DOM.
892 case DOCUMENT_NODE:
893 case DOCUMENT_TYPE_NODE:
894 case XPATH_NAMESPACE_NODE:
895 break;
896 }
897 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
898 return 0;
899 }
900
adoptNode(PassRefPtr<Node> source,ExceptionState & exceptionState)901 PassRefPtr<Node> Document::adoptNode(PassRefPtr<Node> source, ExceptionState& exceptionState)
902 {
903 if (!source) {
904 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
905 return 0;
906 }
907
908 EventQueueScope scope;
909
910 switch (source->nodeType()) {
911 case ENTITY_NODE:
912 case NOTATION_NODE:
913 case DOCUMENT_NODE:
914 case DOCUMENT_TYPE_NODE:
915 case XPATH_NAMESPACE_NODE:
916 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
917 return 0;
918 case ATTRIBUTE_NODE: {
919 Attr* attr = toAttr(source.get());
920 if (attr->ownerElement())
921 attr->ownerElement()->removeAttributeNode(attr, exceptionState);
922 break;
923 }
924 default:
925 if (source->isShadowRoot()) {
926 // ShadowRoot cannot disconnect itself from the host node.
927 exceptionState.throwUninformativeAndGenericDOMException(HierarchyRequestError);
928 return 0;
929 }
930
931 if (source->isFrameOwnerElement()) {
932 HTMLFrameOwnerElement* frameOwnerElement = toHTMLFrameOwnerElement(source.get());
933 if (frame() && frame()->tree().isDescendantOf(frameOwnerElement->contentFrame())) {
934 exceptionState.throwUninformativeAndGenericDOMException(HierarchyRequestError);
935 return 0;
936 }
937 }
938 if (source->parentNode()) {
939 source->parentNode()->removeChild(source.get(), exceptionState);
940 if (exceptionState.hadException())
941 return 0;
942 }
943 }
944
945 this->adoptIfNeeded(*source);
946
947 return source;
948 }
949
hasValidNamespaceForElements(const QualifiedName & qName)950 bool Document::hasValidNamespaceForElements(const QualifiedName& qName)
951 {
952 // These checks are from DOM Core Level 2, createElementNS
953 // http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-DocCrElNS
954 if (!qName.prefix().isEmpty() && qName.namespaceURI().isNull()) // createElementNS(null, "html:div")
955 return false;
956 if (qName.prefix() == xmlAtom && qName.namespaceURI() != XMLNames::xmlNamespaceURI) // createElementNS("http://www.example.com", "xml:lang")
957 return false;
958
959 // Required by DOM Level 3 Core and unspecified by DOM Level 2 Core:
960 // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-DocCrElNS
961 // createElementNS("http://www.w3.org/2000/xmlns/", "foo:bar"), createElementNS(null, "xmlns:bar")
962 if ((qName.prefix() == xmlnsAtom && qName.namespaceURI() != XMLNSNames::xmlnsNamespaceURI) || (qName.prefix() != xmlnsAtom && qName.namespaceURI() == XMLNSNames::xmlnsNamespaceURI))
963 return false;
964
965 return true;
966 }
967
hasValidNamespaceForAttributes(const QualifiedName & qName)968 bool Document::hasValidNamespaceForAttributes(const QualifiedName& qName)
969 {
970 // Spec: DOM Level 2 Core: http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-ElSetAttrNS
971 if (qName.prefix().isEmpty() && qName.localName() == xmlnsAtom) {
972 // Note: The case of an "xmlns" qualified name with a namespace of
973 // xmlnsNamespaceURI is specifically allowed (See <http://www.w3.org/2000/xmlns/>).
974 return qName.namespaceURI() == XMLNSNames::xmlnsNamespaceURI;
975 }
976 return hasValidNamespaceForElements(qName);
977 }
978
979 // FIXME: This should really be in a possible ElementFactory class
createElement(const QualifiedName & qName,bool createdByParser)980 PassRefPtr<Element> Document::createElement(const QualifiedName& qName, bool createdByParser)
981 {
982 RefPtr<Element> e;
983
984 // FIXME: Use registered namespaces and look up in a hash to find the right factory.
985 if (qName.namespaceURI() == xhtmlNamespaceURI)
986 e = HTMLElementFactory::createHTMLElement(qName.localName(), document(), 0, createdByParser);
987 else if (qName.namespaceURI() == SVGNames::svgNamespaceURI)
988 e = SVGElementFactory::createSVGElement(qName.localName(), document(), createdByParser);
989
990 if (e)
991 m_sawElementsInKnownNamespaces = true;
992 else
993 e = Element::create(qName, &document());
994
995 if (e->prefix() != qName.prefix())
996 e->setTagNameForCreateElementNS(qName);
997
998 ASSERT(qName == e->tagQName());
999
1000 return e.release();
1001 }
1002
regionBasedColumnsEnabled() const1003 bool Document::regionBasedColumnsEnabled() const
1004 {
1005 return settings() && settings()->regionBasedColumnsEnabled();
1006 }
1007
webkitGetNamedFlows()1008 PassRefPtr<DOMNamedFlowCollection> Document::webkitGetNamedFlows()
1009 {
1010 if (!RuntimeEnabledFeatures::cssRegionsEnabled() || !renderView())
1011 return 0;
1012
1013 updateStyleIfNeeded();
1014
1015 return namedFlows()->createCSSOMSnapshot();
1016 }
1017
namedFlows()1018 NamedFlowCollection* Document::namedFlows()
1019 {
1020 if (!m_namedFlows)
1021 m_namedFlows = NamedFlowCollection::create(this);
1022
1023 return m_namedFlows.get();
1024 }
1025
createElementNS(const AtomicString & namespaceURI,const AtomicString & qualifiedName,ExceptionState & exceptionState)1026 PassRefPtr<Element> Document::createElementNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionState& exceptionState)
1027 {
1028 AtomicString prefix, localName;
1029 if (!parseQualifiedName(qualifiedName, prefix, localName, exceptionState))
1030 return 0;
1031
1032 QualifiedName qName(prefix, localName, namespaceURI);
1033 if (!hasValidNamespaceForElements(qName)) {
1034 exceptionState.throwUninformativeAndGenericDOMException(NamespaceError);
1035 return 0;
1036 }
1037
1038 return createElement(qName, false);
1039 }
1040
readyState() const1041 String Document::readyState() const
1042 {
1043 DEFINE_STATIC_LOCAL(const String, loading, ("loading"));
1044 DEFINE_STATIC_LOCAL(const String, interactive, ("interactive"));
1045 DEFINE_STATIC_LOCAL(const String, complete, ("complete"));
1046
1047 switch (m_readyState) {
1048 case Loading:
1049 return loading;
1050 case Interactive:
1051 return interactive;
1052 case Complete:
1053 return complete;
1054 }
1055
1056 ASSERT_NOT_REACHED();
1057 return String();
1058 }
1059
setReadyState(ReadyState readyState)1060 void Document::setReadyState(ReadyState readyState)
1061 {
1062 if (readyState == m_readyState)
1063 return;
1064
1065 switch (readyState) {
1066 case Loading:
1067 if (!m_documentTiming.domLoading) {
1068 m_documentTiming.domLoading = monotonicallyIncreasingTime();
1069 if (RuntimeEnabledFeatures::webAnimationsCSSEnabled())
1070 m_timeline->setZeroTime(m_documentTiming.domLoading);
1071 }
1072 break;
1073 case Interactive:
1074 if (!m_documentTiming.domInteractive)
1075 m_documentTiming.domInteractive = monotonicallyIncreasingTime();
1076 break;
1077 case Complete:
1078 if (!m_documentTiming.domComplete)
1079 m_documentTiming.domComplete = monotonicallyIncreasingTime();
1080 break;
1081 }
1082
1083 m_readyState = readyState;
1084 dispatchEvent(Event::create(EventTypeNames::readystatechange));
1085 }
1086
isLoadCompleted()1087 bool Document::isLoadCompleted()
1088 {
1089 return m_readyState == Complete;
1090 }
1091
encodingName() const1092 AtomicString Document::encodingName() const
1093 {
1094 // TextEncoding::name() returns a char*, no need to allocate a new
1095 // String for it each time.
1096 // FIXME: We should fix TextEncoding to speak AtomicString anyway.
1097 return AtomicString(encoding().name());
1098 }
1099
defaultCharset() const1100 String Document::defaultCharset() const
1101 {
1102 if (Settings* settings = this->settings())
1103 return settings->defaultTextEncodingName();
1104 return String();
1105 }
1106
setCharset(const String & charset)1107 void Document::setCharset(const String& charset)
1108 {
1109 if (DocumentLoader* documentLoader = loader())
1110 documentLoader->setUserChosenEncoding(charset);
1111 WTF::TextEncoding encoding(charset);
1112 // In case the encoding didn't exist, we keep the old one (helps some sites specifying invalid encodings).
1113 if (!encoding.isValid())
1114 return;
1115 DocumentEncodingData newEncodingData = m_encodingData;
1116 newEncodingData.encoding = encoding;
1117 setEncodingData(newEncodingData);
1118 }
1119
setContentLanguage(const AtomicString & language)1120 void Document::setContentLanguage(const AtomicString& language)
1121 {
1122 if (m_contentLanguage == language)
1123 return;
1124 m_contentLanguage = language;
1125
1126 // Document's style depends on the content language.
1127 setNeedsStyleRecalc();
1128 }
1129
setXMLVersion(const String & version,ExceptionState & exceptionState)1130 void Document::setXMLVersion(const String& version, ExceptionState& exceptionState)
1131 {
1132 if (!implementation()->hasFeature("XML", String())) {
1133 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
1134 return;
1135 }
1136
1137 if (!XMLDocumentParser::supportsXMLVersion(version)) {
1138 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
1139 return;
1140 }
1141
1142 m_xmlVersion = version;
1143 }
1144
setXMLStandalone(bool standalone,ExceptionState & exceptionState)1145 void Document::setXMLStandalone(bool standalone, ExceptionState& exceptionState)
1146 {
1147 if (!implementation()->hasFeature("XML", String())) {
1148 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
1149 return;
1150 }
1151
1152 m_xmlStandalone = standalone ? Standalone : NotStandalone;
1153 }
1154
baseURI() const1155 KURL Document::baseURI() const
1156 {
1157 return m_baseURL;
1158 }
1159
setContent(const String & content)1160 void Document::setContent(const String& content)
1161 {
1162 open();
1163 // FIXME: This should probably use insert(), but that's (intentionally)
1164 // not implemented for the XML parser as it's normally synonymous with
1165 // document.write(). append() will end up yielding, but close() will
1166 // pump the tokenizer syncrhonously and finish the parse.
1167 m_parser->pinToMainThread();
1168 m_parser->append(content.impl());
1169 close();
1170 }
1171
suggestedMIMEType() const1172 String Document::suggestedMIMEType() const
1173 {
1174 if (isXHTMLDocument())
1175 return "application/xhtml+xml";
1176 if (isSVGDocument())
1177 return "image/svg+xml";
1178 if (xmlStandalone())
1179 return "text/xml";
1180 if (isHTMLDocument())
1181 return "text/html";
1182
1183 if (DocumentLoader* documentLoader = loader())
1184 return documentLoader->responseMIMEType();
1185 return String();
1186 }
1187
elementFromPoint(int x,int y) const1188 Element* Document::elementFromPoint(int x, int y) const
1189 {
1190 if (!renderView())
1191 return 0;
1192
1193 return TreeScope::elementFromPoint(x, y);
1194 }
1195
caretRangeFromPoint(int x,int y)1196 PassRefPtr<Range> Document::caretRangeFromPoint(int x, int y)
1197 {
1198 if (!renderView())
1199 return 0;
1200 LayoutPoint localPoint;
1201 RenderObject* renderer = rendererFromPoint(this, x, y, &localPoint);
1202 if (!renderer)
1203 return 0;
1204
1205 Node* node = renderer->node();
1206 Node* shadowAncestorNode = ancestorInThisScope(node);
1207 if (shadowAncestorNode != node) {
1208 unsigned offset = shadowAncestorNode->nodeIndex();
1209 ContainerNode* container = shadowAncestorNode->parentNode();
1210 return Range::create(*this, container, offset, container, offset);
1211 }
1212
1213 PositionWithAffinity positionWithAffinity = renderer->positionForPoint(localPoint);
1214 if (positionWithAffinity.position().isNull())
1215 return 0;
1216
1217 Position rangeCompliantPosition = positionWithAffinity.position().parentAnchoredEquivalent();
1218 return Range::create(*this, rangeCompliantPosition, rangeCompliantPosition);
1219 }
1220
1221 /*
1222 * Performs three operations:
1223 * 1. Convert control characters to spaces
1224 * 2. Trim leading and trailing spaces
1225 * 3. Collapse internal whitespace.
1226 */
1227 template <typename CharacterType>
canonicalizedTitle(Document * document,const String & title)1228 static inline String canonicalizedTitle(Document* document, const String& title)
1229 {
1230 const CharacterType* characters = title.getCharacters<CharacterType>();
1231 unsigned length = title.length();
1232 unsigned i;
1233
1234 StringBuffer<CharacterType> buffer(length);
1235 unsigned builderIndex = 0;
1236
1237 // Skip leading spaces and leading characters that would convert to spaces
1238 for (i = 0; i < length; ++i) {
1239 CharacterType c = characters[i];
1240 if (!(c <= 0x20 || c == 0x7F))
1241 break;
1242 }
1243
1244 if (i == length)
1245 return String();
1246
1247 // Replace control characters with spaces, and backslashes with currency symbols, and collapse whitespace.
1248 bool previousCharWasWS = false;
1249 for (; i < length; ++i) {
1250 CharacterType c = characters[i];
1251 if (c <= 0x20 || c == 0x7F || (WTF::Unicode::category(c) & (WTF::Unicode::Separator_Line | WTF::Unicode::Separator_Paragraph))) {
1252 if (previousCharWasWS)
1253 continue;
1254 buffer[builderIndex++] = ' ';
1255 previousCharWasWS = true;
1256 } else {
1257 buffer[builderIndex++] = c;
1258 previousCharWasWS = false;
1259 }
1260 }
1261
1262 // Strip trailing spaces
1263 while (builderIndex > 0) {
1264 --builderIndex;
1265 if (buffer[builderIndex] != ' ')
1266 break;
1267 }
1268
1269 if (!builderIndex && buffer[builderIndex] == ' ')
1270 return String();
1271
1272 buffer.shrink(builderIndex + 1);
1273
1274 return String::adopt(buffer);
1275 }
1276
updateTitle(const String & title)1277 void Document::updateTitle(const String& title)
1278 {
1279 if (m_rawTitle == title)
1280 return;
1281
1282 m_rawTitle = title;
1283
1284 String oldTitle = m_title;
1285 if (m_rawTitle.isEmpty())
1286 m_title = String();
1287 else if (m_rawTitle.is8Bit())
1288 m_title = canonicalizedTitle<LChar>(this, m_rawTitle);
1289 else
1290 m_title = canonicalizedTitle<UChar>(this, m_rawTitle);
1291
1292 if (!m_frame || oldTitle == m_title)
1293 return;
1294 m_frame->loader().client()->dispatchDidReceiveTitle(m_title);
1295 }
1296
setTitle(const String & title)1297 void Document::setTitle(const String& title)
1298 {
1299 // Title set by JavaScript -- overrides any title elements.
1300 m_titleSetExplicitly = true;
1301 if (!isHTMLDocument() && !isXHTMLDocument())
1302 m_titleElement = 0;
1303 else if (!m_titleElement) {
1304 if (HTMLElement* headElement = head()) {
1305 m_titleElement = createElement(titleTag, false);
1306 headElement->appendChild(m_titleElement);
1307 }
1308 }
1309
1310 updateTitle(title);
1311
1312 if (m_titleElement && isHTMLTitleElement(m_titleElement.get()))
1313 toHTMLTitleElement(m_titleElement)->setText(title);
1314 }
1315
setTitleElement(const String & title,Element * titleElement)1316 void Document::setTitleElement(const String& title, Element* titleElement)
1317 {
1318 if (titleElement != m_titleElement) {
1319 if (m_titleElement || m_titleSetExplicitly)
1320 // Only allow the first title element to change the title -- others have no effect.
1321 return;
1322 m_titleElement = titleElement;
1323 }
1324
1325 updateTitle(title);
1326 }
1327
removeTitle(Element * titleElement)1328 void Document::removeTitle(Element* titleElement)
1329 {
1330 if (m_titleElement != titleElement)
1331 return;
1332
1333 m_titleElement = 0;
1334 m_titleSetExplicitly = false;
1335
1336 // FIXME: This is broken for SVG.
1337 // Update title based on first title element in the head, if one exists.
1338 if (HTMLElement* headElement = head()) {
1339 for (Element* element = headElement->firstElementChild(); element; element = element->nextElementSibling()) {
1340 if (!isHTMLTitleElement(element))
1341 continue;
1342 HTMLTitleElement* title = toHTMLTitleElement(element);
1343 setTitleElement(title->text(), title);
1344 break;
1345 }
1346 }
1347
1348 if (!m_titleElement)
1349 updateTitle(String());
1350 }
1351
pageVisibilityState() const1352 PageVisibilityState Document::pageVisibilityState() const
1353 {
1354 // The visibility of the document is inherited from the visibility of the
1355 // page. If there is no page associated with the document, we will assume
1356 // that the page is hidden, as specified by the spec:
1357 // http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html#dom-document-hidden
1358 if (!m_frame || !m_frame->page())
1359 return PageVisibilityStateHidden;
1360 return m_frame->page()->visibilityState();
1361 }
1362
visibilityState() const1363 String Document::visibilityState() const
1364 {
1365 return pageVisibilityStateString(pageVisibilityState());
1366 }
1367
hidden() const1368 bool Document::hidden() const
1369 {
1370 return pageVisibilityState() != PageVisibilityStateVisible;
1371 }
1372
dispatchVisibilityStateChangeEvent()1373 void Document::dispatchVisibilityStateChangeEvent()
1374 {
1375 dispatchEvent(Event::create(EventTypeNames::visibilitychange));
1376 // Also send out the deprecated version until it can be removed.
1377 dispatchEvent(Event::create(EventTypeNames::webkitvisibilitychange));
1378 }
1379
securityPolicy()1380 DOMSecurityPolicy* Document::securityPolicy()
1381 {
1382 if (!m_domSecurityPolicy)
1383 m_domSecurityPolicy = DOMSecurityPolicy::create(this);
1384 return m_domSecurityPolicy.get();
1385 }
1386
nodeName() const1387 String Document::nodeName() const
1388 {
1389 return "#document";
1390 }
1391
nodeType() const1392 Node::NodeType Document::nodeType() const
1393 {
1394 return DOCUMENT_NODE;
1395 }
1396
formController()1397 FormController* Document::formController()
1398 {
1399 if (!m_formController)
1400 m_formController = FormController::create();
1401 return m_formController.get();
1402 }
1403
formElementsState() const1404 Vector<String> Document::formElementsState() const
1405 {
1406 if (!m_formController)
1407 return Vector<String>();
1408 return m_formController->formElementsState();
1409 }
1410
setStateForNewFormElements(const Vector<String> & stateVector)1411 void Document::setStateForNewFormElements(const Vector<String>& stateVector)
1412 {
1413 if (!stateVector.size() && !m_formController)
1414 return;
1415 formController()->setStateForNewFormElements(stateVector);
1416 }
1417
view() const1418 FrameView* Document::view() const
1419 {
1420 return m_frame ? m_frame->view() : 0;
1421 }
1422
page() const1423 Page* Document::page() const
1424 {
1425 return m_frame ? m_frame->page() : 0;
1426 }
1427
settings() const1428 Settings* Document::settings() const
1429 {
1430 return m_frame ? m_frame->settings() : 0;
1431 }
1432
createRange()1433 PassRefPtr<Range> Document::createRange()
1434 {
1435 return Range::create(*this);
1436 }
1437
createNodeIterator(Node * root,ExceptionState & exceptionState)1438 PassRefPtr<NodeIterator> Document::createNodeIterator(Node* root, ExceptionState& exceptionState)
1439 {
1440 // FIXME: Probably this should be handled within the bindings layer and TypeError should be thrown.
1441 if (!root) {
1442 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
1443 return 0;
1444 }
1445 return NodeIterator::create(root, NodeFilter::SHOW_ALL, PassRefPtr<NodeFilter>());
1446 }
1447
createNodeIterator(Node * root,unsigned whatToShow,ExceptionState & exceptionState)1448 PassRefPtr<NodeIterator> Document::createNodeIterator(Node* root, unsigned whatToShow, ExceptionState& exceptionState)
1449 {
1450 if (!root) {
1451 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
1452 return 0;
1453 }
1454 // FIXME: It might be a good idea to emit a warning if |whatToShow| contains a bit that is not defined in
1455 // NodeFilter.
1456 return NodeIterator::create(root, whatToShow, PassRefPtr<NodeFilter>());
1457 }
1458
createNodeIterator(Node * root,unsigned whatToShow,PassRefPtr<NodeFilter> filter,ExceptionState & exceptionState)1459 PassRefPtr<NodeIterator> Document::createNodeIterator(Node* root, unsigned whatToShow, PassRefPtr<NodeFilter> filter, ExceptionState& exceptionState)
1460 {
1461 if (!root) {
1462 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
1463 return 0;
1464 }
1465 // FIXME: Ditto.
1466 return NodeIterator::create(root, whatToShow, filter);
1467 }
1468
createTreeWalker(Node * root,ExceptionState & exceptionState)1469 PassRefPtr<TreeWalker> Document::createTreeWalker(Node* root, ExceptionState& exceptionState)
1470 {
1471 if (!root) {
1472 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
1473 return 0;
1474 }
1475 return TreeWalker::create(root, NodeFilter::SHOW_ALL, PassRefPtr<NodeFilter>());
1476 }
1477
createTreeWalker(Node * root,unsigned whatToShow,ExceptionState & exceptionState)1478 PassRefPtr<TreeWalker> Document::createTreeWalker(Node* root, unsigned whatToShow, ExceptionState& exceptionState)
1479 {
1480 if (!root) {
1481 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
1482 return 0;
1483 }
1484 return TreeWalker::create(root, whatToShow, PassRefPtr<NodeFilter>());
1485 }
1486
createTreeWalker(Node * root,unsigned whatToShow,PassRefPtr<NodeFilter> filter,ExceptionState & exceptionState)1487 PassRefPtr<TreeWalker> Document::createTreeWalker(Node* root, unsigned whatToShow, PassRefPtr<NodeFilter> filter, ExceptionState& exceptionState)
1488 {
1489 if (!root) {
1490 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
1491 return 0;
1492 }
1493 return TreeWalker::create(root, whatToShow, filter);
1494 }
1495
scheduleStyleRecalc()1496 void Document::scheduleStyleRecalc()
1497 {
1498 if (shouldDisplaySeamlesslyWithParent()) {
1499 // When we're seamless, our parent document manages our style recalcs.
1500 ownerElement()->setNeedsStyleRecalc();
1501 ownerElement()->document().scheduleStyleRecalc();
1502 return;
1503 }
1504
1505 if (m_styleRecalcTimer.isActive())
1506 return;
1507
1508 ASSERT(needsStyleRecalc() || childNeedsStyleRecalc() || childNeedsDistributionRecalc());
1509
1510 m_styleRecalcTimer.startOneShot(0);
1511
1512 InspectorInstrumentation::didScheduleStyleRecalculation(this);
1513 }
1514
unscheduleStyleRecalc()1515 void Document::unscheduleStyleRecalc()
1516 {
1517 ASSERT(!isActive() || (!needsStyleRecalc() && !childNeedsStyleRecalc()));
1518 m_styleRecalcTimer.stop();
1519 }
1520
hasPendingStyleRecalc() const1521 bool Document::hasPendingStyleRecalc() const
1522 {
1523 return m_styleRecalcTimer.isActive() && !m_inStyleRecalc;
1524 }
1525
hasPendingForcedStyleRecalc() const1526 bool Document::hasPendingForcedStyleRecalc() const
1527 {
1528 return hasPendingStyleRecalc() && styleChangeType() >= SubtreeStyleChange;
1529 }
1530
styleRecalcTimerFired(Timer<Document> *)1531 void Document::styleRecalcTimerFired(Timer<Document>*)
1532 {
1533 updateStyleIfNeeded();
1534 }
1535
updateDistributionIfNeeded()1536 void Document::updateDistributionIfNeeded()
1537 {
1538 if (!childNeedsDistributionRecalc())
1539 return;
1540 TRACE_EVENT0("webkit", "Document::recalcDistribution");
1541 recalcDistribution();
1542 }
1543
updateDistributionForNodeIfNeeded(Node * node)1544 void Document::updateDistributionForNodeIfNeeded(Node* node)
1545 {
1546 if (node->inDocument()) {
1547 updateDistributionIfNeeded();
1548 return;
1549 }
1550 Node* root = node;
1551 while (Node* host = root->shadowHost())
1552 root = host;
1553 while (Node* ancestor = root->parentOrShadowHostNode())
1554 root = ancestor;
1555 if (root->childNeedsDistributionRecalc())
1556 root->recalcDistribution();
1557 }
1558
setStyleDependentState(RenderStyle * documentStyle)1559 void Document::setStyleDependentState(RenderStyle* documentStyle)
1560 {
1561 const Pagination& pagination = view()->pagination();
1562 if (pagination.mode != Pagination::Unpaginated) {
1563 Pagination::setStylesForPaginationMode(pagination.mode, documentStyle);
1564 documentStyle->setColumnGap(pagination.gap);
1565 if (renderView()->hasColumns())
1566 renderView()->updateColumnInfoFromStyle(documentStyle);
1567 }
1568
1569 // Seamless iframes want to inherit their font from their parent iframe, so early return before setting the font.
1570 if (shouldDisplaySeamlesslyWithParent())
1571 return;
1572
1573 FontBuilder fontBuilder;
1574 fontBuilder.initForStyleResolve(*this, documentStyle, isSVGDocument());
1575 RefPtr<CSSFontSelector> selector = m_styleEngine->fontSelector();
1576 fontBuilder.createFontForDocument(selector, documentStyle);
1577 }
1578
inheritHtmlAndBodyElementStyles(StyleRecalcChange change)1579 void Document::inheritHtmlAndBodyElementStyles(StyleRecalcChange change)
1580 {
1581 ASSERT(inStyleRecalc());
1582 ASSERT(documentElement());
1583
1584 RefPtr<RenderStyle> documentElementStyle = documentElement()->renderStyle();
1585 if (!documentElementStyle || documentElement()->needsStyleRecalc() || change == Force)
1586 documentElementStyle = ensureStyleResolver().styleForElement(documentElement());
1587
1588 WritingMode rootWritingMode = documentElementStyle->writingMode();
1589 TextDirection rootDirection = documentElementStyle->direction();
1590 HTMLElement* body = this->body();
1591
1592 if (body) {
1593 RefPtr<RenderStyle> bodyStyle = body->renderStyle();
1594 if (!bodyStyle || body->needsStyleRecalc() || documentElement()->needsStyleRecalc() || change == Force)
1595 bodyStyle = ensureStyleResolver().styleForElement(body, documentElementStyle.get());
1596 if (!writingModeSetOnDocumentElement())
1597 rootWritingMode = bodyStyle->writingMode();
1598 if (!directionSetOnDocumentElement())
1599 rootDirection = bodyStyle->direction();
1600 }
1601
1602 RefPtr<RenderStyle> documentStyle = renderView()->style();
1603 if (documentStyle->writingMode() != rootWritingMode || documentStyle->direction() != rootDirection) {
1604 RefPtr<RenderStyle> newStyle = RenderStyle::clone(documentStyle.get());
1605 newStyle->setWritingMode(rootWritingMode);
1606 newStyle->setDirection(rootDirection);
1607 renderView()->setStyle(newStyle);
1608 setStyleDependentState(newStyle.get());
1609 }
1610
1611 if (body) {
1612 if (RenderStyle* style = body->renderStyle()) {
1613 if (style->direction() != rootDirection || style->writingMode() != rootWritingMode)
1614 body->setNeedsStyleRecalc();
1615 }
1616 }
1617
1618 if (RenderStyle* style = documentElement()->renderStyle()) {
1619 if (style->direction() != rootDirection || style->writingMode() != rootWritingMode)
1620 documentElement()->setNeedsStyleRecalc();
1621 }
1622 }
1623
recalcStyle(StyleRecalcChange change)1624 void Document::recalcStyle(StyleRecalcChange change)
1625 {
1626 // we should not enter style recalc while painting
1627 RELEASE_ASSERT(!view() || !view()->isPainting());
1628
1629 // FIXME: We should never enter here without a FrameView or with an inactive document.
1630 if (!isActive() || !view())
1631 return;
1632
1633 if (m_inStyleRecalc)
1634 return;
1635
1636 TRACE_EVENT0("webkit", "Document::recalcStyle");
1637 TRACE_EVENT_SCOPED_SAMPLING_STATE("Blink", "RecalcStyle");
1638
1639 updateDistributionIfNeeded();
1640
1641 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRecalculateStyle(this);
1642
1643 if (m_evaluateMediaQueriesOnStyleRecalc) {
1644 m_evaluateMediaQueriesOnStyleRecalc = false;
1645 evaluateMediaQueryList();
1646 }
1647
1648 // FIXME: We should update style on our ancestor chain before proceeding (especially for seamless),
1649 // however doing so currently causes several tests to crash, as Frame::setDocument calls Document::attach
1650 // before setting the DOMWindow on the Frame, or the SecurityOrigin on the document. The attach, in turn
1651 // resolves style (here) and then when we resolve style on the parent chain, we may end up
1652 // re-attaching our containing iframe, which when asked HTMLFrameElementBase::isURLAllowed
1653 // hits a null-dereference due to security code always assuming the document has a SecurityOrigin.
1654
1655 if (m_styleEngine->needsUpdateActiveStylesheetsOnStyleRecalc())
1656 m_styleEngine->updateActiveStyleSheets(FullStyleUpdate);
1657
1658 if (m_elemSheet && m_elemSheet->contents()->usesRemUnits())
1659 m_styleEngine->setUsesRemUnit(true);
1660
1661 {
1662 PostAttachCallbacks::SuspendScope suspendPostAttachCallbacks;
1663 RenderWidget::UpdateSuspendScope suspendWidgetHierarchyUpdates;
1664 FrameView::DeferredRepaintScope deferRepaints(*view());
1665 TemporaryChange<bool> changeInStyleRecalc(m_inStyleRecalc, true);
1666
1667 if (styleChangeType() >= SubtreeStyleChange)
1668 change = Force;
1669
1670 // FIXME: Cannot access the ensureStyleResolver() before calling styleForDocument below because
1671 // apparently the StyleResolver's constructor has side effects. We should fix it.
1672 // See printing/setPrinting.html, printing/width-overflow.html though they only fail on
1673 // mac when accessing the resolver by what appears to be a viewport size difference.
1674
1675 if (change == Force || (change >= Inherit && shouldDisplaySeamlesslyWithParent())) {
1676 m_hasNodesWithPlaceholderStyle = false;
1677 RefPtr<RenderStyle> documentStyle = StyleResolver::styleForDocument(*this, m_styleEngine->fontSelector());
1678 StyleRecalcChange localChange = RenderStyle::compare(documentStyle.get(), renderView()->style());
1679 if (localChange != NoChange)
1680 renderView()->setStyle(documentStyle.release());
1681 }
1682
1683 clearNeedsStyleRecalc();
1684
1685 // Uncomment to enable printing of statistics about style sharing and the matched property cache.
1686 // Optionally pass StyleResolver::ReportSlowStats to print numbers that require crawling the
1687 // entire DOM (where collecting them is very slow).
1688 // FIXME: Expose this as a runtime flag.
1689 // ensureStyleResolver().enableStats(/*StyleResolver::ReportSlowStats*/);
1690
1691 if (StyleResolverStats* stats = ensureStyleResolver().stats())
1692 stats->reset();
1693
1694 if (Element* documentElement = this->documentElement()) {
1695 inheritHtmlAndBodyElementStyles(change);
1696 if (shouldRecalcStyle(change, documentElement))
1697 documentElement->recalcStyle(change);
1698 }
1699
1700 ensureStyleResolver().printStats();
1701
1702 view()->updateCompositingLayersAfterStyleChange();
1703
1704 clearChildNeedsStyleRecalc();
1705 unscheduleStyleRecalc();
1706
1707 // FIXME: SVG <use> element can schedule a recalc in the middle of an already running one.
1708 // See StyleEngine::updateActiveStyleSheets.
1709 if (m_styleEngine->needsUpdateActiveStylesheetsOnStyleRecalc())
1710 setNeedsStyleRecalc();
1711
1712 if (m_styleEngine->hasResolver()) {
1713 // Pseudo element removal and similar may only work with these flags still set. Reset them after the style recalc.
1714 StyleResolver& resolver = m_styleEngine->ensureResolver();
1715 m_styleEngine->resetCSSFeatureFlags(resolver.ensureRuleFeatureSet());
1716 resolver.clearStyleSharingList();
1717 }
1718 }
1719
1720 InspectorInstrumentation::didRecalculateStyle(cookie);
1721
1722 // As a result of the style recalculation, the currently hovered element might have been
1723 // detached (for example, by setting display:none in the :hover style), schedule another mouseMove event
1724 // to check if any other elements ended up under the mouse pointer due to re-layout.
1725 if (hoverNode() && !hoverNode()->renderer() && frame())
1726 frame()->eventHandler().dispatchFakeMouseMoveEventSoon();
1727 }
1728
updateStyleIfNeeded()1729 void Document::updateStyleIfNeeded()
1730 {
1731 ASSERT(isMainThread());
1732 ASSERT(!view() || (!view()->isInLayout() && !view()->isPainting()));
1733
1734 if (!needsStyleRecalc() && !childNeedsStyleRecalc() && !childNeedsDistributionRecalc())
1735 return;
1736
1737 RefPtr<Frame> holder(m_frame);
1738 AnimationUpdateBlock animationUpdateBlock(m_frame ? &m_frame->animation() : 0);
1739 recalcStyle(NoChange);
1740 DocumentAnimations::serviceAfterStyleRecalc(*this);
1741 }
1742
updateStyleForNodeIfNeeded(Node * node)1743 void Document::updateStyleForNodeIfNeeded(Node* node)
1744 {
1745 if (!hasPendingForcedStyleRecalc() && !childNeedsStyleRecalc() && !needsStyleRecalc())
1746 return;
1747
1748 bool needsStyleRecalc = hasPendingForcedStyleRecalc();
1749 for (Node* ancestor = node; ancestor && !needsStyleRecalc; ancestor = ancestor->parentOrShadowHostNode())
1750 needsStyleRecalc = ancestor->needsStyleRecalc();
1751 if (needsStyleRecalc)
1752 updateStyleIfNeeded();
1753 }
1754
updateLayout()1755 void Document::updateLayout()
1756 {
1757 ASSERT(isMainThread());
1758
1759 RefPtr<FrameView> frameView = view();
1760 if (frameView && frameView->isInLayout()) {
1761 // View layout should not be re-entrant.
1762 ASSERT_NOT_REACHED();
1763 return;
1764 }
1765
1766 if (Element* oe = ownerElement())
1767 oe->document().updateLayout();
1768
1769 updateStyleIfNeeded();
1770
1771 // Only do a layout if changes have occurred that make it necessary.
1772 if (isActive() && frameView && renderView() && (frameView->layoutPending() || renderView()->needsLayout()))
1773 frameView->layout();
1774
1775 if (isActive() && frameView)
1776 frameView->partialLayout().reset();
1777
1778 setNeedsFocusedElementCheck();
1779 }
1780
setNeedsFocusedElementCheck()1781 void Document::setNeedsFocusedElementCheck()
1782 {
1783 // FIXME: Using a Task doesn't look a good idea.
1784 if (!m_focusedElement || m_didPostCheckFocusedElementTask)
1785 return;
1786 m_taskRunner->postTask(CheckFocusedElementTask::create());
1787 m_didPostCheckFocusedElementTask = true;
1788 }
1789
recalcStyleForLayoutIgnoringPendingStylesheets()1790 void Document::recalcStyleForLayoutIgnoringPendingStylesheets()
1791 {
1792 ASSERT(m_styleEngine->ignoringPendingStylesheets());
1793
1794 if (!m_styleEngine->hasPendingSheets())
1795 return;
1796
1797 // FIXME: We are willing to attempt to suppress painting with outdated style info only once.
1798 // Our assumption is that it would be dangerous to try to stop it a second time, after page
1799 // content has already been loaded and displayed with accurate style information. (Our
1800 // suppression involves blanking the whole page at the moment. If it were more refined, we
1801 // might be able to do something better.) It's worth noting though that this entire method
1802 // is a hack, since what we really want to do is suspend JS instead of doing a layout with
1803 // inaccurate information.
1804 HTMLElement* bodyElement = body();
1805 if (bodyElement && !bodyElement->renderer() && m_pendingSheetLayout == NoLayoutWithPendingSheets) {
1806 m_pendingSheetLayout = DidLayoutWithPendingSheets;
1807 styleResolverChanged(RecalcStyleImmediately);
1808 } else if (m_hasNodesWithPlaceholderStyle) {
1809 // If new nodes have been added or style recalc has been done with style sheets still
1810 // pending, some nodes may not have had their real style calculated yet. Normally this
1811 // gets cleaned when style sheets arrive but here we need up-to-date style immediately.
1812 recalcStyle(Force);
1813 }
1814 }
1815
1816 // FIXME: This is a bad idea and needs to be removed eventually.
1817 // Other browsers load stylesheets before they continue parsing the web page.
1818 // Since we don't, we can run JavaScript code that needs answers before the
1819 // stylesheets are loaded. Doing a layout ignoring the pending stylesheets
1820 // lets us get reasonable answers. The long term solution to this problem is
1821 // to instead suspend JavaScript execution.
updateLayoutIgnorePendingStylesheets(Document::RunPostLayoutTasks runPostLayoutTasks)1822 void Document::updateLayoutIgnorePendingStylesheets(Document::RunPostLayoutTasks runPostLayoutTasks)
1823 {
1824 StyleEngine::IgnoringPendingStylesheet ignoring(m_styleEngine.get());
1825 recalcStyleForLayoutIgnoringPendingStylesheets();
1826 updateLayout();
1827 if (runPostLayoutTasks == RunPostLayoutTasksSynchronously && view())
1828 view()->flushAnyPendingPostLayoutTasks();
1829 }
1830
partialUpdateLayoutIgnorePendingStylesheets(Node * stopLayoutAtNode)1831 void Document::partialUpdateLayoutIgnorePendingStylesheets(Node* stopLayoutAtNode)
1832 {
1833 // Non-overlay scrollbars can cause a second layout that is dependent
1834 // on a first layout. This is disabled for partial layout for now.
1835 if (!RuntimeEnabledFeatures::partialLayoutEnabled() || !ScrollbarTheme::theme()->usesOverlayScrollbars()) {
1836 updateLayoutIgnorePendingStylesheets();
1837 return;
1838 }
1839
1840 StyleEngine::IgnoringPendingStylesheet ignoring(m_styleEngine.get());
1841 recalcStyleForLayoutIgnoringPendingStylesheets();
1842
1843 if (stopLayoutAtNode) {
1844 RenderObject* renderer = stopLayoutAtNode->renderer();
1845 bool canPartialLayout = renderer;
1846 while (renderer) {
1847 if (!renderer->supportsPartialLayout()) {
1848 canPartialLayout = false;
1849 break;
1850 }
1851 renderer = renderer->parent();
1852 }
1853 if (canPartialLayout && view())
1854 view()->partialLayout().setStopAtRenderer(stopLayoutAtNode->renderer());
1855 }
1856
1857 updateLayout();
1858
1859 if (view())
1860 view()->partialLayout().reset();
1861 }
1862
styleForElementIgnoringPendingStylesheets(Element * element)1863 PassRefPtr<RenderStyle> Document::styleForElementIgnoringPendingStylesheets(Element* element)
1864 {
1865 ASSERT_ARG(element, element->document() == this);
1866 StyleEngine::IgnoringPendingStylesheet ignoring(m_styleEngine.get());
1867 return ensureStyleResolver().styleForElement(element, element->parentNode() ? element->parentNode()->computedStyle() : 0);
1868 }
1869
styleForPage(int pageIndex)1870 PassRefPtr<RenderStyle> Document::styleForPage(int pageIndex)
1871 {
1872 return ensureStyleResolver().styleForPage(pageIndex);
1873 }
1874
isPageBoxVisible(int pageIndex)1875 bool Document::isPageBoxVisible(int pageIndex)
1876 {
1877 return styleForPage(pageIndex)->visibility() != HIDDEN; // display property doesn't apply to @page.
1878 }
1879
pageSizeAndMarginsInPixels(int pageIndex,IntSize & pageSize,int & marginTop,int & marginRight,int & marginBottom,int & marginLeft)1880 void Document::pageSizeAndMarginsInPixels(int pageIndex, IntSize& pageSize, int& marginTop, int& marginRight, int& marginBottom, int& marginLeft)
1881 {
1882 RefPtr<RenderStyle> style = styleForPage(pageIndex);
1883 RenderView* view = renderView();
1884
1885 int width = pageSize.width();
1886 int height = pageSize.height();
1887 switch (style->pageSizeType()) {
1888 case PAGE_SIZE_AUTO:
1889 break;
1890 case PAGE_SIZE_AUTO_LANDSCAPE:
1891 if (width < height)
1892 std::swap(width, height);
1893 break;
1894 case PAGE_SIZE_AUTO_PORTRAIT:
1895 if (width > height)
1896 std::swap(width, height);
1897 break;
1898 case PAGE_SIZE_RESOLVED: {
1899 LengthSize size = style->pageSize();
1900 ASSERT(size.width().isFixed());
1901 ASSERT(size.height().isFixed());
1902 width = valueForLength(size.width(), 0, view);
1903 height = valueForLength(size.height(), 0, view);
1904 break;
1905 }
1906 default:
1907 ASSERT_NOT_REACHED();
1908 }
1909 pageSize = IntSize(width, height);
1910
1911 // The percentage is calculated with respect to the width even for margin top and bottom.
1912 // http://www.w3.org/TR/CSS2/box.html#margin-properties
1913 marginTop = style->marginTop().isAuto() ? marginTop : intValueForLength(style->marginTop(), width, view);
1914 marginRight = style->marginRight().isAuto() ? marginRight : intValueForLength(style->marginRight(), width, view);
1915 marginBottom = style->marginBottom().isAuto() ? marginBottom : intValueForLength(style->marginBottom(), width, view);
1916 marginLeft = style->marginLeft().isAuto() ? marginLeft : intValueForLength(style->marginLeft(), width, view);
1917 }
1918
setIsViewSource(bool isViewSource)1919 void Document::setIsViewSource(bool isViewSource)
1920 {
1921 m_isViewSource = isViewSource;
1922 if (!m_isViewSource)
1923 return;
1924
1925 setSecurityOrigin(SecurityOrigin::createUnique());
1926 didUpdateSecurityOrigin();
1927 }
1928
styleResolver() const1929 StyleResolver* Document::styleResolver() const
1930 {
1931 return m_styleEngine->resolver();
1932 }
1933
ensureStyleResolver() const1934 StyleResolver& Document::ensureStyleResolver() const
1935 {
1936 return m_styleEngine->ensureResolver();
1937 }
1938
clearStyleResolver()1939 void Document::clearStyleResolver()
1940 {
1941 m_styleEngine->clearResolver();
1942 }
1943
attach(const AttachContext & context)1944 void Document::attach(const AttachContext& context)
1945 {
1946 ASSERT(m_lifecyle.state() == DocumentLifecycle::Inactive);
1947 ASSERT(!m_axObjectCache || this != topDocument());
1948
1949 m_renderView = new RenderView(this);
1950 setRenderer(m_renderView);
1951
1952 m_renderView->setIsInWindow(true);
1953 m_renderView->setStyle(StyleResolver::styleForDocument(*this));
1954 view()->updateCompositingLayersAfterStyleChange();
1955
1956 m_styleEngine->didAttach();
1957
1958 ContainerNode::attach(context);
1959
1960 m_lifecyle.advanceTo(DocumentLifecycle::Active);
1961 }
1962
detach(const AttachContext & context)1963 void Document::detach(const AttachContext& context)
1964 {
1965 ASSERT(isActive());
1966 m_lifecyle.advanceTo(DocumentLifecycle::Stopping);
1967
1968 if (page())
1969 page()->documentDetached(this);
1970
1971 if (this == topDocument())
1972 clearAXObjectCache();
1973
1974 stopActiveDOMObjects();
1975
1976 // FIXME: consider using ActiveDOMObject.
1977 if (m_scriptedAnimationController)
1978 m_scriptedAnimationController->clearDocumentPointer();
1979 m_scriptedAnimationController.clear();
1980
1981 if (svgExtensions())
1982 accessSVGExtensions()->pauseAnimations();
1983
1984 // FIXME: This shouldn't be needed once DOMWindow becomes ExecutionContext.
1985 if (m_domWindow)
1986 m_domWindow->clearEventQueue();
1987
1988 RenderView* renderView = m_renderView;
1989
1990 if (renderView)
1991 renderView->setIsInWindow(false);
1992
1993 if (m_frame) {
1994 FrameView* view = m_frame->view();
1995 if (view)
1996 view->detachCustomScrollbars();
1997 }
1998
1999 // Indicate destruction mode by setting the renderer to null.
2000 // FIXME: Don't do this and use m_lifecycle.state() == Stopping instead.
2001 setRenderer(0);
2002 m_renderView = 0;
2003
2004 m_hoverNode = 0;
2005 m_focusedElement = 0;
2006 m_activeElement = 0;
2007
2008 ContainerNode::detach(context);
2009
2010 unscheduleStyleRecalc();
2011
2012 m_styleEngine->didDetach();
2013
2014 if (renderView)
2015 renderView->destroy();
2016
2017 if (m_touchEventTargets && m_touchEventTargets->size() && parentDocument())
2018 parentDocument()->didRemoveEventTargetNode(this);
2019
2020 // This is required, as our Frame might delete itself as soon as it detaches
2021 // us. However, this violates Node::detach() semantics, as it's never
2022 // possible to re-attach. Eventually Document::detach() should be renamed,
2023 // or this setting of the frame to 0 could be made explicit in each of the
2024 // callers of Document::detach().
2025 m_frame = 0;
2026
2027 if (m_mediaQueryMatcher)
2028 m_mediaQueryMatcher->documentDestroyed();
2029
2030 lifecycleNotifier().notifyDocumentWasDetached();
2031 m_lifecyle.advanceTo(DocumentLifecycle::Stopped);
2032 }
2033
prepareForDestruction()2034 void Document::prepareForDestruction()
2035 {
2036 m_markers->prepareForDestruction();
2037 disconnectDescendantFrames();
2038
2039 // The process of disconnecting descendant frames could have already detached us.
2040 if (!isActive())
2041 return;
2042
2043 if (DOMWindow* window = this->domWindow())
2044 window->willDetachDocumentFromFrame();
2045 detach();
2046 }
2047
removeAllEventListeners()2048 void Document::removeAllEventListeners()
2049 {
2050 EventTarget::removeAllEventListeners();
2051
2052 if (DOMWindow* domWindow = this->domWindow())
2053 domWindow->removeAllEventListeners();
2054 for (Node* node = firstChild(); node; node = NodeTraversal::next(*node))
2055 node->removeAllEventListeners();
2056 }
2057
clearAXObjectCache()2058 void Document::clearAXObjectCache()
2059 {
2060 ASSERT(topDocument() == this);
2061 // Clear the cache member variable before calling delete because attempts
2062 // are made to access it during destruction.
2063 m_axObjectCache.clear();
2064 }
2065
existingAXObjectCache() const2066 AXObjectCache* Document::existingAXObjectCache() const
2067 {
2068 if (!AXObjectCache::accessibilityEnabled())
2069 return 0;
2070
2071 // If the renderer is gone then we are in the process of destruction.
2072 // This method will be called before m_frame = 0.
2073 if (!topDocument()->renderView())
2074 return 0;
2075
2076 return topDocument()->m_axObjectCache.get();
2077 }
2078
axObjectCache() const2079 AXObjectCache* Document::axObjectCache() const
2080 {
2081 if (!AXObjectCache::accessibilityEnabled())
2082 return 0;
2083
2084 // The only document that actually has a AXObjectCache is the top-level
2085 // document. This is because we need to be able to get from any WebCoreAXObject
2086 // to any other WebCoreAXObject on the same page. Using a single cache allows
2087 // lookups across nested webareas (i.e. multiple documents).
2088 Document* topDocument = this->topDocument();
2089
2090 // If the document has already been detached, do not make a new axObjectCache.
2091 if (!topDocument->renderView())
2092 return 0;
2093
2094 ASSERT(topDocument == this || !m_axObjectCache);
2095 if (!topDocument->m_axObjectCache)
2096 topDocument->m_axObjectCache = adoptPtr(new AXObjectCache(topDocument));
2097 return topDocument->m_axObjectCache.get();
2098 }
2099
setVisuallyOrdered()2100 void Document::setVisuallyOrdered()
2101 {
2102 m_visuallyOrdered = true;
2103 // FIXME: How is possible to not have a renderer here?
2104 if (renderView())
2105 renderView()->style()->setRTLOrdering(VisualOrder);
2106 setNeedsStyleRecalc();
2107 }
2108
createParser()2109 PassRefPtr<DocumentParser> Document::createParser()
2110 {
2111 if (isHTMLDocument()) {
2112 bool reportErrors = InspectorInstrumentation::collectingHTMLParseErrors(this->page());
2113 return HTMLDocumentParser::create(toHTMLDocument(this), reportErrors);
2114 }
2115 // FIXME: this should probably pass the frame instead
2116 return XMLDocumentParser::create(this, view());
2117 }
2118
isFrameSet() const2119 bool Document::isFrameSet() const
2120 {
2121 if (!isHTMLDocument())
2122 return false;
2123 HTMLElement* bodyElement = body();
2124 return bodyElement && bodyElement->hasTagName(framesetTag);
2125 }
2126
scriptableDocumentParser() const2127 ScriptableDocumentParser* Document::scriptableDocumentParser() const
2128 {
2129 return parser() ? parser()->asScriptableDocumentParser() : 0;
2130 }
2131
open(Document * ownerDocument)2132 void Document::open(Document* ownerDocument)
2133 {
2134 if (ownerDocument) {
2135 setURL(ownerDocument->url());
2136 m_cookieURL = ownerDocument->cookieURL();
2137 setSecurityOrigin(ownerDocument->securityOrigin());
2138 }
2139
2140 if (m_frame) {
2141 if (ScriptableDocumentParser* parser = scriptableDocumentParser()) {
2142 if (parser->isParsing()) {
2143 // FIXME: HTML5 doesn't tell us to check this, it might not be correct.
2144 if (parser->isExecutingScript())
2145 return;
2146
2147 if (!parser->wasCreatedByScript() && parser->hasInsertionPoint())
2148 return;
2149 }
2150 }
2151
2152 if (m_frame->loader().state() == FrameStateProvisional)
2153 m_frame->loader().stopAllLoaders();
2154 }
2155
2156 removeAllEventListeners();
2157 implicitOpen();
2158 if (ScriptableDocumentParser* parser = scriptableDocumentParser())
2159 parser->setWasCreatedByScript(true);
2160
2161 if (m_frame)
2162 m_frame->loader().didExplicitOpen();
2163 if (m_loadEventProgress != LoadEventInProgress && m_loadEventProgress != UnloadEventInProgress)
2164 m_loadEventProgress = LoadEventNotRun;
2165 }
2166
detachParser()2167 void Document::detachParser()
2168 {
2169 if (!m_parser)
2170 return;
2171 m_parser->detach();
2172 m_parser.clear();
2173 }
2174
cancelParsing()2175 void Document::cancelParsing()
2176 {
2177 if (!m_parser)
2178 return;
2179
2180 // We have to clear the parser to avoid possibly triggering
2181 // the onload handler when closing as a side effect of a cancel-style
2182 // change, such as opening a new document or closing the window while
2183 // still parsing.
2184 detachParser();
2185 explicitClose();
2186 }
2187
implicitOpen()2188 PassRefPtr<DocumentParser> Document::implicitOpen()
2189 {
2190 cancelParsing();
2191
2192 removeChildren();
2193 ASSERT(!m_focusedElement);
2194
2195 setCompatibilityMode(NoQuirksMode);
2196
2197 // Documents rendered seamlessly should start out requiring a stylesheet
2198 // collection update in order to ensure they inherit all the relevant data
2199 // from their parent.
2200 if (shouldDisplaySeamlesslyWithParent())
2201 styleResolverChanged(RecalcStyleDeferred);
2202
2203 m_parser = createParser();
2204 setParsing(true);
2205 setReadyState(Loading);
2206
2207 return m_parser;
2208 }
2209
body() const2210 HTMLElement* Document::body() const
2211 {
2212 if (!documentElement())
2213 return 0;
2214
2215 for (Node* child = documentElement()->firstChild(); child; child = child->nextSibling()) {
2216 if (child->hasTagName(framesetTag) || child->hasTagName(bodyTag))
2217 return toHTMLElement(child);
2218 }
2219
2220 return 0;
2221 }
2222
setBody(PassRefPtr<HTMLElement> prpNewBody,ExceptionState & exceptionState)2223 void Document::setBody(PassRefPtr<HTMLElement> prpNewBody, ExceptionState& exceptionState)
2224 {
2225 RefPtr<HTMLElement> newBody = prpNewBody;
2226
2227 if (!newBody || !documentElement()) {
2228 exceptionState.throwUninformativeAndGenericDOMException(HierarchyRequestError);
2229 return;
2230 }
2231
2232 if (!newBody->hasTagName(bodyTag) && !newBody->hasTagName(framesetTag)) {
2233 exceptionState.throwUninformativeAndGenericDOMException(HierarchyRequestError);
2234 return;
2235 }
2236
2237 HTMLElement* oldBody = body();
2238 if (oldBody == newBody)
2239 return;
2240
2241 if (oldBody)
2242 documentElement()->replaceChild(newBody.release(), oldBody, exceptionState);
2243 else
2244 documentElement()->appendChild(newBody.release(), exceptionState);
2245 }
2246
head()2247 HTMLHeadElement* Document::head()
2248 {
2249 Node* de = documentElement();
2250 if (!de)
2251 return 0;
2252
2253 for (Node* node = de->firstChild(); node; node = node->nextSibling()) {
2254 if (node->hasTagName(headTag))
2255 return toHTMLHeadElement(node);
2256 }
2257 return 0;
2258 }
2259
close()2260 void Document::close()
2261 {
2262 // FIXME: We should follow the specification more closely:
2263 // http://www.whatwg.org/specs/web-apps/current-work/#dom-document-close
2264
2265 if (!scriptableDocumentParser() || !scriptableDocumentParser()->wasCreatedByScript() || !scriptableDocumentParser()->isParsing())
2266 return;
2267
2268 explicitClose();
2269 }
2270
explicitClose()2271 void Document::explicitClose()
2272 {
2273 if (RefPtr<DocumentParser> parser = m_parser)
2274 parser->finish();
2275
2276 if (!m_frame) {
2277 // Because we have no frame, we don't know if all loading has completed,
2278 // so we just call implicitClose() immediately. FIXME: This might fire
2279 // the load event prematurely <http://bugs.webkit.org/show_bug.cgi?id=14568>.
2280 implicitClose();
2281 return;
2282 }
2283
2284 m_frame->loader().checkCompleted();
2285 }
2286
implicitClose()2287 void Document::implicitClose()
2288 {
2289 ASSERT(!inStyleRecalc());
2290
2291 bool wasLocationChangePending = frame() && frame()->navigationScheduler().locationChangePending();
2292 bool doload = !parsing() && m_parser && !processingLoadEvent() && !wasLocationChangePending;
2293
2294 // If the load was blocked because of a pending location change and the location change triggers a same document
2295 // navigation, don't fire load events after the same document navigation completes (unless there's an explicit open).
2296 m_loadEventProgress = LoadEventTried;
2297
2298 if (!doload)
2299 return;
2300
2301 // The call to dispatchWindowLoadEvent can detach the DOMWindow and cause it (and its
2302 // attached Document) to be destroyed.
2303 RefPtr<DOMWindow> protectedWindow(this->domWindow());
2304
2305 m_loadEventProgress = LoadEventInProgress;
2306
2307 ScriptableDocumentParser* parser = scriptableDocumentParser();
2308 m_wellFormed = parser && parser->wellFormed();
2309
2310 // We have to clear the parser, in case someone document.write()s from the
2311 // onLoad event handler, as in Radar 3206524.
2312 detachParser();
2313
2314 if (frame() && frame()->script().canExecuteScripts(NotAboutToExecuteScript)) {
2315 ImageLoader::dispatchPendingBeforeLoadEvents();
2316 ImageLoader::dispatchPendingLoadEvents();
2317 ImageLoader::dispatchPendingErrorEvents();
2318
2319 HTMLLinkElement::dispatchPendingLoadEvents();
2320 HTMLStyleElement::dispatchPendingLoadEvents();
2321 }
2322
2323 // JS running below could remove the frame or destroy the RenderView so we call
2324 // those two functions repeatedly and don't save them on the stack.
2325
2326 // To align the HTML load event and the SVGLoad event for the outermost <svg> element, fire it from
2327 // here, instead of doing it from SVGElement::finishedParsingChildren (if externalResourcesRequired="false",
2328 // which is the default, for ='true' its fired at a later time, once all external resources finished loading).
2329 if (svgExtensions())
2330 accessSVGExtensions()->dispatchSVGLoadEventToOutermostSVGElements();
2331
2332 if (protectedWindow)
2333 protectedWindow->documentWasClosed();
2334
2335 if (frame()) {
2336 frame()->loader().client()->dispatchDidHandleOnloadEvents();
2337 loader()->applicationCacheHost()->stopDeferringEvents();
2338 }
2339
2340 if (!frame()) {
2341 m_loadEventProgress = LoadEventCompleted;
2342 return;
2343 }
2344
2345 // Make sure both the initial layout and reflow happen after the onload
2346 // fires. This will improve onload scores, and other browsers do it.
2347 // If they wanna cheat, we can too. -dwh
2348
2349 if (frame()->navigationScheduler().locationChangePending() && elapsedTime() < cLayoutScheduleThreshold) {
2350 // Just bail out. Before or during the onload we were shifted to another page.
2351 // The old i-Bench suite does this. When this happens don't bother painting or laying out.
2352 m_loadEventProgress = LoadEventCompleted;
2353 view()->unscheduleRelayout();
2354 return;
2355 }
2356
2357 // We used to force a synchronous display and flush here. This really isn't
2358 // necessary and can in fact be actively harmful if pages are loading at a rate of > 60fps
2359 // (if your platform is syncing flushes and limiting them to 60fps).
2360 m_overMinimumLayoutThreshold = true;
2361 if (!ownerElement() || (ownerElement()->renderer() && !ownerElement()->renderer()->needsLayout())) {
2362 updateStyleIfNeeded();
2363
2364 // Always do a layout after loading if needed.
2365 if (view() && renderView() && (!renderView()->firstChild() || renderView()->needsLayout()))
2366 view()->layout();
2367 }
2368
2369 m_loadEventProgress = LoadEventCompleted;
2370
2371 if (frame() && renderView() && AXObjectCache::accessibilityEnabled()) {
2372 // The AX cache may have been cleared at this point, but we need to make sure it contains an
2373 // AX object to send the notification to. getOrCreate will make sure that an valid AX object
2374 // exists in the cache (we ignore the return value because we don't need it here). This is
2375 // only safe to call when a layout is not in progress, so it can not be used in postNotification.
2376 if (AXObjectCache* cache = axObjectCache()) {
2377 cache->getOrCreate(renderView());
2378 if (this == topDocument()) {
2379 cache->postNotification(renderView(), AXObjectCache::AXLoadComplete, true);
2380 } else {
2381 // AXLoadComplete can only be posted on the top document, so if it's a document
2382 // in an iframe that just finished loading, post AXLayoutComplete instead.
2383 cache->postNotification(renderView(), AXObjectCache::AXLayoutComplete, true);
2384 }
2385 }
2386 }
2387
2388 if (svgExtensions())
2389 accessSVGExtensions()->startAnimations();
2390 }
2391
dispatchBeforeUnloadEvent(Chrome & chrome,bool & didAllowNavigation)2392 bool Document::dispatchBeforeUnloadEvent(Chrome& chrome, bool& didAllowNavigation)
2393 {
2394 if (!m_domWindow)
2395 return true;
2396
2397 if (!body())
2398 return true;
2399
2400 RefPtr<Document> protect(this);
2401
2402 RefPtr<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create();
2403 m_loadEventProgress = BeforeUnloadEventInProgress;
2404 m_domWindow->dispatchEvent(beforeUnloadEvent.get(), this);
2405 m_loadEventProgress = BeforeUnloadEventCompleted;
2406 if (!beforeUnloadEvent->defaultPrevented())
2407 defaultEventHandler(beforeUnloadEvent.get());
2408 if (beforeUnloadEvent->returnValue().isNull())
2409 return true;
2410
2411 if (didAllowNavigation) {
2412 addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Blocked attempt to show multiple 'beforeunload' confirmation panels for a single navigation.");
2413 return true;
2414 }
2415
2416 String text = beforeUnloadEvent->returnValue();
2417 if (chrome.runBeforeUnloadConfirmPanel(text, m_frame)) {
2418 didAllowNavigation = true;
2419 return true;
2420 }
2421 return false;
2422 }
2423
dispatchUnloadEvents()2424 void Document::dispatchUnloadEvents()
2425 {
2426 RefPtr<Document> protect(this);
2427 if (m_parser)
2428 m_parser->stopParsing();
2429
2430 if (m_loadEventProgress >= LoadEventTried && m_loadEventProgress <= UnloadEventInProgress) {
2431 Element* currentFocusedElement = focusedElement();
2432 if (currentFocusedElement && currentFocusedElement->hasTagName(inputTag))
2433 toHTMLInputElement(currentFocusedElement)->endEditing();
2434 if (m_loadEventProgress < PageHideInProgress) {
2435 m_loadEventProgress = PageHideInProgress;
2436 if (DOMWindow* window = domWindow())
2437 window->dispatchEvent(PageTransitionEvent::create(EventTypeNames::pagehide, false), this);
2438 if (!m_frame)
2439 return;
2440
2441 // The DocumentLoader (and thus its DocumentLoadTiming) might get destroyed
2442 // while dispatching the event, so protect it to prevent writing the end
2443 // time into freed memory.
2444 RefPtr<DocumentLoader> documentLoader = m_frame->loader().provisionalDocumentLoader();
2445 m_loadEventProgress = UnloadEventInProgress;
2446 RefPtr<Event> unloadEvent(Event::create(EventTypeNames::unload));
2447 if (documentLoader && !documentLoader->timing()->unloadEventStart() && !documentLoader->timing()->unloadEventEnd()) {
2448 DocumentLoadTiming* timing = documentLoader->timing();
2449 ASSERT(timing->navigationStart());
2450 timing->markUnloadEventStart();
2451 m_frame->domWindow()->dispatchEvent(unloadEvent, this);
2452 timing->markUnloadEventEnd();
2453 } else {
2454 m_frame->domWindow()->dispatchEvent(unloadEvent, m_frame->document());
2455 }
2456 }
2457 m_loadEventProgress = UnloadEventHandled;
2458 }
2459
2460 if (!m_frame)
2461 return;
2462
2463 // Don't remove event listeners from a transitional empty document (see https://bugs.webkit.org/show_bug.cgi?id=28716 for more information).
2464 bool keepEventListeners = m_frame->loader().stateMachine()->isDisplayingInitialEmptyDocument() && m_frame->loader().provisionalDocumentLoader()
2465 && isSecureTransitionTo(m_frame->loader().provisionalDocumentLoader()->url());
2466 if (!keepEventListeners)
2467 removeAllEventListeners();
2468 }
2469
pageDismissalEventBeingDispatched() const2470 Document::PageDismissalType Document::pageDismissalEventBeingDispatched() const
2471 {
2472 if (m_loadEventProgress == BeforeUnloadEventInProgress)
2473 return BeforeUnloadDismissal;
2474 if (m_loadEventProgress == PageHideInProgress)
2475 return PageHideDismissal;
2476 if (m_loadEventProgress == UnloadEventInProgress)
2477 return UnloadDismissal;
2478 return NoDismissal;
2479 }
2480
setParsing(bool b)2481 void Document::setParsing(bool b)
2482 {
2483 m_bParsing = b;
2484
2485 if (m_bParsing && !m_sharedObjectPool)
2486 m_sharedObjectPool = DocumentSharedObjectPool::create();
2487
2488 if (!m_bParsing && view())
2489 view()->scheduleRelayout();
2490 }
2491
shouldScheduleLayout()2492 bool Document::shouldScheduleLayout()
2493 {
2494 // This function will only be called when FrameView thinks a layout is needed.
2495 // This enforces a couple extra rules.
2496 //
2497 // (a) Only schedule a layout once the stylesheets are loaded.
2498 // (b) Only schedule layout once we have a body element.
2499
2500 return (haveStylesheetsLoaded() && body())
2501 || (documentElement() && !isHTMLHtmlElement(documentElement()));
2502 }
2503
shouldParserYieldAgressivelyBeforeScriptExecution()2504 bool Document::shouldParserYieldAgressivelyBeforeScriptExecution()
2505 {
2506 return view() && view()->layoutPending() && !minimumLayoutDelay();
2507 }
2508
minimumLayoutDelay()2509 int Document::minimumLayoutDelay()
2510 {
2511 if (m_overMinimumLayoutThreshold)
2512 return 0;
2513
2514 int elapsed = elapsedTime();
2515 m_overMinimumLayoutThreshold = elapsed > cLayoutScheduleThreshold;
2516
2517 // We'll want to schedule the timer to fire at the minimum layout threshold.
2518 return max(0, cLayoutScheduleThreshold - elapsed);
2519 }
2520
elapsedTime() const2521 int Document::elapsedTime() const
2522 {
2523 return static_cast<int>((currentTime() - m_startTime) * 1000);
2524 }
2525
write(const SegmentedString & text,Document * ownerDocument)2526 void Document::write(const SegmentedString& text, Document* ownerDocument)
2527 {
2528 NestingLevelIncrementer nestingLevelIncrementer(m_writeRecursionDepth);
2529
2530 m_writeRecursionIsTooDeep = (m_writeRecursionDepth > 1) && m_writeRecursionIsTooDeep;
2531 m_writeRecursionIsTooDeep = (m_writeRecursionDepth > cMaxWriteRecursionDepth) || m_writeRecursionIsTooDeep;
2532
2533 if (m_writeRecursionIsTooDeep)
2534 return;
2535
2536 bool hasInsertionPoint = m_parser && m_parser->hasInsertionPoint();
2537 if (!hasInsertionPoint && m_ignoreDestructiveWriteCount)
2538 return;
2539
2540 if (!hasInsertionPoint)
2541 open(ownerDocument);
2542
2543 ASSERT(m_parser);
2544 m_parser->insert(text);
2545 }
2546
write(const String & text,Document * ownerDocument)2547 void Document::write(const String& text, Document* ownerDocument)
2548 {
2549 write(SegmentedString(text), ownerDocument);
2550 }
2551
writeln(const String & text,Document * ownerDocument)2552 void Document::writeln(const String& text, Document* ownerDocument)
2553 {
2554 write(text, ownerDocument);
2555 write("\n", ownerDocument);
2556 }
2557
virtualURL() const2558 const KURL& Document::virtualURL() const
2559 {
2560 return m_url;
2561 }
2562
virtualCompleteURL(const String & url) const2563 KURL Document::virtualCompleteURL(const String& url) const
2564 {
2565 return completeURL(url);
2566 }
2567
timerAlignmentInterval() const2568 double Document::timerAlignmentInterval() const
2569 {
2570 Page* p = page();
2571 if (!p)
2572 return DOMTimer::visiblePageAlignmentInterval();
2573 return p->timerAlignmentInterval();
2574 }
2575
errorEventTarget()2576 EventTarget* Document::errorEventTarget()
2577 {
2578 return domWindow();
2579 }
2580
logExceptionToConsole(const String & errorMessage,const String & sourceURL,int lineNumber,int columnNumber,PassRefPtr<ScriptCallStack> callStack)2581 void Document::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtr<ScriptCallStack> callStack)
2582 {
2583 internalAddMessage(JSMessageSource, ErrorMessageLevel, errorMessage, sourceURL, lineNumber, callStack, 0);
2584 }
2585
setURL(const KURL & url)2586 void Document::setURL(const KURL& url)
2587 {
2588 const KURL& newURL = url.isEmpty() ? blankURL() : url;
2589 if (newURL == m_url)
2590 return;
2591
2592 m_url = newURL;
2593 m_documentURI = m_url.string();
2594 updateBaseURL();
2595 contextFeatures()->urlDidChange(this);
2596 }
2597
updateBaseURL()2598 void Document::updateBaseURL()
2599 {
2600 KURL oldBaseURL = m_baseURL;
2601 // DOM 3 Core: When the Document supports the feature "HTML" [DOM Level 2 HTML], the base URI is computed using
2602 // first the value of the href attribute of the HTML BASE element if any, and the value of the documentURI attribute
2603 // from the Document interface otherwise.
2604 if (!m_baseElementURL.isEmpty())
2605 m_baseURL = m_baseElementURL;
2606 else if (!m_baseURLOverride.isEmpty())
2607 m_baseURL = m_baseURLOverride;
2608 else {
2609 // The documentURI attribute is read-only from JavaScript, but writable from Objective C, so we need to retain
2610 // this fallback behavior. We use a null base URL, since the documentURI attribute is an arbitrary string
2611 // and DOM 3 Core does not specify how it should be resolved.
2612 // FIXME: Now that we don't support Objective-C this can probably be removed.
2613 m_baseURL = KURL(ParsedURLString, documentURI());
2614 }
2615 selectorQueryCache().invalidate();
2616
2617 if (!m_baseURL.isValid())
2618 m_baseURL = KURL();
2619
2620 if (m_elemSheet) {
2621 // Element sheet is silly. It never contains anything.
2622 ASSERT(!m_elemSheet->contents()->ruleCount());
2623 bool usesRemUnits = m_elemSheet->contents()->usesRemUnits();
2624 m_elemSheet = CSSStyleSheet::createInline(this, m_baseURL);
2625 // FIXME: So we are not really the parser. The right fix is to eliminate the element sheet completely.
2626 m_elemSheet->contents()->parserSetUsesRemUnits(usesRemUnits);
2627 }
2628
2629 if (!equalIgnoringFragmentIdentifier(oldBaseURL, m_baseURL)) {
2630 // Base URL change changes any relative visited links.
2631 // FIXME: There are other URLs in the tree that would need to be re-evaluated on dynamic base URL change. Style should be invalidated too.
2632 for (Element* element = ElementTraversal::firstWithin(*this); element; element = ElementTraversal::next(*element)) {
2633 if (isHTMLAnchorElement(element))
2634 toHTMLAnchorElement(element)->invalidateCachedVisitedLinkHash();
2635 }
2636 }
2637 }
2638
setBaseURLOverride(const KURL & url)2639 void Document::setBaseURLOverride(const KURL& url)
2640 {
2641 m_baseURLOverride = url;
2642 updateBaseURL();
2643 }
2644
processBaseElement()2645 void Document::processBaseElement()
2646 {
2647 // Find the first href attribute in a base element and the first target attribute in a base element.
2648 const AtomicString* href = 0;
2649 const AtomicString* target = 0;
2650 for (Element* element = ElementTraversal::firstWithin(*this); element && (!href || !target); element = ElementTraversal::next(*element)) {
2651 if (element->hasTagName(baseTag)) {
2652 if (!href) {
2653 const AtomicString& value = element->fastGetAttribute(hrefAttr);
2654 if (!value.isNull())
2655 href = &value;
2656 }
2657 if (!target) {
2658 const AtomicString& value = element->fastGetAttribute(targetAttr);
2659 if (!value.isNull())
2660 target = &value;
2661 }
2662 if (contentSecurityPolicy()->isActive())
2663 UseCounter::count(*this, UseCounter::ContentSecurityPolicyWithBaseElement);
2664 }
2665 }
2666
2667 // FIXME: Since this doesn't share code with completeURL it may not handle encodings correctly.
2668 KURL baseElementURL;
2669 if (href) {
2670 String strippedHref = stripLeadingAndTrailingHTMLSpaces(*href);
2671 if (!strippedHref.isEmpty())
2672 baseElementURL = KURL(url(), strippedHref);
2673 }
2674 if (m_baseElementURL != baseElementURL && contentSecurityPolicy()->allowBaseURI(baseElementURL)) {
2675 m_baseElementURL = baseElementURL;
2676 updateBaseURL();
2677 }
2678
2679 m_baseTarget = target ? *target : nullAtom;
2680 }
2681
userAgent(const KURL & url) const2682 String Document::userAgent(const KURL& url) const
2683 {
2684 return frame() ? frame()->loader().userAgent(url) : String();
2685 }
2686
disableEval(const String & errorMessage)2687 void Document::disableEval(const String& errorMessage)
2688 {
2689 if (!frame())
2690 return;
2691
2692 frame()->script().disableEval(errorMessage);
2693 }
2694
canNavigate(Frame * targetFrame)2695 bool Document::canNavigate(Frame* targetFrame)
2696 {
2697 if (!m_frame)
2698 return false;
2699
2700 // FIXME: We shouldn't call this function without a target frame, but
2701 // fast/forms/submit-to-blank-multiple-times.html depends on this function
2702 // returning true when supplied with a 0 targetFrame.
2703 if (!targetFrame)
2704 return true;
2705
2706 // Frame-busting is generally allowed, but blocked for sandboxed frames lacking the 'allow-top-navigation' flag.
2707 if (!isSandboxed(SandboxTopNavigation) && targetFrame == m_frame->tree().top())
2708 return true;
2709
2710 if (isSandboxed(SandboxNavigation)) {
2711 if (targetFrame->tree().isDescendantOf(m_frame))
2712 return true;
2713
2714 const char* reason = "The frame attempting navigation is sandboxed, and is therefore disallowed from navigating its ancestors.";
2715 if (isSandboxed(SandboxTopNavigation) && targetFrame == m_frame->tree().top())
2716 reason = "The frame attempting navigation of the top-level window is sandboxed, but the 'allow-top-navigation' flag is not set.";
2717
2718 printNavigationErrorMessage(*targetFrame, url(), reason);
2719 return false;
2720 }
2721
2722 ASSERT(securityOrigin());
2723 SecurityOrigin& origin = *securityOrigin();
2724
2725 // This is the normal case. A document can navigate its decendant frames,
2726 // or, more generally, a document can navigate a frame if the document is
2727 // in the same origin as any of that frame's ancestors (in the frame
2728 // hierarchy).
2729 //
2730 // See http://www.adambarth.com/papers/2008/barth-jackson-mitchell.pdf for
2731 // historical information about this security check.
2732 if (canAccessAncestor(origin, targetFrame))
2733 return true;
2734
2735 // Top-level frames are easier to navigate than other frames because they
2736 // display their URLs in the address bar (in most browsers). However, there
2737 // are still some restrictions on navigation to avoid nuisance attacks.
2738 // Specifically, a document can navigate a top-level frame if that frame
2739 // opened the document or if the document is the same-origin with any of
2740 // the top-level frame's opener's ancestors (in the frame hierarchy).
2741 //
2742 // In both of these cases, the document performing the navigation is in
2743 // some way related to the frame being navigate (e.g., by the "opener"
2744 // and/or "parent" relation). Requiring some sort of relation prevents a
2745 // document from navigating arbitrary, unrelated top-level frames.
2746 if (!targetFrame->tree().parent()) {
2747 if (targetFrame == m_frame->loader().opener())
2748 return true;
2749
2750 if (canAccessAncestor(origin, targetFrame->loader().opener()))
2751 return true;
2752 }
2753
2754 printNavigationErrorMessage(*targetFrame, url(), "The frame attempting navigation is neither same-origin with the target, nor is it the target's parent or opener.");
2755 return false;
2756 }
2757
findUnsafeParentScrollPropagationBoundary()2758 Frame* Document::findUnsafeParentScrollPropagationBoundary()
2759 {
2760 Frame* currentFrame = m_frame;
2761 Frame* ancestorFrame = currentFrame->tree().parent();
2762
2763 while (ancestorFrame) {
2764 if (!ancestorFrame->document()->securityOrigin()->canAccess(securityOrigin()))
2765 return currentFrame;
2766 currentFrame = ancestorFrame;
2767 ancestorFrame = ancestorFrame->tree().parent();
2768 }
2769 return 0;
2770 }
2771
2772
seamlessParentUpdatedStylesheets()2773 void Document::seamlessParentUpdatedStylesheets()
2774 {
2775 m_styleEngine->didModifySeamlessParentStyleSheet();
2776 styleResolverChanged(RecalcStyleImmediately);
2777 }
2778
didRemoveAllPendingStylesheet()2779 void Document::didRemoveAllPendingStylesheet()
2780 {
2781 m_needsNotifyRemoveAllPendingStylesheet = false;
2782
2783 styleResolverChanged(RecalcStyleDeferred, AnalyzedStyleUpdate);
2784 executeScriptsWaitingForResourcesIfNeeded();
2785
2786 if (m_gotoAnchorNeededAfterStylesheetsLoad && view())
2787 view()->scrollToFragment(m_url);
2788 }
2789
executeScriptsWaitingForResourcesIfNeeded()2790 void Document::executeScriptsWaitingForResourcesIfNeeded()
2791 {
2792 if (!haveStylesheetsAndImportsLoaded())
2793 return;
2794 if (ScriptableDocumentParser* parser = scriptableDocumentParser())
2795 parser->executeScriptsWaitingForResources();
2796 }
2797
2798
elementSheet()2799 CSSStyleSheet* Document::elementSheet()
2800 {
2801 if (!m_elemSheet)
2802 m_elemSheet = CSSStyleSheet::createInline(this, m_baseURL);
2803 return m_elemSheet.get();
2804 }
2805
processHttpEquiv(const AtomicString & equiv,const AtomicString & content)2806 void Document::processHttpEquiv(const AtomicString& equiv, const AtomicString& content)
2807 {
2808 ASSERT(!equiv.isNull() && !content.isNull());
2809
2810 if (equalIgnoringCase(equiv, "default-style"))
2811 processHttpEquivDefaultStyle(content);
2812 else if (equalIgnoringCase(equiv, "refresh"))
2813 processHttpEquivRefresh(content);
2814 else if (equalIgnoringCase(equiv, "set-cookie"))
2815 processHttpEquivSetCookie(content);
2816 else if (equalIgnoringCase(equiv, "content-language"))
2817 setContentLanguage(content);
2818 else if (equalIgnoringCase(equiv, "x-dns-prefetch-control"))
2819 parseDNSPrefetchControlHeader(content);
2820 else if (equalIgnoringCase(equiv, "x-frame-options"))
2821 processHttpEquivXFrameOptions(content);
2822 else if (equalIgnoringCase(equiv, "content-security-policy")
2823 || equalIgnoringCase(equiv, "content-security-policy-report-only")
2824 || equalIgnoringCase(equiv, "x-webkit-csp")
2825 || equalIgnoringCase(equiv, "x-webkit-csp-report-only"))
2826 processHttpEquivContentSecurityPolicy(equiv, content);
2827 }
2828
processHttpEquivContentSecurityPolicy(const AtomicString & equiv,const AtomicString & content)2829 void Document::processHttpEquivContentSecurityPolicy(const AtomicString& equiv, const AtomicString& content)
2830 {
2831 if (equalIgnoringCase(equiv, "content-security-policy"))
2832 contentSecurityPolicy()->didReceiveHeader(content, ContentSecurityPolicy::Enforce);
2833 else if (equalIgnoringCase(equiv, "content-security-policy-report-only"))
2834 contentSecurityPolicy()->didReceiveHeader(content, ContentSecurityPolicy::Report);
2835 // FIXME: Remove deprecation messages after the next release branch.
2836 else if (equalIgnoringCase(equiv, "x-webkit-csp"))
2837 UseCounter::countDeprecation(this, UseCounter::PrefixedContentSecurityPolicy);
2838 else if (equalIgnoringCase(equiv, "x-webkit-csp-report-only"))
2839 UseCounter::countDeprecation(this, UseCounter::PrefixedContentSecurityPolicyReportOnly);
2840 else
2841 ASSERT_NOT_REACHED();
2842 }
2843
processHttpEquivDefaultStyle(const AtomicString & content)2844 void Document::processHttpEquivDefaultStyle(const AtomicString& content)
2845 {
2846 // The preferred style set has been overridden as per section
2847 // 14.3.2 of the HTML4.0 specification. We need to update the
2848 // sheet used variable and then update our style selector.
2849 // For more info, see the test at:
2850 // http://www.hixie.ch/tests/evil/css/import/main/preferred.html
2851 // -dwh
2852 m_styleEngine->setSelectedStylesheetSetName(content);
2853 m_styleEngine->setPreferredStylesheetSetName(content);
2854 styleResolverChanged(RecalcStyleDeferred);
2855 }
2856
processHttpEquivRefresh(const AtomicString & content)2857 void Document::processHttpEquivRefresh(const AtomicString& content)
2858 {
2859 maybeHandleHttpRefresh(content, HttpRefreshFromMetaTag);
2860 }
2861
maybeHandleHttpRefresh(const String & content,HttpRefreshType httpRefreshType)2862 void Document::maybeHandleHttpRefresh(const String& content, HttpRefreshType httpRefreshType)
2863 {
2864 if (m_isViewSource || !m_frame)
2865 return;
2866
2867 double delay;
2868 String refreshURL;
2869 if (!parseHTTPRefresh(content, httpRefreshType == HttpRefreshFromMetaTag, delay, refreshURL))
2870 return;
2871 if (refreshURL.isEmpty())
2872 refreshURL = url().string();
2873 else
2874 refreshURL = completeURL(refreshURL).string();
2875
2876 if (protocolIsJavaScript(refreshURL)) {
2877 String message = "Refused to refresh " + m_url.elidedString() + " to a javascript: URL";
2878 addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message);
2879 return;
2880 }
2881
2882 if (httpRefreshType == HttpRefreshFromMetaTag && isSandboxed(SandboxAutomaticFeatures)) {
2883 String message = "Refused to execute the redirect specified via '<meta http-equiv='refresh' content='...'>'. The document is sandboxed, and the 'allow-scripts' keyword is not set.";
2884 addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message);
2885 return;
2886 }
2887 m_frame->navigationScheduler().scheduleRedirect(delay, refreshURL);
2888 }
2889
processHttpEquivSetCookie(const AtomicString & content)2890 void Document::processHttpEquivSetCookie(const AtomicString& content)
2891 {
2892 // FIXME: make setCookie work on XML documents too; e.g. in case of <html:meta .....>
2893 if (!isHTMLDocument())
2894 return;
2895
2896 // Exception (for sandboxed documents) ignored.
2897 toHTMLDocument(this)->setCookie(content, IGNORE_EXCEPTION);
2898 }
2899
processHttpEquivXFrameOptions(const AtomicString & content)2900 void Document::processHttpEquivXFrameOptions(const AtomicString& content)
2901 {
2902 Frame* frame = this->frame();
2903 if (!frame)
2904 return;
2905
2906 FrameLoader& frameLoader = frame->loader();
2907 unsigned long requestIdentifier = loader()->mainResourceIdentifier();
2908 if (frameLoader.shouldInterruptLoadForXFrameOptions(content, url(), requestIdentifier)) {
2909 String message = "Refused to display '" + url().elidedString() + "' in a frame because it set 'X-Frame-Options' to '" + content + "'.";
2910 frameLoader.stopAllLoaders();
2911 // Stopping the loader isn't enough, as we're already parsing the document; to honor the header's
2912 // intent, we must navigate away from the possibly partially-rendered document to a location that
2913 // doesn't inherit the parent's SecurityOrigin.
2914 frame->navigationScheduler().scheduleLocationChange(this, SecurityOrigin::urlWithUniqueSecurityOrigin(), String());
2915 addConsoleMessageWithRequestIdentifier(SecurityMessageSource, ErrorMessageLevel, message, requestIdentifier);
2916 }
2917 }
2918
shouldMergeWithLegacyDescription(ViewportDescription::Type origin)2919 bool Document::shouldMergeWithLegacyDescription(ViewportDescription::Type origin)
2920 {
2921 return settings() && settings()->viewportMetaMergeContentQuirk() && m_legacyViewportDescription.isMetaViewportType() && m_legacyViewportDescription.type == origin;
2922 }
2923
setViewportDescription(const ViewportDescription & viewportDescription)2924 void Document::setViewportDescription(const ViewportDescription& viewportDescription)
2925 {
2926 if (viewportDescription.isLegacyViewportType()) {
2927 if (settings() && !settings()->viewportMetaEnabled())
2928 return;
2929
2930 m_legacyViewportDescription = viewportDescription;
2931
2932 // When no author style for @viewport is present, and a meta tag for defining
2933 // the viewport is, apply the meta tag viewport instead of the UA styles.
2934 if (m_viewportDescription.type == ViewportDescription::AuthorStyleSheet)
2935 return;
2936 m_viewportDescription = viewportDescription;
2937 } else {
2938 // If the legacy viewport tag has higher priority than the cascaded @viewport
2939 // descriptors, use the values from the legacy tag.
2940 if (!shouldOverrideLegacyDescription(viewportDescription.type))
2941 m_viewportDescription = m_legacyViewportDescription;
2942 else
2943 m_viewportDescription = viewportDescription;
2944 }
2945
2946 updateViewportDescription();
2947 }
2948
updateViewportDescription()2949 void Document::updateViewportDescription()
2950 {
2951 if (frame() && frame()->isMainFrame()) {
2952 #ifndef NDEBUG
2953 m_didDispatchViewportPropertiesChanged = true;
2954 #endif
2955 page()->chrome().dispatchViewportPropertiesDidChange(m_viewportDescription);
2956 }
2957 }
2958
processReferrerPolicy(const String & policy)2959 void Document::processReferrerPolicy(const String& policy)
2960 {
2961 ASSERT(!policy.isNull());
2962
2963 m_referrerPolicy = ReferrerPolicyDefault;
2964
2965 if (equalIgnoringCase(policy, "never"))
2966 m_referrerPolicy = ReferrerPolicyNever;
2967 else if (equalIgnoringCase(policy, "always"))
2968 m_referrerPolicy = ReferrerPolicyAlways;
2969 else if (equalIgnoringCase(policy, "origin"))
2970 m_referrerPolicy = ReferrerPolicyOrigin;
2971 }
2972
outgoingReferrer()2973 String Document::outgoingReferrer()
2974 {
2975 // See http://www.whatwg.org/specs/web-apps/current-work/#fetching-resources
2976 // for why we walk the parent chain for srcdoc documents.
2977 Document* referrerDocument = this;
2978 if (Frame* frame = m_frame) {
2979 while (frame->document()->isSrcdocDocument()) {
2980 frame = frame->tree().parent();
2981 // Srcdoc documents cannot be top-level documents, by definition,
2982 // because they need to be contained in iframes with the srcdoc.
2983 ASSERT(frame);
2984 }
2985 referrerDocument = frame->document();
2986 }
2987 return referrerDocument->m_url.strippedForUseAsReferrer();
2988 }
2989
outgoingOrigin() const2990 String Document::outgoingOrigin() const
2991 {
2992 return securityOrigin()->toString();
2993 }
2994
prepareMouseEvent(const HitTestRequest & request,const LayoutPoint & documentPoint,const PlatformMouseEvent & event)2995 MouseEventWithHitTestResults Document::prepareMouseEvent(const HitTestRequest& request, const LayoutPoint& documentPoint, const PlatformMouseEvent& event)
2996 {
2997 ASSERT(!renderView() || renderView()->isRenderView());
2998
2999 // RenderView::hitTest causes a layout, and we don't want to hit that until the first
3000 // layout because until then, there is nothing shown on the screen - the user can't
3001 // have intentionally clicked on something belonging to this page. Furthermore,
3002 // mousemove events before the first layout should not lead to a premature layout()
3003 // happening, which could show a flash of white.
3004 // See also the similar code in EventHandler::hitTestResultAtPoint.
3005 if (!renderView() || !view() || !view()->didFirstLayout())
3006 return MouseEventWithHitTestResults(event, HitTestResult(LayoutPoint()));
3007
3008 HitTestResult result(documentPoint);
3009 renderView()->hitTest(request, result);
3010
3011 if (!request.readOnly())
3012 updateHoverActiveState(request, result.innerElement(), &event);
3013
3014 return MouseEventWithHitTestResults(event, result);
3015 }
3016
3017 // DOM Section 1.1.1
childTypeAllowed(NodeType type) const3018 bool Document::childTypeAllowed(NodeType type) const
3019 {
3020 switch (type) {
3021 case ATTRIBUTE_NODE:
3022 case CDATA_SECTION_NODE:
3023 case DOCUMENT_FRAGMENT_NODE:
3024 case DOCUMENT_NODE:
3025 case ENTITY_NODE:
3026 case NOTATION_NODE:
3027 case TEXT_NODE:
3028 case XPATH_NAMESPACE_NODE:
3029 return false;
3030 case COMMENT_NODE:
3031 case PROCESSING_INSTRUCTION_NODE:
3032 return true;
3033 case DOCUMENT_TYPE_NODE:
3034 case ELEMENT_NODE:
3035 // Documents may contain no more than one of each of these.
3036 // (One Element and one DocumentType.)
3037 for (Node* c = firstChild(); c; c = c->nextSibling())
3038 if (c->nodeType() == type)
3039 return false;
3040 return true;
3041 }
3042 return false;
3043 }
3044
canReplaceChild(const Node & newChild,const Node & oldChild) const3045 bool Document::canReplaceChild(const Node& newChild, const Node& oldChild) const
3046 {
3047 if (oldChild.nodeType() == newChild.nodeType())
3048 return true;
3049
3050 int numDoctypes = 0;
3051 int numElements = 0;
3052
3053 // First, check how many doctypes and elements we have, not counting
3054 // the child we're about to remove.
3055 for (Node* c = firstChild(); c; c = c->nextSibling()) {
3056 if (c == oldChild)
3057 continue;
3058
3059 switch (c->nodeType()) {
3060 case DOCUMENT_TYPE_NODE:
3061 numDoctypes++;
3062 break;
3063 case ELEMENT_NODE:
3064 numElements++;
3065 break;
3066 default:
3067 break;
3068 }
3069 }
3070
3071 // Then, see how many doctypes and elements might be added by the new child.
3072 if (newChild.nodeType() == DOCUMENT_FRAGMENT_NODE) {
3073 for (Node* c = newChild.firstChild(); c; c = c->nextSibling()) {
3074 switch (c->nodeType()) {
3075 case ATTRIBUTE_NODE:
3076 case CDATA_SECTION_NODE:
3077 case DOCUMENT_FRAGMENT_NODE:
3078 case DOCUMENT_NODE:
3079 case ENTITY_NODE:
3080 case NOTATION_NODE:
3081 case TEXT_NODE:
3082 case XPATH_NAMESPACE_NODE:
3083 return false;
3084 case COMMENT_NODE:
3085 case PROCESSING_INSTRUCTION_NODE:
3086 break;
3087 case DOCUMENT_TYPE_NODE:
3088 numDoctypes++;
3089 break;
3090 case ELEMENT_NODE:
3091 numElements++;
3092 break;
3093 }
3094 }
3095 } else {
3096 switch (newChild.nodeType()) {
3097 case ATTRIBUTE_NODE:
3098 case CDATA_SECTION_NODE:
3099 case DOCUMENT_FRAGMENT_NODE:
3100 case DOCUMENT_NODE:
3101 case ENTITY_NODE:
3102 case NOTATION_NODE:
3103 case TEXT_NODE:
3104 case XPATH_NAMESPACE_NODE:
3105 return false;
3106 case COMMENT_NODE:
3107 case PROCESSING_INSTRUCTION_NODE:
3108 return true;
3109 case DOCUMENT_TYPE_NODE:
3110 numDoctypes++;
3111 break;
3112 case ELEMENT_NODE:
3113 numElements++;
3114 break;
3115 }
3116 }
3117
3118 if (numElements > 1 || numDoctypes > 1)
3119 return false;
3120
3121 return true;
3122 }
3123
cloneNode(bool deep)3124 PassRefPtr<Node> Document::cloneNode(bool deep)
3125 {
3126 RefPtr<Document> clone = cloneDocumentWithoutChildren();
3127 clone->cloneDataFromDocument(*this);
3128 if (deep)
3129 cloneChildNodes(clone.get());
3130 return clone.release();
3131 }
3132
cloneDocumentWithoutChildren()3133 PassRefPtr<Document> Document::cloneDocumentWithoutChildren()
3134 {
3135 DocumentInit init(url());
3136 if (isXHTMLDocument())
3137 return createXHTML(init.withRegistrationContext(registrationContext()));
3138 return create(init);
3139 }
3140
cloneDataFromDocument(const Document & other)3141 void Document::cloneDataFromDocument(const Document& other)
3142 {
3143 setCompatibilityMode(other.compatibilityMode());
3144 setEncodingData(other.m_encodingData);
3145 setContextFeatures(other.contextFeatures());
3146 setSecurityOrigin(other.securityOrigin()->isolatedCopy());
3147 }
3148
styleSheets()3149 StyleSheetList* Document::styleSheets()
3150 {
3151 if (!m_styleSheetList)
3152 m_styleSheetList = StyleSheetList::create(this);
3153 return m_styleSheetList.get();
3154 }
3155
preferredStylesheetSet() const3156 String Document::preferredStylesheetSet() const
3157 {
3158 return m_styleEngine->preferredStylesheetSetName();
3159 }
3160
selectedStylesheetSet() const3161 String Document::selectedStylesheetSet() const
3162 {
3163 return m_styleEngine->selectedStylesheetSetName();
3164 }
3165
setSelectedStylesheetSet(const String & aString)3166 void Document::setSelectedStylesheetSet(const String& aString)
3167 {
3168 m_styleEngine->setSelectedStylesheetSetName(aString);
3169 styleResolverChanged(RecalcStyleDeferred);
3170 }
3171
evaluateMediaQueryList()3172 void Document::evaluateMediaQueryList()
3173 {
3174 if (m_mediaQueryMatcher)
3175 m_mediaQueryMatcher->styleResolverChanged();
3176 }
3177
styleResolverChanged(RecalcStyleTime updateTime,StyleResolverUpdateMode updateMode)3178 void Document::styleResolverChanged(RecalcStyleTime updateTime, StyleResolverUpdateMode updateMode)
3179 {
3180 // styleResolverChanged() can be invoked during Document destruction.
3181 // We just skip that case.
3182 if (!m_styleEngine)
3183 return;
3184
3185 StyleResolverChange change = m_styleEngine->resolverChanged(updateTime, updateMode);
3186 if (change.needsRepaint()) {
3187 // We need to manually repaint because we avoid doing all repaints in layout or style
3188 // recalc while sheets are still loading to avoid FOUC.
3189 m_pendingSheetLayout = IgnoreLayoutWithPendingSheets;
3190 renderView()->repaintViewAndCompositedLayers();
3191 }
3192
3193 if (!change.needsStyleRecalc())
3194 return;
3195
3196 m_evaluateMediaQueriesOnStyleRecalc = true;
3197 setNeedsStyleRecalc();
3198
3199 if (updateTime == RecalcStyleImmediately)
3200 updateStyleIfNeeded();
3201 }
3202
notifySeamlessChildDocumentsOfStylesheetUpdate() const3203 void Document::notifySeamlessChildDocumentsOfStylesheetUpdate() const
3204 {
3205 // If we're not in a frame yet any potential child documents won't have a StyleResolver to update.
3206 if (!frame())
3207 return;
3208
3209 // Seamless child frames are expected to notify their seamless children recursively, so we only do direct children.
3210 for (Frame* child = frame()->tree().firstChild(); child; child = child->tree().nextSibling()) {
3211 Document* childDocument = child->document();
3212 if (childDocument->shouldDisplaySeamlesslyWithParent()) {
3213 ASSERT(childDocument->seamlessParentIFrame()->document() == this);
3214 childDocument->seamlessParentUpdatedStylesheets();
3215 }
3216 }
3217 }
3218
setHoverNode(PassRefPtr<Node> newHoverNode)3219 void Document::setHoverNode(PassRefPtr<Node> newHoverNode)
3220 {
3221 m_hoverNode = newHoverNode;
3222 }
3223
setActiveElement(PassRefPtr<Element> newActiveElement)3224 void Document::setActiveElement(PassRefPtr<Element> newActiveElement)
3225 {
3226 if (!newActiveElement) {
3227 m_activeElement.clear();
3228 return;
3229 }
3230
3231 m_activeElement = newActiveElement;
3232 }
3233
removeFocusedElementOfSubtree(Node * node,bool amongChildrenOnly)3234 void Document::removeFocusedElementOfSubtree(Node* node, bool amongChildrenOnly)
3235 {
3236 if (!m_focusedElement)
3237 return;
3238
3239 // We can't be focused if we're not in the document.
3240 if (!node->inDocument())
3241 return;
3242 bool contains = node->containsIncludingShadowDOM(m_focusedElement.get());
3243 if (contains && (m_focusedElement != node || !amongChildrenOnly))
3244 setFocusedElement(0);
3245 }
3246
hoveredNodeDetached(Node * node)3247 void Document::hoveredNodeDetached(Node* node)
3248 {
3249 if (!m_hoverNode)
3250 return;
3251
3252 if (node != m_hoverNode && (!m_hoverNode->isTextNode() || node != NodeRenderingTraversal::parent(m_hoverNode.get())))
3253 return;
3254
3255 m_hoverNode = NodeRenderingTraversal::parent(node);
3256 while (m_hoverNode && !m_hoverNode->renderer())
3257 m_hoverNode = NodeRenderingTraversal::parent(m_hoverNode.get());
3258
3259 // If the mouse cursor is not visible, do not clear existing
3260 // hover effects on the ancestors of |node| and do not invoke
3261 // new hover effects on any other element.
3262 if (!page()->isCursorVisible())
3263 return;
3264
3265 if (frame())
3266 frame()->eventHandler().scheduleHoverStateUpdate();
3267 }
3268
activeChainNodeDetached(Node * node)3269 void Document::activeChainNodeDetached(Node* node)
3270 {
3271 if (!m_activeElement)
3272 return;
3273
3274 if (node != m_activeElement && (!m_activeElement->isTextNode() || node != NodeRenderingTraversal::parent(m_activeElement.get())))
3275 return;
3276
3277 Node* activeNode = NodeRenderingTraversal::parent(node);
3278 while (activeNode && activeNode->isElementNode() && !activeNode->renderer())
3279 activeNode = NodeRenderingTraversal::parent(activeNode);
3280
3281 m_activeElement = activeNode && activeNode->isElementNode() ? toElement(activeNode) : 0;
3282 }
3283
annotatedRegions() const3284 const Vector<AnnotatedRegionValue>& Document::annotatedRegions() const
3285 {
3286 return m_annotatedRegions;
3287 }
3288
setAnnotatedRegions(const Vector<AnnotatedRegionValue> & regions)3289 void Document::setAnnotatedRegions(const Vector<AnnotatedRegionValue>& regions)
3290 {
3291 m_annotatedRegions = regions;
3292 setAnnotatedRegionsDirty(false);
3293 }
3294
setFocusedElement(PassRefPtr<Element> prpNewFocusedElement,FocusDirection direction)3295 bool Document::setFocusedElement(PassRefPtr<Element> prpNewFocusedElement, FocusDirection direction)
3296 {
3297 RefPtr<Element> newFocusedElement = prpNewFocusedElement;
3298
3299 // Make sure newFocusedNode is actually in this document
3300 if (newFocusedElement && (newFocusedElement->document() != this))
3301 return true;
3302
3303 if (NodeChildRemovalTracker::isBeingRemoved(newFocusedElement.get()))
3304 return true;
3305
3306 if (m_focusedElement == newFocusedElement)
3307 return true;
3308
3309 bool focusChangeBlocked = false;
3310 RefPtr<Element> oldFocusedElement = m_focusedElement;
3311 m_focusedElement = 0;
3312
3313 // Remove focus from the existing focus node (if any)
3314 if (oldFocusedElement) {
3315 ASSERT(!oldFocusedElement->inDetach());
3316
3317 if (oldFocusedElement->active())
3318 oldFocusedElement->setActive(false);
3319
3320 oldFocusedElement->setFocus(false);
3321
3322 // Dispatch a change event for text fields or textareas that have been edited
3323 if (oldFocusedElement->wasChangedSinceLastFormControlChangeEvent())
3324 oldFocusedElement->dispatchFormControlChangeEvent();
3325
3326 // Dispatch the blur event and let the node do any other blur related activities (important for text fields)
3327 oldFocusedElement->dispatchBlurEvent(newFocusedElement.get());
3328
3329 if (m_focusedElement) {
3330 // handler shifted focus
3331 focusChangeBlocked = true;
3332 newFocusedElement = 0;
3333 }
3334
3335 oldFocusedElement->dispatchFocusOutEvent(EventTypeNames::focusout, newFocusedElement.get()); // DOM level 3 name for the bubbling blur event.
3336 // FIXME: We should remove firing DOMFocusOutEvent event when we are sure no content depends
3337 // on it, probably when <rdar://problem/8503958> is resolved.
3338 oldFocusedElement->dispatchFocusOutEvent(EventTypeNames::DOMFocusOut, newFocusedElement.get()); // DOM level 2 name for compatibility.
3339
3340 if (m_focusedElement) {
3341 // handler shifted focus
3342 focusChangeBlocked = true;
3343 newFocusedElement = 0;
3344 }
3345
3346 if (view()) {
3347 Widget* oldWidget = widgetForElement(*oldFocusedElement);
3348 if (oldWidget)
3349 oldWidget->setFocus(false);
3350 else
3351 view()->setFocus(false);
3352 }
3353 }
3354
3355 if (newFocusedElement && newFocusedElement->isFocusable()) {
3356 if (newFocusedElement->isRootEditableElement() && !acceptsEditingFocus(*newFocusedElement)) {
3357 // delegate blocks focus change
3358 focusChangeBlocked = true;
3359 goto SetFocusedElementDone;
3360 }
3361 // Set focus on the new node
3362 m_focusedElement = newFocusedElement;
3363
3364 // Dispatch the focus event and let the node do any other focus related activities (important for text fields)
3365 m_focusedElement->dispatchFocusEvent(oldFocusedElement.get(), direction);
3366
3367 if (m_focusedElement != newFocusedElement) {
3368 // handler shifted focus
3369 focusChangeBlocked = true;
3370 goto SetFocusedElementDone;
3371 }
3372
3373 m_focusedElement->dispatchFocusInEvent(EventTypeNames::focusin, oldFocusedElement.get()); // DOM level 3 bubbling focus event.
3374
3375 if (m_focusedElement != newFocusedElement) {
3376 // handler shifted focus
3377 focusChangeBlocked = true;
3378 goto SetFocusedElementDone;
3379 }
3380
3381 // FIXME: We should remove firing DOMFocusInEvent event when we are sure no content depends
3382 // on it, probably when <rdar://problem/8503958> is m.
3383 m_focusedElement->dispatchFocusInEvent(EventTypeNames::DOMFocusIn, oldFocusedElement.get()); // DOM level 2 for compatibility.
3384
3385 if (m_focusedElement != newFocusedElement) {
3386 // handler shifted focus
3387 focusChangeBlocked = true;
3388 goto SetFocusedElementDone;
3389 }
3390 m_focusedElement->setFocus(true);
3391
3392 if (m_focusedElement->isRootEditableElement())
3393 frame()->spellChecker().didBeginEditing(m_focusedElement.get());
3394
3395 // eww, I suck. set the qt focus correctly
3396 // ### find a better place in the code for this
3397 if (view()) {
3398 Widget* focusWidget = widgetForElement(*m_focusedElement);
3399 if (focusWidget) {
3400 // Make sure a widget has the right size before giving it focus.
3401 // Otherwise, we are testing edge cases of the Widget code.
3402 // Specifically, in WebCore this does not work well for text fields.
3403 updateLayout();
3404 // Re-get the widget in case updating the layout changed things.
3405 focusWidget = widgetForElement(*m_focusedElement);
3406 }
3407 if (focusWidget)
3408 focusWidget->setFocus(true);
3409 else
3410 view()->setFocus(true);
3411 }
3412 }
3413
3414 if (!focusChangeBlocked && m_focusedElement) {
3415 // Create the AXObject cache in a focus change because Chromium relies on it.
3416 if (AXObjectCache* cache = axObjectCache())
3417 cache->handleFocusedUIElementChanged(oldFocusedElement.get(), newFocusedElement.get());
3418 }
3419
3420 if (!focusChangeBlocked && page())
3421 page()->chrome().focusedNodeChanged(m_focusedElement.get());
3422
3423 SetFocusedElementDone:
3424 updateStyleIfNeeded();
3425 if (Frame* frame = this->frame())
3426 frame->selection().didChangeFocus();
3427 return !focusChangeBlocked;
3428 }
3429
setCSSTarget(Element * n)3430 void Document::setCSSTarget(Element* n)
3431 {
3432 if (m_cssTarget)
3433 m_cssTarget->didAffectSelector(AffectedSelectorTarget);
3434 m_cssTarget = n;
3435 if (n)
3436 n->didAffectSelector(AffectedSelectorTarget);
3437 }
3438
registerNodeList(LiveNodeListBase * list)3439 void Document::registerNodeList(LiveNodeListBase* list)
3440 {
3441 if (list->hasIdNameCache())
3442 m_nodeListCounts[InvalidateOnIdNameAttrChange]++;
3443 m_nodeListCounts[list->invalidationType()]++;
3444 if (list->isRootedAtDocument())
3445 m_listsInvalidatedAtDocument.add(list);
3446 }
3447
unregisterNodeList(LiveNodeListBase * list)3448 void Document::unregisterNodeList(LiveNodeListBase* list)
3449 {
3450 if (list->hasIdNameCache())
3451 m_nodeListCounts[InvalidateOnIdNameAttrChange]--;
3452 m_nodeListCounts[list->invalidationType()]--;
3453 if (list->isRootedAtDocument()) {
3454 ASSERT(m_listsInvalidatedAtDocument.contains(list));
3455 m_listsInvalidatedAtDocument.remove(list);
3456 }
3457 }
3458
attachNodeIterator(NodeIterator * ni)3459 void Document::attachNodeIterator(NodeIterator* ni)
3460 {
3461 m_nodeIterators.add(ni);
3462 }
3463
detachNodeIterator(NodeIterator * ni)3464 void Document::detachNodeIterator(NodeIterator* ni)
3465 {
3466 // The node iterator can be detached without having been attached if its root node didn't have a document
3467 // when the iterator was created, but has it now.
3468 m_nodeIterators.remove(ni);
3469 }
3470
moveNodeIteratorsToNewDocument(Node * node,Document * newDocument)3471 void Document::moveNodeIteratorsToNewDocument(Node* node, Document* newDocument)
3472 {
3473 HashSet<NodeIterator*> nodeIteratorsList = m_nodeIterators;
3474 HashSet<NodeIterator*>::const_iterator nodeIteratorsEnd = nodeIteratorsList.end();
3475 for (HashSet<NodeIterator*>::const_iterator it = nodeIteratorsList.begin(); it != nodeIteratorsEnd; ++it) {
3476 if ((*it)->root() == node) {
3477 detachNodeIterator(*it);
3478 newDocument->attachNodeIterator(*it);
3479 }
3480 }
3481 }
3482
updateRangesAfterChildrenChanged(ContainerNode * container)3483 void Document::updateRangesAfterChildrenChanged(ContainerNode* container)
3484 {
3485 if (!m_ranges.isEmpty()) {
3486 HashSet<Range*>::const_iterator end = m_ranges.end();
3487 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it)
3488 (*it)->nodeChildrenChanged(container);
3489 }
3490 }
3491
nodeChildrenWillBeRemoved(ContainerNode * container)3492 void Document::nodeChildrenWillBeRemoved(ContainerNode* container)
3493 {
3494 NoEventDispatchAssertion assertNoEventDispatch;
3495 if (!m_ranges.isEmpty()) {
3496 HashSet<Range*>::const_iterator end = m_ranges.end();
3497 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it)
3498 (*it)->nodeChildrenWillBeRemoved(container);
3499 }
3500
3501 HashSet<NodeIterator*>::const_iterator nodeIteratorsEnd = m_nodeIterators.end();
3502 for (HashSet<NodeIterator*>::const_iterator it = m_nodeIterators.begin(); it != nodeIteratorsEnd; ++it) {
3503 for (Node* n = container->firstChild(); n; n = n->nextSibling())
3504 (*it)->nodeWillBeRemoved(*n);
3505 }
3506
3507 if (Frame* frame = this->frame()) {
3508 for (Node* n = container->firstChild(); n; n = n->nextSibling()) {
3509 frame->eventHandler().nodeWillBeRemoved(*n);
3510 frame->selection().nodeWillBeRemoved(*n);
3511 frame->page()->dragCaretController().nodeWillBeRemoved(*n);
3512 }
3513 }
3514 }
3515
nodeWillBeRemoved(Node & n)3516 void Document::nodeWillBeRemoved(Node& n)
3517 {
3518 HashSet<NodeIterator*>::const_iterator nodeIteratorsEnd = m_nodeIterators.end();
3519 for (HashSet<NodeIterator*>::const_iterator it = m_nodeIterators.begin(); it != nodeIteratorsEnd; ++it)
3520 (*it)->nodeWillBeRemoved(n);
3521
3522 if (!m_ranges.isEmpty()) {
3523 HashSet<Range*>::const_iterator rangesEnd = m_ranges.end();
3524 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != rangesEnd; ++it)
3525 (*it)->nodeWillBeRemoved(n);
3526 }
3527
3528 if (Frame* frame = this->frame()) {
3529 frame->eventHandler().nodeWillBeRemoved(n);
3530 frame->selection().nodeWillBeRemoved(n);
3531 frame->page()->dragCaretController().nodeWillBeRemoved(n);
3532 }
3533 }
3534
didInsertText(Node * text,unsigned offset,unsigned length)3535 void Document::didInsertText(Node* text, unsigned offset, unsigned length)
3536 {
3537 if (!m_ranges.isEmpty()) {
3538 HashSet<Range*>::const_iterator end = m_ranges.end();
3539 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it)
3540 (*it)->didInsertText(text, offset, length);
3541 }
3542
3543 // Update the markers for spelling and grammar checking.
3544 m_markers->shiftMarkers(text, offset, length);
3545 }
3546
didRemoveText(Node * text,unsigned offset,unsigned length)3547 void Document::didRemoveText(Node* text, unsigned offset, unsigned length)
3548 {
3549 if (!m_ranges.isEmpty()) {
3550 HashSet<Range*>::const_iterator end = m_ranges.end();
3551 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it)
3552 (*it)->didRemoveText(text, offset, length);
3553 }
3554
3555 // Update the markers for spelling and grammar checking.
3556 m_markers->removeMarkers(text, offset, length);
3557 m_markers->shiftMarkers(text, offset + length, 0 - length);
3558 }
3559
didMergeTextNodes(Text * oldNode,unsigned offset)3560 void Document::didMergeTextNodes(Text* oldNode, unsigned offset)
3561 {
3562 if (!m_ranges.isEmpty()) {
3563 NodeWithIndex oldNodeWithIndex(oldNode);
3564 HashSet<Range*>::const_iterator end = m_ranges.end();
3565 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it)
3566 (*it)->didMergeTextNodes(oldNodeWithIndex, offset);
3567 }
3568
3569 if (m_frame)
3570 m_frame->selection().didMergeTextNodes(*oldNode, offset);
3571
3572 // FIXME: This should update markers for spelling and grammar checking.
3573 }
3574
didSplitTextNode(Text * oldNode)3575 void Document::didSplitTextNode(Text* oldNode)
3576 {
3577 if (!m_ranges.isEmpty()) {
3578 HashSet<Range*>::const_iterator end = m_ranges.end();
3579 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it)
3580 (*it)->didSplitTextNode(oldNode);
3581 }
3582
3583 if (m_frame)
3584 m_frame->selection().didSplitTextNode(*oldNode);
3585
3586 // FIXME: This should update markers for spelling and grammar checking.
3587 }
3588
setWindowAttributeEventListener(const AtomicString & eventType,PassRefPtr<EventListener> listener,DOMWrapperWorld * isolatedWorld)3589 void Document::setWindowAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, DOMWrapperWorld* isolatedWorld)
3590 {
3591 DOMWindow* domWindow = this->domWindow();
3592 if (!domWindow)
3593 return;
3594 domWindow->setAttributeEventListener(eventType, listener, isolatedWorld);
3595 }
3596
getWindowAttributeEventListener(const AtomicString & eventType,DOMWrapperWorld * isolatedWorld)3597 EventListener* Document::getWindowAttributeEventListener(const AtomicString& eventType, DOMWrapperWorld* isolatedWorld)
3598 {
3599 DOMWindow* domWindow = this->domWindow();
3600 if (!domWindow)
3601 return 0;
3602 return domWindow->getAttributeEventListener(eventType, isolatedWorld);
3603 }
3604
eventQueue() const3605 EventQueue* Document::eventQueue() const
3606 {
3607 if (!m_domWindow)
3608 return 0;
3609 return m_domWindow->eventQueue();
3610 }
3611
enqueueAnimationFrameEvent(PassRefPtr<Event> event)3612 void Document::enqueueAnimationFrameEvent(PassRefPtr<Event> event)
3613 {
3614 ensureScriptedAnimationController().enqueueEvent(event);
3615 }
3616
enqueueScrollEventForNode(Node * target)3617 void Document::enqueueScrollEventForNode(Node* target)
3618 {
3619 // Per the W3C CSSOM View Module only scroll events fired at the document should bubble.
3620 RefPtr<Event> scrollEvent = target->isDocumentNode() ? Event::createBubble(EventTypeNames::scroll) : Event::create(EventTypeNames::scroll);
3621 scrollEvent->setTarget(target);
3622 ensureScriptedAnimationController().enqueuePerFrameEvent(scrollEvent.release());
3623 }
3624
enqueueResizeEvent()3625 void Document::enqueueResizeEvent()
3626 {
3627 RefPtr<Event> event = Event::create(EventTypeNames::resize);
3628 event->setTarget(domWindow());
3629 ensureScriptedAnimationController().enqueuePerFrameEvent(event.release());
3630 }
3631
createEvent(const String & eventType,ExceptionState & exceptionState)3632 PassRefPtr<Event> Document::createEvent(const String& eventType, ExceptionState& exceptionState)
3633 {
3634 RefPtr<Event> event = EventFactory::create(eventType);
3635 if (event)
3636 return event.release();
3637
3638 exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
3639 return 0;
3640 }
3641
addMutationEventListenerTypeIfEnabled(ListenerType listenerType)3642 void Document::addMutationEventListenerTypeIfEnabled(ListenerType listenerType)
3643 {
3644 if (ContextFeatures::mutationEventsEnabled(this))
3645 addListenerType(listenerType);
3646 }
3647
addListenerTypeIfNeeded(const AtomicString & eventType)3648 void Document::addListenerTypeIfNeeded(const AtomicString& eventType)
3649 {
3650 if (eventType == EventTypeNames::DOMSubtreeModified) {
3651 UseCounter::count(*this, UseCounter::DOMSubtreeModifiedEvent);
3652 addMutationEventListenerTypeIfEnabled(DOMSUBTREEMODIFIED_LISTENER);
3653 } else if (eventType == EventTypeNames::DOMNodeInserted) {
3654 UseCounter::count(*this, UseCounter::DOMNodeInsertedEvent);
3655 addMutationEventListenerTypeIfEnabled(DOMNODEINSERTED_LISTENER);
3656 } else if (eventType == EventTypeNames::DOMNodeRemoved) {
3657 UseCounter::count(*this, UseCounter::DOMNodeRemovedEvent);
3658 addMutationEventListenerTypeIfEnabled(DOMNODEREMOVED_LISTENER);
3659 } else if (eventType == EventTypeNames::DOMNodeRemovedFromDocument) {
3660 UseCounter::count(*this, UseCounter::DOMNodeRemovedFromDocumentEvent);
3661 addMutationEventListenerTypeIfEnabled(DOMNODEREMOVEDFROMDOCUMENT_LISTENER);
3662 } else if (eventType == EventTypeNames::DOMNodeInsertedIntoDocument) {
3663 UseCounter::count(*this, UseCounter::DOMNodeInsertedIntoDocumentEvent);
3664 addMutationEventListenerTypeIfEnabled(DOMNODEINSERTEDINTODOCUMENT_LISTENER);
3665 } else if (eventType == EventTypeNames::DOMCharacterDataModified) {
3666 UseCounter::count(*this, UseCounter::DOMCharacterDataModifiedEvent);
3667 addMutationEventListenerTypeIfEnabled(DOMCHARACTERDATAMODIFIED_LISTENER);
3668 } else if (eventType == EventTypeNames::overflowchanged) {
3669 UseCounter::count(*this, UseCounter::OverflowChangedEvent);
3670 addListenerType(OVERFLOWCHANGED_LISTENER);
3671 } else if (eventType == EventTypeNames::webkitAnimationStart || (RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled() && eventType == EventTypeNames::animationstart)) {
3672 addListenerType(ANIMATIONSTART_LISTENER);
3673 } else if (eventType == EventTypeNames::webkitAnimationEnd || (RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled() && eventType == EventTypeNames::animationend)) {
3674 addListenerType(ANIMATIONEND_LISTENER);
3675 } else if (eventType == EventTypeNames::webkitAnimationIteration || (RuntimeEnabledFeatures::cssAnimationUnprefixedEnabled() && eventType == EventTypeNames::animationiteration)) {
3676 addListenerType(ANIMATIONITERATION_LISTENER);
3677 } else if (eventType == EventTypeNames::webkitTransitionEnd || eventType == EventTypeNames::transitionend) {
3678 addListenerType(TRANSITIONEND_LISTENER);
3679 } else if (eventType == EventTypeNames::beforeload) {
3680 if (m_frame && m_frame->script().shouldBypassMainWorldContentSecurityPolicy()) {
3681 UseCounter::count(*this, UseCounter::BeforeLoadEventInIsolatedWorld);
3682 } else {
3683 UseCounter::count(*this, UseCounter::BeforeLoadEvent);
3684 }
3685 addListenerType(BEFORELOAD_LISTENER);
3686 } else if (eventType == EventTypeNames::scroll) {
3687 addListenerType(SCROLL_LISTENER);
3688 } else if (eventType == EventTypeNames::DOMFocusIn || eventType == EventTypeNames::DOMFocusOut) {
3689 UseCounter::count(*this, UseCounter::DOMFocusInOutEvent);
3690 }
3691 }
3692
getOverrideStyle(Element *,const String &)3693 CSSStyleDeclaration* Document::getOverrideStyle(Element*, const String&)
3694 {
3695 return 0;
3696 }
3697
ownerElement() const3698 HTMLFrameOwnerElement* Document::ownerElement() const
3699 {
3700 if (!frame())
3701 return 0;
3702 return frame()->ownerElement();
3703 }
3704
cookie(ExceptionState & exceptionState) const3705 String Document::cookie(ExceptionState& exceptionState) const
3706 {
3707 if (settings() && !settings()->cookieEnabled())
3708 return String();
3709
3710 // FIXME: The HTML5 DOM spec states that this attribute can raise an
3711 // InvalidStateError exception on getting if the Document has no
3712 // browsing context.
3713
3714 if (!securityOrigin()->canAccessCookies()) {
3715 if (isSandboxed(SandboxOrigin))
3716 exceptionState.throwSecurityError("The document is sandboxed and lacks the 'allow-same-origin' flag.");
3717 else if (url().protocolIs("data"))
3718 exceptionState.throwSecurityError("Cookies are disabled inside 'data:' URLs.");
3719 else
3720 exceptionState.throwSecurityError("Access is denied for this document.");
3721 return String();
3722 }
3723
3724 KURL cookieURL = this->cookieURL();
3725 if (cookieURL.isEmpty())
3726 return String();
3727
3728 return cookies(this, cookieURL);
3729 }
3730
setCookie(const String & value,ExceptionState & exceptionState)3731 void Document::setCookie(const String& value, ExceptionState& exceptionState)
3732 {
3733 if (settings() && !settings()->cookieEnabled())
3734 return;
3735
3736 // FIXME: The HTML5 DOM spec states that this attribute can raise an
3737 // InvalidStateError exception on setting if the Document has no
3738 // browsing context.
3739
3740 if (!securityOrigin()->canAccessCookies()) {
3741 if (isSandboxed(SandboxOrigin))
3742 exceptionState.throwSecurityError("The document is sandboxed and lacks the 'allow-same-origin' flag.");
3743 else if (url().protocolIs("data"))
3744 exceptionState.throwSecurityError("Cookies are disabled inside 'data:' URLs.");
3745 else
3746 exceptionState.throwSecurityError("Access is denied for this document.");
3747 return;
3748 }
3749
3750 KURL cookieURL = this->cookieURL();
3751 if (cookieURL.isEmpty())
3752 return;
3753
3754 setCookies(this, cookieURL, value);
3755 }
3756
referrer() const3757 const AtomicString& Document::referrer() const
3758 {
3759 if (loader())
3760 return loader()->request().httpReferrer();
3761 return nullAtom;
3762 }
3763
domain() const3764 String Document::domain() const
3765 {
3766 return securityOrigin()->domain();
3767 }
3768
setDomain(const String & newDomain,ExceptionState & exceptionState)3769 void Document::setDomain(const String& newDomain, ExceptionState& exceptionState)
3770 {
3771 if (isSandboxed(SandboxDocumentDomain)) {
3772 exceptionState.throwSecurityError("Assignment is forbidden for sandboxed iframes.");
3773 return;
3774 }
3775
3776 if (SchemeRegistry::isDomainRelaxationForbiddenForURLScheme(securityOrigin()->protocol())) {
3777 exceptionState.throwSecurityError("Assignment is forbidden for the '" + securityOrigin()->protocol() + "' scheme.");
3778 return;
3779 }
3780
3781 if (newDomain.isEmpty()) {
3782 exceptionState.throwSecurityError("'" + newDomain + "' is an empty domain.");
3783 return;
3784 }
3785
3786 OriginAccessEntry::IPAddressSetting ipAddressSetting = settings() && settings()->treatIPAddressAsDomain() ? OriginAccessEntry::TreatIPAddressAsDomain : OriginAccessEntry::TreatIPAddressAsIPAddress;
3787 OriginAccessEntry accessEntry(securityOrigin()->protocol(), newDomain, OriginAccessEntry::AllowSubdomains, ipAddressSetting);
3788 OriginAccessEntry::MatchResult result = accessEntry.matchesOrigin(*securityOrigin());
3789 if (result == OriginAccessEntry::DoesNotMatchOrigin) {
3790 exceptionState.throwSecurityError("'" + newDomain + "' is not a suffix of '" + domain() + "'.");
3791 return;
3792 }
3793
3794 if (result == OriginAccessEntry::MatchesOriginButIsPublicSuffix) {
3795 exceptionState.throwSecurityError("'" + newDomain + "' is a top-level domain.");
3796 return;
3797 }
3798
3799 securityOrigin()->setDomainFromDOM(newDomain);
3800 if (m_frame)
3801 m_frame->script().updateSecurityOrigin();
3802 }
3803
3804 // http://www.whatwg.org/specs/web-apps/current-work/#dom-document-lastmodified
lastModified() const3805 String Document::lastModified() const
3806 {
3807 DateComponents date;
3808 bool foundDate = false;
3809 if (m_frame) {
3810 if (DocumentLoader* documentLoader = loader()) {
3811 const AtomicString& httpLastModified = documentLoader->response().httpHeaderField("Last-Modified");
3812 if (!httpLastModified.isEmpty()) {
3813 date.setMillisecondsSinceEpochForDateTime(parseDate(httpLastModified));
3814 foundDate = true;
3815 }
3816 }
3817 }
3818 // FIXME: If this document came from the file system, the HTML5
3819 // specificiation tells us to read the last modification date from the file
3820 // system.
3821 if (!foundDate)
3822 date.setMillisecondsSinceEpochForDateTime(currentTimeMS());
3823 return String::format("%02d/%02d/%04d %02d:%02d:%02d", date.month() + 1, date.monthDay(), date.fullYear(), date.hour(), date.minute(), date.second());
3824 }
3825
firstPartyForCookies() const3826 const KURL& Document::firstPartyForCookies() const
3827 {
3828 return topDocument()->url();
3829 }
3830
isValidNameNonASCII(const LChar * characters,unsigned length)3831 static bool isValidNameNonASCII(const LChar* characters, unsigned length)
3832 {
3833 if (!isValidNameStart(characters[0]))
3834 return false;
3835
3836 for (unsigned i = 1; i < length; ++i) {
3837 if (!isValidNamePart(characters[i]))
3838 return false;
3839 }
3840
3841 return true;
3842 }
3843
isValidNameNonASCII(const UChar * characters,unsigned length)3844 static bool isValidNameNonASCII(const UChar* characters, unsigned length)
3845 {
3846 unsigned i = 0;
3847
3848 UChar32 c;
3849 U16_NEXT(characters, i, length, c)
3850 if (!isValidNameStart(c))
3851 return false;
3852
3853 while (i < length) {
3854 U16_NEXT(characters, i, length, c)
3855 if (!isValidNamePart(c))
3856 return false;
3857 }
3858
3859 return true;
3860 }
3861
3862 template<typename CharType>
isValidNameASCII(const CharType * characters,unsigned length)3863 static inline bool isValidNameASCII(const CharType* characters, unsigned length)
3864 {
3865 CharType c = characters[0];
3866 if (!(isASCIIAlpha(c) || c == ':' || c == '_'))
3867 return false;
3868
3869 for (unsigned i = 1; i < length; ++i) {
3870 c = characters[i];
3871 if (!(isASCIIAlphanumeric(c) || c == ':' || c == '_' || c == '-' || c == '.'))
3872 return false;
3873 }
3874
3875 return true;
3876 }
3877
isValidName(const String & name)3878 bool Document::isValidName(const String& name)
3879 {
3880 unsigned length = name.length();
3881 if (!length)
3882 return false;
3883
3884 if (name.is8Bit()) {
3885 const LChar* characters = name.characters8();
3886
3887 if (isValidNameASCII(characters, length))
3888 return true;
3889
3890 return isValidNameNonASCII(characters, length);
3891 }
3892
3893 const UChar* characters = name.characters16();
3894
3895 if (isValidNameASCII(characters, length))
3896 return true;
3897
3898 return isValidNameNonASCII(characters, length);
3899 }
3900
3901 template<typename CharType>
parseQualifiedNameInternal(const AtomicString & qualifiedName,const CharType * characters,unsigned length,AtomicString & prefix,AtomicString & localName,ExceptionState & exceptionState)3902 static bool parseQualifiedNameInternal(const AtomicString& qualifiedName, const CharType* characters, unsigned length, AtomicString& prefix, AtomicString& localName, ExceptionState& exceptionState)
3903 {
3904 bool nameStart = true;
3905 bool sawColon = false;
3906 int colonPos = 0;
3907
3908 for (unsigned i = 0; i < length;) {
3909 UChar32 c;
3910 U16_NEXT(characters, i, length, c)
3911 if (c == ':') {
3912 if (sawColon) {
3913 exceptionState.throwUninformativeAndGenericDOMException(NamespaceError);
3914 return false; // multiple colons: not allowed
3915 }
3916 nameStart = true;
3917 sawColon = true;
3918 colonPos = i - 1;
3919 } else if (nameStart) {
3920 if (!isValidNameStart(c)) {
3921 exceptionState.throwUninformativeAndGenericDOMException(InvalidCharacterError);
3922 return false;
3923 }
3924 nameStart = false;
3925 } else {
3926 if (!isValidNamePart(c)) {
3927 exceptionState.throwUninformativeAndGenericDOMException(InvalidCharacterError);
3928 return false;
3929 }
3930 }
3931 }
3932
3933 if (!sawColon) {
3934 prefix = nullAtom;
3935 localName = qualifiedName;
3936 } else {
3937 prefix = AtomicString(characters, colonPos);
3938 if (prefix.isEmpty()) {
3939 exceptionState.throwUninformativeAndGenericDOMException(NamespaceError);
3940 return false;
3941 }
3942 int prefixStart = colonPos + 1;
3943 localName = AtomicString(characters + prefixStart, length - prefixStart);
3944 }
3945
3946 if (localName.isEmpty()) {
3947 exceptionState.throwUninformativeAndGenericDOMException(NamespaceError);
3948 return false;
3949 }
3950
3951 return true;
3952 }
3953
parseQualifiedName(const AtomicString & qualifiedName,AtomicString & prefix,AtomicString & localName,ExceptionState & exceptionState)3954 bool Document::parseQualifiedName(const AtomicString& qualifiedName, AtomicString& prefix, AtomicString& localName, ExceptionState& exceptionState)
3955 {
3956 unsigned length = qualifiedName.length();
3957
3958 if (!length) {
3959 exceptionState.throwUninformativeAndGenericDOMException(InvalidCharacterError);
3960 return false;
3961 }
3962
3963 if (qualifiedName.is8Bit())
3964 return parseQualifiedNameInternal(qualifiedName, qualifiedName.characters8(), length, prefix, localName, exceptionState);
3965 return parseQualifiedNameInternal(qualifiedName, qualifiedName.characters16(), length, prefix, localName, exceptionState);
3966 }
3967
setEncodingData(const DocumentEncodingData & newData)3968 void Document::setEncodingData(const DocumentEncodingData& newData)
3969 {
3970 // It's possible for the encoding of the document to change while we're decoding
3971 // data. That can only occur while we're processing the <head> portion of the
3972 // document. There isn't much user-visible content in the <head>, but there is
3973 // the <title> element. This function detects that situation and re-decodes the
3974 // document's title so that the user doesn't see an incorrectly decoded title
3975 // in the title bar.
3976 if (m_titleElement
3977 && encoding() != newData.encoding
3978 && !m_titleElement->firstElementChild()
3979 && encoding() == Latin1Encoding()
3980 && m_titleElement->textContent().containsOnlyLatin1()) {
3981
3982 CString originalBytes = m_titleElement->textContent().latin1();
3983 OwnPtr<TextCodec> codec = newTextCodec(newData.encoding);
3984 String correctlyDecodedTitle = codec->decode(originalBytes.data(), originalBytes.length(), true);
3985 m_titleElement->setTextContent(correctlyDecodedTitle);
3986 }
3987
3988 m_encodingData = newData;
3989 }
3990
completeURL(const String & url,const KURL & baseURLOverride) const3991 KURL Document::completeURL(const String& url, const KURL& baseURLOverride) const
3992 {
3993 // Always return a null URL when passed a null string.
3994 // FIXME: Should we change the KURL constructor to have this behavior?
3995 // See also [CSS]StyleSheet::completeURL(const String&)
3996 if (url.isNull())
3997 return KURL();
3998 const KURL* baseURLFromParent = 0;
3999 if (baseURLOverride.isEmpty() || baseURLOverride == blankURL()) {
4000 if (Document* parent = parentDocument())
4001 baseURLFromParent = &parent->baseURL();
4002 }
4003 const KURL& baseURL = baseURLFromParent ? *baseURLFromParent : baseURLOverride;
4004 if (!encoding().isValid())
4005 return KURL(baseURL, url);
4006 return KURL(baseURL, url, encoding());
4007 }
4008
completeURL(const String & url) const4009 KURL Document::completeURL(const String& url) const
4010 {
4011 return completeURL(url, m_baseURL);
4012 }
4013
4014 // Support for Javascript execCommand, and related methods
4015
command(Document * document,const String & commandName,bool userInterface=false)4016 static Editor::Command command(Document* document, const String& commandName, bool userInterface = false)
4017 {
4018 Frame* frame = document->frame();
4019 if (!frame || frame->document() != document)
4020 return Editor::Command();
4021
4022 document->updateStyleIfNeeded();
4023 return frame->editor().command(commandName, userInterface ? CommandFromDOMWithUserInterface : CommandFromDOM);
4024 }
4025
execCommand(const String & commandName,bool userInterface,const String & value)4026 bool Document::execCommand(const String& commandName, bool userInterface, const String& value)
4027 {
4028 return command(this, commandName, userInterface).execute(value);
4029 }
4030
queryCommandEnabled(const String & commandName)4031 bool Document::queryCommandEnabled(const String& commandName)
4032 {
4033 return command(this, commandName).isEnabled();
4034 }
4035
queryCommandIndeterm(const String & commandName)4036 bool Document::queryCommandIndeterm(const String& commandName)
4037 {
4038 return command(this, commandName).state() == MixedTriState;
4039 }
4040
queryCommandState(const String & commandName)4041 bool Document::queryCommandState(const String& commandName)
4042 {
4043 return command(this, commandName).state() == TrueTriState;
4044 }
4045
queryCommandSupported(const String & commandName)4046 bool Document::queryCommandSupported(const String& commandName)
4047 {
4048 return command(this, commandName).isSupported();
4049 }
4050
queryCommandValue(const String & commandName)4051 String Document::queryCommandValue(const String& commandName)
4052 {
4053 return command(this, commandName).value();
4054 }
4055
openSearchDescriptionURL()4056 KURL Document::openSearchDescriptionURL()
4057 {
4058 static const char openSearchMIMEType[] = "application/opensearchdescription+xml";
4059 static const char openSearchRelation[] = "search";
4060
4061 // FIXME: Why do only top-level frames have openSearchDescriptionURLs?
4062 if (!frame() || frame()->tree().parent())
4063 return KURL();
4064
4065 // FIXME: Why do we need to wait for FrameStateComplete?
4066 if (frame()->loader().state() != FrameStateComplete)
4067 return KURL();
4068
4069 if (!head())
4070 return KURL();
4071
4072 RefPtr<HTMLCollection> children = head()->children();
4073 for (unsigned i = 0; Node* child = children->item(i); i++) {
4074 if (!child->hasTagName(linkTag))
4075 continue;
4076 HTMLLinkElement* linkElement = toHTMLLinkElement(child);
4077 if (!equalIgnoringCase(linkElement->type(), openSearchMIMEType) || !equalIgnoringCase(linkElement->rel(), openSearchRelation))
4078 continue;
4079 if (linkElement->href().isEmpty())
4080 continue;
4081 return linkElement->href();
4082 }
4083
4084 return KURL();
4085 }
4086
pushCurrentScript(PassRefPtr<HTMLScriptElement> newCurrentScript)4087 void Document::pushCurrentScript(PassRefPtr<HTMLScriptElement> newCurrentScript)
4088 {
4089 ASSERT(newCurrentScript);
4090 m_currentScriptStack.append(newCurrentScript);
4091 }
4092
popCurrentScript()4093 void Document::popCurrentScript()
4094 {
4095 ASSERT(!m_currentScriptStack.isEmpty());
4096 m_currentScriptStack.removeLast();
4097 }
4098
applyXSLTransform(ProcessingInstruction * pi)4099 void Document::applyXSLTransform(ProcessingInstruction* pi)
4100 {
4101 ASSERT(!pi->isLoading());
4102 UseCounter::count(*this, UseCounter::XSLProcessingInstruction);
4103 RefPtr<XSLTProcessor> processor = XSLTProcessor::create();
4104 processor->setXSLStyleSheet(toXSLStyleSheet(pi->sheet()));
4105 String resultMIMEType;
4106 String newSource;
4107 String resultEncoding;
4108 if (!processor->transformToString(this, resultMIMEType, newSource, resultEncoding))
4109 return;
4110 // FIXME: If the transform failed we should probably report an error (like Mozilla does).
4111 Frame* ownerFrame = frame();
4112 processor->createDocumentFromSource(newSource, resultEncoding, resultMIMEType, this, ownerFrame);
4113 InspectorInstrumentation::frameDocumentUpdated(ownerFrame);
4114 }
4115
setTransformSource(PassOwnPtr<TransformSource> source)4116 void Document::setTransformSource(PassOwnPtr<TransformSource> source)
4117 {
4118 m_transformSource = source;
4119 }
4120
setDesignMode(InheritedBool value)4121 void Document::setDesignMode(InheritedBool value)
4122 {
4123 m_designMode = value;
4124 for (Frame* frame = m_frame; frame && frame->document(); frame = frame->tree().traverseNext(m_frame))
4125 frame->document()->setNeedsStyleRecalc();
4126 }
4127
getDesignMode() const4128 Document::InheritedBool Document::getDesignMode() const
4129 {
4130 return m_designMode;
4131 }
4132
inDesignMode() const4133 bool Document::inDesignMode() const
4134 {
4135 for (const Document* d = this; d; d = d->parentDocument()) {
4136 if (d->m_designMode != inherit)
4137 return d->m_designMode;
4138 }
4139 return false;
4140 }
4141
parentDocument() const4142 Document* Document::parentDocument() const
4143 {
4144 if (!m_frame)
4145 return 0;
4146 Frame* parent = m_frame->tree().parent();
4147 if (!parent)
4148 return 0;
4149 return parent->document();
4150 }
4151
topDocument() const4152 Document* Document::topDocument() const
4153 {
4154 Document* doc = const_cast<Document*>(this);
4155 Element* element;
4156 while ((element = doc->ownerElement()))
4157 doc = &element->document();
4158
4159 return doc;
4160 }
4161
contextDocument()4162 WeakPtr<Document> Document::contextDocument()
4163 {
4164 if (m_contextDocument)
4165 return m_contextDocument;
4166 if (m_frame)
4167 return m_weakFactory.createWeakPtr();
4168 return WeakPtr<Document>(0);
4169 }
4170
createAttribute(const AtomicString & name,ExceptionState & exceptionState)4171 PassRefPtr<Attr> Document::createAttribute(const AtomicString& name, ExceptionState& exceptionState)
4172 {
4173 return createAttributeNS(nullAtom, name, exceptionState, true);
4174 }
4175
createAttributeNS(const AtomicString & namespaceURI,const AtomicString & qualifiedName,ExceptionState & exceptionState,bool shouldIgnoreNamespaceChecks)4176 PassRefPtr<Attr> Document::createAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionState& exceptionState, bool shouldIgnoreNamespaceChecks)
4177 {
4178 AtomicString prefix, localName;
4179 if (!parseQualifiedName(qualifiedName, prefix, localName, exceptionState))
4180 return 0;
4181
4182 QualifiedName qName(prefix, localName, namespaceURI);
4183
4184 if (!shouldIgnoreNamespaceChecks && !hasValidNamespaceForAttributes(qName)) {
4185 exceptionState.throwUninformativeAndGenericDOMException(NamespaceError);
4186 return 0;
4187 }
4188
4189 return Attr::create(*this, qName, emptyString());
4190 }
4191
svgExtensions()4192 const SVGDocumentExtensions* Document::svgExtensions()
4193 {
4194 return m_svgExtensions.get();
4195 }
4196
accessSVGExtensions()4197 SVGDocumentExtensions* Document::accessSVGExtensions()
4198 {
4199 if (!m_svgExtensions)
4200 m_svgExtensions = adoptPtr(new SVGDocumentExtensions(this));
4201 return m_svgExtensions.get();
4202 }
4203
hasSVGRootNode() const4204 bool Document::hasSVGRootNode() const
4205 {
4206 return documentElement() && documentElement()->hasTagName(SVGNames::svgTag);
4207 }
4208
ensureCachedCollection(CollectionType type)4209 PassRefPtr<HTMLCollection> Document::ensureCachedCollection(CollectionType type)
4210 {
4211 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLCollection>(this, type);
4212 }
4213
images()4214 PassRefPtr<HTMLCollection> Document::images()
4215 {
4216 return ensureCachedCollection(DocImages);
4217 }
4218
applets()4219 PassRefPtr<HTMLCollection> Document::applets()
4220 {
4221 return ensureCachedCollection(DocApplets);
4222 }
4223
embeds()4224 PassRefPtr<HTMLCollection> Document::embeds()
4225 {
4226 return ensureCachedCollection(DocEmbeds);
4227 }
4228
scripts()4229 PassRefPtr<HTMLCollection> Document::scripts()
4230 {
4231 return ensureCachedCollection(DocScripts);
4232 }
4233
links()4234 PassRefPtr<HTMLCollection> Document::links()
4235 {
4236 return ensureCachedCollection(DocLinks);
4237 }
4238
forms()4239 PassRefPtr<HTMLCollection> Document::forms()
4240 {
4241 return ensureCachedCollection(DocForms);
4242 }
4243
anchors()4244 PassRefPtr<HTMLCollection> Document::anchors()
4245 {
4246 return ensureCachedCollection(DocAnchors);
4247 }
4248
allForBinding()4249 PassRefPtr<HTMLCollection> Document::allForBinding()
4250 {
4251 UseCounter::count(*this, UseCounter::DocumentAll);
4252 return all();
4253 }
4254
all()4255 PassRefPtr<HTMLCollection> Document::all()
4256 {
4257 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLAllCollection>(this, DocAll);
4258 }
4259
windowNamedItems(const AtomicString & name)4260 PassRefPtr<HTMLCollection> Document::windowNamedItems(const AtomicString& name)
4261 {
4262 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLNameCollection>(this, WindowNamedItems, name);
4263 }
4264
documentNamedItems(const AtomicString & name)4265 PassRefPtr<HTMLCollection> Document::documentNamedItems(const AtomicString& name)
4266 {
4267 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLNameCollection>(this, DocumentNamedItems, name);
4268 }
4269
finishedParsing()4270 void Document::finishedParsing()
4271 {
4272 ASSERT(!scriptableDocumentParser() || !m_parser->isParsing());
4273 ASSERT(!scriptableDocumentParser() || m_readyState != Loading);
4274 setParsing(false);
4275 if (!m_documentTiming.domContentLoadedEventStart)
4276 m_documentTiming.domContentLoadedEventStart = monotonicallyIncreasingTime();
4277 dispatchEvent(Event::createBubble(EventTypeNames::DOMContentLoaded));
4278 if (!m_documentTiming.domContentLoadedEventEnd)
4279 m_documentTiming.domContentLoadedEventEnd = monotonicallyIncreasingTime();
4280
4281 // The loader's finishedParsing() method may invoke script that causes this object to
4282 // be dereferenced (when this document is in an iframe and the onload causes the iframe's src to change).
4283 // Keep it alive until we are done.
4284 RefPtr<Document> protect(this);
4285
4286 if (RefPtr<Frame> f = frame()) {
4287 // FrameLoader::finishedParsing() might end up calling Document::implicitClose() if all
4288 // resource loads are complete. HTMLObjectElements can start loading their resources from
4289 // post attach callbacks triggered by recalcStyle(). This means if we parse out an <object>
4290 // tag and then reach the end of the document without updating styles, we might not have yet
4291 // started the resource load and might fire the window load event too early. To avoid this
4292 // we force the styles to be up to date before calling FrameLoader::finishedParsing().
4293 // See https://bugs.webkit.org/show_bug.cgi?id=36864 starting around comment 35.
4294 updateStyleIfNeeded();
4295
4296 f->loader().finishedParsing();
4297
4298 InspectorInstrumentation::domContentLoadedEventFired(f.get());
4299 }
4300
4301 // Schedule dropping of the DocumentSharedObjectPool. We keep it alive for a while after parsing finishes
4302 // so that dynamically inserted content can also benefit from sharing optimizations.
4303 // Note that we don't refresh the timer on pool access since that could lead to huge caches being kept
4304 // alive indefinitely by something innocuous like JS setting .innerHTML repeatedly on a timer.
4305 static const int timeToKeepSharedObjectPoolAliveAfterParsingFinishedInSeconds = 10;
4306 m_sharedObjectPoolClearTimer.startOneShot(timeToKeepSharedObjectPoolAliveAfterParsingFinishedInSeconds);
4307
4308 // Parser should have picked up all preloads by now
4309 m_fetcher->clearPreloads();
4310
4311 if (m_import)
4312 m_import->didFinishParsing();
4313 }
4314
sharedObjectPoolClearTimerFired(Timer<Document> *)4315 void Document::sharedObjectPoolClearTimerFired(Timer<Document>*)
4316 {
4317 m_sharedObjectPool.clear();
4318 }
4319
iconURLs(int iconTypesMask)4320 Vector<IconURL> Document::iconURLs(int iconTypesMask)
4321 {
4322 IconURL firstFavicon;
4323 IconURL firstTouchIcon;
4324 IconURL firstTouchPrecomposedIcon;
4325 Vector<IconURL> secondaryIcons;
4326
4327 // Start from the last child node so that icons seen later take precedence as required by the spec.
4328 RefPtr<HTMLCollection> children = head() ? head()->children() : 0;
4329 unsigned length = children ? children->length() : 0;
4330 for (unsigned i = 0; i < length; i++) {
4331 Node* child = children->item(i);
4332 if (!child->hasTagName(linkTag))
4333 continue;
4334 HTMLLinkElement* linkElement = toHTMLLinkElement(child);
4335 if (!(linkElement->iconType() & iconTypesMask))
4336 continue;
4337 if (linkElement->href().isEmpty())
4338 continue;
4339 #if !ENABLE(TOUCH_ICON_LOADING)
4340 if (linkElement->iconType() != Favicon)
4341 continue;
4342 #endif
4343
4344 IconURL newURL(linkElement->href(), linkElement->iconSizes(), linkElement->type(), linkElement->iconType());
4345 if (linkElement->iconType() == Favicon) {
4346 if (firstFavicon.m_iconType != InvalidIcon)
4347 secondaryIcons.append(firstFavicon);
4348 firstFavicon = newURL;
4349 } else if (linkElement->iconType() == TouchIcon) {
4350 if (firstTouchIcon.m_iconType != InvalidIcon)
4351 secondaryIcons.append(firstTouchIcon);
4352 firstTouchIcon = newURL;
4353 } else if (linkElement->iconType() == TouchPrecomposedIcon) {
4354 if (firstTouchPrecomposedIcon.m_iconType != InvalidIcon)
4355 secondaryIcons.append(firstTouchPrecomposedIcon);
4356 firstTouchPrecomposedIcon = newURL;
4357 } else {
4358 ASSERT_NOT_REACHED();
4359 }
4360 }
4361
4362 Vector<IconURL> iconURLs;
4363 if (firstFavicon.m_iconType != InvalidIcon)
4364 iconURLs.append(firstFavicon);
4365 else if (m_url.protocolIsInHTTPFamily() && iconTypesMask & Favicon)
4366 iconURLs.append(IconURL::defaultFavicon(m_url));
4367
4368 if (firstTouchIcon.m_iconType != InvalidIcon)
4369 iconURLs.append(firstTouchIcon);
4370 if (firstTouchPrecomposedIcon.m_iconType != InvalidIcon)
4371 iconURLs.append(firstTouchPrecomposedIcon);
4372 for (int i = secondaryIcons.size() - 1; i >= 0; --i)
4373 iconURLs.append(secondaryIcons[i]);
4374 return iconURLs;
4375 }
4376
setUseSecureKeyboardEntryWhenActive(bool usesSecureKeyboard)4377 void Document::setUseSecureKeyboardEntryWhenActive(bool usesSecureKeyboard)
4378 {
4379 if (m_useSecureKeyboardEntryWhenActive == usesSecureKeyboard)
4380 return;
4381
4382 m_useSecureKeyboardEntryWhenActive = usesSecureKeyboard;
4383 m_frame->selection().updateSecureKeyboardEntryIfActive();
4384 }
4385
useSecureKeyboardEntryWhenActive() const4386 bool Document::useSecureKeyboardEntryWhenActive() const
4387 {
4388 return m_useSecureKeyboardEntryWhenActive;
4389 }
4390
initSecurityContext()4391 void Document::initSecurityContext()
4392 {
4393 initSecurityContext(DocumentInit(m_url, m_frame, contextDocument(), m_import));
4394 }
4395
initSecurityContext(const DocumentInit & initializer)4396 void Document::initSecurityContext(const DocumentInit& initializer)
4397 {
4398 if (haveInitializedSecurityOrigin()) {
4399 ASSERT(securityOrigin());
4400 return;
4401 }
4402
4403 if (!initializer.hasSecurityContext()) {
4404 // No source for a security context.
4405 // This can occur via document.implementation.createDocument().
4406 m_cookieURL = KURL(ParsedURLString, emptyString());
4407 setSecurityOrigin(SecurityOrigin::createUnique());
4408 setContentSecurityPolicy(ContentSecurityPolicy::create(this));
4409 return;
4410 }
4411
4412 // In the common case, create the security context from the currently
4413 // loading URL with a fresh content security policy.
4414 m_cookieURL = m_url;
4415 enforceSandboxFlags(initializer.sandboxFlags());
4416 setSecurityOrigin(isSandboxed(SandboxOrigin) ? SecurityOrigin::createUnique() : SecurityOrigin::create(m_url));
4417 setContentSecurityPolicy(ContentSecurityPolicy::create(this));
4418
4419 if (Settings* settings = initializer.settings()) {
4420 if (!settings->webSecurityEnabled()) {
4421 // Web security is turned off. We should let this document access every other document. This is used primary by testing
4422 // harnesses for web sites.
4423 securityOrigin()->grantUniversalAccess();
4424 } else if (securityOrigin()->isLocal()) {
4425 if (settings->allowUniversalAccessFromFileURLs()) {
4426 // Some clients want local URLs to have universal access, but that setting is dangerous for other clients.
4427 securityOrigin()->grantUniversalAccess();
4428 } else if (!settings->allowFileAccessFromFileURLs()) {
4429 // Some clients want local URLs to have even tighter restrictions by default, and not be able to access other local files.
4430 // FIXME 81578: The naming of this is confusing. Files with restricted access to other local files
4431 // still can have other privileges that can be remembered, thereby not making them unique origins.
4432 securityOrigin()->enforceFilePathSeparation();
4433 }
4434 }
4435 }
4436
4437 if (initializer.shouldTreatURLAsSrcdocDocument()) {
4438 m_isSrcdocDocument = true;
4439 setBaseURLOverride(initializer.parentBaseURL());
4440 }
4441
4442 // FIXME: What happens if we inherit the security origin? This check may need to be later.
4443 // <iframe seamless src="about:blank"> likely won't work as-is.
4444 m_mayDisplaySeamlesslyWithParent = initializer.isSeamlessAllowedFor(this);
4445
4446 if (!shouldInheritSecurityOriginFromOwner(m_url))
4447 return;
4448
4449 // If we do not obtain a meaningful origin from the URL, then we try to
4450 // find one via the frame hierarchy.
4451
4452 if (!initializer.owner()) {
4453 didFailToInitializeSecurityOrigin();
4454 return;
4455 }
4456
4457 if (isSandboxed(SandboxOrigin)) {
4458 // If we're supposed to inherit our security origin from our owner,
4459 // but we're also sandboxed, the only thing we inherit is the ability
4460 // to load local resources. This lets about:blank iframes in file://
4461 // URL documents load images and other resources from the file system.
4462 if (initializer.owner()->securityOrigin()->canLoadLocalResources())
4463 securityOrigin()->grantLoadLocalResources();
4464 return;
4465 }
4466
4467 m_cookieURL = initializer.owner()->cookieURL();
4468 // We alias the SecurityOrigins to match Firefox, see Bug 15313
4469 // https://bugs.webkit.org/show_bug.cgi?id=15313
4470 setSecurityOrigin(initializer.owner()->securityOrigin());
4471 }
4472
initContentSecurityPolicy(const ContentSecurityPolicyResponseHeaders & headers)4473 void Document::initContentSecurityPolicy(const ContentSecurityPolicyResponseHeaders& headers)
4474 {
4475 if (m_frame && m_frame->tree().parent() && (shouldInheritSecurityOriginFromOwner(m_url) || isPluginDocument()))
4476 contentSecurityPolicy()->copyStateFrom(m_frame->tree().parent()->document()->contentSecurityPolicy());
4477 contentSecurityPolicy()->didReceiveHeaders(headers);
4478 }
4479
allowInlineEventHandlers(Node * node,EventListener * listener,const String & contextURL,const WTF::OrdinalNumber & contextLine)4480 bool Document::allowInlineEventHandlers(Node* node, EventListener* listener, const String& contextURL, const WTF::OrdinalNumber& contextLine)
4481 {
4482 if (!contentSecurityPolicy()->allowInlineEventHandlers(contextURL, contextLine))
4483 return false;
4484
4485 // HTML says that inline script needs browsing context to create its execution environment.
4486 // http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#event-handler-attributes
4487 // Also, if the listening node came from other document, which happens on context-less event dispatching,
4488 // we also need to ask the owner document of the node.
4489 if (!m_frame)
4490 return false;
4491 if (!m_frame->script().canExecuteScripts(NotAboutToExecuteScript))
4492 return false;
4493 if (node && node->document() != this && !node->document().allowInlineEventHandlers(node, listener, contextURL, contextLine))
4494 return false;
4495
4496 return true;
4497 }
4498
allowExecutingScripts(Node * node)4499 bool Document::allowExecutingScripts(Node* node)
4500 {
4501 // FIXME: Eventually we'd like to evaluate scripts which are inserted into a
4502 // viewless document but this'll do for now.
4503 // See http://bugs.webkit.org/show_bug.cgi?id=5727
4504 if (!frame() && !import())
4505 return false;
4506 if (!node->document().frame() && !node->document().import())
4507 return false;
4508 if (!contextDocument().get()->frame()->script().canExecuteScripts(AboutToExecuteScript))
4509 return false;
4510 return true;
4511 }
4512
updateSecurityOrigin(PassRefPtr<SecurityOrigin> origin)4513 void Document::updateSecurityOrigin(PassRefPtr<SecurityOrigin> origin)
4514 {
4515 setSecurityOrigin(origin);
4516 didUpdateSecurityOrigin();
4517 }
4518
didUpdateSecurityOrigin()4519 void Document::didUpdateSecurityOrigin()
4520 {
4521 if (!m_frame)
4522 return;
4523 m_frame->script().updateSecurityOrigin();
4524 }
4525
isContextThread() const4526 bool Document::isContextThread() const
4527 {
4528 return isMainThread();
4529 }
4530
updateFocusAppearanceSoon(bool restorePreviousSelection)4531 void Document::updateFocusAppearanceSoon(bool restorePreviousSelection)
4532 {
4533 m_updateFocusAppearanceRestoresSelection = restorePreviousSelection;
4534 if (!m_updateFocusAppearanceTimer.isActive())
4535 m_updateFocusAppearanceTimer.startOneShot(0);
4536 }
4537
cancelFocusAppearanceUpdate()4538 void Document::cancelFocusAppearanceUpdate()
4539 {
4540 m_updateFocusAppearanceTimer.stop();
4541 }
4542
updateFocusAppearanceTimerFired(Timer<Document> *)4543 void Document::updateFocusAppearanceTimerFired(Timer<Document>*)
4544 {
4545 Element* element = focusedElement();
4546 if (!element)
4547 return;
4548 updateLayout();
4549 if (element->isFocusable())
4550 element->updateFocusAppearance(m_updateFocusAppearanceRestoresSelection);
4551 }
4552
attachRange(Range * range)4553 void Document::attachRange(Range* range)
4554 {
4555 ASSERT(!m_ranges.contains(range));
4556 m_ranges.add(range);
4557 }
4558
detachRange(Range * range)4559 void Document::detachRange(Range* range)
4560 {
4561 // We don't ASSERT m_ranges.contains(range) to allow us to call this
4562 // unconditionally to fix: https://bugs.webkit.org/show_bug.cgi?id=26044
4563 m_ranges.remove(range);
4564 }
4565
getCSSCanvasContext(const String & type,const String & name,int width,int height)4566 CanvasRenderingContext* Document::getCSSCanvasContext(const String& type, const String& name, int width, int height)
4567 {
4568 HTMLCanvasElement* element = getCSSCanvasElement(name);
4569 if (!element)
4570 return 0;
4571 element->setSize(IntSize(width, height));
4572 return element->getContext(type);
4573 }
4574
getCSSCanvasElement(const String & name)4575 HTMLCanvasElement* Document::getCSSCanvasElement(const String& name)
4576 {
4577 RefPtr<HTMLCanvasElement>& element = m_cssCanvasElements.add(name, 0).iterator->value;
4578 if (!element) {
4579 element = HTMLCanvasElement::create(*this);
4580 element->setAccelerationDisabled(true);
4581 }
4582 return element.get();
4583 }
4584
initDNSPrefetch()4585 void Document::initDNSPrefetch()
4586 {
4587 Settings* settings = this->settings();
4588
4589 m_haveExplicitlyDisabledDNSPrefetch = false;
4590 m_isDNSPrefetchEnabled = settings && settings->dnsPrefetchingEnabled() && securityOrigin()->protocol() == "http";
4591
4592 // Inherit DNS prefetch opt-out from parent frame
4593 if (Document* parent = parentDocument()) {
4594 if (!parent->isDNSPrefetchEnabled())
4595 m_isDNSPrefetchEnabled = false;
4596 }
4597 }
4598
parseDNSPrefetchControlHeader(const String & dnsPrefetchControl)4599 void Document::parseDNSPrefetchControlHeader(const String& dnsPrefetchControl)
4600 {
4601 if (equalIgnoringCase(dnsPrefetchControl, "on") && !m_haveExplicitlyDisabledDNSPrefetch) {
4602 m_isDNSPrefetchEnabled = true;
4603 return;
4604 }
4605
4606 m_isDNSPrefetchEnabled = false;
4607 m_haveExplicitlyDisabledDNSPrefetch = true;
4608 }
4609
reportBlockedScriptExecutionToInspector(const String & directiveText)4610 void Document::reportBlockedScriptExecutionToInspector(const String& directiveText)
4611 {
4612 InspectorInstrumentation::scriptExecutionBlockedByCSP(this, directiveText);
4613 }
4614
addMessage(MessageSource source,MessageLevel level,const String & message,const String & sourceURL,unsigned lineNumber,ScriptState * state)4615 void Document::addMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, ScriptState* state)
4616 {
4617 internalAddMessage(source, level, message, sourceURL, lineNumber, 0, state);
4618 }
4619
internalAddMessage(MessageSource source,MessageLevel level,const String & message,const String & sourceURL,unsigned lineNumber,PassRefPtr<ScriptCallStack> callStack,ScriptState * state)4620 void Document::internalAddMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, PassRefPtr<ScriptCallStack> callStack, ScriptState* state)
4621 {
4622 if (!isContextThread()) {
4623 m_taskRunner->postTask(AddConsoleMessageTask::create(source, level, message));
4624 return;
4625 }
4626 Page* page = this->page();
4627 if (!page)
4628 return;
4629
4630 String messageURL = sourceURL;
4631 if (!state && sourceURL.isNull() && !lineNumber) {
4632 messageURL = url().string();
4633 if (parsing() && !isInDocumentWrite() && scriptableDocumentParser()) {
4634 ScriptableDocumentParser* parser = scriptableDocumentParser();
4635 if (!parser->isWaitingForScripts() && !parser->isExecutingScript())
4636 lineNumber = parser->lineNumber().oneBasedInt();
4637 }
4638 }
4639 page->console().addMessage(source, level, message, messageURL, lineNumber, 0, callStack, state, 0);
4640 }
4641
addConsoleMessageWithRequestIdentifier(MessageSource source,MessageLevel level,const String & message,unsigned long requestIdentifier)4642 void Document::addConsoleMessageWithRequestIdentifier(MessageSource source, MessageLevel level, const String& message, unsigned long requestIdentifier)
4643 {
4644 if (!isContextThread()) {
4645 m_taskRunner->postTask(AddConsoleMessageTask::create(source, level, message));
4646 return;
4647 }
4648
4649 if (Page* page = this->page())
4650 page->console().addMessage(source, level, message, String(), 0, 0, 0, 0, requestIdentifier);
4651 }
4652
4653 // FIXME(crbug.com/305497): This should be removed after ExecutionContext-DOMWindow migration.
postTask(PassOwnPtr<ExecutionContextTask> task)4654 void Document::postTask(PassOwnPtr<ExecutionContextTask> task)
4655 {
4656 m_taskRunner->postTask(task);
4657 }
4658
tasksWereSuspended()4659 void Document::tasksWereSuspended()
4660 {
4661 scriptRunner()->suspend();
4662
4663 if (m_parser)
4664 m_parser->suspendScheduledTasks();
4665 if (m_scriptedAnimationController)
4666 m_scriptedAnimationController->suspend();
4667 }
4668
tasksWereResumed()4669 void Document::tasksWereResumed()
4670 {
4671 scriptRunner()->resume();
4672
4673 if (m_parser)
4674 m_parser->resumeScheduledTasks();
4675 if (m_scriptedAnimationController)
4676 m_scriptedAnimationController->resume();
4677 }
4678
4679 // FIXME: suspendScheduledTasks(), resumeScheduledTasks(), tasksNeedSuspension()
4680 // should be moved to DOMWindow once it inherits ExecutionContext
suspendScheduledTasks()4681 void Document::suspendScheduledTasks()
4682 {
4683 ExecutionContext::suspendScheduledTasks();
4684 m_taskRunner->suspend();
4685 }
4686
resumeScheduledTasks()4687 void Document::resumeScheduledTasks()
4688 {
4689 ExecutionContext::resumeScheduledTasks();
4690 m_taskRunner->resume();
4691 }
4692
tasksNeedSuspension()4693 bool Document::tasksNeedSuspension()
4694 {
4695 Page* page = this->page();
4696 return page && page->defersLoading();
4697 }
4698
addToTopLayer(Element * element,const Element * before)4699 void Document::addToTopLayer(Element* element, const Element* before)
4700 {
4701 if (element->isInTopLayer())
4702 return;
4703
4704 ASSERT(!m_topLayerElements.contains(element));
4705 ASSERT(!before || m_topLayerElements.contains(before));
4706 if (before) {
4707 size_t beforePosition = m_topLayerElements.find(before);
4708 m_topLayerElements.insert(beforePosition, element);
4709 } else {
4710 m_topLayerElements.append(element);
4711 }
4712 element->setIsInTopLayer(true);
4713 }
4714
removeFromTopLayer(Element * element)4715 void Document::removeFromTopLayer(Element* element)
4716 {
4717 if (!element->isInTopLayer())
4718 return;
4719 size_t position = m_topLayerElements.find(element);
4720 ASSERT(position != kNotFound);
4721 m_topLayerElements.remove(position);
4722 element->setIsInTopLayer(false);
4723 }
4724
activeModalDialog() const4725 HTMLDialogElement* Document::activeModalDialog() const
4726 {
4727 if (m_topLayerElements.isEmpty())
4728 return 0;
4729 return toHTMLDialogElement(m_topLayerElements.last().get());
4730 }
4731
webkitExitPointerLock()4732 void Document::webkitExitPointerLock()
4733 {
4734 if (!page())
4735 return;
4736 if (Element* target = page()->pointerLockController().element()) {
4737 if (target->document() != this)
4738 return;
4739 }
4740 page()->pointerLockController().requestPointerUnlock();
4741 }
4742
webkitPointerLockElement() const4743 Element* Document::webkitPointerLockElement() const
4744 {
4745 if (!page() || page()->pointerLockController().lockPending())
4746 return 0;
4747 if (Element* element = page()->pointerLockController().element()) {
4748 if (element->document() == this)
4749 return element;
4750 }
4751 return 0;
4752 }
4753
decrementLoadEventDelayCount()4754 void Document::decrementLoadEventDelayCount()
4755 {
4756 ASSERT(m_loadEventDelayCount);
4757 --m_loadEventDelayCount;
4758
4759 if (frame() && !m_loadEventDelayCount && !m_loadEventDelayTimer.isActive())
4760 m_loadEventDelayTimer.startOneShot(0);
4761 }
4762
loadEventDelayTimerFired(Timer<Document> *)4763 void Document::loadEventDelayTimerFired(Timer<Document>*)
4764 {
4765 if (frame())
4766 frame()->loader().checkCompleted();
4767 }
4768
ensureScriptedAnimationController()4769 ScriptedAnimationController& Document::ensureScriptedAnimationController()
4770 {
4771 if (!m_scriptedAnimationController) {
4772 m_scriptedAnimationController = ScriptedAnimationController::create(this);
4773 // We need to make sure that we don't start up the animation controller on a background tab, for example.
4774 if (!page())
4775 m_scriptedAnimationController->suspend();
4776 }
4777 return *m_scriptedAnimationController;
4778 }
4779
requestAnimationFrame(PassOwnPtr<RequestAnimationFrameCallback> callback)4780 int Document::requestAnimationFrame(PassOwnPtr<RequestAnimationFrameCallback> callback)
4781 {
4782 return ensureScriptedAnimationController().registerCallback(callback);
4783 }
4784
cancelAnimationFrame(int id)4785 void Document::cancelAnimationFrame(int id)
4786 {
4787 if (!m_scriptedAnimationController)
4788 return;
4789 m_scriptedAnimationController->cancelCallback(id);
4790 }
4791
serviceScriptedAnimations(double monotonicAnimationStartTime)4792 void Document::serviceScriptedAnimations(double monotonicAnimationStartTime)
4793 {
4794 if (!m_scriptedAnimationController)
4795 return;
4796 m_scriptedAnimationController->serviceScriptedAnimations(monotonicAnimationStartTime);
4797 }
4798
createTouch(DOMWindow * window,EventTarget * target,int identifier,int pageX,int pageY,int screenX,int screenY,int radiusX,int radiusY,float rotationAngle,float force) const4799 PassRefPtr<Touch> Document::createTouch(DOMWindow* window, EventTarget* target, int identifier, int pageX, int pageY, int screenX, int screenY, int radiusX, int radiusY, float rotationAngle, float force) const
4800 {
4801 // FIXME: It's not clear from the documentation at
4802 // http://developer.apple.com/library/safari/#documentation/UserExperience/Reference/DocumentAdditionsReference/DocumentAdditions/DocumentAdditions.html
4803 // when this method should throw and nor is it by inspection of iOS behavior. It would be nice to verify any cases where it throws under iOS
4804 // and implement them here. See https://bugs.webkit.org/show_bug.cgi?id=47819
4805 Frame* frame = window ? window->frame() : this->frame();
4806 return Touch::create(frame, target, identifier, screenX, screenY, pageX, pageY, radiusX, radiusY, rotationAngle, force);
4807 }
4808
createTouchList(Vector<RefPtr<Touch>> & touches) const4809 PassRefPtr<TouchList> Document::createTouchList(Vector<RefPtr<Touch> >& touches) const
4810 {
4811 return TouchList::create(touches);
4812 }
4813
didAddTouchEventHandler(Node * handler)4814 void Document::didAddTouchEventHandler(Node* handler)
4815 {
4816 if (!m_touchEventTargets.get())
4817 m_touchEventTargets = adoptPtr(new TouchEventTargetSet);
4818 m_touchEventTargets->add(handler);
4819 if (Document* parent = parentDocument()) {
4820 parent->didAddTouchEventHandler(this);
4821 return;
4822 }
4823 if (Page* page = this->page()) {
4824 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
4825 scrollingCoordinator->touchEventTargetRectsDidChange(this);
4826 if (m_touchEventTargets->size() == 1)
4827 page->chrome().client().needTouchEvents(true);
4828 }
4829 }
4830
didRemoveTouchEventHandler(Node * handler)4831 void Document::didRemoveTouchEventHandler(Node* handler)
4832 {
4833 if (!m_touchEventTargets.get())
4834 return;
4835 ASSERT(m_touchEventTargets->contains(handler));
4836 m_touchEventTargets->remove(handler);
4837 if (Document* parent = parentDocument()) {
4838 parent->didRemoveTouchEventHandler(this);
4839 return;
4840 }
4841
4842 Page* page = this->page();
4843 if (!page)
4844 return;
4845 if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
4846 scrollingCoordinator->touchEventTargetRectsDidChange(this);
4847 if (m_touchEventTargets->size())
4848 return;
4849 for (const Frame* frame = page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
4850 if (frame->document() && frame->document()->hasTouchEventHandlers())
4851 return;
4852 }
4853 page->chrome().client().needTouchEvents(false);
4854 }
4855
didRemoveEventTargetNode(Node * handler)4856 void Document::didRemoveEventTargetNode(Node* handler)
4857 {
4858 if (m_touchEventTargets && !m_touchEventTargets->isEmpty()) {
4859 if (handler == this)
4860 m_touchEventTargets->clear();
4861 else
4862 m_touchEventTargets->removeAll(handler);
4863 if (m_touchEventTargets->isEmpty() && parentDocument())
4864 parentDocument()->didRemoveEventTargetNode(this);
4865 }
4866 }
4867
resetLastHandledUserGestureTimestamp()4868 void Document::resetLastHandledUserGestureTimestamp()
4869 {
4870 m_lastHandledUserGestureTimestamp = currentTime();
4871 }
4872
seamlessParentIFrame() const4873 HTMLIFrameElement* Document::seamlessParentIFrame() const
4874 {
4875 if (!shouldDisplaySeamlesslyWithParent())
4876 return 0;
4877
4878 return toHTMLIFrameElement(this->ownerElement());
4879 }
4880
shouldDisplaySeamlesslyWithParent() const4881 bool Document::shouldDisplaySeamlesslyWithParent() const
4882 {
4883 if (!RuntimeEnabledFeatures::seamlessIFramesEnabled())
4884 return false;
4885 HTMLFrameOwnerElement* ownerElement = this->ownerElement();
4886 if (!ownerElement)
4887 return false;
4888 return m_mayDisplaySeamlesslyWithParent && ownerElement->hasTagName(iframeTag) && ownerElement->fastHasAttribute(seamlessAttr);
4889 }
4890
loader() const4891 DocumentLoader* Document::loader() const
4892 {
4893 if (!m_frame)
4894 return 0;
4895
4896 DocumentLoader* loader = m_frame->loader().documentLoader();
4897 if (!loader)
4898 return 0;
4899
4900 if (m_frame->document() != this)
4901 return 0;
4902
4903 return loader;
4904 }
4905
initialViewportSize() const4906 IntSize Document::initialViewportSize() const
4907 {
4908 if (!view())
4909 return IntSize();
4910 return view()->unscaledVisibleContentSize(ScrollableArea::IncludeScrollbars);
4911 }
4912
eventTargetNodeForDocument(Document * doc)4913 Node* eventTargetNodeForDocument(Document* doc)
4914 {
4915 if (!doc)
4916 return 0;
4917 Node* node = doc->focusedElement();
4918 if (!node && doc->isPluginDocument()) {
4919 PluginDocument* pluginDocument = toPluginDocument(doc);
4920 node = pluginDocument->pluginNode();
4921 }
4922 if (!node && doc->isHTMLDocument())
4923 node = doc->body();
4924 if (!node)
4925 node = doc->documentElement();
4926 return node;
4927 }
4928
adjustFloatQuadsForScrollAndAbsoluteZoom(Vector<FloatQuad> & quads,RenderObject & renderer)4929 void Document::adjustFloatQuadsForScrollAndAbsoluteZoom(Vector<FloatQuad>& quads, RenderObject& renderer)
4930 {
4931 if (!view())
4932 return;
4933
4934 LayoutRect visibleContentRect = view()->visibleContentRect();
4935 for (size_t i = 0; i < quads.size(); ++i) {
4936 quads[i].move(-visibleContentRect.x(), -visibleContentRect.y());
4937 adjustFloatQuadForAbsoluteZoom(quads[i], renderer);
4938 }
4939 }
4940
adjustFloatRectForScrollAndAbsoluteZoom(FloatRect & rect,RenderObject & renderer)4941 void Document::adjustFloatRectForScrollAndAbsoluteZoom(FloatRect& rect, RenderObject& renderer)
4942 {
4943 if (!view())
4944 return;
4945
4946 LayoutRect visibleContentRect = view()->visibleContentRect();
4947 rect.move(-visibleContentRect.x(), -visibleContentRect.y());
4948 adjustFloatRectForAbsoluteZoom(rect, renderer);
4949 }
4950
hasActiveParser()4951 bool Document::hasActiveParser()
4952 {
4953 return m_activeParserCount || (m_parser && m_parser->processingData());
4954 }
4955
decrementActiveParserCount()4956 void Document::decrementActiveParserCount()
4957 {
4958 --m_activeParserCount;
4959 if (!frame())
4960 return;
4961 // FIXME: This should always be enabled, but it seems to cause
4962 // http/tests/security/feed-urls-from-remote.html to timeout on Mac WK1
4963 // see http://webkit.org/b/110554 and http://webkit.org/b/110401
4964 loader()->checkLoadComplete();
4965 frame()->loader().checkLoadComplete();
4966 }
4967
setContextFeatures(PassRefPtr<ContextFeatures> features)4968 void Document::setContextFeatures(PassRefPtr<ContextFeatures> features)
4969 {
4970 m_contextFeatures = features;
4971 }
4972
nearestCommonHoverAncestor(RenderObject * obj1,RenderObject * obj2)4973 static RenderObject* nearestCommonHoverAncestor(RenderObject* obj1, RenderObject* obj2)
4974 {
4975 if (!obj1 || !obj2)
4976 return 0;
4977
4978 for (RenderObject* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAncestor()) {
4979 for (RenderObject* currObj2 = obj2; currObj2; currObj2 = currObj2->hoverAncestor()) {
4980 if (currObj1 == currObj2)
4981 return currObj1;
4982 }
4983 }
4984
4985 return 0;
4986 }
4987
updateHoverActiveState(const HitTestRequest & request,Element * innerElement,const PlatformMouseEvent * event)4988 void Document::updateHoverActiveState(const HitTestRequest& request, Element* innerElement, const PlatformMouseEvent* event)
4989 {
4990 ASSERT(!request.readOnly());
4991
4992 if (request.active() && m_frame)
4993 m_frame->eventHandler().notifyElementActivated();
4994
4995 Element* innerElementInDocument = innerElement;
4996 while (innerElementInDocument && innerElementInDocument->document() != this) {
4997 innerElementInDocument->document().updateHoverActiveState(request, innerElementInDocument, event);
4998 innerElementInDocument = innerElementInDocument->document().ownerElement();
4999 }
5000
5001 Element* oldActiveElement = activeElement();
5002 if (oldActiveElement && !request.active()) {
5003 // We are clearing the :active chain because the mouse has been released.
5004 for (RenderObject* curr = oldActiveElement->renderer(); curr; curr = curr->parent()) {
5005 if (curr->node()) {
5006 ASSERT(!curr->node()->isTextNode());
5007 curr->node()->setActive(false);
5008 m_userActionElements.setInActiveChain(curr->node(), false);
5009 }
5010 }
5011 setActiveElement(0);
5012 } else {
5013 Element* newActiveElement = innerElementInDocument;
5014 if (!oldActiveElement && newActiveElement && request.active() && !request.touchMove()) {
5015 // We are setting the :active chain and freezing it. If future moves happen, they
5016 // will need to reference this chain.
5017 for (RenderObject* curr = newActiveElement->renderer(); curr; curr = curr->parent()) {
5018 if (curr->node() && !curr->isText())
5019 m_userActionElements.setInActiveChain(curr->node(), true);
5020 }
5021
5022 setActiveElement(newActiveElement);
5023 }
5024 }
5025 // If the mouse has just been pressed, set :active on the chain. Those (and only those)
5026 // nodes should remain :active until the mouse is released.
5027 bool allowActiveChanges = !oldActiveElement && activeElement();
5028
5029 // If the mouse is down and if this is a mouse move event, we want to restrict changes in
5030 // :hover/:active to only apply to elements that are in the :active chain that we froze
5031 // at the time the mouse went down.
5032 bool mustBeInActiveChain = request.active() && request.move();
5033
5034 RefPtr<Node> oldHoverNode = hoverNode();
5035
5036 // Check to see if the hovered node has changed.
5037 // If it hasn't, we do not need to do anything.
5038 Node* newHoverNode = innerElementInDocument;
5039 while (newHoverNode && !newHoverNode->renderer())
5040 newHoverNode = newHoverNode->parentOrShadowHostNode();
5041
5042 // Update our current hover node.
5043 setHoverNode(newHoverNode);
5044
5045 // We have two different objects. Fetch their renderers.
5046 RenderObject* oldHoverObj = oldHoverNode ? oldHoverNode->renderer() : 0;
5047 RenderObject* newHoverObj = newHoverNode ? newHoverNode->renderer() : 0;
5048
5049 // Locate the common ancestor render object for the two renderers.
5050 RenderObject* ancestor = nearestCommonHoverAncestor(oldHoverObj, newHoverObj);
5051 RefPtr<Node> ancestorNode(ancestor ? ancestor->node() : 0);
5052
5053 Vector<RefPtr<Node>, 32> nodesToRemoveFromChain;
5054 Vector<RefPtr<Node>, 32> nodesToAddToChain;
5055
5056 if (oldHoverObj != newHoverObj) {
5057 // If the old hovered node is not nil but it's renderer is, it was probably detached as part of the :hover style
5058 // (for instance by setting display:none in the :hover pseudo-class). In this case, the old hovered element (and its ancestors)
5059 // must be updated, to ensure it's normal style is re-applied.
5060 if (oldHoverNode && !oldHoverObj) {
5061 for (Node* node = oldHoverNode.get(); node; node = node->parentNode()) {
5062 if (!mustBeInActiveChain || (node->isElementNode() && toElement(node)->inActiveChain()))
5063 nodesToRemoveFromChain.append(node);
5064 }
5065
5066 }
5067
5068 // The old hover path only needs to be cleared up to (and not including) the common ancestor;
5069 for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = curr->hoverAncestor()) {
5070 if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain()))
5071 nodesToRemoveFromChain.append(curr->node());
5072 }
5073 }
5074
5075 // Now set the hover state for our new object up to the root.
5076 for (RenderObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) {
5077 if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain()))
5078 nodesToAddToChain.append(curr->node());
5079 }
5080
5081 // mouseenter and mouseleave events do not bubble, so they are dispatched iff there is a capturing
5082 // event handler on an ancestor or a normal event handler on the element itself. This special
5083 // handling is necessary to avoid O(n^2) capturing event handler checks. We'll check the previously
5084 // hovered node's ancestor tree for 'mouseleave' handlers here, then check the newly hovered node's
5085 // ancestor tree for 'mouseenter' handlers after dispatching the 'mouseleave' events (as the handler
5086 // for 'mouseleave' might set a capturing 'mouseenter' handler, odd as that might be).
5087 bool ancestorHasCapturingMouseleaveListener = false;
5088 if (event && newHoverNode != oldHoverNode.get()) {
5089 for (Node* node = oldHoverNode.get(); node; node = node->parentOrShadowHostNode()) {
5090 if (node->hasCapturingEventListeners(EventTypeNames::mouseleave)) {
5091 ancestorHasCapturingMouseleaveListener = true;
5092 break;
5093 }
5094 }
5095 }
5096
5097 size_t removeCount = nodesToRemoveFromChain.size();
5098 for (size_t i = 0; i < removeCount; ++i) {
5099 nodesToRemoveFromChain[i]->setHovered(false);
5100 if (event && (ancestorHasCapturingMouseleaveListener || nodesToRemoveFromChain[i]->hasEventListeners(EventTypeNames::mouseleave)))
5101 nodesToRemoveFromChain[i]->dispatchMouseEvent(*event, EventTypeNames::mouseleave, 0, newHoverNode);
5102 }
5103
5104 bool ancestorHasCapturingMouseenterListener = false;
5105 if (event && newHoverNode != oldHoverNode.get()) {
5106 for (Node* node = newHoverNode; node; node = node->parentOrShadowHostNode()) {
5107 if (node->hasCapturingEventListeners(EventTypeNames::mouseenter)) {
5108 ancestorHasCapturingMouseenterListener = true;
5109 break;
5110 }
5111 }
5112 }
5113
5114 bool sawCommonAncestor = false;
5115 size_t addCount = nodesToAddToChain.size();
5116 for (size_t i = 0; i < addCount; ++i) {
5117 // Elements past the common ancestor do not change hover state, but might change active state.
5118 if (ancestorNode && nodesToAddToChain[i] == ancestorNode)
5119 sawCommonAncestor = true;
5120 if (allowActiveChanges)
5121 nodesToAddToChain[i]->setActive(true);
5122 if (!sawCommonAncestor) {
5123 nodesToAddToChain[i]->setHovered(true);
5124 if (event && (ancestorHasCapturingMouseenterListener || nodesToAddToChain[i]->hasEventListeners(EventTypeNames::mouseenter)))
5125 nodesToAddToChain[i]->dispatchMouseEvent(*event, EventTypeNames::mouseenter, 0, oldHoverNode.get());
5126 }
5127 }
5128
5129 updateStyleIfNeeded();
5130 }
5131
haveStylesheetsLoaded() const5132 bool Document::haveStylesheetsLoaded() const
5133 {
5134 return m_styleEngine->haveStylesheetsLoaded();
5135 }
5136
getCachedLocale(const AtomicString & locale)5137 Locale& Document::getCachedLocale(const AtomicString& locale)
5138 {
5139 AtomicString localeKey = locale;
5140 if (locale.isEmpty() || !RuntimeEnabledFeatures::langAttributeAwareFormControlUIEnabled())
5141 return Locale::defaultLocale();
5142 LocaleIdentifierToLocaleMap::AddResult result = m_localeCache.add(localeKey, nullptr);
5143 if (result.isNewEntry)
5144 result.iterator->value = Locale::create(localeKey);
5145 return *(result.iterator->value);
5146 }
5147
ensureTemplateDocument()5148 Document& Document::ensureTemplateDocument()
5149 {
5150 if (const Document* document = templateDocument())
5151 return *const_cast<Document*>(document);
5152
5153 if (isHTMLDocument()) {
5154 DocumentInit init = DocumentInit::fromContext(contextDocument(), blankURL());
5155 m_templateDocument = HTMLDocument::create(init);
5156 } else {
5157 m_templateDocument = Document::create(DocumentInit(blankURL()));
5158 }
5159
5160 m_templateDocument->setTemplateDocumentHost(this); // balanced in dtor.
5161
5162 return *m_templateDocument.get();
5163 }
5164
didAssociateFormControl(Element * element)5165 void Document::didAssociateFormControl(Element* element)
5166 {
5167 if (!frame() || !frame()->page())
5168 return;
5169 m_associatedFormControls.add(element);
5170 if (!m_didAssociateFormControlsTimer.isActive())
5171 m_didAssociateFormControlsTimer.startOneShot(0);
5172 }
5173
didAssociateFormControlsTimerFired(Timer<Document> * timer)5174 void Document::didAssociateFormControlsTimerFired(Timer<Document>* timer)
5175 {
5176 ASSERT_UNUSED(timer, timer == &m_didAssociateFormControlsTimer);
5177 if (!frame() || !frame()->page())
5178 return;
5179
5180 Vector<RefPtr<Element> > associatedFormControls;
5181 copyToVector(m_associatedFormControls, associatedFormControls);
5182
5183 frame()->page()->chrome().client().didAssociateFormControls(associatedFormControls);
5184 m_associatedFormControls.clear();
5185 }
5186
devicePixelRatio() const5187 float Document::devicePixelRatio() const
5188 {
5189 return m_frame ? m_frame->devicePixelRatio() : 1.0;
5190 }
5191
createLifecycleNotifier()5192 PassOwnPtr<LifecycleNotifier<Document> > Document::createLifecycleNotifier()
5193 {
5194 return DocumentLifecycleNotifier::create(this);
5195 }
5196
lifecycleNotifier()5197 DocumentLifecycleNotifier& Document::lifecycleNotifier()
5198 {
5199 return static_cast<DocumentLifecycleNotifier&>(LifecycleContext<Document>::lifecycleNotifier());
5200 }
5201
removedStyleSheet(StyleSheet * sheet,RecalcStyleTime when,StyleResolverUpdateMode updateMode)5202 void Document::removedStyleSheet(StyleSheet* sheet, RecalcStyleTime when, StyleResolverUpdateMode updateMode)
5203 {
5204 // If we're in document teardown, then we don't need this notification of our sheet's removal.
5205 // styleResolverChanged() is needed even when the document is inactive so that
5206 // imported docuements (which is inactive) notifies the change to the master document.
5207 if (isActive())
5208 styleEngine()->modifiedStyleSheet(sheet);
5209 styleResolverChanged(when, updateMode);
5210 }
5211
modifiedStyleSheet(StyleSheet * sheet,RecalcStyleTime when,StyleResolverUpdateMode updateMode)5212 void Document::modifiedStyleSheet(StyleSheet* sheet, RecalcStyleTime when, StyleResolverUpdateMode updateMode)
5213 {
5214 // If we're in document teardown, then we don't need this notification of our sheet's removal.
5215 // styleResolverChanged() is needed even when the document is inactive so that
5216 // imported docuements (which is inactive) notifies the change to the master document.
5217 if (isActive())
5218 styleEngine()->modifiedStyleSheet(sheet);
5219 styleResolverChanged(when, updateMode);
5220 }
5221
textAutosizer()5222 TextAutosizer* Document::textAutosizer()
5223 {
5224 if (!m_textAutosizer && !RuntimeEnabledFeatures::fastTextAutosizingEnabled())
5225 m_textAutosizer = TextAutosizer::create(this);
5226 return m_textAutosizer.get();
5227 }
5228
fastTextAutosizer()5229 FastTextAutosizer* Document::fastTextAutosizer()
5230 {
5231 if (!m_fastTextAutosizer && RuntimeEnabledFeatures::fastTextAutosizingEnabled())
5232 m_fastTextAutosizer = FastTextAutosizer::create(this);
5233 return m_fastTextAutosizer.get();
5234 }
5235
5236 } // namespace WebCore
5237