/* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Dirk Mueller (mueller@kde.org) * (C) 2006 Alexey Proskuryakov (ap@webkit.org) * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All rights reserved. * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) * Copyright (C) 2011 Google Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #ifndef SKY_ENGINE_CORE_DOM_DOCUMENT_H_ #define SKY_ENGINE_CORE_DOM_DOCUMENT_H_ #include "sky/engine/tonic/dart_value.h" #include "sky/engine/bindings/exception_state_placeholder.h" #include "sky/engine/core/animation/AnimationClock.h" #include "sky/engine/core/animation/PendingAnimations.h" #include "sky/engine/core/dom/ContainerNode.h" #include "sky/engine/core/dom/DocumentInit.h" #include "sky/engine/core/dom/DocumentLifecycle.h" #include "sky/engine/core/dom/DocumentSupplementable.h" #include "sky/engine/core/dom/ExecutionContext.h" #include "sky/engine/core/dom/MutationObserver.h" #include "sky/engine/core/dom/TextLinkColors.h" #include "sky/engine/core/dom/TreeScope.h" #include "sky/engine/core/dom/UserActionElementSet.h" #include "sky/engine/core/fetch/ResourceClient.h" #include "sky/engine/core/loader/DocumentLoadTiming.h" #include "sky/engine/core/page/FocusType.h" #include "sky/engine/core/page/PageVisibilityState.h" #include "sky/engine/platform/Length.h" #include "sky/engine/platform/Timer.h" #include "sky/engine/platform/heap/Handle.h" #include "sky/engine/platform/weborigin/KURL.h" #include "sky/engine/platform/weborigin/ReferrerPolicy.h" #include "sky/engine/wtf/HashSet.h" #include "sky/engine/wtf/OwnPtr.h" #include "sky/engine/wtf/PassOwnPtr.h" #include "sky/engine/wtf/PassRefPtr.h" #include "sky/engine/wtf/WeakPtr.h" #include "sky/engine/wtf/text/TextEncoding.h" #include "sky/engine/wtf/text/TextPosition.h" namespace blink { class AbstractModule; class AnimationTimeline; class Attr; class Comment; class ConsoleMessage; class CSSStyleDeclaration; class CSSStyleSheet; class CustomElementRegistry; class DocumentFragment; class DocumentLifecycleNotifier; class DocumentLoadTiming; class DocumentMarkerController; class DocumentParser; class Element; class ElementDataCache; class Event; class EventListener; class ExceptionState; class FloatQuad; class FloatRect; class Frame; class FrameHost; class FrameView; class HitTestRequest; class HTMLDocumentParser; class HTMLElement; class HTMLImport; class HTMLImportLoader; class HTMLImportsController; class HTMLScriptElement; class LayoutPoint; class LocalDOMWindow; class LocalFrame; class Location; class MediaQueryListListener; class MediaQueryMatcher; class Page; class Picture; class QualifiedName; class Range; class RenderView; class RequestAnimationFrameCallback; class ResourceFetcher; class ScriptedAnimationController; class ScriptRunner; class SegmentedString; class SelectorQueryCache; class Settings; class StyleEngine; class StyleResolver; class Text; struct AnnotatedRegionValue; typedef int ExceptionCode; class Document; class Document : public ContainerNode, public TreeScope, public ExecutionContext, public ExecutionContextClient , public DocumentSupplementable, public LifecycleContext, public ResourceClient { DEFINE_WRAPPERTYPEINFO(); public: static PassRefPtr create(const DocumentInit& initializer = DocumentInit()) { return adoptRef(new Document(initializer)); } virtual ~Document(); MediaQueryMatcher& mediaQueryMatcher(); void mediaQueryAffectingValueChanged(); #if !ENABLE(OILPAN) using ContainerNode::ref; using ContainerNode::deref; #endif using ExecutionContextClient::addConsoleMessage; using TreeScope::getElementById; virtual bool canContainRangeEndPoint() const override { return true; } SelectorQueryCache& selectorQueryCache(); // Focus Management. Element* activeElement() const; bool hasFocus() const; AbstractModule* module() const { return m_module; } void setModule(AbstractModule* module) { m_module = module; } // DOM methods & attributes for Document Length viewportDefaultMinWidth() const { return m_viewportDefaultMinWidth; } ReferrerPolicy referrerPolicy() const { return m_referrerPolicy; } String outgoingReferrer(); Location* location() const; PassRefPtr createElement(const AtomicString& name, ExceptionState&); PassRefPtr createText(const String& text); PassRefPtr createDocumentFragment(); PassRefPtr importNode(Node* importedNode, bool deep, ExceptionState&); PassRefPtr createElement(const QualifiedName&, bool createdByParser); Element* elementFromPoint(int x, int y) const; PassRefPtr caretRangeFromPoint(int x, int y); String readyState() const; AtomicString inputEncoding() const { return Document::encodingName(); } AtomicString charset() const { return Document::encodingName(); } AtomicString characterSet() const { return Document::encodingName(); } AtomicString encodingName() const; AtomicString contentType() const; // DOM 4 document.contentType const AtomicString& contentLanguage() const { return m_contentLanguage; } void setContentLanguage(const AtomicString&); KURL baseURI() const; String visibilityState() const; bool hidden() const; void didChangeVisibilityState(); PassRefPtr adoptNode(PassRefPtr source, ExceptionState&); struct TransitionElementData { String scope; String selector; String markup; }; void getTransitionElementData(Vector&); StyleResolver& styleResolver() const; StyleEngine* styleEngine() { return m_styleEngine.get(); } // Called when one or more stylesheets in the document may have been added, removed, or changed. void styleResolverChanged(); void evaluateMediaQueryList(); void setStateForNewFormElements(const Vector&); FrameView* view() const; // can be null LocalFrame* frame() const { return m_frame; } // can be null FrameHost* frameHost() const; // can be null Page* page() const; // can be null Settings* settings() const; // can be null float devicePixelRatio() const; PassRefPtr createRange(); // Special support for editing PassRefPtr createEditingTextNode(const String&); void setupFontBuilder(RenderStyle* documentStyle); bool needsRenderTreeUpdate() const; void updateRenderTreeIfNeeded() { updateRenderTree(NoChange); } void updateRenderTreeForNodeIfNeeded(Node*); void updateLayout(); void updateDistributionForNodeIfNeeded(Node*); ResourceFetcher* fetcher() { return m_fetcher.get(); } virtual void attach(const AttachContext& = AttachContext()) override; virtual void detach(const AttachContext& = AttachContext()) override; void prepareForDestruction(); // If you have a Document, use renderView() instead which is faster. void renderer() const = delete; RenderView* renderView() const { return m_renderView; } DocumentLoadTiming* timing() const; DocumentParser* startParsing(); void cancelParsing(); // close() is the DOM API document.close() void close(ExceptionState& = ASSERT_NO_EXCEPTION); // In some situations (see the code), we ignore document.close(). // explicitClose() bypass these checks and actually tries to close the // input stream. void explicitClose(); // implicitClose() actually does the work of closing the input stream. void implicitClose(); void checkCompleted(); void dispatchUnloadEvents(); enum PageDismissalType { NoDismissal = 0, PageHideDismissal = 2, UnloadDismissal = 3 }; PageDismissalType pageDismissalEventBeingDispatched() const; const KURL& url() const { return m_url; } void setURL(const KURL&); // To understand how these concepts relate to one another, please see the // comments surrounding their declaration. const KURL& baseURL() const { return m_baseURL; } KURL completeURL(const String&) const; CSSStyleSheet& elementSheet(); TextPosition parserPosition() const; enum ReadyState { Loading, Interactive, Complete }; void setReadyState(ReadyState); bool isLoadCompleted(); void setParsing(bool); bool parsing() const { return m_isParsing; } int elapsedTime() const; TextLinkColors& textLinkColors() { return m_textLinkColors; } bool setFocusedElement(PassRefPtr, FocusType = FocusTypeNone); Element* focusedElement() const { return m_focusedElement.get(); } UserActionElementSet& userActionElements() { return m_userActionElements; } const UserActionElementSet& userActionElements() const { return m_userActionElements; } void setNeedsFocusedElementCheck(); void setActiveHoverElement(PassRefPtr); Element* activeHoverElement() const { return m_activeHoverElement.get(); } void removeFocusedElementOfSubtree(Node*, bool amongChildrenOnly = false); void hoveredNodeDetached(Node*); void activeChainNodeDetached(Node*); void scheduleVisualUpdate(); void scheduleRenderTreeUpdateIfNeeded(); void attachRange(Range*); void detachRange(Range*); void updateRangesAfterChildrenChanged(ContainerNode*); void updateRangesAfterNodeMovedToAnotherDocument(const Node&); // nodeChildrenWillBeRemoved is used when removing all node children at once. void nodeChildrenWillBeRemoved(ContainerNode&); // nodeWillBeRemoved is only safe when removing one node at a time. void nodeWillBeRemoved(Node&); void didInsertText(Node*, unsigned offset, unsigned length); void didRemoveText(Node*, unsigned offset, unsigned length); void didMergeTextNodes(Text& oldNode, unsigned offset); void didSplitTextNode(Text& oldNode); void clearDOMWindow() { m_domWindow = nullptr; } LocalDOMWindow* domWindow() const { return m_domWindow; } // keep track of what types of event listeners are registered, so we don't // dispatch events unnecessarily enum ListenerType { DOMSUBTREEMODIFIED_LISTENER = 1, DOMNODEINSERTED_LISTENER = 1 << 1, DOMNODEREMOVED_LISTENER = 1 << 2, DOMNODEREMOVEDFROMDOCUMENT_LISTENER = 1 << 3, DOMNODEINSERTEDINTODOCUMENT_LISTENER = 1 << 4, DOMCHARACTERDATAMODIFIED_LISTENER = 1 << 5, ANIMATIONEND_LISTENER = 1 << 6, ANIMATIONSTART_LISTENER = 1 << 7, ANIMATIONITERATION_LISTENER = 1 << 8, TRANSITIONEND_LISTENER = 1 << 9, }; bool hasListenerType(ListenerType listenerType) const { return (m_listenerTypes & listenerType); } void addListenerTypeIfNeeded(const AtomicString& eventType); bool hasMutationObserversOfType(MutationObserver::MutationType type) const { return m_mutationObserverTypes & type; } bool hasMutationObservers() const { return m_mutationObserverTypes; } void addMutationObserverTypes(MutationObserverOptions types) { m_mutationObserverTypes |= types; } String title() const { return m_title; } void setTitle(const String&); Element* titleElement() const { return m_titleElement.get(); } void setTitleElement(Element*); void removeTitle(Element* titleElement); const AtomicString& dir(); void setDir(const AtomicString&); const AtomicString& referrer() const; String domain() const; void setDomain(const String& newDomain, ExceptionState&); // The following implements the rule from HTML 4 for what valid names are. // To get this right for all the XML cases, we probably have to improve this or move it // and make it sensitive to the type of document. static bool isValidName(const String&); // The following breaks a qualified name into a prefix and a local name. // It also does a validity check, and returns false if the qualified name // is invalid. It also sets ExceptionCode when name is invalid. static bool parseQualifiedName(const AtomicString& qualifiedName, AtomicString& prefix, AtomicString& localName, ExceptionState&); DocumentMarkerController& markers() const { return *m_markers; } KURL openSearchDescriptionURL(); Document& topDocument() const; WeakPtr contextDocument(); HTMLScriptElement* currentScript() const { return !m_currentScriptStack.isEmpty() ? m_currentScriptStack.last().get() : 0; } void pushCurrentScript(PassRefPtr); void popCurrentScript(); void finishedParsing(); const WTF::TextEncoding& encoding() const { return WTF::UTF8Encoding(); } virtual void removeAllEventListeners() override final; bool allowExecutingScripts(Node*); enum LoadEventProgress { LoadEventNotRun, LoadEventTried, LoadEventInProgress, LoadEventCompleted, PageHideInProgress, UnloadEventInProgress, UnloadEventHandled }; bool loadEventStillNeeded() const { return m_loadEventProgress == LoadEventNotRun; } bool processingLoadEvent() const { return m_loadEventProgress == LoadEventInProgress; } bool loadEventFinished() const { return m_loadEventProgress >= LoadEventCompleted; } bool unloadStarted() const { return m_loadEventProgress >= PageHideInProgress; } virtual bool isContextThread() const override final; bool containsValidityStyleRules() const { return m_containsValidityStyleRules; } void setContainsValidityStyleRules() { m_containsValidityStyleRules = true; } void enqueueResizeEvent(); void enqueueAnimationFrameEvent(PassRefPtr); // Only one event for a target/event type combination will be dispatched per frame. void enqueueUniqueAnimationFrameEvent(PassRefPtr); void enqueueMediaQueryChangeListeners(Vector >&); // Used to allow element that loads data without going through a FrameLoader to delay the 'load' event. void incrementLoadEventDelayCount() { ++m_loadEventDelayCount; } void decrementLoadEventDelayCount(); void checkLoadEventSoon(); bool isDelayingLoadEvent(); int requestAnimationFrame(PassOwnPtr); void cancelAnimationFrame(int id); void serviceScriptedAnimations(double monotonicAnimationStartTime); virtual EventTarget* errorEventTarget() override final; virtual void logExceptionToConsole(const String& errorMessage, int scriptId, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtr) override final; IntSize initialViewportSize() const; void registerElement(const AtomicString& name, PassRefPtr type, ExceptionState&); CustomElementRegistry& elementRegistry() const { return *m_elementRegistry; } void setImportsController(HTMLImportsController*); HTMLImportsController* importsController() const { return m_importsController; } HTMLImportsController& ensureImportsController(); HTMLImportLoader* importLoader() const; HTMLImport* import() const; bool haveImportsLoaded() const; void didLoadAllImports(); unsigned activeParserCount() { return m_activeParserCount; } void incrementActiveParserCount() { ++m_activeParserCount; } void decrementActiveParserCount(); ElementDataCache* elementDataCache() { return m_elementDataCache.get(); } void didLoadAllParserBlockingResources(); bool inStyleRecalc() const { return m_lifecycle.state() == DocumentLifecycle::InStyleRecalc; } AnimationClock& animationClock() { return m_animationClock; } AnimationTimeline& timeline() const { return *m_timeline; } PendingAnimations& pendingAnimations() { return m_pendingAnimations; } // A non-null m_templateDocumentHost implies that |this| was created by ensureTemplateDocument(). bool isTemplateDocument() const { return !!m_templateDocumentHost; } Document& ensureTemplateDocument(); Document* templateDocumentHost() { return m_templateDocumentHost; } virtual void addMessage(PassRefPtr) override final; virtual LocalDOMWindow* executingWindow() override final; LocalFrame* executingFrame(); DocumentLifecycleNotifier& lifecycleNotifier(); DocumentLifecycle& lifecycle() { return m_lifecycle; } bool isActive() const { return m_lifecycle.isActive(); } bool isStopped() const { return m_lifecycle.state() == DocumentLifecycle::Stopped; } bool isDisposed() const { return m_lifecycle.state() == DocumentLifecycle::Disposed; } enum HttpRefreshType { HttpRefreshFromHeader, HttpRefreshFromMetaTag }; void maybeHandleHttpRefresh(const String&, HttpRefreshType); PassOwnPtr > createLifecycleNotifier(); void setHasViewportUnits() { m_hasViewportUnits = true; } bool hasViewportUnits() const { return m_hasViewportUnits; } void notifyResizeForViewportUnits(); void didRecalculateStyleForElement() { ++m_styleRecalcElementCounter; } Picture* rootPicture() const; void setRootPicture(PassRefPtr picture); void setFrame(LocalFrame* frame) { m_frame = frame; } void setFrameView(FrameView* view) { m_frameView = view; } protected: explicit Document(const DocumentInit&); #if !ENABLE(OILPAN) virtual void dispose() override; #endif PassRefPtr cloneDocumentWithoutChildren(); bool importContainerNodeChildren(ContainerNode* oldContainerNode, PassRefPtr newContainerNode, ExceptionState&); private: friend class Node; bool isDocumentFragment() const = delete; // This will catch anyone doing an unnecessary check. bool isDocumentNode() const = delete; // This will catch anyone doing an unnecessary check. bool isElementNode() const = delete; // This will catch anyone doing an unnecessary check. ScriptedAnimationController& ensureScriptedAnimationController(); virtual EventQueue* eventQueue() const override final; // FIXME: Rename the StyleRecalc state to RenderTreeUpdate. bool hasPendingStyleRecalc() const { return m_lifecycle.state() == DocumentLifecycle::VisualUpdatePending; } bool shouldScheduleRenderTreeUpdate() const; void scheduleRenderTreeUpdate(); bool needsFullRenderTreeUpdate() const; bool dirtyElementsForLayerUpdate(); void updateDistributionIfNeeded(); void evaluateMediaQueryListIfNeeded(); void updateRenderTree(StyleRecalcChange); void updateStyle(StyleRecalcChange); void detachParser(); virtual bool isDocument() const override final { return true; } virtual String nodeName() const override final; virtual NodeType nodeType() const override final; virtual PassRefPtr cloneNode(bool deep = true) override final; #if !ENABLE(OILPAN) virtual void refExecutionContext() override final { ref(); } virtual void derefExecutionContext() override final { deref(); } #endif virtual const KURL& virtualURL() const override final; // Same as url(), but needed for ExecutionContext to implement it without a performance loss for direct calls. virtual KURL virtualCompleteURL(const String&) const override final; // Same as completeURL() for the same reason as above. virtual void reportBlockedScriptExecutionToInspector(const String& directiveText) override final; virtual double timerAlignmentInterval() const override final; void updateTitle(const String&); void updateBaseURL(); void resumeParserWaitingForResourcesTimerFired(Timer*); void loadEventDelayTimerFired(Timer*); PageVisibilityState pageVisibilityState() const; // Note that dispatching a window load event may cause the LocalDOMWindow to be detached from // the LocalFrame, so callers should take a reference to the LocalDOMWindow (which owns us) to // prevent the Document from getting blown away from underneath them. void dispatchWindowLoadEvent(); void addListenerType(ListenerType listenerType) { m_listenerTypes |= listenerType; } void clearFocusedElementSoon(); void clearFocusedElementTimerFired(Timer*); void setHoverNode(PassRefPtr); Node* hoverNode() const { return m_hoverNode.get(); } DocumentLifecycle m_lifecycle; AbstractModule* m_module; bool m_evaluateMediaQueriesOnStyleRecalc; LocalFrame* m_frame; RawPtr m_domWindow; // FIXME: oilpan: when we get rid of the transition types change the // HTMLImportsController to not be a DocumentSupplement since it is // redundant with oilpan. RawPtr m_importsController; RefPtr m_fetcher; RefPtr m_parser; unsigned m_activeParserCount; // Document URLs. KURL m_url; // Document.URL: The URL from which this document was retrieved. KURL m_baseURL; // Node.baseURI: The URL to use when resolving relative URLs. // Mime-type of the document in case it was cloned or created by XHR. AtomicString m_mimeType; RefPtr m_elemSheet; Timer m_resumeParserWaitingForResourcesTimer; Timer m_clearFocusedElementTimer; RefPtr m_focusedElement; RefPtr m_hoverNode; RefPtr m_activeHoverElement; UserActionElementSet m_userActionElements; typedef HashSet > AttachedRangeSet; AttachedRangeSet m_ranges; unsigned short m_listenerTypes; MutationObserverOptions m_mutationObserverTypes; OwnPtr m_styleEngine; TextLinkColors m_textLinkColors; ReadyState m_readyState; bool m_isParsing; bool m_containsValidityStyleRules; String m_title; String m_rawTitle; RefPtr m_titleElement; OwnPtr m_markers; LoadEventProgress m_loadEventProgress; double m_startTime; Vector > m_currentScriptStack; AtomicString m_contentLanguage; OwnPtr m_selectorQueryCache; RenderView* m_renderView; #if !ENABLE(OILPAN) WeakPtrFactory m_weakFactory; #endif WeakPtr m_contextDocument; int m_loadEventDelayCount; Timer m_loadEventDelayTimer; Length m_viewportDefaultMinWidth; bool m_didSetReferrerPolicy; ReferrerPolicy m_referrerPolicy; RefPtr m_mediaQueryMatcher; RefPtr m_scriptedAnimationController; RefPtr m_elementRegistry; void elementDataCacheClearTimerFired(Timer*); Timer m_elementDataCacheClearTimer; OwnPtr m_elementDataCache; AnimationClock m_animationClock; RefPtr m_timeline; PendingAnimations m_pendingAnimations; RefPtr m_templateDocument; // With Oilpan the templateDocument and the templateDocumentHost // live and die together. Without Oilpan, the templateDocumentHost // is a manually managed backpointer from m_templateDocument. RawPtr m_templateDocumentHost; bool m_hasViewportUnits; int m_styleRecalcElementCounter; mutable DocumentLoadTiming m_documentLoadTiming; RefPtr m_picture; FrameView* m_frameView; }; inline void Document::scheduleRenderTreeUpdateIfNeeded() { // Inline early out to avoid the function calls below. if (hasPendingStyleRecalc()) return; if (shouldScheduleRenderTreeUpdate() && needsRenderTreeUpdate()) scheduleRenderTreeUpdate(); } DEFINE_TYPE_CASTS(Document, ExecutionContextClient, client, client->isDocument(), client.isDocument()); DEFINE_TYPE_CASTS(Document, ExecutionContext, context, context->isDocument(), context.isDocument()); DEFINE_NODE_TYPE_CASTS(Document, isDocumentNode()); #define DEFINE_DOCUMENT_TYPE_CASTS(thisType) \ DEFINE_TYPE_CASTS(thisType, Document, document, document->is##thisType(), document.is##thisType()) // This is needed to avoid ambiguous overloads with the Node and TreeScope versions. DEFINE_COMPARISON_OPERATORS_WITH_REFERENCES(Document) // Put these methods here, because they require the Document definition, but we really want to inline them. inline bool Node::isDocumentNode() const { return this == document(); } } // namespace blink #ifndef NDEBUG // Outside the WebCore namespace for ease of invocation from gdb. void showLiveDocumentInstances(); #endif #endif // SKY_ENGINE_CORE_DOM_DOCUMENT_H_