From 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c Mon Sep 17 00:00:00 2001 From: Lorry Tar Creator Date: Tue, 27 Jun 2017 06:07:23 +0000 Subject: webkitgtk-2.16.5 --- Source/WebCore/dom/ActiveDOMCallback.cpp | 53 + Source/WebCore/dom/ActiveDOMCallback.h | 52 + Source/WebCore/dom/ActiveDOMCallbackMicrotask.cpp | 57 + Source/WebCore/dom/ActiveDOMCallbackMicrotask.h | 52 + Source/WebCore/dom/ActiveDOMObject.cpp | 31 +- Source/WebCore/dom/ActiveDOMObject.h | 60 +- Source/WebCore/dom/AllDescendantsCollection.h | 48 + Source/WebCore/dom/AnimationEvent.cpp | 64 + Source/WebCore/dom/AnimationEvent.h | 64 + Source/WebCore/dom/AnimationEvent.idl | 43 + Source/WebCore/dom/Attr.cpp | 107 +- Source/WebCore/dom/Attr.h | 60 +- Source/WebCore/dom/Attr.idl | 24 +- Source/WebCore/dom/Attribute.h | 21 +- Source/WebCore/dom/AutocompleteErrorEvent.h | 79 + Source/WebCore/dom/AutocompleteErrorEvent.idl | 35 + Source/WebCore/dom/BeforeLoadEvent.h | 42 +- Source/WebCore/dom/BeforeLoadEvent.idl | 9 +- Source/WebCore/dom/BeforeTextInsertedEvent.cpp | 6 +- Source/WebCore/dom/BeforeTextInsertedEvent.h | 23 +- Source/WebCore/dom/BeforeUnloadEvent.cpp | 2 +- Source/WebCore/dom/BeforeUnloadEvent.h | 21 +- Source/WebCore/dom/BeforeUnloadEvent.idl | 2 +- Source/WebCore/dom/CDATASection.cpp | 12 +- Source/WebCore/dom/CDATASection.h | 25 +- Source/WebCore/dom/CDATASection.idl | 4 +- Source/WebCore/dom/CharacterData.cpp | 178 +- Source/WebCore/dom/CharacterData.h | 48 +- Source/WebCore/dom/CharacterData.idl | 24 +- Source/WebCore/dom/CheckedRadioButtons.cpp | 270 -- Source/WebCore/dom/CheckedRadioButtons.h | 53 - Source/WebCore/dom/ChildListMutationScope.cpp | 31 +- Source/WebCore/dom/ChildListMutationScope.h | 18 +- Source/WebCore/dom/ChildNode.idl | 14 +- Source/WebCore/dom/ChildNodeList.cpp | 40 +- Source/WebCore/dom/ChildNodeList.h | 44 +- Source/WebCore/dom/ClassCollection.cpp | 49 + Source/WebCore/dom/ClassCollection.h | 71 + Source/WebCore/dom/ClassNodeList.cpp | 55 - Source/WebCore/dom/ClassNodeList.h | 75 - Source/WebCore/dom/ClientRect.cpp | 4 +- Source/WebCore/dom/ClientRect.h | 23 +- Source/WebCore/dom/ClientRect.idl | 22 +- Source/WebCore/dom/ClientRectList.cpp | 17 +- Source/WebCore/dom/ClientRectList.h | 23 +- Source/WebCore/dom/ClientRectList.idl | 7 +- Source/WebCore/dom/Clipboard.cpp | 428 -- Source/WebCore/dom/Clipboard.h | 123 - Source/WebCore/dom/Clipboard.idl | 44 - Source/WebCore/dom/ClipboardAccessPolicy.h | 37 - Source/WebCore/dom/ClipboardEvent.cpp | 15 +- Source/WebCore/dom/ClipboardEvent.h | 45 +- Source/WebCore/dom/ClipboardEvent.idl | 35 + Source/WebCore/dom/CollectionIndexCache.cpp | 44 + Source/WebCore/dom/CollectionIndexCache.h | 178 +- Source/WebCore/dom/Comment.cpp | 15 +- Source/WebCore/dom/Comment.h | 24 +- Source/WebCore/dom/Comment.idl | 5 +- Source/WebCore/dom/ComposedTreeAncestorIterator.h | 131 + Source/WebCore/dom/ComposedTreeIterator.cpp | 241 + Source/WebCore/dom/ComposedTreeIterator.h | 202 + Source/WebCore/dom/CompositionEvent.cpp | 23 +- Source/WebCore/dom/CompositionEvent.h | 43 +- Source/WebCore/dom/CompositionEvent.idl | 23 +- Source/WebCore/dom/ContainerNode.cpp | 1125 ++--- Source/WebCore/dom/ContainerNode.h | 256 +- Source/WebCore/dom/ContainerNodeAlgorithms.cpp | 211 +- Source/WebCore/dom/ContainerNodeAlgorithms.h | 240 +- Source/WebCore/dom/ContextDestructionObserver.cpp | 14 +- Source/WebCore/dom/ContextDestructionObserver.h | 17 +- Source/WebCore/dom/CrossThreadTask.h | 476 -- Source/WebCore/dom/CurrentScriptIncrementer.h | 27 +- Source/WebCore/dom/CustomElementReactionQueue.cpp | 293 ++ Source/WebCore/dom/CustomElementReactionQueue.h | 106 + Source/WebCore/dom/CustomElementRegistry.cpp | 116 + Source/WebCore/dom/CustomElementRegistry.h | 82 + Source/WebCore/dom/CustomElementRegistry.idl | 34 + Source/WebCore/dom/CustomEvent.cpp | 37 +- Source/WebCore/dom/CustomEvent.h | 47 +- Source/WebCore/dom/CustomEvent.idl | 20 +- Source/WebCore/dom/DOMAllInOne.cpp | 171 + Source/WebCore/dom/DOMCoreException.cpp | 89 +- Source/WebCore/dom/DOMCoreException.h | 15 +- Source/WebCore/dom/DOMCoreException.idl | 70 +- Source/WebCore/dom/DOMError.cpp | 5 +- Source/WebCore/dom/DOMError.h | 17 +- Source/WebCore/dom/DOMError.idl | 3 +- Source/WebCore/dom/DOMExceptions.in | 9 +- Source/WebCore/dom/DOMImplementation.cpp | 314 +- Source/WebCore/dom/DOMImplementation.h | 54 +- Source/WebCore/dom/DOMImplementation.idl | 29 +- Source/WebCore/dom/DOMNamedFlowCollection.cpp | 76 +- Source/WebCore/dom/DOMNamedFlowCollection.h | 44 +- Source/WebCore/dom/DOMNamedFlowCollection.idl | 9 +- Source/WebCore/dom/DOMPoint.h | 56 + Source/WebCore/dom/DOMPoint.idl | 46 + Source/WebCore/dom/DOMPointInit.h | 42 + Source/WebCore/dom/DOMPointInit.idl | 36 + Source/WebCore/dom/DOMPointReadOnly.h | 68 + Source/WebCore/dom/DOMPointReadOnly.idl | 51 + Source/WebCore/dom/DOMRect.h | 51 + Source/WebCore/dom/DOMRect.idl | 41 + Source/WebCore/dom/DOMRectInit.h | 37 + Source/WebCore/dom/DOMRectInit.idl | 33 + Source/WebCore/dom/DOMRectReadOnly.h | 69 + Source/WebCore/dom/DOMRectReadOnly.idl | 47 + Source/WebCore/dom/DOMStringList.cpp | 5 +- Source/WebCore/dom/DOMStringList.h | 11 +- Source/WebCore/dom/DOMStringList.idl | 9 +- Source/WebCore/dom/DOMStringMap.h | 7 +- Source/WebCore/dom/DOMStringMap.idl | 8 +- Source/WebCore/dom/DOMTimeStamp.h | 5 +- Source/WebCore/dom/DataTransfer.cpp | 447 ++ Source/WebCore/dom/DataTransfer.h | 119 + Source/WebCore/dom/DataTransfer.idl | 46 + Source/WebCore/dom/DataTransferAccessPolicy.h | 34 + Source/WebCore/dom/DataTransferItem.h | 11 +- Source/WebCore/dom/DataTransferItem.idl | 2 +- Source/WebCore/dom/DataTransferItemList.h | 19 +- Source/WebCore/dom/DataTransferItemList.idl | 7 +- Source/WebCore/dom/DatasetDOMStringMap.cpp | 109 +- Source/WebCore/dom/DatasetDOMStringMap.h | 26 +- Source/WebCore/dom/DecodedDataDocumentParser.h | 13 +- Source/WebCore/dom/DeviceMotionClient.h | 5 +- Source/WebCore/dom/DeviceMotionController.cpp | 10 +- Source/WebCore/dom/DeviceMotionController.h | 19 +- Source/WebCore/dom/DeviceMotionData.cpp | 60 +- Source/WebCore/dom/DeviceMotionData.h | 106 +- Source/WebCore/dom/DeviceMotionEvent.cpp | 67 +- Source/WebCore/dom/DeviceMotionEvent.h | 48 +- Source/WebCore/dom/DeviceMotionEvent.idl | 46 +- Source/WebCore/dom/DeviceOrientationClient.h | 8 +- Source/WebCore/dom/DeviceOrientationController.cpp | 10 +- Source/WebCore/dom/DeviceOrientationController.h | 20 +- Source/WebCore/dom/DeviceOrientationData.cpp | 122 +- Source/WebCore/dom/DeviceOrientationData.h | 66 +- Source/WebCore/dom/DeviceOrientationEvent.cpp | 50 +- Source/WebCore/dom/DeviceOrientationEvent.h | 36 +- Source/WebCore/dom/DeviceOrientationEvent.idl | 42 +- Source/WebCore/dom/Document.cpp | 4910 ++++++++++++-------- Source/WebCore/dom/Document.h | 1385 +++--- Source/WebCore/dom/Document.idl | 407 +- Source/WebCore/dom/DocumentEventQueue.cpp | 34 +- Source/WebCore/dom/DocumentEventQueue.h | 23 +- Source/WebCore/dom/DocumentFragment.cpp | 53 +- Source/WebCore/dom/DocumentFragment.h | 34 +- Source/WebCore/dom/DocumentFragment.idl | 14 +- Source/WebCore/dom/DocumentMarker.cpp | 159 - Source/WebCore/dom/DocumentMarker.h | 180 +- Source/WebCore/dom/DocumentMarkerController.cpp | 420 +- Source/WebCore/dom/DocumentMarkerController.h | 41 +- Source/WebCore/dom/DocumentOrShadowRoot.idl | 35 + Source/WebCore/dom/DocumentOrderedMap.cpp | 111 +- Source/WebCore/dom/DocumentOrderedMap.h | 26 +- Source/WebCore/dom/DocumentParser.cpp | 2 +- Source/WebCore/dom/DocumentParser.h | 15 +- Source/WebCore/dom/DocumentSharedObjectPool.cpp | 14 +- Source/WebCore/dom/DocumentSharedObjectPool.h | 21 +- .../WebCore/dom/DocumentStyleSheetCollection.cpp | 520 --- Source/WebCore/dom/DocumentStyleSheetCollection.h | 173 - Source/WebCore/dom/DocumentTiming.h | 30 +- Source/WebCore/dom/DocumentType.cpp | 15 +- Source/WebCore/dom/DocumentType.h | 34 +- Source/WebCore/dom/DocumentType.idl | 15 +- Source/WebCore/dom/Element.cpp | 2678 +++++++---- Source/WebCore/dom/Element.h | 630 ++- Source/WebCore/dom/Element.idl | 298 +- Source/WebCore/dom/ElementAncestorIterator.h | 19 +- .../WebCore/dom/ElementAndTextDescendantIterator.h | 321 ++ Source/WebCore/dom/ElementChildIterator.h | 46 +- Source/WebCore/dom/ElementData.cpp | 73 +- Source/WebCore/dom/ElementData.h | 114 +- Source/WebCore/dom/ElementDescendantIterator.h | 349 +- Source/WebCore/dom/ElementIterator.h | 69 +- Source/WebCore/dom/ElementIteratorAssertions.h | 37 +- Source/WebCore/dom/ElementRareData.cpp | 15 +- Source/WebCore/dom/ElementRareData.h | 132 +- Source/WebCore/dom/ElementTraversal.h | 321 +- Source/WebCore/dom/Entity.h | 43 - Source/WebCore/dom/Entity.idl | 26 - Source/WebCore/dom/EntityReference.cpp | 54 - Source/WebCore/dom/EntityReference.h | 45 - Source/WebCore/dom/EntityReference.idl | 22 - Source/WebCore/dom/ErrorEvent.cpp | 58 +- Source/WebCore/dom/ErrorEvent.h | 56 +- Source/WebCore/dom/ErrorEvent.idl | 22 +- Source/WebCore/dom/Event.cpp | 130 +- Source/WebCore/dom/Event.h | 152 +- Source/WebCore/dom/Event.idl | 85 +- Source/WebCore/dom/EventContext.cpp | 45 +- Source/WebCore/dom/EventContext.h | 135 +- Source/WebCore/dom/EventDispatcher.cpp | 444 +- Source/WebCore/dom/EventDispatcher.h | 14 +- Source/WebCore/dom/EventException.cpp | 60 - Source/WebCore/dom/EventException.h | 62 - Source/WebCore/dom/EventException.idl | 49 - Source/WebCore/dom/EventFactory.h | 43 - Source/WebCore/dom/EventInit.h | 36 + Source/WebCore/dom/EventInit.idl | 30 + Source/WebCore/dom/EventListener.h | 75 +- Source/WebCore/dom/EventListener.idl | 11 +- Source/WebCore/dom/EventListenerMap.cpp | 202 +- Source/WebCore/dom/EventListenerMap.h | 50 +- Source/WebCore/dom/EventModifierInit.h | 42 + Source/WebCore/dom/EventModifierInit.idl | 45 + Source/WebCore/dom/EventNames.cpp | 7 +- Source/WebCore/dom/EventNames.h | 409 +- Source/WebCore/dom/EventNames.in | 47 +- Source/WebCore/dom/EventPath.cpp | 406 ++ Source/WebCore/dom/EventPath.h | 74 + Source/WebCore/dom/EventQueue.h | 13 +- Source/WebCore/dom/EventSender.h | 46 +- Source/WebCore/dom/EventTarget.cpp | 357 +- Source/WebCore/dom/EventTarget.h | 329 +- Source/WebCore/dom/EventTarget.idl | 29 +- Source/WebCore/dom/EventTargetFactory.in | 21 +- Source/WebCore/dom/Exception.h | 62 + Source/WebCore/dom/ExceptionBase.cpp | 32 +- Source/WebCore/dom/ExceptionBase.h | 16 +- Source/WebCore/dom/ExceptionCode.h | 104 +- Source/WebCore/dom/ExceptionCodePlaceholder.cpp | 52 - Source/WebCore/dom/ExceptionCodePlaceholder.h | 86 - Source/WebCore/dom/ExceptionOr.h | 170 + Source/WebCore/dom/ExtensionStyleSheets.cpp | 213 + Source/WebCore/dom/ExtensionStyleSheets.h | 96 + Source/WebCore/dom/FocusEvent.cpp | 17 +- Source/WebCore/dom/FocusEvent.h | 54 +- Source/WebCore/dom/FocusEvent.idl | 9 +- Source/WebCore/dom/FragmentScriptingPermission.h | 5 +- Source/WebCore/dom/GenericEventQueue.cpp | 62 +- Source/WebCore/dom/GenericEventQueue.h | 29 +- Source/WebCore/dom/GlobalEventHandlers.idl | 116 + Source/WebCore/dom/HashChangeEvent.h | 39 +- Source/WebCore/dom/HashChangeEvent.idl | 22 +- Source/WebCore/dom/IconURL.cpp | 53 - Source/WebCore/dom/IconURL.h | 82 - Source/WebCore/dom/IdTargetObserver.h | 5 +- Source/WebCore/dom/IdTargetObserverRegistry.cpp | 15 +- Source/WebCore/dom/IdTargetObserverRegistry.h | 15 +- .../dom/IgnoreDestructiveWriteCountIncrementer.h | 9 +- .../dom/IgnoreOpensDuringUnloadCountIncrementer.h | 54 + Source/WebCore/dom/InlineClassicScript.cpp | 45 + Source/WebCore/dom/InlineClassicScript.h | 48 + Source/WebCore/dom/InlineStyleSheetOwner.cpp | 163 +- Source/WebCore/dom/InlineStyleSheetOwner.h | 24 +- Source/WebCore/dom/InputEvent.cpp | 63 + Source/WebCore/dom/InputEvent.h | 67 + Source/WebCore/dom/InputEvent.idl | 39 + Source/WebCore/dom/KeyboardEvent.cpp | 90 +- Source/WebCore/dom/KeyboardEvent.h | 136 +- Source/WebCore/dom/KeyboardEvent.idl | 126 +- Source/WebCore/dom/LiveNodeList.cpp | 150 +- Source/WebCore/dom/LiveNodeList.h | 148 +- Source/WebCore/dom/LoadableClassicScript.cpp | 120 + Source/WebCore/dom/LoadableClassicScript.h | 74 + Source/WebCore/dom/LoadableModuleScript.cpp | 103 + Source/WebCore/dom/LoadableModuleScript.h | 74 + Source/WebCore/dom/LoadableScript.cpp | 63 + Source/WebCore/dom/LoadableScript.h | 81 + Source/WebCore/dom/LoadableScriptClient.h | 39 + Source/WebCore/dom/MessageChannel.cpp | 4 +- Source/WebCore/dom/MessageChannel.h | 12 +- Source/WebCore/dom/MessageChannel.idl | 7 +- Source/WebCore/dom/MessageEvent.cpp | 150 +- Source/WebCore/dom/MessageEvent.h | 107 +- Source/WebCore/dom/MessageEvent.idl | 70 +- Source/WebCore/dom/MessagePort.cpp | 139 +- Source/WebCore/dom/MessagePort.h | 119 +- Source/WebCore/dom/MessagePort.idl | 33 +- Source/WebCore/dom/MessagePortChannel.cpp | 35 - Source/WebCore/dom/MessagePortChannel.h | 34 +- Source/WebCore/dom/Microtasks.cpp | 98 + Source/WebCore/dom/Microtasks.h | 74 + Source/WebCore/dom/MouseEvent.cpp | 195 +- Source/WebCore/dom/MouseEvent.h | 125 +- Source/WebCore/dom/MouseEvent.idl | 74 +- Source/WebCore/dom/MouseEventInit.h | 39 + Source/WebCore/dom/MouseEventInit.idl | 37 + Source/WebCore/dom/MouseRelatedEvent.cpp | 51 +- Source/WebCore/dom/MouseRelatedEvent.h | 115 +- Source/WebCore/dom/MutationCallback.h | 11 +- Source/WebCore/dom/MutationEvent.cpp | 22 +- Source/WebCore/dom/MutationEvent.h | 74 +- Source/WebCore/dom/MutationEvent.idl | 30 +- Source/WebCore/dom/MutationObserver.cpp | 197 +- Source/WebCore/dom/MutationObserver.h | 62 +- Source/WebCore/dom/MutationObserver.idl | 12 +- .../WebCore/dom/MutationObserverInterestGroup.cpp | 44 +- Source/WebCore/dom/MutationObserverInterestGroup.h | 30 +- .../WebCore/dom/MutationObserverRegistration.cpp | 55 +- Source/WebCore/dom/MutationObserverRegistration.h | 28 +- Source/WebCore/dom/MutationRecord.cpp | 89 +- Source/WebCore/dom/MutationRecord.h | 14 +- Source/WebCore/dom/MutationRecord.idl | 6 +- Source/WebCore/dom/NameNodeList.cpp | 9 +- Source/WebCore/dom/NameNodeList.h | 24 +- Source/WebCore/dom/NamedFlowCollection.cpp | 35 +- Source/WebCore/dom/NamedFlowCollection.h | 16 +- Source/WebCore/dom/NamedNodeMap.cpp | 69 +- Source/WebCore/dom/NamedNodeMap.h | 51 +- Source/WebCore/dom/NamedNodeMap.idl | 31 +- Source/WebCore/dom/NativeNodeFilter.cpp | 41 + Source/WebCore/dom/NativeNodeFilter.h | 58 + Source/WebCore/dom/NoEventDispatchAssertion.h | 142 + Source/WebCore/dom/Node.cpp | 1645 ++++--- Source/WebCore/dom/Node.h | 554 ++- Source/WebCore/dom/Node.idl | 188 +- Source/WebCore/dom/NodeConstants.h | 52 + Source/WebCore/dom/NodeFilter.cpp | 38 - Source/WebCore/dom/NodeFilter.h | 100 +- Source/WebCore/dom/NodeFilter.idl | 45 +- Source/WebCore/dom/NodeFilterCondition.cpp | 2 +- Source/WebCore/dom/NodeFilterCondition.h | 22 +- Source/WebCore/dom/NodeIterator.cpp | 106 +- Source/WebCore/dom/NodeIterator.h | 68 +- Source/WebCore/dom/NodeIterator.idl | 10 +- Source/WebCore/dom/NodeList.h | 18 +- Source/WebCore/dom/NodeList.idl | 10 +- Source/WebCore/dom/NodeRareData.h | 260 +- Source/WebCore/dom/NodeRenderStyle.h | 17 +- Source/WebCore/dom/NodeRenderingTraversal.cpp | 310 -- Source/WebCore/dom/NodeRenderingTraversal.h | 81 - Source/WebCore/dom/NodeTraversal.cpp | 169 +- Source/WebCore/dom/NodeTraversal.h | 115 +- Source/WebCore/dom/NodeWithIndex.h | 11 +- Source/WebCore/dom/NonDocumentTypeChildNode.idl | 33 + Source/WebCore/dom/NonElementParentNode.idl | 32 + Source/WebCore/dom/Notation.cpp | 57 - Source/WebCore/dom/Notation.h | 51 - Source/WebCore/dom/Notation.idl | 24 - Source/WebCore/dom/OverflowEvent.cpp | 20 +- Source/WebCore/dom/OverflowEvent.h | 47 +- Source/WebCore/dom/OverflowEvent.idl | 23 +- Source/WebCore/dom/PageTransitionEvent.cpp | 16 +- Source/WebCore/dom/PageTransitionEvent.h | 35 +- Source/WebCore/dom/PageTransitionEvent.idl | 7 +- Source/WebCore/dom/ParentNode.idl | 43 + Source/WebCore/dom/PendingScript.cpp | 73 +- Source/WebCore/dom/PendingScript.h | 101 +- Source/WebCore/dom/PendingScriptClient.h | 39 + Source/WebCore/dom/PopStateEvent.cpp | 49 +- Source/WebCore/dom/PopStateEvent.h | 44 +- Source/WebCore/dom/PopStateEvent.idl | 13 +- Source/WebCore/dom/Position.cpp | 784 ++-- Source/WebCore/dom/Position.h | 118 +- Source/WebCore/dom/PositionIterator.cpp | 36 +- Source/WebCore/dom/PositionIterator.h | 20 +- Source/WebCore/dom/ProcessingInstruction.cpp | 137 +- Source/WebCore/dom/ProcessingInstruction.h | 54 +- Source/WebCore/dom/ProcessingInstruction.idl | 8 +- Source/WebCore/dom/ProgressEvent.cpp | 24 +- Source/WebCore/dom/ProgressEvent.h | 42 +- Source/WebCore/dom/ProgressEvent.idl | 19 +- Source/WebCore/dom/PseudoElement.cpp | 40 +- Source/WebCore/dom/PseudoElement.h | 41 +- Source/WebCore/dom/QualifiedName.cpp | 46 +- Source/WebCore/dom/QualifiedName.h | 49 +- Source/WebCore/dom/RadioButtonGroups.cpp | 323 ++ Source/WebCore/dom/RadioButtonGroups.h | 51 + Source/WebCore/dom/Range.cpp | 1867 +++----- Source/WebCore/dom/Range.h | 175 +- Source/WebCore/dom/Range.idl | 103 +- Source/WebCore/dom/RangeBoundaryPoint.h | 99 +- Source/WebCore/dom/RangeException.cpp | 60 - Source/WebCore/dom/RangeException.h | 58 - Source/WebCore/dom/RangeException.idl | 38 - Source/WebCore/dom/RawDataDocumentParser.h | 15 +- Source/WebCore/dom/RegisteredEventListener.cpp | 29 - Source/WebCore/dom/RegisteredEventListener.h | 56 +- Source/WebCore/dom/RenderedDocumentMarker.h | 58 +- Source/WebCore/dom/RequestAnimationFrameCallback.h | 7 +- .../WebCore/dom/RequestAnimationFrameCallback.idl | 11 +- Source/WebCore/dom/ScopedEventQueue.cpp | 36 +- Source/WebCore/dom/ScopedEventQueue.h | 26 +- Source/WebCore/dom/ScriptElement.cpp | 425 +- Source/WebCore/dom/ScriptElement.h | 79 +- .../dom/ScriptElementCachedScriptFetcher.cpp | 42 + .../WebCore/dom/ScriptElementCachedScriptFetcher.h | 52 + Source/WebCore/dom/ScriptExecutionContext.cpp | 476 +- Source/WebCore/dom/ScriptExecutionContext.h | 216 +- Source/WebCore/dom/ScriptRunner.cpp | 72 +- Source/WebCore/dom/ScriptRunner.h | 32 +- Source/WebCore/dom/ScriptableDocumentParser.cpp | 40 +- Source/WebCore/dom/ScriptableDocumentParser.h | 29 +- Source/WebCore/dom/ScriptedAnimationController.cpp | 85 +- Source/WebCore/dom/ScriptedAnimationController.h | 59 +- Source/WebCore/dom/SecurityContext.cpp | 56 +- Source/WebCore/dom/SecurityContext.h | 44 +- Source/WebCore/dom/SecurityOriginPolicy.cpp | 47 + Source/WebCore/dom/SecurityOriginPolicy.h | 49 + Source/WebCore/dom/SecurityPolicyViolationEvent.h | 77 +- .../WebCore/dom/SecurityPolicyViolationEvent.idl | 35 +- Source/WebCore/dom/SelectorQuery.cpp | 483 +- Source/WebCore/dom/SelectorQuery.h | 86 +- Source/WebCore/dom/ShadowRoot.cpp | 160 +- Source/WebCore/dom/ShadowRoot.h | 120 +- Source/WebCore/dom/ShadowRoot.idl | 74 +- Source/WebCore/dom/ShadowRootMode.h | 36 + Source/WebCore/dom/ShadowRootMode.idl | 31 + Source/WebCore/dom/SimulatedClick.cpp | 111 + Source/WebCore/dom/SimulatedClick.h | 42 + Source/WebCore/dom/SimulatedClickOptions.h | 5 +- Source/WebCore/dom/SlotAssignment.cpp | 262 ++ Source/WebCore/dom/SlotAssignment.h | 126 + Source/WebCore/dom/Slotable.idl | 32 + Source/WebCore/dom/SpaceSplitString.cpp | 88 +- Source/WebCore/dom/SpaceSplitString.h | 30 +- Source/WebCore/dom/StaticNodeList.cpp | 28 +- Source/WebCore/dom/StaticNodeList.h | 52 +- Source/WebCore/dom/StaticRange.cpp | 71 + Source/WebCore/dom/StaticRange.h | 58 + Source/WebCore/dom/StaticRange.idl | 35 + Source/WebCore/dom/StringCallback.cpp | 32 +- Source/WebCore/dom/StringCallback.h | 5 +- Source/WebCore/dom/StringCallback.idl | 4 +- Source/WebCore/dom/StyledElement.cpp | 260 +- Source/WebCore/dom/StyledElement.h | 51 +- Source/WebCore/dom/SuccessOr.h | 41 + Source/WebCore/dom/TagCollection.cpp | 69 + Source/WebCore/dom/TagCollection.h | 103 + Source/WebCore/dom/TagNodeList.cpp | 67 - Source/WebCore/dom/TagNodeList.h | 91 - .../WebCore/dom/TemplateContentDocumentFragment.h | 19 +- Source/WebCore/dom/Text.cpp | 148 +- Source/WebCore/dom/Text.h | 45 +- Source/WebCore/dom/Text.idl | 23 +- Source/WebCore/dom/TextDecoder.cpp | 148 + Source/WebCore/dom/TextDecoder.h | 64 + Source/WebCore/dom/TextDecoder.idl | 45 + Source/WebCore/dom/TextEncoder.cpp | 46 + Source/WebCore/dom/TextEncoder.h | 44 + Source/WebCore/dom/TextEncoder.idl | 35 + Source/WebCore/dom/TextEvent.cpp | 51 +- Source/WebCore/dom/TextEvent.h | 43 +- Source/WebCore/dom/TextEvent.idl | 15 +- Source/WebCore/dom/TextEventInputType.h | 6 +- Source/WebCore/dom/TextNodeTraversal.cpp | 16 +- Source/WebCore/dom/TextNodeTraversal.h | 91 +- Source/WebCore/dom/Touch.cpp | 10 +- Source/WebCore/dom/Touch.h | 16 +- Source/WebCore/dom/Touch.idl | 26 +- Source/WebCore/dom/TouchEvent.cpp | 14 +- Source/WebCore/dom/TouchEvent.h | 65 +- Source/WebCore/dom/TouchEvent.idl | 36 +- Source/WebCore/dom/TouchList.cpp | 6 +- Source/WebCore/dom/TouchList.h | 17 +- Source/WebCore/dom/TouchList.idl | 2 +- Source/WebCore/dom/TransformSource.h | 28 +- Source/WebCore/dom/TransformSourceLibxslt.cpp | 2 +- Source/WebCore/dom/TransitionEvent.cpp | 20 +- Source/WebCore/dom/TransitionEvent.h | 44 +- Source/WebCore/dom/TransitionEvent.idl | 17 +- Source/WebCore/dom/Traversal.cpp | 11 +- Source/WebCore/dom/Traversal.h | 40 +- Source/WebCore/dom/TreeDepthLimit.h | 9 +- Source/WebCore/dom/TreeScope.cpp | 328 +- Source/WebCore/dom/TreeScope.h | 116 +- Source/WebCore/dom/TreeScopeAdopter.cpp | 91 +- Source/WebCore/dom/TreeScopeAdopter.h | 28 +- Source/WebCore/dom/TreeWalker.cpp | 208 +- Source/WebCore/dom/TreeWalker.h | 48 +- Source/WebCore/dom/TreeWalker.idl | 24 +- .../WebCore/dom/TypedElementDescendantIterator.h | 322 ++ Source/WebCore/dom/UIEvent.cpp | 37 +- Source/WebCore/dom/UIEvent.h | 47 +- Source/WebCore/dom/UIEvent.idl | 33 +- Source/WebCore/dom/UIEventInit.h | 39 + Source/WebCore/dom/UIEventInit.idl | 29 + Source/WebCore/dom/UIEventWithKeyState.cpp | 2 +- Source/WebCore/dom/UIEventWithKeyState.h | 84 +- Source/WebCore/dom/UserActionElementSet.cpp | 8 - Source/WebCore/dom/UserActionElementSet.h | 15 +- Source/WebCore/dom/UserGestureIndicator.cpp | 64 +- Source/WebCore/dom/UserGestureIndicator.h | 59 +- Source/WebCore/dom/UserTypingGestureIndicator.cpp | 2 +- Source/WebCore/dom/UserTypingGestureIndicator.h | 9 +- Source/WebCore/dom/ViewportArguments.cpp | 194 +- Source/WebCore/dom/ViewportArguments.h | 73 +- Source/WebCore/dom/VisitedLinkState.cpp | 36 +- Source/WebCore/dom/VisitedLinkState.h | 23 +- Source/WebCore/dom/WebKitAnimationEvent.cpp | 21 +- Source/WebCore/dom/WebKitAnimationEvent.h | 41 +- Source/WebCore/dom/WebKitAnimationEvent.idl | 14 +- Source/WebCore/dom/WebKitNamedFlow.cpp | 83 +- Source/WebCore/dom/WebKitNamedFlow.h | 29 +- Source/WebCore/dom/WebKitNamedFlow.idl | 19 +- Source/WebCore/dom/WebKitTransitionEvent.cpp | 20 +- Source/WebCore/dom/WebKitTransitionEvent.h | 43 +- Source/WebCore/dom/WebKitTransitionEvent.idl | 17 +- Source/WebCore/dom/WheelEvent.cpp | 69 +- Source/WebCore/dom/WheelEvent.h | 94 +- Source/WebCore/dom/WheelEvent.idl | 65 +- Source/WebCore/dom/XMLDocument.h | 55 + Source/WebCore/dom/XMLDocument.idl | 29 + .../dom/default/PlatformMessagePortChannel.cpp | 81 +- .../dom/default/PlatformMessagePortChannel.h | 48 +- Source/WebCore/dom/make_dom_exceptions.pl | 18 +- Source/WebCore/dom/make_event_factory.pl | 25 +- Source/WebCore/dom/make_names.pl | 407 +- 499 files changed, 28135 insertions(+), 22869 deletions(-) create mode 100644 Source/WebCore/dom/ActiveDOMCallback.cpp create mode 100644 Source/WebCore/dom/ActiveDOMCallback.h create mode 100644 Source/WebCore/dom/ActiveDOMCallbackMicrotask.cpp create mode 100644 Source/WebCore/dom/ActiveDOMCallbackMicrotask.h create mode 100644 Source/WebCore/dom/AllDescendantsCollection.h create mode 100644 Source/WebCore/dom/AnimationEvent.cpp create mode 100644 Source/WebCore/dom/AnimationEvent.h create mode 100644 Source/WebCore/dom/AnimationEvent.idl create mode 100644 Source/WebCore/dom/AutocompleteErrorEvent.h create mode 100644 Source/WebCore/dom/AutocompleteErrorEvent.idl delete mode 100644 Source/WebCore/dom/CheckedRadioButtons.cpp delete mode 100644 Source/WebCore/dom/CheckedRadioButtons.h create mode 100644 Source/WebCore/dom/ClassCollection.cpp create mode 100644 Source/WebCore/dom/ClassCollection.h delete mode 100644 Source/WebCore/dom/ClassNodeList.cpp delete mode 100644 Source/WebCore/dom/ClassNodeList.h delete mode 100644 Source/WebCore/dom/Clipboard.cpp delete mode 100644 Source/WebCore/dom/Clipboard.h delete mode 100644 Source/WebCore/dom/Clipboard.idl delete mode 100644 Source/WebCore/dom/ClipboardAccessPolicy.h create mode 100644 Source/WebCore/dom/ClipboardEvent.idl create mode 100644 Source/WebCore/dom/CollectionIndexCache.cpp create mode 100644 Source/WebCore/dom/ComposedTreeAncestorIterator.h create mode 100644 Source/WebCore/dom/ComposedTreeIterator.cpp create mode 100644 Source/WebCore/dom/ComposedTreeIterator.h delete mode 100644 Source/WebCore/dom/CrossThreadTask.h create mode 100644 Source/WebCore/dom/CustomElementReactionQueue.cpp create mode 100644 Source/WebCore/dom/CustomElementReactionQueue.h create mode 100644 Source/WebCore/dom/CustomElementRegistry.cpp create mode 100644 Source/WebCore/dom/CustomElementRegistry.h create mode 100644 Source/WebCore/dom/CustomElementRegistry.idl create mode 100644 Source/WebCore/dom/DOMAllInOne.cpp create mode 100644 Source/WebCore/dom/DOMPoint.h create mode 100644 Source/WebCore/dom/DOMPoint.idl create mode 100644 Source/WebCore/dom/DOMPointInit.h create mode 100644 Source/WebCore/dom/DOMPointInit.idl create mode 100644 Source/WebCore/dom/DOMPointReadOnly.h create mode 100644 Source/WebCore/dom/DOMPointReadOnly.idl create mode 100644 Source/WebCore/dom/DOMRect.h create mode 100644 Source/WebCore/dom/DOMRect.idl create mode 100644 Source/WebCore/dom/DOMRectInit.h create mode 100644 Source/WebCore/dom/DOMRectInit.idl create mode 100644 Source/WebCore/dom/DOMRectReadOnly.h create mode 100644 Source/WebCore/dom/DOMRectReadOnly.idl create mode 100644 Source/WebCore/dom/DataTransfer.cpp create mode 100644 Source/WebCore/dom/DataTransfer.h create mode 100644 Source/WebCore/dom/DataTransfer.idl create mode 100644 Source/WebCore/dom/DataTransferAccessPolicy.h delete mode 100644 Source/WebCore/dom/DocumentMarker.cpp create mode 100644 Source/WebCore/dom/DocumentOrShadowRoot.idl delete mode 100644 Source/WebCore/dom/DocumentStyleSheetCollection.cpp delete mode 100644 Source/WebCore/dom/DocumentStyleSheetCollection.h create mode 100644 Source/WebCore/dom/ElementAndTextDescendantIterator.h delete mode 100644 Source/WebCore/dom/Entity.h delete mode 100644 Source/WebCore/dom/Entity.idl delete mode 100644 Source/WebCore/dom/EntityReference.cpp delete mode 100644 Source/WebCore/dom/EntityReference.h delete mode 100644 Source/WebCore/dom/EntityReference.idl delete mode 100644 Source/WebCore/dom/EventException.cpp delete mode 100644 Source/WebCore/dom/EventException.h delete mode 100644 Source/WebCore/dom/EventException.idl delete mode 100644 Source/WebCore/dom/EventFactory.h create mode 100644 Source/WebCore/dom/EventInit.h create mode 100644 Source/WebCore/dom/EventInit.idl create mode 100644 Source/WebCore/dom/EventModifierInit.h create mode 100644 Source/WebCore/dom/EventModifierInit.idl create mode 100644 Source/WebCore/dom/EventPath.cpp create mode 100644 Source/WebCore/dom/EventPath.h create mode 100644 Source/WebCore/dom/Exception.h delete mode 100644 Source/WebCore/dom/ExceptionCodePlaceholder.cpp delete mode 100644 Source/WebCore/dom/ExceptionCodePlaceholder.h create mode 100644 Source/WebCore/dom/ExceptionOr.h create mode 100644 Source/WebCore/dom/ExtensionStyleSheets.cpp create mode 100644 Source/WebCore/dom/ExtensionStyleSheets.h create mode 100644 Source/WebCore/dom/GlobalEventHandlers.idl delete mode 100644 Source/WebCore/dom/IconURL.cpp delete mode 100644 Source/WebCore/dom/IconURL.h create mode 100644 Source/WebCore/dom/IgnoreOpensDuringUnloadCountIncrementer.h create mode 100644 Source/WebCore/dom/InlineClassicScript.cpp create mode 100644 Source/WebCore/dom/InlineClassicScript.h create mode 100644 Source/WebCore/dom/InputEvent.cpp create mode 100644 Source/WebCore/dom/InputEvent.h create mode 100644 Source/WebCore/dom/InputEvent.idl create mode 100644 Source/WebCore/dom/LoadableClassicScript.cpp create mode 100644 Source/WebCore/dom/LoadableClassicScript.h create mode 100644 Source/WebCore/dom/LoadableModuleScript.cpp create mode 100644 Source/WebCore/dom/LoadableModuleScript.h create mode 100644 Source/WebCore/dom/LoadableScript.cpp create mode 100644 Source/WebCore/dom/LoadableScript.h create mode 100644 Source/WebCore/dom/LoadableScriptClient.h delete mode 100644 Source/WebCore/dom/MessagePortChannel.cpp create mode 100644 Source/WebCore/dom/Microtasks.cpp create mode 100644 Source/WebCore/dom/Microtasks.h create mode 100644 Source/WebCore/dom/MouseEventInit.h create mode 100644 Source/WebCore/dom/MouseEventInit.idl create mode 100644 Source/WebCore/dom/NativeNodeFilter.cpp create mode 100644 Source/WebCore/dom/NativeNodeFilter.h create mode 100644 Source/WebCore/dom/NoEventDispatchAssertion.h create mode 100644 Source/WebCore/dom/NodeConstants.h delete mode 100644 Source/WebCore/dom/NodeFilter.cpp delete mode 100644 Source/WebCore/dom/NodeRenderingTraversal.cpp delete mode 100644 Source/WebCore/dom/NodeRenderingTraversal.h create mode 100644 Source/WebCore/dom/NonDocumentTypeChildNode.idl create mode 100644 Source/WebCore/dom/NonElementParentNode.idl delete mode 100644 Source/WebCore/dom/Notation.cpp delete mode 100644 Source/WebCore/dom/Notation.h delete mode 100644 Source/WebCore/dom/Notation.idl create mode 100644 Source/WebCore/dom/ParentNode.idl create mode 100644 Source/WebCore/dom/PendingScriptClient.h create mode 100644 Source/WebCore/dom/RadioButtonGroups.cpp create mode 100644 Source/WebCore/dom/RadioButtonGroups.h delete mode 100644 Source/WebCore/dom/RangeException.cpp delete mode 100644 Source/WebCore/dom/RangeException.h delete mode 100644 Source/WebCore/dom/RangeException.idl delete mode 100644 Source/WebCore/dom/RegisteredEventListener.cpp create mode 100644 Source/WebCore/dom/ScriptElementCachedScriptFetcher.cpp create mode 100644 Source/WebCore/dom/ScriptElementCachedScriptFetcher.h create mode 100644 Source/WebCore/dom/SecurityOriginPolicy.cpp create mode 100644 Source/WebCore/dom/SecurityOriginPolicy.h create mode 100644 Source/WebCore/dom/ShadowRootMode.h create mode 100644 Source/WebCore/dom/ShadowRootMode.idl create mode 100644 Source/WebCore/dom/SimulatedClick.cpp create mode 100644 Source/WebCore/dom/SimulatedClick.h create mode 100644 Source/WebCore/dom/SlotAssignment.cpp create mode 100644 Source/WebCore/dom/SlotAssignment.h create mode 100644 Source/WebCore/dom/Slotable.idl create mode 100644 Source/WebCore/dom/StaticRange.cpp create mode 100644 Source/WebCore/dom/StaticRange.h create mode 100644 Source/WebCore/dom/StaticRange.idl create mode 100644 Source/WebCore/dom/SuccessOr.h create mode 100644 Source/WebCore/dom/TagCollection.cpp create mode 100644 Source/WebCore/dom/TagCollection.h delete mode 100644 Source/WebCore/dom/TagNodeList.cpp delete mode 100644 Source/WebCore/dom/TagNodeList.h create mode 100644 Source/WebCore/dom/TextDecoder.cpp create mode 100644 Source/WebCore/dom/TextDecoder.h create mode 100644 Source/WebCore/dom/TextDecoder.idl create mode 100644 Source/WebCore/dom/TextEncoder.cpp create mode 100644 Source/WebCore/dom/TextEncoder.h create mode 100644 Source/WebCore/dom/TextEncoder.idl create mode 100644 Source/WebCore/dom/TypedElementDescendantIterator.h create mode 100644 Source/WebCore/dom/UIEventInit.h create mode 100644 Source/WebCore/dom/UIEventInit.idl create mode 100644 Source/WebCore/dom/XMLDocument.h create mode 100644 Source/WebCore/dom/XMLDocument.idl (limited to 'Source/WebCore/dom') diff --git a/Source/WebCore/dom/ActiveDOMCallback.cpp b/Source/WebCore/dom/ActiveDOMCallback.cpp new file mode 100644 index 000000000..5b1741e13 --- /dev/null +++ b/Source/WebCore/dom/ActiveDOMCallback.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010. 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ActiveDOMCallback.h" + +#include "ScriptExecutionContext.h" + +namespace WebCore { + +ActiveDOMCallback::ActiveDOMCallback(ScriptExecutionContext* context) + : ContextDestructionObserver(context) +{ +} + +ActiveDOMCallback::~ActiveDOMCallback() +{ +} + +bool ActiveDOMCallback::canInvokeCallback() const +{ + ScriptExecutionContext* context = scriptExecutionContext(); + return context && !context->activeDOMObjectsAreSuspended() && !context->activeDOMObjectsAreStopped(); +} + +} // namespace WebCore diff --git a/Source/WebCore/dom/ActiveDOMCallback.h b/Source/WebCore/dom/ActiveDOMCallback.h new file mode 100644 index 000000000..566b40a1f --- /dev/null +++ b/Source/WebCore/dom/ActiveDOMCallback.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010, 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "ContextDestructionObserver.h" + +namespace WebCore { + +class ScriptExecutionContext; + +// A base class that prevents binding callbacks from executing when +// active dom objects are stopped or suspended. +// +// Should only be created, used, and destroyed on the script execution +// context thread. +class ActiveDOMCallback : public ContextDestructionObserver { +public: + ActiveDOMCallback(ScriptExecutionContext* context); + virtual ~ActiveDOMCallback(); + + bool canInvokeCallback() const; +}; + +} // namespace WebCore diff --git a/Source/WebCore/dom/ActiveDOMCallbackMicrotask.cpp b/Source/WebCore/dom/ActiveDOMCallbackMicrotask.cpp new file mode 100644 index 000000000..66f590a49 --- /dev/null +++ b/Source/WebCore/dom/ActiveDOMCallbackMicrotask.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ActiveDOMCallbackMicrotask.h" + +namespace WebCore { + +ActiveDOMCallbackMicrotask::ActiveDOMCallbackMicrotask(MicrotaskQueue& queue, ScriptExecutionContext& scriptExecutionContext, Function&& task) + : ActiveDOMCallback(&scriptExecutionContext) + , m_queue(queue) + , m_task(WTFMove(task)) +{ +} + +ActiveDOMCallbackMicrotask::~ActiveDOMCallbackMicrotask() +{ +} + +Microtask::Result ActiveDOMCallbackMicrotask::run() +{ + if (!canInvokeCallback()) + return Result::KeepInQueue; + + m_task(); + return Result::Done; +} + +void ActiveDOMCallbackMicrotask::contextDestroyed() +{ + // NOTE: Calling the function below will cause this to be destroyed. + removeSelfFromQueue(m_queue); +} + +} // namespace WebCore diff --git a/Source/WebCore/dom/ActiveDOMCallbackMicrotask.h b/Source/WebCore/dom/ActiveDOMCallbackMicrotask.h new file mode 100644 index 000000000..5f4688969 --- /dev/null +++ b/Source/WebCore/dom/ActiveDOMCallbackMicrotask.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015, 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "ActiveDOMCallback.h" +#include "Microtasks.h" +#include + +namespace WebCore { + +class ActiveDOMCallbackMicrotask final : public Microtask, public ActiveDOMCallback { + WTF_MAKE_FAST_ALLOCATED; +public: + WEBCORE_EXPORT ActiveDOMCallbackMicrotask(MicrotaskQueue&, ScriptExecutionContext&, WTF::Function&&); + WEBCORE_EXPORT virtual ~ActiveDOMCallbackMicrotask(); + + Result run() override; + +private: + void contextDestroyed() override; + + // FIXME: It should not be necessary to have the queue as a member. Instead, it should + // be accessed via the ScriptExecutionContext, which should hold a reference to the relevent + // queue. + MicrotaskQueue& m_queue; + WTF::Function m_task; +}; + +} // namespace WebCore diff --git a/Source/WebCore/dom/ActiveDOMObject.cpp b/Source/WebCore/dom/ActiveDOMObject.cpp index 0c6e8ed02..d6cfe2971 100644 --- a/Source/WebCore/dom/ActiveDOMObject.cpp +++ b/Source/WebCore/dom/ActiveDOMObject.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -28,8 +28,6 @@ #include "ActiveDOMObject.h" #include "ScriptExecutionContext.h" -#include "WorkerGlobalScope.h" -#include "WorkerThread.h" namespace WebCore { @@ -37,14 +35,14 @@ ActiveDOMObject::ActiveDOMObject(ScriptExecutionContext* scriptExecutionContext) : ContextDestructionObserver(scriptExecutionContext) , m_pendingActivityCount(0) #if !ASSERT_DISABLED - , m_suspendIfNeededCalled(false) + , m_suspendIfNeededWasCalled(false) #endif { if (!m_scriptExecutionContext) return; ASSERT(m_scriptExecutionContext->isContextThread()); - m_scriptExecutionContext->didCreateActiveDOMObject(this); + m_scriptExecutionContext->didCreateActiveDOMObject(*this); } ActiveDOMObject::~ActiveDOMObject() @@ -52,7 +50,7 @@ ActiveDOMObject::~ActiveDOMObject() if (!m_scriptExecutionContext) return; - ASSERT(m_suspendIfNeededCalled); + ASSERT(m_suspendIfNeededWasCalled); // ActiveDOMObject may be inherited by a sub-class whose life-cycle // exceeds that of the associated ScriptExecutionContext. In those cases, @@ -62,28 +60,37 @@ ActiveDOMObject::~ActiveDOMObject() // here. if (m_scriptExecutionContext) { ASSERT(m_scriptExecutionContext->isContextThread()); - m_scriptExecutionContext->willDestroyActiveDOMObject(this); + m_scriptExecutionContext->willDestroyActiveDOMObject(*this); } } void ActiveDOMObject::suspendIfNeeded() { #if !ASSERT_DISABLED - ASSERT(!m_suspendIfNeededCalled); - m_suspendIfNeededCalled = true; + ASSERT(!m_suspendIfNeededWasCalled); + m_suspendIfNeededWasCalled = true; #endif if (!m_scriptExecutionContext) return; - m_scriptExecutionContext->suspendActiveDOMObjectIfNeeded(this); + m_scriptExecutionContext->suspendActiveDOMObjectIfNeeded(*this); } +#if !ASSERT_DISABLED + +void ActiveDOMObject::assertSuspendIfNeededWasCalled() const +{ + ASSERT(m_suspendIfNeededWasCalled); +} + +#endif + bool ActiveDOMObject::hasPendingActivity() const { return m_pendingActivityCount; } -bool ActiveDOMObject::canSuspend() const +bool ActiveDOMObject::canSuspendForDocumentSuspension() const { return false; } diff --git a/Source/WebCore/dom/ActiveDOMObject.h b/Source/WebCore/dom/ActiveDOMObject.h index 5a1f3d121..c47b1f45a 100644 --- a/Source/WebCore/dom/ActiveDOMObject.h +++ b/Source/WebCore/dom/ActiveDOMObject.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -24,8 +24,7 @@ * */ -#ifndef ActiveDOMObject_h -#define ActiveDOMObject_h +#pragma once #include "ContextDestructionObserver.h" #include @@ -35,40 +34,46 @@ namespace WebCore { class ActiveDOMObject : public ContextDestructionObserver { public: - explicit ActiveDOMObject(ScriptExecutionContext*); - - // suspendIfNeeded() should be called exactly once after object construction to synchronize - // the suspend state with that in ScriptExecutionContext. + // The suspendIfNeeded must be called exactly once after object construction to update + // the suspended state to match that of the ScriptExecutionContext. void suspendIfNeeded(); -#if !ASSERT_DISABLED - bool suspendIfNeededCalled() const { return m_suspendIfNeededCalled; } -#endif + void assertSuspendIfNeededWasCalled() const; virtual bool hasPendingActivity() const; - // canSuspend() is used by the caller if there is a choice between suspending and stopping. - // For example, a page won't be suspended and placed in the back/forward cache if it has - // the objects that can not be suspended. - // However, 'suspend' can be called even if canSuspend() would return 'false'. That - // happens in step-by-step JS debugging for example - in this case it would be incorrect - // to stop the object. Exact semantics of suspend is up to the object then. + // The canSuspendForDocumentSuspension() function is used by the caller if there is a choice between suspending + // and stopping. For example, a page won't be suspended and placed in the back/forward + // cache if it contains any objects that cannot be suspended. + + // However, the suspend function will sometimes be called even if canSuspendForDocumentSuspension() returns false. + // That happens in step-by-step JS debugging for example - in this case it would be incorrect + // to stop the object. Exact semantics of suspend is up to the object in cases like that. + enum ReasonForSuspension { JavaScriptDebuggerPaused, WillDeferLoading, - DocumentWillBecomeInactive, + PageCache, PageWillBeSuspended, - DocumentWillBePaused }; - virtual bool canSuspend() const; + + virtual const char* activeDOMObjectName() const = 0; + + // These three functions must not have a side effect of creating or destroying + // any ActiveDOMObject. That means they must not result in calls to arbitrary JavaScript. + virtual bool canSuspendForDocumentSuspension() const = 0; // Returning false in canSuspendForDocumentSuspension() will prevent the page from entering the PageCache. virtual void suspend(ReasonForSuspension); virtual void resume(); + + // This function must not have a side effect of creating an ActiveDOMObject. + // That means it must not result in calls to arbitrary JavaScript. + // It can, however, have a side effect of deleting an ActiveDOMObject. virtual void stop(); template void setPendingActivity(T* thisObject) { ASSERT(thisObject == this); thisObject->ref(); - m_pendingActivityCount++; + ++m_pendingActivityCount; } template void unsetPendingActivity(T* thisObject) @@ -79,15 +84,22 @@ public: } protected: + explicit ActiveDOMObject(ScriptExecutionContext*); virtual ~ActiveDOMObject(); private: unsigned m_pendingActivityCount; #if !ASSERT_DISABLED - bool m_suspendIfNeededCalled; + bool m_suspendIfNeededWasCalled; #endif }; -} // namespace WebCore +#if ASSERT_DISABLED + +inline void ActiveDOMObject::assertSuspendIfNeededWasCalled() const +{ +} -#endif // ActiveDOMObject_h +#endif + +} // namespace WebCore diff --git a/Source/WebCore/dom/AllDescendantsCollection.h b/Source/WebCore/dom/AllDescendantsCollection.h new file mode 100644 index 000000000..22ed9d89b --- /dev/null +++ b/Source/WebCore/dom/AllDescendantsCollection.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "CachedHTMLCollection.h" + +namespace WebCore { + +class AllDescendantsCollection : public CachedHTMLCollection::traversalType> { +public: + static Ref create(ContainerNode& rootNode, CollectionType type) + { + ASSERT_UNUSED(type, type == AllDescendants); + return adoptRef(*new AllDescendantsCollection(rootNode, type)); + } + + bool elementMatches(Element&) const { return true; } + +protected: + AllDescendantsCollection(ContainerNode& rootNode, CollectionType type) + : CachedHTMLCollection::traversalType>(rootNode, type) + { } +}; + +} diff --git a/Source/WebCore/dom/AnimationEvent.cpp b/Source/WebCore/dom/AnimationEvent.cpp new file mode 100644 index 000000000..67d2006f9 --- /dev/null +++ b/Source/WebCore/dom/AnimationEvent.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AnimationEvent.h" + +namespace WebCore { + +AnimationEvent::AnimationEvent(const AtomicString& type, const Init& initializer, IsTrusted isTrusted) + : Event(type, initializer, isTrusted) + , m_animationName(initializer.animationName) + , m_elapsedTime(initializer.elapsedTime) +{ +} + +AnimationEvent::AnimationEvent(const AtomicString& type, const String& animationName, double elapsedTime) + : Event(type, true, false) + , m_animationName(animationName) + , m_elapsedTime(elapsedTime) +{ +} + +AnimationEvent::~AnimationEvent() +{ +} + +const String& AnimationEvent::animationName() const +{ + return m_animationName; +} + +double AnimationEvent::elapsedTime() const +{ + return m_elapsedTime; +} + +EventInterface AnimationEvent::eventInterface() const +{ + return AnimationEventInterfaceType; +} + +} // namespace WebCore diff --git a/Source/WebCore/dom/AnimationEvent.h b/Source/WebCore/dom/AnimationEvent.h new file mode 100644 index 000000000..52bebf428 --- /dev/null +++ b/Source/WebCore/dom/AnimationEvent.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "Event.h" + +namespace WebCore { + +class AnimationEvent final : public Event { +public: + static Ref create(const AtomicString& type, const String& animationName, double elapsedTime) + { + return adoptRef(*new AnimationEvent(type, animationName, elapsedTime)); + } + + struct Init : EventInit { + String animationName; + double elapsedTime { 0 }; + }; + + static Ref create(const AtomicString& type, const Init& initializer, IsTrusted isTrusted = IsTrusted::No) + { + return adoptRef(*new AnimationEvent(type, initializer, isTrusted)); + } + + virtual ~AnimationEvent(); + + const String& animationName() const; + double elapsedTime() const; + + EventInterface eventInterface() const override; + +private: + AnimationEvent(const AtomicString& type, const String& animationName, double elapsedTime); + AnimationEvent(const AtomicString&, const Init&, IsTrusted); + + String m_animationName; + double m_elapsedTime; +}; + +} // namespace WebCore diff --git a/Source/WebCore/dom/AnimationEvent.idl b/Source/WebCore/dom/AnimationEvent.idl new file mode 100644 index 000000000..a50c4cece --- /dev/null +++ b/Source/WebCore/dom/AnimationEvent.idl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +[ + Constructor(DOMString type, optional AnimationEventInit animationEventInitDict), +] interface AnimationEvent : Event { + readonly attribute DOMString animationName; + readonly attribute double elapsedTime; + + // FIXME: This is not supported yet. + // readonly attribute DOMString pseudoElement; +}; + +dictionary AnimationEventInit : EventInit { + DOMString animationName = ""; + double elapsedTime = 0.0; + + // FIXME: This is not supported yet. + // DOMString pseudoElement = ""; +}; + diff --git a/Source/WebCore/dom/Attr.cpp b/Source/WebCore/dom/Attr.cpp index ea9f35716..392f34220 100644 --- a/Source/WebCore/dom/Attr.cpp +++ b/Source/WebCore/dom/Attr.cpp @@ -23,7 +23,10 @@ #include "config.h" #include "Attr.h" +#include "AttributeChangeInvalidation.h" +#include "Event.h" #include "ExceptionCode.h" +#include "NoEventDispatchAssertion.h" #include "ScopedEventQueue.h" #include "StyleProperties.h" #include "StyledElement.h" @@ -36,35 +39,32 @@ namespace WebCore { using namespace HTMLNames; -Attr::Attr(Element* element, const QualifiedName& name) - : ContainerNode(&element->document()) - , m_element(element) +Attr::Attr(Element& element, const QualifiedName& name) + : ContainerNode(element.document()) + , m_element(&element) , m_name(name) - , m_ignoreChildrenChanged(0) { } Attr::Attr(Document& document, const QualifiedName& name, const AtomicString& standaloneValue) - : ContainerNode(&document) - , m_element(0) + : ContainerNode(document) , m_name(name) , m_standaloneValue(standaloneValue) - , m_ignoreChildrenChanged(0) { } -PassRefPtr Attr::create(Element* element, const QualifiedName& name) +Ref Attr::create(Element& element, const QualifiedName& name) { - RefPtr attr = adoptRef(new Attr(element, name)); + Ref attr = adoptRef(*new Attr(element, name)); attr->createTextChild(); - return attr.release(); + return attr; } -PassRefPtr Attr::create(Document& document, const QualifiedName& name, const AtomicString& value) +Ref Attr::create(Document& document, const QualifiedName& name, const AtomicString& value) { - RefPtr attr = adoptRef(new Attr(document, name, value)); + Ref attr = adoptRef(*new Attr(document, name, value)); attr->createTextChild(); - return attr.release(); + return attr; } Attr::~Attr() @@ -75,34 +75,31 @@ void Attr::createTextChild() { ASSERT(refCount()); if (!value().isEmpty()) { - RefPtr textNode = document().createTextNode(value().string()); + auto textNode = document().createTextNode(value().string()); // This does everything appendChild() would do in this situation (assuming m_ignoreChildrenChanged was set), // but much more efficiently. textNode->setParentNode(this); - setFirstChild(textNode.get()); - setLastChild(textNode.get()); + setFirstChild(textNode.ptr()); + setLastChild(textNode.ptr()); } } -void Attr::setPrefix(const AtomicString& prefix, ExceptionCode& ec) +ExceptionOr Attr::setPrefix(const AtomicString& prefix) { - ec = 0; - checkSetPrefix(prefix, ec); - if (ec) - return; + auto result = checkSetPrefix(prefix); + if (result.hasException()) + return result.releaseException(); - if ((prefix == xmlnsAtom && namespaceURI() != XMLNSNames::xmlnsNamespaceURI) - || static_cast(this)->qualifiedName() == xmlnsAtom) { - ec = NAMESPACE_ERR; - return; - } + if ((prefix == xmlnsAtom && namespaceURI() != XMLNSNames::xmlnsNamespaceURI) || qualifiedName() == xmlnsAtom) + return Exception { NAMESPACE_ERR }; const AtomicString& newPrefix = prefix.isEmpty() ? nullAtom : prefix; - if (m_element) elementAttribute().setPrefix(newPrefix); m_name.setPrefix(newPrefix); + + return { }; } void Attr::setValue(const AtomicString& value) @@ -110,9 +107,10 @@ void Attr::setValue(const AtomicString& value) EventQueueScope scope; m_ignoreChildrenChanged++; removeChildren(); - if (m_element) + if (m_element) { + Style::AttributeChangeInvalidation styleInvalidation(*m_element, qualifiedName(), elementAttribute().value(), value); elementAttribute().setValue(value); - else + } else m_standaloneValue = value; createTextChild(); m_ignoreChildrenChanged--; @@ -120,40 +118,33 @@ void Attr::setValue(const AtomicString& value) invalidateNodeListAndCollectionCachesInAncestors(&m_name, m_element); } -void Attr::setValue(const AtomicString& value, ExceptionCode&) +void Attr::setValueForBindings(const AtomicString& value) { AtomicString oldValue = this->value(); if (m_element) m_element->willModifyAttribute(qualifiedName(), oldValue, value); - setValue(value); - if (m_element) m_element->didModifyAttribute(qualifiedName(), oldValue, value); } -void Attr::setNodeValue(const String& v, ExceptionCode& ec) +ExceptionOr Attr::setNodeValue(const String& value) { - setValue(v, ec); + setValueForBindings(value); + return { }; } -PassRefPtr Attr::cloneNode(bool /*deep*/) +Ref Attr::cloneNodeInternal(Document& targetDocument, CloningOperation) { - RefPtr clone = adoptRef(new Attr(document(), qualifiedName(), value())); - cloneChildNodes(clone.get()); - return clone.release(); + Ref clone = adoptRef(*new Attr(targetDocument, qualifiedName(), value())); + cloneChildNodes(clone); + return WTFMove(clone); } // DOM Section 1.1.1 bool Attr::childTypeAllowed(NodeType type) const { - switch (type) { - case TEXT_NODE: - case ENTITY_REFERENCE_NODE: - return true; - default: - return false; - } + return type == TEXT_NODE; } void Attr::childrenChanged(const ChildChange&) @@ -164,34 +155,32 @@ void Attr::childrenChanged(const ChildChange&) invalidateNodeListAndCollectionCachesInAncestors(&qualifiedName(), m_element); StringBuilder valueBuilder; - TextNodeTraversal::appendContents(this, valueBuilder); + TextNodeTraversal::appendContents(*this, valueBuilder); AtomicString oldValue = value(); AtomicString newValue = valueBuilder.toAtomicString(); if (m_element) m_element->willModifyAttribute(qualifiedName(), oldValue, newValue); - if (m_element) + if (m_element) { + Style::AttributeChangeInvalidation styleInvalidation(*m_element, qualifiedName(), oldValue, newValue); elementAttribute().setValue(newValue); - else + } else m_standaloneValue = newValue; - if (m_element) + if (m_element) { + NoEventDispatchAssertion::DisableAssertionsInScope allowedScope; m_element->attributeChanged(qualifiedName(), oldValue, newValue); -} - -bool Attr::isId() const -{ - return qualifiedName().matches(document().idAttributeName()); + } } CSSStyleDeclaration* Attr::style() { // This function only exists to support the Obj-C bindings. - if (!m_element || !m_element->isStyledElement()) + if (!is(m_element)) return nullptr; m_style = MutableStyleProperties::create(); - toStyledElement(m_element)->collectStyleForPresentationAttribute(qualifiedName(), value(), *m_style); + downcast(*m_element).collectStyleForPresentationAttribute(qualifiedName(), value(), *m_style); return m_style->ensureCSSStyleDeclaration(); } @@ -214,13 +203,13 @@ void Attr::detachFromElementWithValue(const AtomicString& value) ASSERT(m_element); ASSERT(m_standaloneValue.isNull()); m_standaloneValue = value; - m_element = 0; + m_element = nullptr; } -void Attr::attachToElement(Element* element) +void Attr::attachToElement(Element& element) { ASSERT(!m_element); - m_element = element; + m_element = &element; m_standaloneValue = nullAtom; } diff --git a/Source/WebCore/dom/Attr.h b/Source/WebCore/dom/Attr.h index 3e34cca66..f2715995e 100644 --- a/Source/WebCore/dom/Attr.h +++ b/Source/WebCore/dom/Attr.h @@ -22,18 +22,18 @@ * */ -#ifndef Attr_h -#define Attr_h +#pragma once #include "ContainerNode.h" #include "QualifiedName.h" namespace WebCore { +class Attribute; class CSSStyleDeclaration; class MutableStyleProperties; -// Attr can have Text and EntityReference children +// Attr can have Text children // therefore it has to be a fullblown Node. The plan // is to dynamically allocate a textchild and store the // resulting nodevalue in the attribute upon @@ -41,69 +41,65 @@ class MutableStyleProperties; class Attr final : public ContainerNode { public: - static PassRefPtr create(Element*, const QualifiedName&); - static PassRefPtr create(Document&, const QualifiedName&, const AtomicString& value); + static Ref create(Element&, const QualifiedName&); + static Ref create(Document&, const QualifiedName&, const AtomicString& value); virtual ~Attr(); String name() const { return qualifiedName().toString(); } bool specified() const { return true; } Element* ownerElement() const { return m_element; } - const AtomicString& value() const; - void setValue(const AtomicString&, ExceptionCode&); + WEBCORE_EXPORT const AtomicString& value() const; void setValue(const AtomicString&); + const AtomicString& valueForBindings() const { return value(); } + WEBCORE_EXPORT void setValueForBindings(const AtomicString&); const QualifiedName& qualifiedName() const { return m_name; } - bool isId() const; + WEBCORE_EXPORT CSSStyleDeclaration* style(); - CSSStyleDeclaration* style(); - - void attachToElement(Element*); + void attachToElement(Element&); void detachFromElementWithValue(const AtomicString&); - virtual const AtomicString& namespaceURI() const override { return m_name.namespaceURI(); } + const AtomicString& namespaceURI() const final { return m_name.namespaceURI(); } + const AtomicString& localName() const final { return m_name.localName(); } + const AtomicString& prefix() const final { return m_name.prefix(); } private: - Attr(Element*, const QualifiedName&); + Attr(Element&, const QualifiedName&); Attr(Document&, const QualifiedName&, const AtomicString& value); void createTextChild(); - virtual String nodeName() const override { return name(); } - virtual NodeType nodeType() const override { return ATTRIBUTE_NODE; } + String nodeName() const final { return name(); } + NodeType nodeType() const final { return ATTRIBUTE_NODE; } - virtual const AtomicString& localName() const override { return m_name.localName(); } - virtual const AtomicString& prefix() const override { return m_name.prefix(); } + String nodeValue() const final { return value(); } + ExceptionOr setNodeValue(const String&) final; - virtual void setPrefix(const AtomicString&, ExceptionCode&) override; + ExceptionOr setPrefix(const AtomicString&) final; - virtual String nodeValue() const override { return value(); } - virtual void setNodeValue(const String&, ExceptionCode&) override; - virtual PassRefPtr cloneNode(bool deep) override; + Ref cloneNodeInternal(Document&, CloningOperation) final; - virtual bool isAttributeNode() const override { return true; } - virtual bool childTypeAllowed(NodeType) const override; + bool isAttributeNode() const final { return true; } + bool childTypeAllowed(NodeType) const final; - virtual void childrenChanged(const ChildChange&) override; + void childrenChanged(const ChildChange&) final; Attribute& elementAttribute(); // Attr wraps either an element/name, or a name/value pair (when it's a standalone Node.) // Note that m_name is always set, but m_element/m_standaloneValue may be null. - Element* m_element; + Element* m_element { nullptr }; QualifiedName m_name; AtomicString m_standaloneValue; RefPtr m_style; - unsigned m_ignoreChildrenChanged; + unsigned m_ignoreChildrenChanged { 0 }; }; -inline bool isAttr(const Node& node) { return node.isAttributeNode(); } -void isAttr(const Attr&); // Catch unnecessary runtime check of type known at compile time. - -NODE_TYPE_CASTS(Attr) - } // namespace WebCore -#endif // Attr_h +SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::Attr) + static bool isType(const WebCore::Node& node) { return node.isAttributeNode(); } +SPECIALIZE_TYPE_TRAITS_END() diff --git a/Source/WebCore/dom/Attr.idl b/Source/WebCore/dom/Attr.idl index 15c001a6b..4cf65336f 100644 --- a/Source/WebCore/dom/Attr.idl +++ b/Source/WebCore/dom/Attr.idl @@ -20,28 +20,18 @@ [ JSCustomMarkFunction, - JSGenerateToNativeObject + JSGenerateToJSObject, + JSGenerateToNativeObject, ] interface Attr : Node { - - // DOM Level 1 - - [TreatReturnedNullStringAs=Null] readonly attribute DOMString name; + readonly attribute DOMString? name; readonly attribute boolean specified; - [TreatReturnedNullStringAs=Null, TreatNullAs=NullString, SetterRaisesException] attribute DOMString value; - - // DOM Level 2 + [CEReactions, ImplementedAs=valueForBindings] attribute DOMString value; readonly attribute Element ownerElement; - // DOM Level 3 - - readonly attribute boolean isId; - -#if defined(LANGUAGE_OBJECTIVE_C) && LANGUAGE_OBJECTIVE_C - // This extension is no longer needed, but it has to remain available in Objective C, as it's public API. - readonly attribute CSSStyleDeclaration style; -#endif + readonly attribute DOMString? namespaceURI; + readonly attribute DOMString? prefix; + readonly attribute DOMString localName; }; - diff --git a/Source/WebCore/dom/Attribute.h b/Source/WebCore/dom/Attribute.h index 61c9ec5a8..72dbed69e 100644 --- a/Source/WebCore/dom/Attribute.h +++ b/Source/WebCore/dom/Attribute.h @@ -3,7 +3,7 @@ * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Peter Kelly (pmk@post.com) * (C) 2001 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2012, 2014 Apple 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 @@ -22,8 +22,7 @@ * */ -#ifndef Attribute_h -#define Attribute_h +#pragma once #include "QualifiedName.h" @@ -44,13 +43,16 @@ public: // as the Attribute stays in place. For example, calling a function that mutates // an Element's internal attribute storage may invalidate them. const AtomicString& value() const { return m_value; } + static ptrdiff_t valueMemoryOffset() { return OBJECT_OFFSETOF(Attribute, m_value); } const AtomicString& prefix() const { return m_name.prefix(); } const AtomicString& localName() const { return m_name.localName(); } const AtomicString& namespaceURI() const { return m_name.namespaceURI(); } const QualifiedName& name() const { return m_name; } + static ptrdiff_t nameMemoryOffset() { return OBJECT_OFFSETOF(Attribute, m_name); } bool isEmpty() const { return m_value.isEmpty(); } + static bool nameMatchesFilter(const QualifiedName&, const AtomicString& filterPrefix, const AtomicString& filterLocalName, const AtomicString& filterNamespaceURI); bool matches(const AtomicString& prefix, const AtomicString& localName, const AtomicString& namespaceURI) const; void setValue(const AtomicString& value) { m_value = value; } @@ -72,13 +74,16 @@ private: AtomicString m_value; }; -inline bool Attribute::matches(const AtomicString& prefix, const AtomicString& localName, const AtomicString& namespaceURI) const +inline bool Attribute::nameMatchesFilter(const QualifiedName& name, const AtomicString& filterPrefix, const AtomicString& filterLocalName, const AtomicString& filterNamespaceURI) { - if (localName != this->localName()) + if (filterLocalName != name.localName()) return false; - return prefix == starAtom || namespaceURI == this->namespaceURI(); + return filterPrefix == starAtom || filterNamespaceURI == name.namespaceURI(); } -} // namespace WebCore +inline bool Attribute::matches(const AtomicString& prefix, const AtomicString& localName, const AtomicString& namespaceURI) const +{ + return nameMatchesFilter(m_name, prefix, localName, namespaceURI); +} -#endif // Attribute_h +} // namespace WebCore diff --git a/Source/WebCore/dom/AutocompleteErrorEvent.h b/Source/WebCore/dom/AutocompleteErrorEvent.h new file mode 100644 index 000000000..f5d766836 --- /dev/null +++ b/Source/WebCore/dom/AutocompleteErrorEvent.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(REQUEST_AUTOCOMPLETE) + +#include "Event.h" +#include "EventNames.h" + +namespace WebCore { + +class AutocompleteErrorEvent final : public Event { +public: + static Ref create() + { + return adoptRef(*new AutocompleteErrorEvent); + } + + static Ref create(const String& reason) + { + return adoptRef(*new AutocompleteErrorEvent(reason)); + } + + struct Init : EventInit { + String reason; + }; + + static Ref create(const AtomicString& eventType, const Init& initializer, IsTrusted isTrusted = IsTrusted::No) + { + return adoptRef(*new AutocompleteErrorEvent(eventType, initializer, isTrusted)); + } + + const String& reason() const { return m_reason; } + +private: + AutocompleteErrorEvent() + { + } + + AutocompleteErrorEvent(const String& reason) + : Event(eventNames().autocompleteerrorEvent, false, false) + , m_reason(reason) + { + } + + AutocompleteErrorEvent(const AtomicString& eventType, const Init& initializer, IsTrusted isTrusted) + : Event(eventType, initializer, isTrusted) + , m_reason(initializer.reason) + { + } + + String m_reason; +}; + +} // namespace WebCore + +#endif // ENABLE(REQUEST_AUTOCOMPLETE) diff --git a/Source/WebCore/dom/AutocompleteErrorEvent.idl b/Source/WebCore/dom/AutocompleteErrorEvent.idl new file mode 100644 index 000000000..d93fa65fb --- /dev/null +++ b/Source/WebCore/dom/AutocompleteErrorEvent.idl @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +[ + Conditional=REQUEST_AUTOCOMPLETE, + Constructor(DOMString type, optional AutocompleteErrorEventInit eventInitDict), + JSGenerateToJSObject +] interface AutocompleteErrorEvent : Event { + readonly attribute DOMString reason; +}; + +dictionary AutocompleteErrorEventInit : EventInit { + DOMString reason = ""; +}; diff --git a/Source/WebCore/dom/BeforeLoadEvent.h b/Source/WebCore/dom/BeforeLoadEvent.h index 0ae76985c..7c57daaac 100644 --- a/Source/WebCore/dom/BeforeLoadEvent.h +++ b/Source/WebCore/dom/BeforeLoadEvent.h @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY APPLE, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -24,56 +24,42 @@ * */ -#ifndef BeforeLoadEvent_h -#define BeforeLoadEvent_h +#pragma once #include "Event.h" #include "EventNames.h" namespace WebCore { -struct BeforeLoadEventInit : public EventInit { - BeforeLoadEventInit() - { - }; - - String url; -}; - -class BeforeLoadEvent : public Event { +class BeforeLoadEvent final : public Event { public: - static PassRefPtr create() + static Ref create(const String& url) { - return adoptRef(new BeforeLoadEvent); + return adoptRef(*new BeforeLoadEvent(url)); } - static PassRefPtr create(const String& url) - { - return adoptRef(new BeforeLoadEvent(url)); - } + struct Init : EventInit { + String url; + }; - static PassRefPtr create(const AtomicString& type, const BeforeLoadEventInit& initializer) + static Ref create(const AtomicString& type, const Init& initializer, IsTrusted isTrusted = IsTrusted::No) { - return adoptRef(new BeforeLoadEvent(type, initializer)); + return adoptRef(*new BeforeLoadEvent(type, initializer, isTrusted)); } const String& url() const { return m_url; } - virtual EventInterface eventInterface() const override { return BeforeLoadEventInterfaceType; } + EventInterface eventInterface() const override { return BeforeLoadEventInterfaceType; } private: - BeforeLoadEvent() - { - } - explicit BeforeLoadEvent(const String& url) : Event(eventNames().beforeloadEvent, false, true) , m_url(url) { } - BeforeLoadEvent(const AtomicString& type, const BeforeLoadEventInit& initializer) - : Event(type, initializer) + BeforeLoadEvent(const AtomicString& type, const Init& initializer, IsTrusted isTrusted) + : Event(type, initializer, isTrusted) , m_url(initializer.url) { } @@ -82,5 +68,3 @@ private: }; } // namespace WebCore - -#endif // BeforeLoadEvent_h diff --git a/Source/WebCore/dom/BeforeLoadEvent.idl b/Source/WebCore/dom/BeforeLoadEvent.idl index 54b850199..5dd04ce0d 100644 --- a/Source/WebCore/dom/BeforeLoadEvent.idl +++ b/Source/WebCore/dom/BeforeLoadEvent.idl @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY APPLE, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -25,8 +25,11 @@ */ [ - ConstructorTemplate=Event + Constructor(DOMString type, optional BeforeLoadEventInit eventInitDict) ] interface BeforeLoadEvent : Event { - [InitializedByEventConstructor] readonly attribute DOMString url; + readonly attribute DOMString url; }; +dictionary BeforeLoadEventInit : EventInit { + DOMString url = ""; +}; diff --git a/Source/WebCore/dom/BeforeTextInsertedEvent.cpp b/Source/WebCore/dom/BeforeTextInsertedEvent.cpp index 0db1e2803..86ff9e023 100644 --- a/Source/WebCore/dom/BeforeTextInsertedEvent.cpp +++ b/Source/WebCore/dom/BeforeTextInsertedEvent.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2005 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/Source/WebCore/dom/BeforeTextInsertedEvent.h b/Source/WebCore/dom/BeforeTextInsertedEvent.h index 6e5f4eb79..cc92dfcd2 100644 --- a/Source/WebCore/dom/BeforeTextInsertedEvent.h +++ b/Source/WebCore/dom/BeforeTextInsertedEvent.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,34 +23,33 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef BeforeTextInsertedEvent_h -#define BeforeTextInsertedEvent_h +#pragma once #include "Event.h" namespace WebCore { -class BeforeTextInsertedEvent : public Event { +class BeforeTextInsertedEvent final : public Event { public: virtual ~BeforeTextInsertedEvent(); - static PassRefPtr create(const String& text) + static Ref create(const String& text) { - return adoptRef(new BeforeTextInsertedEvent(text)); + return adoptRef(*new BeforeTextInsertedEvent(text)); } - virtual EventInterface eventInterface() const override; - virtual bool isBeforeTextInsertedEvent() const override { return true; } + EventInterface eventInterface() const override; const String& text() const { return m_text; } void setText(const String& s) { m_text = s; } private: explicit BeforeTextInsertedEvent(const String&); + bool isBeforeTextInsertedEvent() const override { return true; } String m_text; }; -} // namespace +} // namespace WebCore -#endif +SPECIALIZE_TYPE_TRAITS_EVENT(BeforeTextInsertedEvent) diff --git a/Source/WebCore/dom/BeforeUnloadEvent.cpp b/Source/WebCore/dom/BeforeUnloadEvent.cpp index d0a999657..25d81fd6b 100644 --- a/Source/WebCore/dom/BeforeUnloadEvent.cpp +++ b/Source/WebCore/dom/BeforeUnloadEvent.cpp @@ -2,7 +2,7 @@ * Copyright (C) 2001 Peter Kelly (pmk@post.com) * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de) * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - * Copyright (C) 2003, 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2003, 2005, 2006 Apple Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public diff --git a/Source/WebCore/dom/BeforeUnloadEvent.h b/Source/WebCore/dom/BeforeUnloadEvent.h index 9188ad576..3e726ad92 100644 --- a/Source/WebCore/dom/BeforeUnloadEvent.h +++ b/Source/WebCore/dom/BeforeUnloadEvent.h @@ -2,7 +2,7 @@ * Copyright (C) 2001 Peter Kelly (pmk@post.com) * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de) * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2003, 2004, 2005, 2006 Apple Inc. * Copyright (C) 2013 Samsung Electronics * * This library is free software; you can redistribute it and/or @@ -22,8 +22,7 @@ * */ -#ifndef BeforeUnloadEvent_h -#define BeforeUnloadEvent_h +#pragma once #include "Event.h" @@ -33,30 +32,24 @@ class BeforeUnloadEvent final : public Event { public: virtual ~BeforeUnloadEvent(); - static PassRefPtr create() + static Ref create() { - return adoptRef(new BeforeUnloadEvent); + return adoptRef(*new BeforeUnloadEvent); } String returnValue() const { return m_returnValue; } void setReturnValue(const String& returnValue) { m_returnValue = returnValue; } - virtual EventInterface eventInterface() const override { return BeforeUnloadEventInterfaceType; } + EventInterface eventInterface() const override { return BeforeUnloadEventInterfaceType; } private: BeforeUnloadEvent(); - virtual bool isBeforeUnloadEvent() const override; + bool isBeforeUnloadEvent() const override; String m_returnValue; }; -inline BeforeUnloadEvent* toBeforeUnloadEvent(Event* event) -{ - ASSERT_WITH_SECURITY_IMPLICATION(!event || event->isBeforeUnloadEvent()); - return static_cast(event); -} - } // namespace WebCore -#endif // BeforeUnloadEvent_h +SPECIALIZE_TYPE_TRAITS_EVENT(BeforeUnloadEvent) diff --git a/Source/WebCore/dom/BeforeUnloadEvent.idl b/Source/WebCore/dom/BeforeUnloadEvent.idl index 3e962ef44..c815dfefc 100644 --- a/Source/WebCore/dom/BeforeUnloadEvent.idl +++ b/Source/WebCore/dom/BeforeUnloadEvent.idl @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY APPLE, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/Source/WebCore/dom/CDATASection.cpp b/Source/WebCore/dom/CDATASection.cpp index 4b3972aab..598530f7c 100644 --- a/Source/WebCore/dom/CDATASection.cpp +++ b/Source/WebCore/dom/CDATASection.cpp @@ -31,14 +31,14 @@ inline CDATASection::CDATASection(Document& document, const String& data) { } -PassRefPtr CDATASection::create(Document& document, const String& data) +Ref CDATASection::create(Document& document, const String& data) { - return adoptRef(new CDATASection(document, data)); + return adoptRef(*new CDATASection(document, data)); } String CDATASection::nodeName() const { - return "#cdata-section"; + return ASCIILiteral("#cdata-section"); } Node::NodeType CDATASection::nodeType() const @@ -46,9 +46,9 @@ Node::NodeType CDATASection::nodeType() const return CDATA_SECTION_NODE; } -PassRefPtr CDATASection::cloneNode(bool /*deep*/) +Ref CDATASection::cloneNodeInternal(Document& targetDocument, CloningOperation) { - return create(document(), data()); + return create(targetDocument, data()); } bool CDATASection::childTypeAllowed(NodeType) const @@ -56,7 +56,7 @@ bool CDATASection::childTypeAllowed(NodeType) const return false; } -PassRefPtr CDATASection::virtualCreate(const String& data) +Ref CDATASection::virtualCreate(const String& data) { return create(document(), data); } diff --git a/Source/WebCore/dom/CDATASection.h b/Source/WebCore/dom/CDATASection.h index a93dc496c..bdb9db7b3 100644 --- a/Source/WebCore/dom/CDATASection.h +++ b/Source/WebCore/dom/CDATASection.h @@ -20,8 +20,7 @@ * */ -#ifndef CDATASection_h -#define CDATASection_h +#pragma once #include "Text.h" @@ -29,24 +28,20 @@ namespace WebCore { class CDATASection final : public Text { public: - static PassRefPtr create(Document&, const String&); + static Ref create(Document&, const String&); private: CDATASection(Document&, const String&); - virtual String nodeName() const override; - virtual NodeType nodeType() const override; - virtual PassRefPtr cloneNode(bool deep) override; - virtual bool childTypeAllowed(NodeType) const override; - virtual PassRefPtr virtualCreate(const String&) override; + String nodeName() const override; + NodeType nodeType() const override; + Ref cloneNodeInternal(Document&, CloningOperation) override; + bool childTypeAllowed(NodeType) const override; + Ref virtualCreate(const String&) override; }; -inline bool isCDATASection(const Node& node) { return node.nodeType() == Node::CDATA_SECTION_NODE; } -void isCDATASection(const CDATASection&); // Catch unnecessary runtime check of type known at compile time. -void isCDATASection(const ContainerNode&); // Catch unnecessary runtime check of type known at compile time. - -NODE_TYPE_CASTS(CDATASection) - } // namespace WebCore -#endif // CDATASection_h +SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::CDATASection) + static bool isType(const WebCore::Node& node) { return node.nodeType() == WebCore::Node::CDATA_SECTION_NODE; } +SPECIALIZE_TYPE_TRAITS_END() diff --git a/Source/WebCore/dom/CDATASection.idl b/Source/WebCore/dom/CDATASection.idl index 939fe27b3..fc7a8ae47 100644 --- a/Source/WebCore/dom/CDATASection.idl +++ b/Source/WebCore/dom/CDATASection.idl @@ -17,6 +17,8 @@ * Boston, MA 02110-1301, USA. */ -interface CDATASection : Text { +[ + JSGenerateToJSObject +] interface CDATASection : Text { }; diff --git a/Source/WebCore/dom/CharacterData.cpp b/Source/WebCore/dom/CharacterData.cpp index 7ac273f62..4e564bce2 100644 --- a/Source/WebCore/dom/CharacterData.cpp +++ b/Source/WebCore/dom/CharacterData.cpp @@ -22,40 +22,53 @@ #include "config.h" #include "CharacterData.h" +#include "Attr.h" #include "ElementTraversal.h" +#include "EventNames.h" #include "ExceptionCode.h" #include "FrameSelection.h" #include "InspectorInstrumentation.h" #include "MutationEvent.h" #include "MutationObserverInterestGroup.h" #include "MutationRecord.h" +#include "NoEventDispatchAssertion.h" #include "ProcessingInstruction.h" #include "RenderText.h" #include "StyleInheritedData.h" -#include "TextBreakIterator.h" +#include #include namespace WebCore { -void CharacterData::setData(const String& data, ExceptionCode&) +static bool canUseSetDataOptimization(const CharacterData& node) +{ + auto& document = node.document(); + return !document.hasListenerType(Document::DOMCHARACTERDATAMODIFIED_LISTENER) && !document.hasMutationObserversOfType(MutationObserver::CharacterData) + && !document.hasListenerType(Document::DOMSUBTREEMODIFIED_LISTENER); +} + +void CharacterData::setData(const String& data) { const String& nonNullData = !data.isNull() ? data : emptyString(); - if (m_data == nonNullData) - return; + unsigned oldLength = length(); - Ref protect(*this); + if (m_data == nonNullData && canUseSetDataOptimization(*this)) { + document().textRemoved(this, 0, oldLength); + if (document().frame()) + document().frame()->selection().textWasReplaced(this, 0, oldLength, oldLength); + return; + } - unsigned oldLength = length(); + Ref protectedThis(*this); setDataAndUpdate(nonNullData, 0, oldLength, nonNullData.length()); document().textRemoved(this, 0, oldLength); } -String CharacterData::substringData(unsigned offset, unsigned count, ExceptionCode& ec) +ExceptionOr CharacterData::substringData(unsigned offset, unsigned count) { - checkCharDataOperation(offset, ec); - if (ec) - return String(); + if (offset > length()) + return Exception { INDEX_SIZE_ERR }; return m_data.substring(offset, count); } @@ -75,8 +88,8 @@ unsigned CharacterData::parserAppendData(const String& string, unsigned offset, // We need at least two characters look-ahead to account for UTF-16 surrogates. if (characterLengthLimit < characterLength) { NonSharedCharacterBreakIterator it(StringView(string).substring(offset, (characterLengthLimit + 2 > characterLength) ? characterLength : characterLengthLimit + 2)); - if (!isTextBreak(it, characterLengthLimit)) - characterLengthLimit = textBreakPreceding(it, characterLengthLimit); + if (!ubrk_isBoundary(it, characterLengthLimit)) + characterLengthLimit = ubrk_preceding(it, characterLengthLimit); } if (!characterLengthLimit) @@ -87,27 +100,16 @@ unsigned CharacterData::parserAppendData(const String& string, unsigned offset, else m_data.append(string.characters16() + offset, characterLengthLimit); - ASSERT(!renderer() || isTextNode()); - if (isTextNode()) - Style::updateTextRendererAfterContentChange(*toText(this), oldLength, 0); + ASSERT(!renderer() || is(*this)); + if (is(*this) && parentNode()) + downcast(*this).updateRendererAfterContentChange(oldLength, 0); - document().incDOMTreeVersion(); - // We don't call dispatchModifiedEvent here because we don't want the - // parser to dispatch DOM mutation events. - if (parentNode()) { - ContainerNode::ChildChange change = { - ContainerNode::TextChanged, - ElementTraversal::previousSibling(this), - ElementTraversal::nextSibling(this), - ContainerNode::ChildChangeSourceParser - }; - parentNode()->childrenChanged(change); - } + notifyParentAfterChange(ContainerNode::ChildChangeSourceParser); return characterLengthLimit; } -void CharacterData::appendData(const String& data, ExceptionCode&) +void CharacterData::appendData(const String& data) { String newStr = m_data; newStr.append(data); @@ -117,11 +119,10 @@ void CharacterData::appendData(const String& data, ExceptionCode&) // FIXME: Should we call textInserted here? } -void CharacterData::insertData(unsigned offset, const String& data, ExceptionCode& ec) +ExceptionOr CharacterData::insertData(unsigned offset, const String& data) { - checkCharDataOperation(offset, ec); - if (ec) - return; + if (offset > length()) + return Exception { INDEX_SIZE_ERR }; String newStr = m_data; newStr.insert(data, offset); @@ -129,49 +130,45 @@ void CharacterData::insertData(unsigned offset, const String& data, ExceptionCod setDataAndUpdate(newStr, offset, 0, data.length()); document().textInserted(this, offset, data.length()); + + return { }; } -void CharacterData::deleteData(unsigned offset, unsigned count, ExceptionCode& ec) +ExceptionOr CharacterData::deleteData(unsigned offset, unsigned count) { - checkCharDataOperation(offset, ec); - if (ec) - return; + if (offset > length()) + return Exception { INDEX_SIZE_ERR }; - unsigned realCount; - if (offset + count > length()) - realCount = length() - offset; - else - realCount = count; + count = std::min(count, length() - offset); String newStr = m_data; - newStr.remove(offset, realCount); + newStr.remove(offset, count); setDataAndUpdate(newStr, offset, count, 0); - document().textRemoved(this, offset, realCount); + document().textRemoved(this, offset, count); + + return { }; } -void CharacterData::replaceData(unsigned offset, unsigned count, const String& data, ExceptionCode& ec) +ExceptionOr CharacterData::replaceData(unsigned offset, unsigned count, const String& data) { - checkCharDataOperation(offset, ec); - if (ec) - return; + if (offset > length()) + return Exception { INDEX_SIZE_ERR }; - unsigned realCount; - if (offset + count > length()) - realCount = length() - offset; - else - realCount = count; + count = std::min(count, length() - offset); String newStr = m_data; - newStr.remove(offset, realCount); + newStr.remove(offset, count); newStr.insert(data, offset); setDataAndUpdate(newStr, offset, count, data.length()); // update the markers for spell checking and grammar checking - document().textRemoved(this, offset, realCount); + document().textRemoved(this, offset, count); document().textInserted(this, offset, data.length()); + + return { }; } String CharacterData::nodeValue() const @@ -184,9 +181,10 @@ bool CharacterData::containsOnlyWhitespace() const return m_data.containsOnlyWhitespace(); } -void CharacterData::setNodeValue(const String& nodeValue, ExceptionCode& ec) +ExceptionOr CharacterData::setNodeValue(const String& nodeValue) { - setData(nodeValue, ec); + setData(nodeValue); + return { }; } void CharacterData::setDataAndUpdate(const String& newData, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength) @@ -194,54 +192,60 @@ void CharacterData::setDataAndUpdate(const String& newData, unsigned offsetOfRep String oldData = m_data; m_data = newData; - ASSERT(!renderer() || isTextNode()); - if (isTextNode()) - Style::updateTextRendererAfterContentChange(*toText(this), offsetOfReplacedData, oldLength); + ASSERT(!renderer() || is(*this)); + if (is(*this) && parentNode()) + downcast(*this).updateRendererAfterContentChange(offsetOfReplacedData, oldLength); - if (nodeType() == PROCESSING_INSTRUCTION_NODE) - toProcessingInstruction(this)->checkStyleSheet(); + if (is(*this)) + downcast(*this).checkStyleSheet(); if (document().frame()) document().frame()->selection().textWasReplaced(this, offsetOfReplacedData, oldLength, newLength); - document().incDOMTreeVersion(); + notifyParentAfterChange(ContainerNode::ChildChangeSourceAPI); + dispatchModifiedEvent(oldData); } +void CharacterData::notifyParentAfterChange(ContainerNode::ChildChangeSource source) +{ +#if !ASSERT_DISABLED + auto assertNoEventDispatch = std::make_unique(); +#endif + + document().incDOMTreeVersion(); + + if (!parentNode()) + return; + + ContainerNode::ChildChange change = { + ContainerNode::TextChanged, + ElementTraversal::previousSibling(*this), + ElementTraversal::nextSibling(*this), + source + }; + +#if !ASSERT_DISABLED + // Attribute CharacterData is expected to fire events. + if (is(*parentNode())) + assertNoEventDispatch = nullptr; +#endif + + parentNode()->childrenChanged(change); +} + void CharacterData::dispatchModifiedEvent(const String& oldData) { - if (OwnPtr mutationRecipients = MutationObserverInterestGroup::createForCharacterDataMutation(*this)) + if (auto mutationRecipients = MutationObserverInterestGroup::createForCharacterDataMutation(*this)) mutationRecipients->enqueueMutationRecord(MutationRecord::createCharacterData(*this, oldData)); if (!isInShadowTree()) { - if (parentNode()) { - ContainerNode::ChildChange change = { - ContainerNode::TextChanged, - ElementTraversal::previousSibling(this), - ElementTraversal::nextSibling(this), - ContainerNode::ChildChangeSourceAPI - }; - parentNode()->childrenChanged(change); - } if (document().hasListenerType(Document::DOMCHARACTERDATAMODIFIED_LISTENER)) - dispatchScopedEvent(MutationEvent::create(eventNames().DOMCharacterDataModifiedEvent, true, 0, oldData, m_data)); + dispatchScopedEvent(MutationEvent::create(eventNames().DOMCharacterDataModifiedEvent, true, nullptr, oldData, m_data)); dispatchSubtreeModifiedEvent(); } -#if ENABLE(INSPECTOR) - InspectorInstrumentation::characterDataModified(&document(), this); -#endif -} -void CharacterData::checkCharDataOperation(unsigned offset, ExceptionCode& ec) -{ - ec = 0; - - // INDEX_SIZE_ERR: Raised if the specified offset is negative or greater than the number of 16-bit - // units in data. - if (offset > length()) { - ec = INDEX_SIZE_ERR; - return; - } + InspectorInstrumentation::characterDataModified(document(), *this); } int CharacterData::maxCharacterOffset() const diff --git a/Source/WebCore/dom/CharacterData.h b/Source/WebCore/dom/CharacterData.h index 681c63b99..e4ad221ed 100644 --- a/Source/WebCore/dom/CharacterData.h +++ b/Source/WebCore/dom/CharacterData.h @@ -20,36 +20,34 @@ * */ -#ifndef CharacterData_h -#define CharacterData_h +#pragma once -#include "Node.h" -#include +#include "ContainerNode.h" namespace WebCore { class CharacterData : public Node { public: - String data() const { return m_data; } - void setData(const String&, ExceptionCode&); + const String& data() const { return m_data; } + static ptrdiff_t dataMemoryOffset() { return OBJECT_OFFSETOF(CharacterData, m_data); } + + WEBCORE_EXPORT void setData(const String&); unsigned length() const { return m_data.length(); } - String substringData(unsigned offset, unsigned count, ExceptionCode&); - void appendData(const String&, ExceptionCode&); - void insertData(unsigned offset, const String&, ExceptionCode&); - void deleteData(unsigned offset, unsigned count, ExceptionCode&); - void replaceData(unsigned offset, unsigned count, const String&, ExceptionCode&); + WEBCORE_EXPORT ExceptionOr substringData(unsigned offset, unsigned count); + WEBCORE_EXPORT void appendData(const String&); + WEBCORE_EXPORT ExceptionOr insertData(unsigned offset, const String&); + WEBCORE_EXPORT ExceptionOr deleteData(unsigned offset, unsigned count); + WEBCORE_EXPORT ExceptionOr replaceData(unsigned offset, unsigned count, const String&); bool containsOnlyWhitespace() const; - StringImpl* dataImpl() { return m_data.impl(); } - // Like appendData, but optimized for the parser (e.g., no mutation events). // Returns how much could be added before length limit was met. unsigned parserAppendData(const String& string, unsigned offset, unsigned lengthLimit); protected: CharacterData(Document& document, const String& text, ConstructionType type) - : Node(&document, type) + : Node(document, type) , m_data(!text.isNull() ? text : emptyString()) { ASSERT(type == CreateOther || type == CreateText || type == CreateEditingText); @@ -63,23 +61,19 @@ protected: void dispatchModifiedEvent(const String& oldValue); private: - virtual String nodeValue() const override final; - virtual void setNodeValue(const String&, ExceptionCode&) override final; - virtual bool isCharacterDataNode() const override final { return true; } - virtual int maxCharacterOffset() const override final; - virtual bool offsetInCharacters() const override final; + String nodeValue() const final; + ExceptionOr setNodeValue(const String&) final; + bool isCharacterDataNode() const final { return true; } + int maxCharacterOffset() const final; + bool offsetInCharacters() const final; void setDataAndUpdate(const String&, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength); - void checkCharDataOperation(unsigned offset, ExceptionCode&); + void notifyParentAfterChange(ContainerNode::ChildChangeSource); String m_data; }; -inline bool isCharacterData(const Node& node) { return node.isCharacterDataNode(); } -void isCharacterData(const CharacterData&); // Catch unnecessary runtime check of type known at compile time. -void isCharacterData(const ContainerNode&); // Catch unnecessary runtime check of type known at compile time. - -NODE_TYPE_CASTS(CharacterData) - } // namespace WebCore -#endif // CharacterData_h +SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::CharacterData) + static bool isType(const WebCore::Node& node) { return node.isCharacterDataNode(); } +SPECIALIZE_TYPE_TRAITS_END() diff --git a/Source/WebCore/dom/CharacterData.idl b/Source/WebCore/dom/CharacterData.idl index c8c972319..366081b41 100644 --- a/Source/WebCore/dom/CharacterData.idl +++ b/Source/WebCore/dom/CharacterData.idl @@ -18,26 +18,16 @@ */ interface CharacterData : Node { - - [TreatNullAs=NullString, SetterRaisesException] attribute DOMString data; - + [CEReactions, TreatNullAs=EmptyString] attribute DOMString data; readonly attribute unsigned long length; - - [TreatReturnedNullStringAs=Null, ObjCLegacyUnnamedParameters, RaisesException] DOMString substringData([IsIndex, Default=Undefined] optional unsigned long offset, - [IsIndex, Default=Undefined] optional unsigned long length); - - [RaisesException] void appendData([Default=Undefined] optional DOMString data); - [ObjCLegacyUnnamedParameters, RaisesException] void insertData([IsIndex, Default=Undefined] optional unsigned long offset, - [Default=Undefined] optional DOMString data); + [MayThrowException] DOMString? substringData(unsigned long offset, unsigned long length); - [ObjCLegacyUnnamedParameters, RaisesException] void deleteData([IsIndex, Default=Undefined] optional unsigned long offset, - [IsIndex, Default=Undefined] optional unsigned long length); - - [ObjCLegacyUnnamedParameters, RaisesException] void replaceData([IsIndex, Default=Undefined] optional unsigned long offset, - [IsIndex, Default=Undefined] optional unsigned long length, - [Default=Undefined] optional DOMString data); + [CEReactions] void appendData(DOMString data); + [CEReactions, MayThrowException] void insertData(unsigned long offset, DOMString data); + [CEReactions, MayThrowException] void deleteData(unsigned long offset, unsigned long length); + [CEReactions, MayThrowException] void replaceData(unsigned long offset, unsigned long length, DOMString data); }; CharacterData implements ChildNode; - +CharacterData implements NonDocumentTypeChildNode; diff --git a/Source/WebCore/dom/CheckedRadioButtons.cpp b/Source/WebCore/dom/CheckedRadioButtons.cpp deleted file mode 100644 index 5e223b918..000000000 --- a/Source/WebCore/dom/CheckedRadioButtons.cpp +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (C) 2007, 2008, 2009 Apple 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. - * - */ - -#include "config.h" -#include "CheckedRadioButtons.h" - -#include "HTMLInputElement.h" -#include - -namespace WebCore { - -class RadioButtonGroup { - WTF_MAKE_FAST_ALLOCATED; -public: - static PassOwnPtr create(); - bool isEmpty() const { return m_members.isEmpty(); } - bool isRequired() const { return m_requiredCount; } - HTMLInputElement* checkedButton() const { return m_checkedButton; } - void add(HTMLInputElement*); - void updateCheckedState(HTMLInputElement*); - void requiredAttributeChanged(HTMLInputElement*); - void remove(HTMLInputElement*); - bool contains(HTMLInputElement*) const; - -private: - RadioButtonGroup(); - void setNeedsValidityCheckForAllButtons(); - bool isValid() const; - void setCheckedButton(HTMLInputElement*); - - HashSet m_members; - HTMLInputElement* m_checkedButton; - size_t m_requiredCount; -}; - -RadioButtonGroup::RadioButtonGroup() - : m_checkedButton(0) - , m_requiredCount(0) -{ -} - -PassOwnPtr RadioButtonGroup::create() -{ - return adoptPtr(new RadioButtonGroup); -} - -inline bool RadioButtonGroup::isValid() const -{ - return !isRequired() || m_checkedButton; -} - -void RadioButtonGroup::setCheckedButton(HTMLInputElement* button) -{ - HTMLInputElement* oldCheckedButton = m_checkedButton; - if (oldCheckedButton == button) - return; - m_checkedButton = button; - if (oldCheckedButton) - oldCheckedButton->setChecked(false); -} - -void RadioButtonGroup::add(HTMLInputElement* button) -{ - ASSERT(button->isRadioButton()); - if (!m_members.add(button).isNewEntry) - return; - bool groupWasValid = isValid(); - if (button->isRequired()) - ++m_requiredCount; - if (button->checked()) - setCheckedButton(button); - - bool groupIsValid = isValid(); - if (groupWasValid != groupIsValid) - setNeedsValidityCheckForAllButtons(); - else if (!groupIsValid) { - // A radio button not in a group is always valid. We need to make it - // invalid only if the group is invalid. - button->setNeedsValidityCheck(); - } -} - -void RadioButtonGroup::updateCheckedState(HTMLInputElement* button) -{ - ASSERT(button->isRadioButton()); - ASSERT(m_members.contains(button)); - bool wasValid = isValid(); - if (button->checked()) - setCheckedButton(button); - else { - if (m_checkedButton == button) - m_checkedButton = 0; - } - if (wasValid != isValid()) - setNeedsValidityCheckForAllButtons(); -} - -void RadioButtonGroup::requiredAttributeChanged(HTMLInputElement* button) -{ - ASSERT(button->isRadioButton()); - ASSERT(m_members.contains(button)); - bool wasValid = isValid(); - if (button->isRequired()) - ++m_requiredCount; - else { - ASSERT(m_requiredCount); - --m_requiredCount; - } - if (wasValid != isValid()) - setNeedsValidityCheckForAllButtons(); -} - -void RadioButtonGroup::remove(HTMLInputElement* button) -{ - ASSERT(button->isRadioButton()); - HashSet::iterator it = m_members.find(button); - if (it == m_members.end()) - return; - bool wasValid = isValid(); - m_members.remove(it); - if (button->isRequired()) { - ASSERT(m_requiredCount); - --m_requiredCount; - } - if (m_checkedButton == button) - m_checkedButton = 0; - - if (m_members.isEmpty()) { - ASSERT(!m_requiredCount); - ASSERT(!m_checkedButton); - } else if (wasValid != isValid()) - setNeedsValidityCheckForAllButtons(); - if (!wasValid) { - // A radio button not in a group is always valid. We need to make it - // valid only if the group was invalid. - button->setNeedsValidityCheck(); - } -} - -void RadioButtonGroup::setNeedsValidityCheckForAllButtons() -{ - typedef HashSet::const_iterator Iterator; - Iterator end = m_members.end(); - for (Iterator it = m_members.begin(); it != end; ++it) { - HTMLInputElement* button = *it; - ASSERT(button->isRadioButton()); - button->setNeedsValidityCheck(); - } -} - -bool RadioButtonGroup::contains(HTMLInputElement* button) const -{ - return m_members.contains(button); -} - -// ---------------------------------------------------------------- - -// Explicity define empty constructor and destructor in order to prevent the -// compiler from generating them as inlines. So we don't need to to define -// RadioButtonGroup in the header. -CheckedRadioButtons::CheckedRadioButtons() -{ -} - -CheckedRadioButtons::~CheckedRadioButtons() -{ -} - -void CheckedRadioButtons::addButton(HTMLInputElement* element) -{ - ASSERT(element->isRadioButton()); - if (element->name().isEmpty()) - return; - - if (!m_nameToGroupMap) - m_nameToGroupMap = adoptPtr(new NameToGroupMap); - - OwnPtr& group = m_nameToGroupMap->add(element->name().impl(), PassOwnPtr()).iterator->value; - if (!group) - group = RadioButtonGroup::create(); - group->add(element); -} - -void CheckedRadioButtons::updateCheckedState(HTMLInputElement* element) -{ - ASSERT(element->isRadioButton()); - if (element->name().isEmpty()) - return; - ASSERT(m_nameToGroupMap); - if (!m_nameToGroupMap) - return; - RadioButtonGroup* group = m_nameToGroupMap->get(element->name().impl()); - ASSERT(group); - group->updateCheckedState(element); -} - -void CheckedRadioButtons::requiredAttributeChanged(HTMLInputElement* element) -{ - ASSERT(element->isRadioButton()); - if (element->name().isEmpty()) - return; - ASSERT(m_nameToGroupMap); - if (!m_nameToGroupMap) - return; - RadioButtonGroup* group = m_nameToGroupMap->get(element->name().impl()); - ASSERT(group); - group->requiredAttributeChanged(element); -} - -HTMLInputElement* CheckedRadioButtons::checkedButtonForGroup(const AtomicString& name) const -{ - if (!m_nameToGroupMap) - return 0; - m_nameToGroupMap->checkConsistency(); - RadioButtonGroup* group = m_nameToGroupMap->get(name.impl()); - return group ? group->checkedButton() : 0; -} - -bool CheckedRadioButtons::isInRequiredGroup(HTMLInputElement* element) const -{ - ASSERT(element->isRadioButton()); - if (element->name().isEmpty()) - return false; - if (!m_nameToGroupMap) - return false; - RadioButtonGroup* group = m_nameToGroupMap->get(element->name().impl()); - return group && group->isRequired() && group->contains(element); -} - -void CheckedRadioButtons::removeButton(HTMLInputElement* element) -{ - ASSERT(element->isRadioButton()); - if (element->name().isEmpty()) - return; - if (!m_nameToGroupMap) - return; - - m_nameToGroupMap->checkConsistency(); - NameToGroupMap::iterator it = m_nameToGroupMap->find(element->name().impl()); - if (it == m_nameToGroupMap->end()) - return; - it->value->remove(element); - if (it->value->isEmpty()) { - // FIXME: We may skip deallocating the empty RadioButtonGroup for - // performance improvement. If we do so, we need to change the key type - // of m_nameToGroupMap from AtomicStringImpl* to RefPtr. - m_nameToGroupMap->remove(it); - if (m_nameToGroupMap->isEmpty()) - m_nameToGroupMap.clear(); - } -} - -} // namespace diff --git a/Source/WebCore/dom/CheckedRadioButtons.h b/Source/WebCore/dom/CheckedRadioButtons.h deleted file mode 100644 index bb3570da9..000000000 --- a/Source/WebCore/dom/CheckedRadioButtons.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2007, 2008, 2009 Apple 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 CheckedRadioButtons_h -#define CheckedRadioButtons_h - -#include -#include -#include - -namespace WebCore { - -class HTMLInputElement; -class RadioButtonGroup; - -// FIXME: Rename the class. The class was a simple map from a name to a checked -// radio button. It manages RadioButtonGroup objects now. -class CheckedRadioButtons { -public: - CheckedRadioButtons(); - ~CheckedRadioButtons(); - void addButton(HTMLInputElement*); - void updateCheckedState(HTMLInputElement*); - void requiredAttributeChanged(HTMLInputElement*); - void removeButton(HTMLInputElement*); - HTMLInputElement* checkedButtonForGroup(const AtomicString& groupName) const; - bool isInRequiredGroup(HTMLInputElement*) const; - -private: - typedef HashMap> NameToGroupMap; - OwnPtr m_nameToGroupMap; -}; - -} // namespace WebCore - -#endif // CheckedRadioButtons_h diff --git a/Source/WebCore/dom/ChildListMutationScope.cpp b/Source/WebCore/dom/ChildListMutationScope.cpp index 2c5071649..0fee84cd7 100644 --- a/Source/WebCore/dom/ChildListMutationScope.cpp +++ b/Source/WebCore/dom/ChildListMutationScope.cpp @@ -29,13 +29,12 @@ */ #include "config.h" - #include "ChildListMutationScope.h" -#include "DocumentFragment.h" #include "MutationObserverInterestGroup.h" #include "MutationRecord.h" #include "StaticNodeList.h" +#include #include namespace WebCore { @@ -43,14 +42,14 @@ namespace WebCore { typedef HashMap AccumulatorMap; static AccumulatorMap& accumulatorMap() { - DEFINE_STATIC_LOCAL(AccumulatorMap, map, ()); + static NeverDestroyed map; return map; } -ChildListMutationAccumulator::ChildListMutationAccumulator(ContainerNode& target, PassOwnPtr observers) +ChildListMutationAccumulator::ChildListMutationAccumulator(ContainerNode& target, std::unique_ptr observers) : m_target(target) - , m_lastAdded(0) - , m_observers(observers) + , m_lastAdded(nullptr) + , m_observers(WTFMove(observers)) { } @@ -58,10 +57,10 @@ ChildListMutationAccumulator::~ChildListMutationAccumulator() { if (!isEmpty()) enqueueMutationRecord(); - accumulatorMap().remove(&m_target.get()); + accumulatorMap().remove(m_target.ptr()); } -PassRefPtr ChildListMutationAccumulator::getOrCreate(ContainerNode& target) +RefPtr ChildListMutationAccumulator::getOrCreate(ContainerNode& target) { AccumulatorMap::AddResult result = accumulatorMap().add(&target, nullptr); RefPtr accumulator; @@ -71,7 +70,7 @@ PassRefPtr ChildListMutationAccumulator::getOrCrea accumulator = adoptRef(new ChildListMutationAccumulator(target, MutationObserverInterestGroup::createForChildListMutation(target))); result.iterator->value = accumulator.get(); } - return accumulator.release(); + return accumulator; } inline bool ChildListMutationAccumulator::isAddedNodeInOrder(Node& child) @@ -85,7 +84,7 @@ void ChildListMutationAccumulator::childAdded(Node& childRef) Ref child(childRef); - if (!isAddedNodeInOrder(child.get())) + if (!isAddedNodeInOrder(child)) enqueueMutationRecord(); if (isEmpty()) { @@ -93,7 +92,7 @@ void ChildListMutationAccumulator::childAdded(Node& childRef) m_nextSibling = child->nextSibling(); } - m_lastAdded = &child.get(); + m_lastAdded = child.ptr(); m_addedNodes.append(child.get()); } @@ -108,7 +107,7 @@ void ChildListMutationAccumulator::willRemoveChild(Node& childRef) Ref child(childRef); - if (!m_addedNodes.isEmpty() || !isRemovedNodeInOrder(child.get())) + if (!m_addedNodes.isEmpty() || !isRemovedNodeInOrder(child)) enqueueMutationRecord(); if (isEmpty()) { @@ -126,11 +125,9 @@ void ChildListMutationAccumulator::enqueueMutationRecord() ASSERT(hasObservers()); ASSERT(!isEmpty()); - RefPtr addedNodes = StaticNodeList::adopt(m_addedNodes); - RefPtr removedNodes = StaticNodeList::adopt(m_removedNodes); - RefPtr record = MutationRecord::createChildList(m_target.get(), addedNodes.release(), removedNodes.release(), m_previousSibling.release(), m_nextSibling.release()); - m_observers->enqueueMutationRecord(record.release()); - m_lastAdded = 0; + auto record = MutationRecord::createChildList(m_target, StaticNodeList::create(WTFMove(m_addedNodes)), StaticNodeList::create(WTFMove(m_removedNodes)), WTFMove(m_previousSibling), WTFMove(m_nextSibling)); + m_observers->enqueueMutationRecord(WTFMove(record)); + m_lastAdded = nullptr; ASSERT(isEmpty()); } diff --git a/Source/WebCore/dom/ChildListMutationScope.h b/Source/WebCore/dom/ChildListMutationScope.h index a179f59b7..945aad5e3 100644 --- a/Source/WebCore/dom/ChildListMutationScope.h +++ b/Source/WebCore/dom/ChildListMutationScope.h @@ -28,15 +28,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ChildListMutationScope_h -#define ChildListMutationScope_h +#pragma once #include "Document.h" #include "MutationObserver.h" #include "Node.h" -#include +#include #include -#include #include namespace WebCore { @@ -46,16 +44,16 @@ class MutationObserverInterestGroup; // ChildListMutationAccumulator is not meant to be used directly; ChildListMutationScope is the public interface. class ChildListMutationAccumulator : public RefCounted { public: - static PassRefPtr getOrCreate(ContainerNode&); + static RefPtr getOrCreate(ContainerNode&); ~ChildListMutationAccumulator(); void childAdded(Node&); void willRemoveChild(Node&); - bool hasObservers() const { return m_observers; } + bool hasObservers() const { return !!m_observers; } private: - ChildListMutationAccumulator(ContainerNode&, PassOwnPtr); + ChildListMutationAccumulator(ContainerNode&, std::unique_ptr); void enqueueMutationRecord(); bool isEmpty(); @@ -70,7 +68,7 @@ private: RefPtr m_nextSibling; Node* m_lastAdded; - OwnPtr m_observers; + std::unique_ptr m_observers; }; class ChildListMutationScope { @@ -82,6 +80,8 @@ public: m_accumulator = ChildListMutationAccumulator::getOrCreate(target); } + bool canObserve() const { return m_accumulator; } + void childAdded(Node& child) { if (m_accumulator && m_accumulator->hasObservers()) @@ -99,5 +99,3 @@ private: }; } // namespace WebCore - -#endif // ChildListMutationScope_h diff --git a/Source/WebCore/dom/ChildNode.idl b/Source/WebCore/dom/ChildNode.idl index a45bcf484..54f70a341 100644 --- a/Source/WebCore/dom/ChildNode.idl +++ b/Source/WebCore/dom/ChildNode.idl @@ -18,16 +18,12 @@ * Boston, MA 02110-1301, USA. */ -// DOM 4 +// https://dom.spec.whatwg.org/#childnode [ NoInterfaceObject, ] interface ChildNode { - // readonly attribute Element? previousElementSibling; - // readonly attribute Element? nextElementSibling; - - // void before((Node or DOMString)... nodes); - // void after((Node or DOMString)... nodes); - // void replace((Node or DOMString)... nodes); - [RaisesException] void remove(); + [CEReactions, Unscopable, MayThrowException] void before((Node or DOMString)... nodes); + [CEReactions, Unscopable, MayThrowException] void after((Node or DOMString)... nodes); + [CEReactions, Unscopable, MayThrowException] void replaceWith((Node or DOMString)... nodes); + [CEReactions, Unscopable, MayThrowException] void remove(); }; - diff --git a/Source/WebCore/dom/ChildNodeList.cpp b/Source/WebCore/dom/ChildNodeList.cpp index c8fff4e03..95baa2f5f 100644 --- a/Source/WebCore/dom/ChildNodeList.cpp +++ b/Source/WebCore/dom/ChildNodeList.cpp @@ -35,6 +35,7 @@ EmptyNodeList::~EmptyNodeList() ChildNodeList::ChildNodeList(ContainerNode& parent) : m_parent(parent) + , m_indexCache(*this) { } @@ -53,7 +54,7 @@ Node* ChildNodeList::item(unsigned index) const return m_indexCache.nodeAt(*this, index); } -Node* ChildNodeList::collectionFirst() const +Node* ChildNodeList::collectionBegin() const { return m_parent->firstChild(); } @@ -63,47 +64,26 @@ Node* ChildNodeList::collectionLast() const return m_parent->lastChild(); } -Node* ChildNodeList::collectionTraverseForward(Node& current, unsigned count, unsigned& traversedCount) const +void ChildNodeList::collectionTraverseForward(Node*& current, unsigned count, unsigned& traversedCount) const { ASSERT(count); - Node* child = ¤t; for (traversedCount = 0; traversedCount < count; ++traversedCount) { - child = child->nextSibling(); - if (!child) - return nullptr; + current = current->nextSibling(); + if (!current) + return; } - return child; } -Node* ChildNodeList::collectionTraverseBackward(Node& current, unsigned count) const +void ChildNodeList::collectionTraverseBackward(Node*& current, unsigned count) const { ASSERT(count); - Node* child = ¤t; - for (; count && child ; --count) - child = child->previousSibling(); - return child; -} - -Node* ChildNodeList::namedItem(const AtomicString& name) const -{ - // FIXME: According to the spec child node list should not have namedItem(). - if (m_parent.get().inDocument()) { - Element* element = m_parent.get().treeScope().getElementById(name); - if (element && element->parentNode() == &m_parent.get()) - return element; - if (!element || !m_parent.get().treeScope().containsMultipleElementsWithId(name)) - return nullptr; - } - for (auto& element : childrenOfType(m_parent.get())) { - if (element.hasID() && element.idForStyleResolution() == name) - return const_cast(&element); - } - return nullptr; + for (; count && current ; --count) + current = current->previousSibling(); } void ChildNodeList::invalidateCache() { - m_indexCache.invalidate(); + m_indexCache.invalidate(*this); } } // namespace WebCore diff --git a/Source/WebCore/dom/ChildNodeList.h b/Source/WebCore/dom/ChildNodeList.h index 2454e8e0c..818227aa8 100644 --- a/Source/WebCore/dom/ChildNodeList.h +++ b/Source/WebCore/dom/ChildNodeList.h @@ -21,13 +21,11 @@ * */ -#ifndef ChildNodeList_h -#define ChildNodeList_h +#pragma once #include "CollectionIndexCache.h" #include "NodeList.h" #include -#include namespace WebCore { @@ -35,59 +33,59 @@ class ContainerNode; class EmptyNodeList final : public NodeList { public: - static PassRefPtr create(Node& owner) + static Ref create(Node& owner) { - return adoptRef(new EmptyNodeList(owner)); + return adoptRef(*new EmptyNodeList(owner)); } virtual ~EmptyNodeList(); - Node& ownerNode() { return m_owner.get(); } + Node& ownerNode() { return m_owner; } private: explicit EmptyNodeList(Node& owner) : m_owner(owner) { } - virtual unsigned length() const override { return 0; } - virtual Node* item(unsigned) const override { return nullptr; } - virtual Node* namedItem(const AtomicString&) const override { return nullptr; } + unsigned length() const override { return 0; } + Node* item(unsigned) const override { return nullptr; } + size_t memoryCost() const override { return 0; } - virtual bool isEmptyNodeList() const override { return true; } + bool isEmptyNodeList() const override { return true; } Ref m_owner; }; class ChildNodeList final : public NodeList { public: - static PassRefPtr create(ContainerNode& parent) + static Ref create(ContainerNode& parent) { - return adoptRef(new ChildNodeList(parent)); + return adoptRef(*new ChildNodeList(parent)); } virtual ~ChildNodeList(); - ContainerNode& ownerNode() { return m_parent.get(); } + ContainerNode& ownerNode() { return m_parent; } void invalidateCache(); // For CollectionIndexCache - Node* collectionFirst() const; + Node* collectionBegin() const; Node* collectionLast() const; - Node* collectionTraverseForward(Node&, unsigned count, unsigned& traversedCount) const; - Node* collectionTraverseBackward(Node&, unsigned count) const; + Node* collectionEnd() const { return nullptr; } + void collectionTraverseForward(Node*&, unsigned count, unsigned& traversedCount) const; + void collectionTraverseBackward(Node*&, unsigned count) const; bool collectionCanTraverseBackward() const { return true; } + void willValidateIndexCache() const { } private: explicit ChildNodeList(ContainerNode& parent); - virtual unsigned length() const override; - virtual Node* item(unsigned index) const override; - virtual Node* namedItem(const AtomicString&) const override; + unsigned length() const override; + Node* item(unsigned index) const override; + size_t memoryCost() const override { return m_indexCache.memoryCost(); } - virtual bool isChildNodeList() const override { return true; } + bool isChildNodeList() const override { return true; } Ref m_parent; - mutable CollectionIndexCache m_indexCache; + mutable CollectionIndexCache m_indexCache; }; } // namespace WebCore - -#endif // ChildNodeList_h diff --git a/Source/WebCore/dom/ClassCollection.cpp b/Source/WebCore/dom/ClassCollection.cpp new file mode 100644 index 000000000..88af086a3 --- /dev/null +++ b/Source/WebCore/dom/ClassCollection.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2007-2008, 2014, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2007 David Smith (catfish.man@gmail.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ClassCollection.h" + +#include "NodeRareData.h" +#include "StyledElement.h" + +namespace WebCore { + +Ref ClassCollection::create(ContainerNode& rootNode, CollectionType type, const AtomicString& classNames) +{ + ASSERT(type == ByClass); + return adoptRef(*new ClassCollection(rootNode, type, classNames)); +} + +ClassCollection::~ClassCollection() +{ + ownerNode().nodeLists()->removeCachedCollection(this, m_originalClassNames); +} + +} // namespace WebCore diff --git a/Source/WebCore/dom/ClassCollection.h b/Source/WebCore/dom/ClassCollection.h new file mode 100644 index 000000000..1af53cca8 --- /dev/null +++ b/Source/WebCore/dom/ClassCollection.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2007, 2014, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2007 David Smith (catfish.man@gmail.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "CachedHTMLCollection.h" +#include "Element.h" +#include "SpaceSplitString.h" + +namespace WebCore { + +class ClassCollection final : public CachedHTMLCollection::traversalType> { +public: + static Ref create(ContainerNode&, CollectionType, const AtomicString& classNames); + + virtual ~ClassCollection(); + + bool elementMatches(Element&) const; + +private: + ClassCollection(ContainerNode& rootNode, CollectionType, const AtomicString& classNames); + + SpaceSplitString m_classNames; + AtomicString m_originalClassNames; +}; + +inline ClassCollection::ClassCollection(ContainerNode& rootNode, CollectionType type, const AtomicString& classNames) + : CachedHTMLCollection::traversalType>(rootNode, type) + , m_classNames(classNames, rootNode.document().inQuirksMode()) + , m_originalClassNames(classNames) +{ +} + +inline bool ClassCollection::elementMatches(Element& element) const +{ + if (!element.hasClass()) + return false; + if (m_classNames.isEmpty()) + return false; + return element.classNames().containsAll(m_classNames); +} + +} // namespace WebCore + +SPECIALIZE_TYPE_TRAITS_HTMLCOLLECTION(ClassCollection, ByClass) diff --git a/Source/WebCore/dom/ClassNodeList.cpp b/Source/WebCore/dom/ClassNodeList.cpp deleted file mode 100644 index 2cd99b1eb..000000000 --- a/Source/WebCore/dom/ClassNodeList.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2007 David Smith (catfish.man@gmail.com) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "ClassNodeList.h" - -#include "NodeRareData.h" -#include "StyledElement.h" - -namespace WebCore { - -ClassNodeList::ClassNodeList(ContainerNode& rootNode, const String& classNames) - : LiveNodeList(rootNode, ClassNodeListType, InvalidateOnClassAttrChange) - , m_classNames(classNames, document().inQuirksMode()) - , m_originalClassNames(classNames) -{ -} - -ClassNodeList::~ClassNodeList() -{ - ownerNode().nodeLists()->removeCacheWithName(this, m_originalClassNames); -} - -bool ClassNodeList::nodeMatches(Element* testNode) const -{ - return nodeMatchesInlined(testNode); -} - -} // namespace WebCore diff --git a/Source/WebCore/dom/ClassNodeList.h b/Source/WebCore/dom/ClassNodeList.h deleted file mode 100644 index 79813e5cf..000000000 --- a/Source/WebCore/dom/ClassNodeList.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2007 Apple Inc. All rights reserved. - * Copyright (C) 2007 David Smith (catfish.man@gmail.com) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef ClassNodeList_h -#define ClassNodeList_h - -#include "Element.h" -#include "LiveNodeList.h" -#include "Node.h" -#include "SpaceSplitString.h" - -namespace WebCore { - -class ClassNodeList : public LiveNodeList { -public: - static PassRefPtr create(ContainerNode& rootNode, const String& classNames) - { - return adoptRef(new ClassNodeList(rootNode, classNames)); - } - - virtual ~ClassNodeList(); - - bool nodeMatchesInlined(Element*) const; - -private: - ClassNodeList(ContainerNode& rootNode, const String& classNames); - - virtual bool nodeMatches(Element*) const override; - - SpaceSplitString m_classNames; - String m_originalClassNames; -}; - -inline bool ClassNodeList::nodeMatchesInlined(Element* testNode) const -{ - if (!testNode->hasClass()) - return false; - if (!m_classNames.size()) - return false; - // FIXME: DOM4 allows getElementsByClassName to return non StyledElement. - // https://bugs.webkit.org/show_bug.cgi?id=94718 - if (!testNode->isStyledElement()) - return false; - return testNode->classNames().containsAll(m_classNames); -} - -} // namespace WebCore - -#endif // ClassNodeList_h diff --git a/Source/WebCore/dom/ClientRect.cpp b/Source/WebCore/dom/ClientRect.cpp index b1322228d..4a64e7551 100644 --- a/Source/WebCore/dom/ClientRect.cpp +++ b/Source/WebCore/dom/ClientRect.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/Source/WebCore/dom/ClientRect.h b/Source/WebCore/dom/ClientRect.h index dc2f0d2d5..2e9efb5b7 100644 --- a/Source/WebCore/dom/ClientRect.h +++ b/Source/WebCore/dom/ClientRect.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -24,12 +24,11 @@ * */ -#ifndef ClientRect_h -#define ClientRect_h +#pragma once #include "FloatRect.h" #include "ScriptWrappable.h" -#include +#include #include namespace WebCore { @@ -38,9 +37,9 @@ namespace WebCore { class ClientRect : public ScriptWrappable, public RefCounted { public: - static PassRefPtr create() { return adoptRef(new ClientRect); } - static PassRefPtr create(const IntRect& rect) { return adoptRef(new ClientRect(rect)); } - static PassRefPtr create(const FloatRect& rect) { return adoptRef(new ClientRect(rect)); } + static Ref create() { return adoptRef(*new ClientRect); } + static Ref create(const IntRect& rect) { return adoptRef(*new ClientRect(rect)); } + static Ref create(const FloatRect& rect) { return adoptRef(*new ClientRect(rect)); } float top() const { return m_rect.y(); } float right() const { return m_rect.maxX(); } @@ -50,13 +49,11 @@ namespace WebCore { float height() const { return m_rect.height(); } private: - ClientRect(); - explicit ClientRect(const IntRect&); - explicit ClientRect(const FloatRect&); + WEBCORE_EXPORT ClientRect(); + WEBCORE_EXPORT explicit ClientRect(const IntRect&); + WEBCORE_EXPORT explicit ClientRect(const FloatRect&); FloatRect m_rect; }; } // namespace WebCore - -#endif // ClientRect_h diff --git a/Source/WebCore/dom/ClientRect.idl b/Source/WebCore/dom/ClientRect.idl index 3dc5b03cf..cd9940a9d 100644 --- a/Source/WebCore/dom/ClientRect.idl +++ b/Source/WebCore/dom/ClientRect.idl @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -25,13 +25,15 @@ */ [ - ImplementationLacksVTable + ImplementationLacksVTable, + ExportMacro=WEBCORE_EXPORT, ] interface ClientRect { - readonly attribute float top; - readonly attribute float right; - readonly attribute float bottom; - readonly attribute float left; - readonly attribute float width; - readonly attribute float height; -}; + readonly attribute unrestricted float top; + readonly attribute unrestricted float right; + readonly attribute unrestricted float bottom; + readonly attribute unrestricted float left; + readonly attribute unrestricted float width; + readonly attribute unrestricted float height; + serializer = { attribute }; +}; diff --git a/Source/WebCore/dom/ClientRectList.cpp b/Source/WebCore/dom/ClientRectList.cpp index 95ec75802..e20fec43d 100644 --- a/Source/WebCore/dom/ClientRectList.cpp +++ b/Source/WebCore/dom/ClientRectList.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -27,7 +27,6 @@ #include "config.h" #include "ClientRectList.h" -#include "ExceptionCode.h" #include "ClientRect.h" namespace WebCore { @@ -39,8 +38,8 @@ ClientRectList::ClientRectList() ClientRectList::ClientRectList(const Vector& quads) { m_list.reserveInitialCapacity(quads.size()); - for (size_t i = 0; i < quads.size(); ++i) - m_list.append(ClientRect::create(quads[i].enclosingBoundingBox())); + for (auto& quad : quads) + m_list.uncheckedAppend(ClientRect::create(quad.enclosingBoundingBox())); } ClientRectList::~ClientRectList() @@ -55,12 +54,10 @@ unsigned ClientRectList::length() const ClientRect* ClientRectList::item(unsigned index) { if (index >= m_list.size()) { - // FIXME: this should throw an exception. - // ec = INDEX_SIZE_ERR; - return 0; + // FIXME: Should this throw an INDEX_SIZE_ERR exception? + return nullptr; } - - return m_list[index].get(); + return m_list[index].ptr(); } } // namespace WebCore diff --git a/Source/WebCore/dom/ClientRectList.h b/Source/WebCore/dom/ClientRectList.h index c421d8035..888430407 100644 --- a/Source/WebCore/dom/ClientRectList.h +++ b/Source/WebCore/dom/ClientRectList.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -24,11 +24,10 @@ * */ -#ifndef ClientRectList_h -#define ClientRectList_h +#pragma once #include "FloatQuad.h" -#include +#include #include #include @@ -38,20 +37,18 @@ namespace WebCore { class ClientRectList : public RefCounted { public: - static PassRefPtr create() { return adoptRef(new ClientRectList); } - static PassRefPtr create(const Vector& quads) { return adoptRef(new ClientRectList(quads)); } - ~ClientRectList(); + static Ref create() { return adoptRef(*new ClientRectList); } + static Ref create(const Vector& quads) { return adoptRef(*new ClientRectList(quads)); } + WEBCORE_EXPORT ~ClientRectList(); unsigned length() const; ClientRect* item(unsigned index); private: - ClientRectList(); - explicit ClientRectList(const Vector&); + WEBCORE_EXPORT ClientRectList(); + WEBCORE_EXPORT explicit ClientRectList(const Vector&); - Vector> m_list; + Vector> m_list; }; } // namespace WebCore - -#endif // ClientRectList_h diff --git a/Source/WebCore/dom/ClientRectList.idl b/Source/WebCore/dom/ClientRectList.idl index 1ad3b53c1..a5dbcf671 100644 --- a/Source/WebCore/dom/ClientRectList.idl +++ b/Source/WebCore/dom/ClientRectList.idl @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,9 +26,10 @@ [ ImplementationLacksVTable, + ExportMacro=WEBCORE_EXPORT, ] interface ClientRectList { readonly attribute unsigned long length; - getter ClientRect item([IsIndex, Default=Undefined] optional unsigned long index); + getter ClientRect item(unsigned long index); // FIXME: Fix list behavior to allow custom exceptions to be thrown. }; diff --git a/Source/WebCore/dom/Clipboard.cpp b/Source/WebCore/dom/Clipboard.cpp deleted file mode 100644 index e40ec5a06..000000000 --- a/Source/WebCore/dom/Clipboard.cpp +++ /dev/null @@ -1,428 +0,0 @@ -/* - * Copyright (C) 2006, 2007, 2008, 2013 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "Clipboard.h" - -#include "CachedImage.h" -#include "CachedImageClient.h" -#include "DragData.h" -#include "Editor.h" -#include "FileList.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "HTMLImageElement.h" -#include "Image.h" -#include "Pasteboard.h" - -namespace WebCore { - -#if ENABLE(DRAG_SUPPORT) - -class DragImageLoader final : private CachedImageClient { - WTF_MAKE_FAST_ALLOCATED; -public: - static PassOwnPtr create(Clipboard*); - void startLoading(CachedResourceHandle&); - void stopLoading(CachedResourceHandle&); - -private: - DragImageLoader(Clipboard*); - virtual void imageChanged(CachedImage*, const IntRect*) override; - Clipboard* m_clipboard; -}; - -#endif - -Clipboard::Clipboard(ClipboardAccessPolicy policy, PassOwnPtr pasteboard, ClipboardType type, bool forFileDrag) - : m_policy(policy) - , m_pasteboard(pasteboard) -#if ENABLE(DRAG_SUPPORT) - , m_forDrag(type != CopyAndPaste) - , m_forFileDrag(forFileDrag) - , m_dropEffect(ASCIILiteral("uninitialized")) - , m_effectAllowed(ASCIILiteral("uninitialized")) - , m_shouldUpdateDragImage(false) -#endif -{ -#if !ENABLE(DRAG_SUPPORT) - ASSERT_UNUSED(type, type == CopyAndPaste); - ASSERT_UNUSED(forFileDrag, !forFileDrag); -#endif -} - -PassRefPtr Clipboard::createForCopyAndPaste(ClipboardAccessPolicy policy) -{ - return adoptRef(new Clipboard(policy, policy == ClipboardWritable ? Pasteboard::createPrivate() : Pasteboard::createForCopyAndPaste())); -} - -Clipboard::~Clipboard() -{ -#if ENABLE(DRAG_SUPPORT) - if (m_dragImageLoader && m_dragImage) - m_dragImageLoader->stopLoading(m_dragImage); -#endif -} - -void Clipboard::setAccessPolicy(ClipboardAccessPolicy policy) -{ - // Once the clipboard goes numb, it can never go back. - ASSERT(m_policy != ClipboardNumb || policy == ClipboardNumb); - m_policy = policy; -} - -bool Clipboard::canReadTypes() const -{ - return m_policy == ClipboardReadable || m_policy == ClipboardTypesReadable || m_policy == ClipboardWritable; -} - -bool Clipboard::canReadData() const -{ - return m_policy == ClipboardReadable || m_policy == ClipboardWritable; -} - -bool Clipboard::canWriteData() const -{ - return m_policy == ClipboardWritable; -} - -void Clipboard::clearData(const String& type) -{ - if (!canWriteData()) - return; - - m_pasteboard->clear(type); -} - -void Clipboard::clearData() -{ - if (!canWriteData()) - return; - - m_pasteboard->clear(); -} - -String Clipboard::getData(const String& type) const -{ - if (!canReadData()) - return String(); - -#if ENABLE(DRAG_SUPPORT) - if (m_forFileDrag) - return String(); -#endif - - return m_pasteboard->readString(type); -} - -bool Clipboard::setData(const String& type, const String& data) -{ - if (!canWriteData()) - return false; - -#if ENABLE(DRAG_SUPPORT) - if (m_forFileDrag) - return false; -#endif - - return m_pasteboard->writeString(type, data); -} - -Vector Clipboard::types() const -{ - if (!canReadTypes()) - return Vector(); - - return m_pasteboard->types(); -} - -PassRefPtr Clipboard::files() const -{ - // FIXME: We could cache the computed file list if it was necessary and helpful. - // Currently, each access gets a new copy, and thus setData() modifications to the - // clipboard are not reflected in any FileList objects the page has accessed and stored. - - if (!canReadData()) - return FileList::create(); - -#if ENABLE(DRAG_SUPPORT) - if (m_forDrag && !m_forFileDrag) - return FileList::create(); -#endif - - Vector filenames = m_pasteboard->readFilenames(); - RefPtr fileList = FileList::create(); - for (size_t i = 0; i < filenames.size(); ++i) - fileList->append(File::create(filenames[i], File::AllContentTypes)); - return fileList.release(); -} - -#if !ENABLE(DRAG_SUPPORT) - -String Clipboard::dropEffect() const -{ - return ASCIILiteral("none"); -} - -void Clipboard::setDropEffect(const String&) -{ -} - -String Clipboard::effectAllowed() const -{ - return ASCIILiteral("uninitialized"); -} - -void Clipboard::setEffectAllowed(const String&) -{ -} - -void Clipboard::setDragImage(Element*, int, int) -{ -} - -#else - -PassRefPtr Clipboard::createForDragAndDrop() -{ - return adoptRef(new Clipboard(ClipboardWritable, Pasteboard::createForDragAndDrop(), DragAndDrop)); -} - -PassRefPtr Clipboard::createForDragAndDrop(ClipboardAccessPolicy policy, const DragData& dragData) -{ - return adoptRef(new Clipboard(policy, Pasteboard::createForDragAndDrop(dragData), DragAndDrop, dragData.containsFiles())); -} - -bool Clipboard::canSetDragImage() const -{ - // Note that the spec doesn't actually allow drag image modification outside the dragstart - // event. This capability is maintained for backwards compatiblity for ports that have - // supported this in the past. On many ports, attempting to set a drag image outside the - // dragstart operation is a no-op anyway. - return m_forDrag && (m_policy == ClipboardImageWritable || m_policy == ClipboardWritable); -} - -void Clipboard::setDragImage(Element* element, int x, int y) -{ - if (!canSetDragImage()) - return; - - CachedImage* image; - if (element && isHTMLImageElement(element) && !element->inDocument()) - image = toHTMLImageElement(element)->cachedImage(); - else - image = 0; - - m_dragLocation = IntPoint(x, y); - - if (m_dragImageLoader && m_dragImage) - m_dragImageLoader->stopLoading(m_dragImage); - m_dragImage = image; - if (m_dragImage) { - if (!m_dragImageLoader) - m_dragImageLoader = DragImageLoader::create(this); - m_dragImageLoader->startLoading(m_dragImage); - } - - m_dragImageElement = image ? 0 : element; - - updateDragImage(); -} - -void Clipboard::updateDragImage() -{ - // Don't allow setting the image if we haven't started dragging yet; we'll rely on the dragging code - // to install this drag image as part of getting the drag kicked off. - if (!m_shouldUpdateDragImage) - return; - - IntPoint computedHotSpot; - DragImageRef computedImage = createDragImage(computedHotSpot); - if (!computedImage) - return; - - m_pasteboard->setDragImage(computedImage, computedHotSpot); -} - -#if !PLATFORM(MAC) - -DragImageRef Clipboard::createDragImage(IntPoint& location) const -{ - location = m_dragLocation; - - if (m_dragImage) - return createDragImageFromImage(m_dragImage->image(), ImageOrientationDescription()); - - if (m_dragImageElement) { - if (Frame* frame = m_dragImageElement->document().frame()) - return createDragImageForNode(*frame, *m_dragImageElement); - } - - // We do not have enough information to create a drag image, use the default icon. - return nullptr; -} - -#endif - -PassOwnPtr DragImageLoader::create(Clipboard* clipboard) -{ - return adoptPtr(new DragImageLoader(clipboard)); -} - -DragImageLoader::DragImageLoader(Clipboard* clipboard) - : m_clipboard(clipboard) -{ -} - -void DragImageLoader::startLoading(CachedResourceHandle& image) -{ - // FIXME: Does this really trigger a load? Does it need to? - image->addClient(this); -} - -void DragImageLoader::stopLoading(CachedResourceHandle& image) -{ - image->removeClient(this); -} - -void DragImageLoader::imageChanged(CachedImage*, const IntRect*) -{ - m_clipboard->updateDragImage(); -} - -static DragOperation dragOpFromIEOp(const String& operation) -{ - if (operation == "uninitialized") - return DragOperationEvery; - if (operation == "none") - return DragOperationNone; - if (operation == "copy") - return DragOperationCopy; - if (operation == "link") - return DragOperationLink; - if (operation == "move") - return (DragOperation)(DragOperationGeneric | DragOperationMove); - if (operation == "copyLink") - return (DragOperation)(DragOperationCopy | DragOperationLink); - if (operation == "copyMove") - return (DragOperation)(DragOperationCopy | DragOperationGeneric | DragOperationMove); - if (operation == "linkMove") - return (DragOperation)(DragOperationLink | DragOperationGeneric | DragOperationMove); - if (operation == "all") - return DragOperationEvery; - return DragOperationPrivate; // really a marker for "no conversion" -} - -static const char* IEOpFromDragOp(DragOperation operation) -{ - bool isGenericMove = operation & (DragOperationGeneric | DragOperationMove); - - if ((isGenericMove && (operation & DragOperationCopy) && (operation & DragOperationLink)) || operation == DragOperationEvery) - return "all"; - if (isGenericMove && (operation & DragOperationCopy)) - return "copyMove"; - if (isGenericMove && (operation & DragOperationLink)) - return "linkMove"; - if ((operation & DragOperationCopy) && (operation & DragOperationLink)) - return "copyLink"; - if (isGenericMove) - return "move"; - if (operation & DragOperationCopy) - return "copy"; - if (operation & DragOperationLink) - return "link"; - return "none"; -} - -DragOperation Clipboard::sourceOperation() const -{ - DragOperation operation = dragOpFromIEOp(m_effectAllowed); - ASSERT(operation != DragOperationPrivate); - return operation; -} - -DragOperation Clipboard::destinationOperation() const -{ - DragOperation operation = dragOpFromIEOp(m_dropEffect); - ASSERT(operation == DragOperationCopy || operation == DragOperationNone || operation == DragOperationLink || operation == (DragOperation)(DragOperationGeneric | DragOperationMove) || operation == DragOperationEvery); - return operation; -} - -void Clipboard::setSourceOperation(DragOperation operation) -{ - ASSERT_ARG(operation, operation != DragOperationPrivate); - m_effectAllowed = IEOpFromDragOp(operation); -} - -void Clipboard::setDestinationOperation(DragOperation operation) -{ - ASSERT_ARG(operation, operation == DragOperationCopy || operation == DragOperationNone || operation == DragOperationLink || operation == DragOperationGeneric || operation == DragOperationMove || operation == (DragOperation)(DragOperationGeneric | DragOperationMove)); - m_dropEffect = IEOpFromDragOp(operation); -} - -String Clipboard::dropEffect() const -{ - return m_dropEffect == "uninitialized" ? ASCIILiteral("none") : m_dropEffect; -} - -void Clipboard::setDropEffect(const String& effect) -{ - if (!m_forDrag) - return; - - if (effect != "none" && effect != "copy" && effect != "link" && effect != "move") - return; - - // FIXME: The spec allows this in all circumstances. There is probably no value - // in ignoring attempts to change it. - if (!canReadTypes()) - return; - - m_dropEffect = effect; -} - -String Clipboard::effectAllowed() const -{ - return m_effectAllowed; -} - -void Clipboard::setEffectAllowed(const String& effect) -{ - if (!m_forDrag) - return; - - // Ignore any attempts to set it to an unknown value. - if (dragOpFromIEOp(effect) == DragOperationPrivate) - return; - - if (!canWriteData()) - return; - - m_effectAllowed = effect; -} - -#endif // ENABLE(DRAG_SUPPORT) - -} // namespace WebCore diff --git a/Source/WebCore/dom/Clipboard.h b/Source/WebCore/dom/Clipboard.h deleted file mode 100644 index 5ca2700b6..000000000 --- a/Source/WebCore/dom/Clipboard.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de) - * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2013 Apple 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 Clipboard_h -#define Clipboard_h - -#include "CachedResourceHandle.h" -#include "ClipboardAccessPolicy.h" -#include "DragActions.h" -#include "DragImage.h" -#include "IntPoint.h" -#include -#include - -namespace WebCore { - - class CachedImage; - class DataTransferItemList; - class DragData; - class DragImageLoader; - class Element; - class FileList; - class Pasteboard; - - class Clipboard : public RefCounted { - public: - static PassRefPtr createForCopyAndPaste(ClipboardAccessPolicy); - - ~Clipboard(); - - String dropEffect() const; - void setDropEffect(const String&); - - String effectAllowed() const; - void setEffectAllowed(const String&); - - Vector types() const; - - PassRefPtr files() const; - - void clearData(const String& type); - void clearData(); - - String getData(const String& type) const; - - bool setData(const String& type, const String& data); - - void setDragImage(Element*, int x, int y); - -#if ENABLE(DATA_TRANSFER_ITEMS) - PassRefPtr items() = 0; -#endif - - void setAccessPolicy(ClipboardAccessPolicy); - bool canReadTypes() const; - bool canReadData() const; - bool canWriteData() const; - - Pasteboard& pasteboard() { return *m_pasteboard; } - -#if ENABLE(DRAG_SUPPORT) - static PassRefPtr createForDragAndDrop(); - static PassRefPtr createForDragAndDrop(ClipboardAccessPolicy, const DragData&); - - bool dropEffectIsUninitialized() const { return m_dropEffect == "uninitialized"; } - - DragOperation sourceOperation() const; - DragOperation destinationOperation() const; - void setSourceOperation(DragOperation); - void setDestinationOperation(DragOperation); - - void setDragHasStarted() { m_shouldUpdateDragImage = true; } - DragImageRef createDragImage(IntPoint& dragLocation) const; - void updateDragImage(); -#endif - - private: - enum ClipboardType { CopyAndPaste, DragAndDrop }; - Clipboard(ClipboardAccessPolicy, PassOwnPtr, ClipboardType = CopyAndPaste, bool forFileDrag = false); - -#if ENABLE(DRAG_SUPPORT) - bool canSetDragImage() const; -#endif - - ClipboardAccessPolicy m_policy; - OwnPtr m_pasteboard; - -#if ENABLE(DRAG_SUPPORT) - bool m_forDrag; - bool m_forFileDrag; - String m_dropEffect; - String m_effectAllowed; - bool m_shouldUpdateDragImage; - IntPoint m_dragLocation; - CachedResourceHandle m_dragImage; - RefPtr m_dragImageElement; - OwnPtr m_dragImageLoader; -#endif - }; - -} // namespace WebCore - -#endif // Clipboard_h diff --git a/Source/WebCore/dom/Clipboard.idl b/Source/WebCore/dom/Clipboard.idl deleted file mode 100644 index 0a6206153..000000000 --- a/Source/WebCore/dom/Clipboard.idl +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2008, 2013 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -[ - SkipVTableValidation, -] interface Clipboard { - attribute DOMString dropEffect; - attribute DOMString effectAllowed; - - [CustomGetter] readonly attribute Array types; - readonly attribute FileList files; - - void clearData(optional DOMString type); - DOMString getData(DOMString type); - boolean setData(DOMString type, DOMString data); - void setDragImage(Element image, long x, long y); - - [Conditional=DATA_TRANSFER_ITEMS] readonly attribute DataTransferItemList items; -}; diff --git a/Source/WebCore/dom/ClipboardAccessPolicy.h b/Source/WebCore/dom/ClipboardAccessPolicy.h deleted file mode 100644 index 7a54009e5..000000000 --- a/Source/WebCore/dom/ClipboardAccessPolicy.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef ClipboardAccessPolicy_h -#define ClipboardAccessPolicy_h - -namespace WebCore { - -enum ClipboardAccessPolicy { - ClipboardNumb, ClipboardImageWritable, ClipboardWritable, ClipboardTypesReadable, ClipboardReadable -}; - -} // namespace - -#endif diff --git a/Source/WebCore/dom/ClipboardEvent.cpp b/Source/WebCore/dom/ClipboardEvent.cpp index 421b8876a..bdc4b9a53 100644 --- a/Source/WebCore/dom/ClipboardEvent.cpp +++ b/Source/WebCore/dom/ClipboardEvent.cpp @@ -23,17 +23,13 @@ #include "config.h" #include "ClipboardEvent.h" -#include "Clipboard.h" -#include "EventNames.h" +#include "DataTransfer.h" namespace WebCore { -ClipboardEvent::ClipboardEvent() -{ -} - -ClipboardEvent::ClipboardEvent(const AtomicString& eventType, bool canBubble, bool cancelable, PassRefPtr clipboard) - : Event(eventType, canBubble, cancelable), m_clipboard(clipboard) +ClipboardEvent::ClipboardEvent(const AtomicString& type, const Init& init, IsTrusted isTrusted) + : Event(type, init, isTrusted) + , m_clipboardData(init.clipboardData) { } @@ -43,8 +39,7 @@ ClipboardEvent::~ClipboardEvent() EventInterface ClipboardEvent::eventInterface() const { - // Notice that there is no ClipboardEvent.idl. - return EventInterfaceType; + return ClipboardEventInterfaceType; } bool ClipboardEvent::isClipboardEvent() const diff --git a/Source/WebCore/dom/ClipboardEvent.h b/Source/WebCore/dom/ClipboardEvent.h index b8474337f..c4993558a 100644 --- a/Source/WebCore/dom/ClipboardEvent.h +++ b/Source/WebCore/dom/ClipboardEvent.h @@ -21,40 +21,37 @@ * */ -#ifndef ClipboardEvent_h -#define ClipboardEvent_h +#pragma once #include "Event.h" namespace WebCore { - class Clipboard; +class DataTransfer; - class ClipboardEvent : public Event { - public: - virtual ~ClipboardEvent(); +class ClipboardEvent final : public Event { +public: + virtual ~ClipboardEvent(); - static PassRefPtr create() - { - return adoptRef(new ClipboardEvent); - } - static PassRefPtr create(const AtomicString& type, bool canBubbleArg, bool cancelableArg, PassRefPtr clipboardArg) - { - return adoptRef(new ClipboardEvent(type, canBubbleArg, cancelableArg, clipboardArg)); - } + struct Init : EventInit { + RefPtr clipboardData; + }; - Clipboard* clipboard() const { return m_clipboard.get(); } + static Ref create(const AtomicString& type, const Init& init, IsTrusted isTrusted = IsTrusted::No) + { + auto event = adoptRef(*new ClipboardEvent(type, init, isTrusted)); + return event; + } - private: - ClipboardEvent(); - ClipboardEvent(const AtomicString& type, bool canBubbleArg, bool cancelableArg, PassRefPtr); + DataTransfer* clipboardData() const { return m_clipboardData.get(); } - virtual EventInterface eventInterface() const override; - virtual bool isClipboardEvent() const override; +private: + ClipboardEvent(const AtomicString& type, const Init&, IsTrusted); - RefPtr m_clipboard; - }; + EventInterface eventInterface() const final; + bool isClipboardEvent() const final; -} // namespace WebCore + RefPtr m_clipboardData; +}; -#endif // ClipboardEvent_h +} // namespace WebCore diff --git a/Source/WebCore/dom/ClipboardEvent.idl b/Source/WebCore/dom/ClipboardEvent.idl new file mode 100644 index 000000000..4a41992ac --- /dev/null +++ b/Source/WebCore/dom/ClipboardEvent.idl @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2016 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +[ + Constructor(DOMString type, optional ClipboardEventInit eventInitDict) +] interface ClipboardEvent : Event { + readonly attribute DataTransfer? clipboardData; +}; + +dictionary ClipboardEventInit : EventInit { + DataTransfer? clipboardData = null; +}; diff --git a/Source/WebCore/dom/CollectionIndexCache.cpp b/Source/WebCore/dom/CollectionIndexCache.cpp new file mode 100644 index 000000000..65bea699e --- /dev/null +++ b/Source/WebCore/dom/CollectionIndexCache.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CollectionIndexCache.h" + +#include "CommonVM.h" +#include "DOMWindow.h" +#include "JSDOMBinding.h" + +namespace WebCore { + +void reportExtraMemoryAllocatedForCollectionIndexCache(size_t cost) +{ + JSC::VM& vm = commonVM(); + JSC::JSLockHolder lock(vm); + // FIXME: Adopt reportExtraMemoryVisited, and switch to reportExtraMemoryAllocated. + // https://bugs.webkit.org/show_bug.cgi?id=142595 + vm.heap.deprecatedReportExtraMemory(cost); +} + +} diff --git a/Source/WebCore/dom/CollectionIndexCache.h b/Source/WebCore/dom/CollectionIndexCache.h index 8a761f9fb..048c9ae63 100644 --- a/Source/WebCore/dom/CollectionIndexCache.h +++ b/Source/WebCore/dom/CollectionIndexCache.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,150 +23,202 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CollectionIndexCache_h -#define CollectionIndexCache_h +#pragma once + +#include namespace WebCore { -template +WEBCORE_EXPORT void reportExtraMemoryAllocatedForCollectionIndexCache(size_t); + +template class CollectionIndexCache { public: - CollectionIndexCache(); + explicit CollectionIndexCache(const Collection&); + + typedef typename std::iterator_traits::value_type NodeType; unsigned nodeCount(const Collection&); NodeType* nodeAt(const Collection&, unsigned index); - void invalidate(); + bool hasValidCache(const Collection& collection) const { return m_current != collection.collectionEnd() || m_nodeCountValid || m_listValid; } + void invalidate(const Collection&); + size_t memoryCost() { return m_cachedList.capacity() * sizeof(NodeType*); } private: - NodeType* nodeBeforeCached(const Collection&, unsigned); - NodeType* nodeAfterCached(const Collection&, unsigned); + unsigned computeNodeCountUpdatingListCache(const Collection&); + NodeType* traverseBackwardTo(const Collection&, unsigned); + NodeType* traverseForwardTo(const Collection&, unsigned); - NodeType* m_currentNode; + Iterator m_current; unsigned m_currentIndex; unsigned m_nodeCount; - bool m_nodeCountValid; + Vector m_cachedList; + bool m_nodeCountValid : 1; + bool m_listValid : 1; }; -template -inline CollectionIndexCache::CollectionIndexCache() - : m_currentNode(nullptr) +template +inline CollectionIndexCache::CollectionIndexCache(const Collection& collection) + : m_current(collection.collectionEnd()) , m_currentIndex(0) , m_nodeCount(0) , m_nodeCountValid(false) + , m_listValid(false) { } -template -inline unsigned CollectionIndexCache::nodeCount(const Collection& collection) +template +inline unsigned CollectionIndexCache::nodeCount(const Collection& collection) { if (!m_nodeCountValid) { - if (auto first = collection.collectionFirst()) { - unsigned count; - collection.collectionTraverseForward(*first, std::numeric_limits::max(), count); - m_nodeCount = count + 1; - } else - m_nodeCount = 0; + if (!hasValidCache(collection)) + collection.willValidateIndexCache(); + m_nodeCount = computeNodeCountUpdatingListCache(collection); m_nodeCountValid = true; } return m_nodeCount; } -template -inline NodeType* CollectionIndexCache::nodeBeforeCached(const Collection& collection, unsigned index) +template +unsigned CollectionIndexCache::computeNodeCountUpdatingListCache(const Collection& collection) +{ + auto current = collection.collectionBegin(); + auto end = collection.collectionEnd(); + if (current == end) + return 0; + + unsigned oldCapacity = m_cachedList.capacity(); + while (current != end) { + m_cachedList.append(&*current); + unsigned traversed; + collection.collectionTraverseForward(current, 1, traversed); + ASSERT(traversed == (current != end ? 1 : 0)); + } + m_listValid = true; + + if (unsigned capacityDifference = m_cachedList.capacity() - oldCapacity) + reportExtraMemoryAllocatedForCollectionIndexCache(capacityDifference * sizeof(NodeType*)); + + return m_cachedList.size(); +} + +template +inline typename CollectionIndexCache::NodeType* CollectionIndexCache::traverseBackwardTo(const Collection& collection, unsigned index) { - ASSERT(m_currentNode); + ASSERT(m_current != collection.collectionEnd()); ASSERT(index < m_currentIndex); bool firstIsCloser = index < m_currentIndex - index; if (firstIsCloser || !collection.collectionCanTraverseBackward()) { - m_currentNode = collection.collectionFirst(); + m_current = collection.collectionBegin(); m_currentIndex = 0; if (index) - m_currentNode = collection.collectionTraverseForward(*m_currentNode, index, m_currentIndex); - ASSERT(m_currentNode); - return m_currentNode; + collection.collectionTraverseForward(m_current, index, m_currentIndex); + ASSERT(m_current != collection.collectionEnd()); + return &*m_current; } - m_currentNode = collection.collectionTraverseBackward(*m_currentNode, m_currentIndex - index); + collection.collectionTraverseBackward(m_current, m_currentIndex - index); m_currentIndex = index; - ASSERT(m_currentNode); - return m_currentNode; + ASSERT(m_current != collection.collectionEnd()); + return &*m_current; } -template -inline NodeType* CollectionIndexCache::nodeAfterCached(const Collection& collection, unsigned index) +template +inline typename CollectionIndexCache::NodeType* CollectionIndexCache::traverseForwardTo(const Collection& collection, unsigned index) { - ASSERT(m_currentNode); + ASSERT(m_current != collection.collectionEnd()); ASSERT(index > m_currentIndex); ASSERT(!m_nodeCountValid || index < m_nodeCount); bool lastIsCloser = m_nodeCountValid && m_nodeCount - index < index - m_currentIndex; if (lastIsCloser && collection.collectionCanTraverseBackward()) { - m_currentNode = collection.collectionLast(); + ASSERT(hasValidCache(collection)); + m_current = collection.collectionLast(); if (index < m_nodeCount - 1) - m_currentNode = collection.collectionTraverseBackward(*m_currentNode, m_nodeCount - index - 1); + collection.collectionTraverseBackward(m_current, m_nodeCount - index - 1); m_currentIndex = index; - ASSERT(m_currentNode); - return m_currentNode; + ASSERT(m_current != collection.collectionEnd()); + return &*m_current; } + if (!hasValidCache(collection)) + collection.willValidateIndexCache(); + unsigned traversedCount; - m_currentNode = collection.collectionTraverseForward(*m_currentNode, index - m_currentIndex, traversedCount); + collection.collectionTraverseForward(m_current, index - m_currentIndex, traversedCount); m_currentIndex = m_currentIndex + traversedCount; - ASSERT(m_currentNode || m_currentIndex < index); - - if (!m_currentNode && !m_nodeCountValid) { + if (m_current == collection.collectionEnd()) { + ASSERT(m_currentIndex < index); // Failed to find the index but at least we now know the size. m_nodeCount = m_currentIndex + 1; m_nodeCountValid = true; + return nullptr; } - return m_currentNode; + ASSERT(hasValidCache(collection)); + return &*m_current; } -template -inline NodeType* CollectionIndexCache::nodeAt(const Collection& collection, unsigned index) +template +inline typename CollectionIndexCache::NodeType* CollectionIndexCache::nodeAt(const Collection& collection, unsigned index) { if (m_nodeCountValid && index >= m_nodeCount) return nullptr; - if (m_currentNode) { + if (m_listValid) + return m_cachedList[index]; + + auto end = collection.collectionEnd(); + if (m_current != end) { if (index > m_currentIndex) - return nodeAfterCached(collection, index); + return traverseForwardTo(collection, index); if (index < m_currentIndex) - return nodeBeforeCached(collection, index); - return m_currentNode; + return traverseBackwardTo(collection, index); + return &*m_current; } bool lastIsCloser = m_nodeCountValid && m_nodeCount - index < index; if (lastIsCloser && collection.collectionCanTraverseBackward()) { - m_currentNode = collection.collectionLast(); + ASSERT(hasValidCache(collection)); + m_current = collection.collectionLast(); if (index < m_nodeCount - 1) - m_currentNode = collection.collectionTraverseBackward(*m_currentNode, m_nodeCount - index - 1); + collection.collectionTraverseBackward(m_current, m_nodeCount - index - 1); m_currentIndex = index; - ASSERT(m_currentNode); - return m_currentNode; + ASSERT(m_current != end); + return &*m_current; } - m_currentNode = collection.collectionFirst(); + if (!hasValidCache(collection)) + collection.willValidateIndexCache(); + + m_current = collection.collectionBegin(); m_currentIndex = 0; - if (index && m_currentNode) { - m_currentNode = collection.collectionTraverseForward(*m_currentNode, index, m_currentIndex); - ASSERT(m_currentNode || m_currentIndex < index); + if (index && m_current != end) { + collection.collectionTraverseForward(m_current, index, m_currentIndex); + ASSERT(m_current != end || m_currentIndex < index); + } + if (m_current == end) { + // Failed to find the index but at least we now know the size. + m_nodeCount = index ? m_currentIndex + 1 : 0; + m_nodeCountValid = true; + return nullptr; } - return m_currentNode; + ASSERT(hasValidCache(collection)); + return &*m_current; } -template -void CollectionIndexCache::invalidate() +template +void CollectionIndexCache::invalidate(const Collection& collection) { - m_currentNode = nullptr; + m_current = collection.collectionEnd(); m_nodeCountValid = false; + m_listValid = false; + m_cachedList.shrink(0); } -} -#endif +} diff --git a/Source/WebCore/dom/Comment.cpp b/Source/WebCore/dom/Comment.cpp index 51300e9e8..731436894 100644 --- a/Source/WebCore/dom/Comment.cpp +++ b/Source/WebCore/dom/Comment.cpp @@ -31,19 +31,14 @@ inline Comment::Comment(Document& document, const String& text) { } -PassRefPtr Comment::create(Document& document, const String& text) +Ref Comment::create(Document& document, const String& text) { - return adoptRef(new Comment(document, text)); -} - -PassRefPtr Comment::create(ScriptExecutionContext& context, const String& text) -{ - return adoptRef(new Comment(toDocument(context), text)); + return adoptRef(*new Comment(document, text)); } String Comment::nodeName() const { - return commentAtom.string(); + return ASCIILiteral("#comment"); } Node::NodeType Comment::nodeType() const @@ -51,9 +46,9 @@ Node::NodeType Comment::nodeType() const return COMMENT_NODE; } -PassRefPtr Comment::cloneNode(bool /*deep*/) +Ref Comment::cloneNodeInternal(Document& targetDocument, CloningOperation) { - return create(document(), data()); + return create(targetDocument, data()); } bool Comment::childTypeAllowed(NodeType) const diff --git a/Source/WebCore/dom/Comment.h b/Source/WebCore/dom/Comment.h index 48729b6ac..fe7d34834 100644 --- a/Source/WebCore/dom/Comment.h +++ b/Source/WebCore/dom/Comment.h @@ -20,8 +20,7 @@ * */ -#ifndef Comment_h -#define Comment_h +#pragma once #include "CharacterData.h" @@ -29,24 +28,19 @@ namespace WebCore { class Comment final : public CharacterData { public: - static PassRefPtr create(Document&, const String&); - static PassRefPtr create(ScriptExecutionContext&, const String&); + static Ref create(Document&, const String&); private: Comment(Document&, const String&); - virtual String nodeName() const override; - virtual NodeType nodeType() const override; - virtual PassRefPtr cloneNode(bool deep) override; - virtual bool childTypeAllowed(NodeType) const override; + String nodeName() const override; + NodeType nodeType() const override; + Ref cloneNodeInternal(Document&, CloningOperation) override; + bool childTypeAllowed(NodeType) const override; }; -inline bool isComment(const Node& node) { return node.nodeType() == Node::COMMENT_NODE; } -void isComment(const Comment&); // Catch unnecessary runtime check of type known at compile time. -void isComment(const ContainerNode&); // Catch unnecessary runtime check of type known at compile time. - -NODE_TYPE_CASTS(Comment) - } // namespace WebCore -#endif // Comment_h +SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::Comment) + static bool isType(const WebCore::Node& node) { return node.nodeType() == WebCore::Node::COMMENT_NODE; } +SPECIALIZE_TYPE_TRAITS_END() diff --git a/Source/WebCore/dom/Comment.idl b/Source/WebCore/dom/Comment.idl index d928c6ef1..579adb4af 100644 --- a/Source/WebCore/dom/Comment.idl +++ b/Source/WebCore/dom/Comment.idl @@ -18,8 +18,9 @@ */ [ - Constructor([Default=NullString] optional DOMString data), - ConstructorCallWith=ScriptExecutionContext + Constructor(optional DOMString data), + ConstructorCallWith=Document, + JSGenerateToJSObject ] interface Comment : CharacterData { }; diff --git a/Source/WebCore/dom/ComposedTreeAncestorIterator.h b/Source/WebCore/dom/ComposedTreeAncestorIterator.h new file mode 100644 index 000000000..c661bce5c --- /dev/null +++ b/Source/WebCore/dom/ComposedTreeAncestorIterator.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "HTMLSlotElement.h" +#include "PseudoElement.h" +#include "ShadowRoot.h" + +namespace WebCore { + +class HTMLSlotElement; + +class ComposedTreeAncestorIterator { +public: + ComposedTreeAncestorIterator(); + ComposedTreeAncestorIterator(Node& current); + + Element& operator*() { return get(); } + Element* operator->() { return &get(); } + + bool operator==(const ComposedTreeAncestorIterator& other) const { return m_current == other.m_current; } + bool operator!=(const ComposedTreeAncestorIterator& other) const { return m_current != other.m_current; } + + ComposedTreeAncestorIterator& operator++() { return traverseParent(); } + + Element& get() { return downcast(*m_current); } + ComposedTreeAncestorIterator& traverseParent(); + +private: + void traverseParentInShadowTree(); + + Node* m_current { 0 }; +}; + +inline ComposedTreeAncestorIterator::ComposedTreeAncestorIterator() +{ +} + +inline ComposedTreeAncestorIterator::ComposedTreeAncestorIterator(Node& current) + : m_current(¤t) +{ + ASSERT(!is(m_current)); +} + +inline ComposedTreeAncestorIterator& ComposedTreeAncestorIterator::traverseParent() +{ + auto* parent = m_current->parentNode(); + if (!parent) { + m_current = nullptr; + return *this; + } + if (is(*parent)) { + m_current = downcast(*parent).host(); + return *this; + } + if (!is(*parent)) { + m_current = nullptr; + return *this; + }; + + if (auto* shadowRoot = parent->shadowRoot()) { + m_current = shadowRoot->findAssignedSlot(*m_current); + return *this; + } + + m_current = parent; + return *this; +} + +class ComposedTreeAncestorAdapter { +public: + using iterator = ComposedTreeAncestorIterator; + + ComposedTreeAncestorAdapter(Node& node) + : m_node(node) + { } + + iterator begin() + { + if (is(m_node)) + return iterator(*downcast(m_node).host()); + if (is(m_node)) + return iterator(*downcast(m_node).hostElement()); + return iterator(m_node).traverseParent(); + } + iterator end() + { + return iterator(); + } + Element* first() + { + auto it = begin(); + if (it == end()) + return nullptr; + return &it.get(); + } + +private: + Node& m_node; +}; + +// FIXME: We should have const versions too. +inline ComposedTreeAncestorAdapter composedTreeAncestors(Node& node) +{ + return ComposedTreeAncestorAdapter(node); +} + +} // namespace WebCore diff --git a/Source/WebCore/dom/ComposedTreeIterator.cpp b/Source/WebCore/dom/ComposedTreeIterator.cpp new file mode 100644 index 000000000..af554ac04 --- /dev/null +++ b/Source/WebCore/dom/ComposedTreeIterator.cpp @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2015-2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ComposedTreeIterator.h" + +#include "HTMLSlotElement.h" +#include "TextStream.h" + +namespace WebCore { + +ComposedTreeIterator::Context::Context() +{ +} + +ComposedTreeIterator::Context::Context(ContainerNode& root, FirstChildTag) + : iterator(root, ElementAndTextDescendantIterator::FirstChild) +{ +} + +ComposedTreeIterator::Context::Context(ContainerNode& root, Node& node) + : iterator(root, &node) +{ +} + +ComposedTreeIterator::Context::Context(ContainerNode& root, Node& node, SlottedTag) + : iterator(root, &node) + , end(iterator) +{ + end.traverseNextSibling(); +} + +ComposedTreeIterator::ComposedTreeIterator(ContainerNode& root, FirstChildTag) + : m_rootIsInShadowTree(root.isInShadowTree()) +{ + ASSERT(!is(root)); + + if (is(root)) { + auto& slot = downcast(root); + if (auto* assignedNodes = slot.assignedNodes()) { + initializeContextStack(root, *assignedNodes->at(0)); + return; + } + } + if (auto* shadowRoot = root.shadowRoot()) { + ElementAndTextDescendantIterator firstChild(*shadowRoot, ElementAndTextDescendantIterator::FirstChild); + initializeContextStack(root, firstChild ? *firstChild : root); + return; + } + + m_contextStack.uncheckedAppend(Context(root, FirstChild)); +} + +ComposedTreeIterator::ComposedTreeIterator(ContainerNode& root, Node& current) + : m_rootIsInShadowTree(root.isInShadowTree()) +{ + ASSERT(!is(root)); + ASSERT(!is(current)); + + bool mayNeedShadowStack = root.shadowRoot() || (¤t != &root && current.parentNode() != &root); + if (mayNeedShadowStack) + initializeContextStack(root, current); + else + m_contextStack.uncheckedAppend(Context(root, current)); +} + +void ComposedTreeIterator::initializeContextStack(ContainerNode& root, Node& current) +{ + // This code sets up the iterator for arbitrary node/root pair. It is not needed in common cases + // or completes fast because node and root are close (like in composedTreeChildren(*parent).at(node) case). + auto* node = ¤t; + auto* contextCurrent = node; + size_t currentSlotNodeIndex = notFound; + while (node != &root) { + auto* parent = node->parentNode(); + if (!parent) { + *this = { }; + return; + } + if (is(*parent)) { + auto& shadowRoot = downcast(*parent); + m_contextStack.append(Context(shadowRoot, *contextCurrent)); + m_contextStack.last().slotNodeIndex = currentSlotNodeIndex; + + node = shadowRoot.host(); + contextCurrent = node; + currentSlotNodeIndex = notFound; + continue; + } + if (auto* shadowRoot = parent->shadowRoot()) { + m_contextStack.append(Context(*parent, *contextCurrent, Context::Slotted)); + m_contextStack.last().slotNodeIndex = currentSlotNodeIndex; + + auto* assignedSlot = shadowRoot->findAssignedSlot(*node); + if (assignedSlot) { + currentSlotNodeIndex = assignedSlot->assignedNodes()->find(node); + ASSERT(currentSlotNodeIndex != notFound); + node = assignedSlot; + contextCurrent = assignedSlot; + continue; + } + // The node is not part of the composed tree. + *this = { }; + return; + } + node = parent; + } + m_contextStack.append(Context(root, *contextCurrent)); + m_contextStack.last().slotNodeIndex = currentSlotNodeIndex; + + m_contextStack.reverse(); +} + +void ComposedTreeIterator::dropAssertions() +{ + for (auto& context : m_contextStack) + context.iterator.dropAssertions(); + m_didDropAssertions = true; +} + +void ComposedTreeIterator::traverseShadowRoot(ShadowRoot& shadowRoot) +{ + Context shadowContext(shadowRoot, FirstChild); + if (!shadowContext.iterator) { + // Empty shadow root. + traverseNextSkippingChildren(); + return; + } + + if (m_didDropAssertions) + shadowContext.iterator.dropAssertions(); + + m_contextStack.append(WTFMove(shadowContext)); +} + +void ComposedTreeIterator::traverseNextInShadowTree() +{ + ASSERT(m_contextStack.size() > 1 || m_rootIsInShadowTree); + + if (is(current())) { + auto& slot = downcast(current()); + if (auto* assignedNodes = slot.assignedNodes()) { + context().slotNodeIndex = 0; + auto* assignedNode = assignedNodes->at(0); + m_contextStack.append(Context(*assignedNode->parentElement(), *assignedNode, Context::Slotted)); + return; + } + } + + context().iterator.traverseNext(); + + if (context().iterator == context().end) + traverseNextLeavingContext(); +} + +void ComposedTreeIterator::traverseNextLeavingContext() +{ + while (context().iterator == context().end && m_contextStack.size() > 1) { + m_contextStack.removeLast(); + if (is(current()) && advanceInSlot(1)) + return; + if (context().iterator == context().end) + return; + context().iterator.traverseNextSkippingChildren(); + } +} + +bool ComposedTreeIterator::advanceInSlot(int direction) +{ + ASSERT(context().slotNodeIndex != notFound); + + auto& assignedNodes = *downcast(current()).assignedNodes(); + // It is fine to underflow this. + context().slotNodeIndex += direction; + if (context().slotNodeIndex >= assignedNodes.size()) + return false; + + auto* slotNode = assignedNodes.at(context().slotNodeIndex); + m_contextStack.append(Context(*slotNode->parentElement(), *slotNode, Context::Slotted)); + return true; +} + +void ComposedTreeIterator::traverseSiblingInSlot(int direction) +{ + ASSERT(m_contextStack.size() > 1); + ASSERT(current().parentNode()->shadowRoot()); + + m_contextStack.removeLast(); + + if (!advanceInSlot(direction)) + *this = { }; +} + +String composedTreeAsText(ContainerNode& root, ComposedTreeAsTextMode mode) +{ + TextStream stream; + auto descendants = composedTreeDescendants(root); + for (auto it = descendants.begin(), end = descendants.end(); it != end; ++it) { + writeIndent(stream, it.depth()); + + if (is(*it)) { + stream << "#text"; + if (mode == ComposedTreeAsTextMode::WithPointers) + stream << " " << &*it; + stream << "\n"; + continue; + } + auto& element = downcast(*it); + stream << element.localName(); + if (element.shadowRoot()) + stream << " (shadow root)"; + if (mode == ComposedTreeAsTextMode::WithPointers) + stream << " " << &*it; + stream << "\n"; + } + return stream.release(); +} + +} diff --git a/Source/WebCore/dom/ComposedTreeIterator.h b/Source/WebCore/dom/ComposedTreeIterator.h new file mode 100644 index 000000000..89740cfb8 --- /dev/null +++ b/Source/WebCore/dom/ComposedTreeIterator.h @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2015-2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "ElementAndTextDescendantIterator.h" +#include "ShadowRoot.h" + +namespace WebCore { + +class HTMLSlotElement; + +class ComposedTreeIterator { +public: + ComposedTreeIterator(); + enum FirstChildTag { FirstChild }; + ComposedTreeIterator(ContainerNode& root, FirstChildTag); + ComposedTreeIterator(ContainerNode& root, Node& current); + + Node& operator*() { return current(); } + Node* operator->() { return ¤t(); } + + bool operator==(const ComposedTreeIterator& other) const { return context().iterator == other.context().iterator; } + bool operator!=(const ComposedTreeIterator& other) const { return context().iterator != other.context().iterator; } + + ComposedTreeIterator& operator++() { return traverseNext(); } + + ComposedTreeIterator& traverseNext(); + ComposedTreeIterator& traverseNextSkippingChildren(); + ComposedTreeIterator& traverseNextSibling(); + ComposedTreeIterator& traversePreviousSibling(); + + unsigned depth() const; + + void dropAssertions(); + +private: + void initializeContextStack(ContainerNode& root, Node& current); + void traverseNextInShadowTree(); + void traverseNextLeavingContext(); + void traverseShadowRoot(ShadowRoot&); + bool advanceInSlot(int direction); + void traverseSiblingInSlot(int direction); + + struct Context { + Context(); + Context(ContainerNode& root, FirstChildTag); + Context(ContainerNode& root, Node& node); + + enum SlottedTag { Slotted }; + Context(ContainerNode& root, Node& node, SlottedTag); + ElementAndTextDescendantIterator iterator; + ElementAndTextDescendantIterator end; + size_t slotNodeIndex { notFound }; + }; + Context& context() { return m_contextStack.last(); } + const Context& context() const { return m_contextStack.last(); } + Node& current() { return *context().iterator; } + + bool m_rootIsInShadowTree { false }; + bool m_didDropAssertions { false }; + Vector m_contextStack; +}; + +inline ComposedTreeIterator::ComposedTreeIterator() +{ + m_contextStack.uncheckedAppend({ }); +} + +inline ComposedTreeIterator& ComposedTreeIterator::traverseNext() +{ + if (auto* shadowRoot = context().iterator->shadowRoot()) { + traverseShadowRoot(*shadowRoot); + return *this; + } + + if (m_contextStack.size() > 1 || m_rootIsInShadowTree) { + traverseNextInShadowTree(); + return *this; + } + + context().iterator.traverseNext(); + return *this; +} + +inline ComposedTreeIterator& ComposedTreeIterator::traverseNextSkippingChildren() +{ + context().iterator.traverseNextSkippingChildren(); + + if (context().iterator == context().end) + traverseNextLeavingContext(); + + return *this; +} + +inline ComposedTreeIterator& ComposedTreeIterator::traverseNextSibling() +{ + if (current().parentNode()->shadowRoot()) { + traverseSiblingInSlot(1); + return *this; + } + context().iterator.traverseNextSibling(); + return *this; +} + +inline ComposedTreeIterator& ComposedTreeIterator::traversePreviousSibling() +{ + if (current().parentNode()->shadowRoot()) { + traverseSiblingInSlot(-1); + return *this; + } + context().iterator.traversePreviousSibling(); + return *this; +} + +inline unsigned ComposedTreeIterator::depth() const +{ + unsigned depth = 0; + for (auto& context : m_contextStack) + depth += context.iterator.depth(); + return depth; +} + +class ComposedTreeDescendantAdapter { +public: + ComposedTreeDescendantAdapter(ContainerNode& parent) + : m_parent(parent) + { } + + ComposedTreeIterator begin() { return ComposedTreeIterator(m_parent, ComposedTreeIterator::FirstChild); } + ComposedTreeIterator end() { return { }; } + ComposedTreeIterator at(const Node& child) { return ComposedTreeIterator(m_parent, const_cast(child)); } + +private: + ContainerNode& m_parent; +}; + +class ComposedTreeChildAdapter { +public: + class Iterator : public ComposedTreeIterator { + public: + Iterator() = default; + explicit Iterator(ContainerNode& root) + : ComposedTreeIterator(root, ComposedTreeIterator::FirstChild) + { } + Iterator(ContainerNode& root, Node& current) + : ComposedTreeIterator(root, current) + { } + + Iterator& operator++() { return static_cast(traverseNextSibling()); } + Iterator& operator--() { return static_cast(traversePreviousSibling()); } + }; + + ComposedTreeChildAdapter(ContainerNode& parent) + : m_parent(parent) + { } + + Iterator begin() { return Iterator(m_parent); } + Iterator end() { return { }; } + Iterator at(const Node& child) { return Iterator(m_parent, const_cast(child)); } + +private: + ContainerNode& m_parent; +}; + +// FIXME: We should have const versions too. +inline ComposedTreeDescendantAdapter composedTreeDescendants(ContainerNode& parent) +{ + return ComposedTreeDescendantAdapter(parent); +} + +inline ComposedTreeChildAdapter composedTreeChildren(ContainerNode& parent) +{ + return ComposedTreeChildAdapter(parent); +} + +enum class ComposedTreeAsTextMode { Normal, WithPointers }; +WEBCORE_EXPORT String composedTreeAsText(ContainerNode& root, ComposedTreeAsTextMode = ComposedTreeAsTextMode::Normal); + +} // namespace WebCore diff --git a/Source/WebCore/dom/CompositionEvent.cpp b/Source/WebCore/dom/CompositionEvent.cpp index df6a2b8f9..3e5ec89f7 100644 --- a/Source/WebCore/dom/CompositionEvent.cpp +++ b/Source/WebCore/dom/CompositionEvent.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -27,26 +27,20 @@ #include "config.h" #include "CompositionEvent.h" -#include "EventNames.h" - namespace WebCore { -CompositionEventInit::CompositionEventInit() -{ -} - CompositionEvent::CompositionEvent() { } -CompositionEvent::CompositionEvent(const AtomicString& type, PassRefPtr view, const String& data) +CompositionEvent::CompositionEvent(const AtomicString& type, DOMWindow* view, const String& data) : UIEvent(type, true, true, view, 0) , m_data(data) { } -CompositionEvent::CompositionEvent(const AtomicString& type, const CompositionEventInit& initializer) - : UIEvent(type, initializer) +CompositionEvent::CompositionEvent(const AtomicString& type, const Init& initializer, IsTrusted isTrusted) + : UIEvent(type, initializer, isTrusted) , m_data(initializer.data) { } @@ -55,7 +49,7 @@ CompositionEvent::~CompositionEvent() { } -void CompositionEvent::initCompositionEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr view, const String& data) +void CompositionEvent::initCompositionEvent(const AtomicString& type, bool canBubble, bool cancelable, DOMWindow* view, const String& data) { if (dispatched()) return; @@ -70,4 +64,9 @@ EventInterface CompositionEvent::eventInterface() const return CompositionEventInterfaceType; } +bool CompositionEvent::isCompositionEvent() const +{ + return true; +} + } // namespace WebCore diff --git a/Source/WebCore/dom/CompositionEvent.h b/Source/WebCore/dom/CompositionEvent.h index 89f69703b..8ff02ec96 100644 --- a/Source/WebCore/dom/CompositionEvent.h +++ b/Source/WebCore/dom/CompositionEvent.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -24,52 +24,51 @@ * */ -#ifndef CompositionEvent_h -#define CompositionEvent_h +#pragma once #include "UIEvent.h" namespace WebCore { -struct CompositionEventInit : UIEventInit { - CompositionEventInit(); - - String data; -}; - -class CompositionEvent : public UIEvent { +class CompositionEvent final : public UIEvent { public: - static PassRefPtr create() + static Ref create(const AtomicString& type, DOMWindow* view, const String& data) { - return adoptRef(new CompositionEvent); + return adoptRef(*new CompositionEvent(type, view, data)); } - static PassRefPtr create(const AtomicString& type, PassRefPtr view, const String& data) + static Ref createForBindings() { - return adoptRef(new CompositionEvent(type, view, data)); + return adoptRef(*new CompositionEvent); } - static PassRefPtr create(const AtomicString& type, const CompositionEventInit& initializer) + struct Init : UIEventInit { + String data; + }; + + static Ref create(const AtomicString& type, const Init& initializer, IsTrusted isTrusted = IsTrusted::No) { - return adoptRef(new CompositionEvent(type, initializer)); + return adoptRef(*new CompositionEvent(type, initializer, isTrusted)); } virtual ~CompositionEvent(); - void initCompositionEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr, const String& data); + void initCompositionEvent(const AtomicString& type, bool canBubble, bool cancelable, DOMWindow*, const String& data); String data() const { return m_data; } - virtual EventInterface eventInterface() const override; + EventInterface eventInterface() const override; private: CompositionEvent(); - CompositionEvent(const AtomicString& type, PassRefPtr, const String&); - CompositionEvent(const AtomicString& type, const CompositionEventInit&); + CompositionEvent(const AtomicString& type, DOMWindow*, const String&); + CompositionEvent(const AtomicString& type, const Init&, IsTrusted); + + bool isCompositionEvent() const override; String m_data; }; } // namespace WebCore -#endif // CompositionEvent_h +SPECIALIZE_TYPE_TRAITS_EVENT(CompositionEvent) diff --git a/Source/WebCore/dom/CompositionEvent.idl b/Source/WebCore/dom/CompositionEvent.idl index 05ace6fdd..d87240883 100644 --- a/Source/WebCore/dom/CompositionEvent.idl +++ b/Source/WebCore/dom/CompositionEvent.idl @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -24,17 +24,20 @@ */ [ - ConstructorConditional=DOM4_EVENTS_CONSTRUCTOR, - ConstructorTemplate=Event, + Constructor(DOMString type, optional CompositionEventInit eventInitDict), ] interface CompositionEvent : UIEvent { - [InitializedByEventConstructor] readonly attribute DOMString data; + readonly attribute DOMString data; - void initCompositionEvent([Default=Undefined] optional DOMString typeArg, - [Default=Undefined] optional boolean canBubbleArg, - [Default=Undefined] optional boolean cancelableArg, - [Default=Undefined] optional DOMWindow viewArg, - [Default=Undefined] optional DOMString dataArg); + // FIXME: Using "undefined" as default parameter value is wrong. + void initCompositionEvent(optional DOMString typeArg = "undefined", + optional boolean canBubbleArg = false, + optional boolean cancelableArg = false, + optional DOMWindow? viewArg = null, + optional DOMString dataArg = "undefined"); }; +dictionary CompositionEventInit : UIEventInit { + DOMString data = ""; +}; diff --git a/Source/WebCore/dom/ContainerNode.cpp b/Source/WebCore/dom/ContainerNode.cpp index 44a4c3a14..e9ed30dd7 100644 --- a/Source/WebCore/dom/ContainerNode.cpp +++ b/Source/WebCore/dom/ContainerNode.cpp @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2016 Apple 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 @@ -24,71 +24,71 @@ #include "ContainerNode.h" #include "AXObjectCache.h" +#include "AllDescendantsCollection.h" #include "ChildListMutationScope.h" -#include "Chrome.h" -#include "ChromeClient.h" -#include "ClassNodeList.h" +#include "ClassCollection.h" +#include "CommonVM.h" #include "ContainerNodeAlgorithms.h" #include "Editor.h" +#include "EventNames.h" #include "FloatRect.h" #include "FrameView.h" +#include "GenericCachedHTMLCollection.h" +#include "HTMLFormControlsCollection.h" +#include "HTMLOptionsCollection.h" +#include "HTMLSlotElement.h" +#include "HTMLTableRowsCollection.h" #include "InlineTextBox.h" -#include "InsertionPoint.h" -#include "JSLazyEventListener.h" +#include "InspectorInstrumentation.h" #include "JSNode.h" #include "LabelsNodeList.h" -#include "LoaderStrategy.h" -#include "MemoryCache.h" #include "MutationEvent.h" #include "NameNodeList.h" +#include "NoEventDispatchAssertion.h" #include "NodeRareData.h" #include "NodeRenderStyle.h" -#include "PlatformStrategies.h" #include "RadioNodeList.h" #include "RenderBox.h" #include "RenderTheme.h" +#include "RenderTreeUpdater.h" #include "RenderWidget.h" -#include "ResourceLoadScheduler.h" #include "RootInlineBox.h" +#include "RuntimeEnabledFeatures.h" +#include "SVGDocumentExtensions.h" +#include "SVGElement.h" +#include "SVGNames.h" +#include "SVGUseElement.h" #include "SelectorQuery.h" #include "TemplateContentDocumentFragment.h" -#include - -#if ENABLE(DELETION_UI) -#include "DeleteButtonController.h" -#endif +#include +#include namespace WebCore { static void dispatchChildInsertionEvents(Node&); static void dispatchChildRemovalEvents(Node&); -typedef std::pair, unsigned> CallbackParameters; -typedef std::pair CallbackInfo; -typedef Vector NodeCallbackQueue; - -static NodeCallbackQueue* s_postAttachCallbackQueue; - -static size_t s_attachDepth; -static bool s_shouldReEnableMemoryCacheCallsAfterAttach; +ChildNodesLazySnapshot* ChildNodesLazySnapshot::latestSnapshot; -ChildNodesLazySnapshot* ChildNodesLazySnapshot::latestSnapshot = 0; - -#ifndef NDEBUG +#if !ASSERT_DISABLED unsigned NoEventDispatchAssertion::s_count = 0; +unsigned NoEventDispatchAssertion::DisableAssertionsInScope::s_existingCount = 0; +NoEventDispatchAssertion::EventAllowedScope* NoEventDispatchAssertion::EventAllowedScope::s_currentScope = nullptr; #endif -static void collectChildrenAndRemoveFromOldParent(Node& node, NodeVector& nodes, ExceptionCode& ec) +static ExceptionOr collectChildrenAndRemoveFromOldParent(Node& node, NodeVector& nodes) { - if (!node.isDocumentFragment()) { + if (!is(node)) { nodes.append(node); - if (ContainerNode* oldParent = node.parentNode()) - oldParent->removeChild(&node, ec); - return; + auto* oldParent = node.parentNode(); + if (!oldParent) + return { }; + return oldParent->removeChild(node); } getChildNodes(node, nodes); - toContainerNode(node).removeChildren(); + downcast(node).removeChildren(); + return { }; } // FIXME: This function must get a new name. @@ -101,18 +101,21 @@ void ContainerNode::removeDetachedChildren() child->updateAncestorConnectedSubframeCountForRemoval(); } // FIXME: We should be able to ASSERT(!attached()) here: https://bugs.webkit.org/show_bug.cgi?id=107801 - removeDetachedChildrenInContainer(*this); + removeDetachedChildrenInContainer(*this); } static inline void destroyRenderTreeIfNeeded(Node& child) { + bool isElement = is(child); + auto hasDisplayContents = isElement && downcast(child).hasDisplayContents(); + auto isNamedFlowElement = isElement && downcast(child).isNamedFlowContentElement(); // FIXME: Get rid of the named flow test. - if (!child.renderer() && !child.inNamedFlow()) + if (!child.renderer() && !hasDisplayContents && !isNamedFlowElement) return; - if (child.isElementNode()) - Style::detachRenderTree(toElement(child)); - else if (child.isTextNode()) - Style::detachTextRenderer(toText(child)); + if (isElement) + RenderTreeUpdater::tearDownRenderers(downcast(child)); + else if (is(child)) + RenderTreeUpdater::tearDownRenderer(downcast(child)); } void ContainerNode::takeAllChildrenFrom(ContainerNode* oldParent) @@ -124,44 +127,48 @@ void ContainerNode::takeAllChildrenFrom(ContainerNode* oldParent) if (oldParent->document().hasMutationObserversOfType(MutationObserver::ChildList)) { ChildListMutationScope mutation(*oldParent); - for (unsigned i = 0; i < children.size(); ++i) - mutation.willRemoveChild(children[i].get()); + for (auto& child : children) + mutation.willRemoveChild(child); } - // FIXME: We need to do notifyMutationObserversNodeWillDetach() for each child, - // probably inside removeDetachedChildrenInContainer. - - oldParent->removeDetachedChildren(); + disconnectSubframesIfNeeded(*oldParent, DescendantsOnly); + { + NoEventDispatchAssertion assertNoEventDispatch; - for (unsigned i = 0; i < children.size(); ++i) { - Node& child = children[i].get(); + oldParent->document().nodeChildrenWillBeRemoved(*oldParent); - destroyRenderTreeIfNeeded(child); + WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates; + while (RefPtr child = oldParent->m_firstChild) { + oldParent->removeBetween(nullptr, child->nextSibling(), *child); + notifyChildNodeRemoved(*oldParent, *child); + } + ChildChange change = { AllChildrenRemoved, nullptr, nullptr, ChildChangeSourceParser }; + childrenChanged(change); + } - // FIXME: We need a no mutation event version of adoptNode. - RefPtr adoptedChild = document().adoptNode(&children[i].get(), ASSERT_NO_EXCEPTION); - parserAppendChild(adoptedChild.get()); - // FIXME: Together with adoptNode above, the tree scope might get updated recursively twice - // (if the document changed or oldParent was in a shadow tree, AND *this is in a shadow tree). - // Can we do better? - treeScope().adoptIfNeeded(adoptedChild.get()); + // FIXME: assert that we don't dispatch events here since this container node is still disconnected. + for (auto& child : children) { + RELEASE_ASSERT(!child->parentNode() && &child->treeScope() == &treeScope()); + ASSERT(!ensurePreInsertionValidity(child, nullptr).hasException()); + treeScope().adoptIfNeeded(child); + parserAppendChild(child); } } ContainerNode::~ContainerNode() { - if (Document* document = documentInternal()) - willBeDeletedFrom(document); + if (!isDocumentNode()) + willBeDeletedFrom(document()); removeDetachedChildren(); } -static inline bool isChildTypeAllowed(ContainerNode* newParent, Node* child) +static inline bool isChildTypeAllowed(ContainerNode& newParent, Node& child) { - if (!child->isDocumentFragment()) - return newParent->childTypeAllowed(child->nodeType()); + if (!child.isDocumentFragment()) + return newParent.childTypeAllowed(child.nodeType()); - for (Node* node = child->firstChild(); node; node = node->nextSibling()) { - if (!newParent->childTypeAllowed(node->nodeType())) + for (Node* node = child.firstChild(); node; node = node->nextSibling()) { + if (!newParent.childTypeAllowed(node->nodeType())) return false; } return true; @@ -169,152 +176,129 @@ static inline bool isChildTypeAllowed(ContainerNode* newParent, Node* child) static inline bool isInTemplateContent(const Node* node) { -#if ENABLE(TEMPLATE_ELEMENT) Document& document = node->document(); return &document == document.templateDocument(); -#else - UNUSED_PARAM(node); - return false; -#endif } -static inline bool containsConsideringHostElements(const Node* newChild, const Node* newParent) +static inline bool containsConsideringHostElements(const Node& newChild, const Node& newParent) { - return (newParent->isInShadowTree() || isInTemplateContent(newParent)) - ? newChild->containsIncludingHostElements(newParent) - : newChild->contains(newParent); + return (newParent.isInShadowTree() || isInTemplateContent(&newParent)) + ? newChild.containsIncludingHostElements(&newParent) + : newChild.contains(&newParent); } -static inline ExceptionCode checkAcceptChild(ContainerNode* newParent, Node* newChild, Node* oldChild) +static inline ExceptionOr checkAcceptChild(ContainerNode& newParent, Node& newChild, const Node* refChild, Document::AcceptChildOperation operation) { - // Not mentioned in spec: throw NOT_FOUND_ERR if newChild is null - if (!newChild) - return NOT_FOUND_ERR; - // Use common case fast path if possible. - if ((newChild->isElementNode() || newChild->isTextNode()) && newParent->isElementNode()) { - ASSERT(!newParent->isReadOnlyNode()); - ASSERT(!newParent->isDocumentTypeNode()); + if ((newChild.isElementNode() || newChild.isTextNode()) && newParent.isElementNode()) { + ASSERT(!newParent.isDocumentTypeNode()); ASSERT(isChildTypeAllowed(newParent, newChild)); if (containsConsideringHostElements(newChild, newParent)) - return HIERARCHY_REQUEST_ERR; - return 0; + return Exception { HIERARCHY_REQUEST_ERR }; + if (operation == Document::AcceptChildOperation::InsertOrAdd && refChild && refChild->parentNode() != &newParent) + return Exception { NOT_FOUND_ERR }; + return { }; } // This should never happen, but also protect release builds from tree corruption. - ASSERT(!newChild->isPseudoElement()); - if (newChild->isPseudoElement()) - return HIERARCHY_REQUEST_ERR; + ASSERT(!newChild.isPseudoElement()); + if (newChild.isPseudoElement()) + return Exception { HIERARCHY_REQUEST_ERR }; - if (newParent->isReadOnlyNode()) - return NO_MODIFICATION_ALLOWED_ERR; if (containsConsideringHostElements(newChild, newParent)) - return HIERARCHY_REQUEST_ERR; + return Exception { HIERARCHY_REQUEST_ERR }; + + if (operation == Document::AcceptChildOperation::InsertOrAdd && refChild && refChild->parentNode() != &newParent) + return Exception { NOT_FOUND_ERR }; - if (oldChild && newParent->isDocumentNode()) { - if (!toDocument(newParent)->canReplaceChild(newChild, oldChild)) - return HIERARCHY_REQUEST_ERR; + if (is(newParent)) { + if (!downcast(newParent).canAcceptChild(newChild, refChild, operation)) + return Exception { HIERARCHY_REQUEST_ERR }; } else if (!isChildTypeAllowed(newParent, newChild)) - return HIERARCHY_REQUEST_ERR; + return Exception { HIERARCHY_REQUEST_ERR }; - return 0; + return { }; } -static inline bool checkAcceptChildGuaranteedNodeTypes(ContainerNode* newParent, Node* newChild, ExceptionCode& ec) +static inline ExceptionOr checkAcceptChildGuaranteedNodeTypes(ContainerNode& newParent, Node& newChild) { - ASSERT(!newParent->isReadOnlyNode()); - ASSERT(!newParent->isDocumentTypeNode()); + ASSERT(!newParent.isDocumentTypeNode()); ASSERT(isChildTypeAllowed(newParent, newChild)); - if (newChild->contains(newParent)) { - ec = HIERARCHY_REQUEST_ERR; - return false; - } - - return true; + if (newChild.contains(&newParent)) + return Exception { HIERARCHY_REQUEST_ERR }; + return { }; } -static inline bool checkAddChild(ContainerNode* newParent, Node* newChild, ExceptionCode& ec) +// https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity +ExceptionOr ContainerNode::ensurePreInsertionValidity(Node& newChild, Node* refChild) { - ec = checkAcceptChild(newParent, newChild, 0); - if (ec) - return false; - - return true; + return checkAcceptChild(*this, newChild, refChild, Document::AcceptChildOperation::InsertOrAdd); } -static inline bool checkReplaceChild(ContainerNode* newParent, Node* newChild, Node* oldChild, ExceptionCode& ec) +// https://dom.spec.whatwg.org/#concept-node-replace +static inline ExceptionOr checkPreReplacementValidity(ContainerNode& newParent, Node& newChild, Node& oldChild) { - ec = checkAcceptChild(newParent, newChild, oldChild); - if (ec) - return false; - - return true; + return checkAcceptChild(newParent, newChild, &oldChild, Document::AcceptChildOperation::Replace); } -bool ContainerNode::insertBefore(PassRefPtr newChild, Node* refChild, ExceptionCode& ec) +ExceptionOr ContainerNode::insertBefore(Node& newChild, Node* refChild) { // Check that this node is not "floating". // If it is, it can be deleted as a side effect of sending mutation events. ASSERT(refCount() || parentOrShadowHostNode()); - Ref protect(*this); - - ec = 0; - - // insertBefore(node, 0) is equivalent to appendChild(node) - if (!refChild) - return appendChild(newChild, ec); - // Make sure adding the new child is OK. - if (!checkAddChild(this, newChild.get(), ec)) - return false; + auto validityCheckResult = ensurePreInsertionValidity(newChild, refChild); + if (validityCheckResult.hasException()) + return validityCheckResult.releaseException(); - // NOT_FOUND_ERR: Raised if refChild is not a child of this node - if (refChild->parentNode() != this) { - ec = NOT_FOUND_ERR; - return false; - } + if (refChild == &newChild) + refChild = newChild.nextSibling(); - if (refChild->previousSibling() == newChild || refChild == newChild) // nothing to do - return true; + // insertBefore(node, null) is equivalent to appendChild(node) + if (!refChild) + return appendChildWithoutPreInsertionValidityCheck(newChild); + Ref protectedThis(*this); Ref next(*refChild); NodeVector targets; - collectChildrenAndRemoveFromOldParent(*newChild.get(), targets, ec); - if (ec) - return false; + auto removeResult = collectChildrenAndRemoveFromOldParent(newChild, targets); + if (removeResult.hasException()) + return removeResult.releaseException(); if (targets.isEmpty()) - return true; + return { }; // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events. - if (!checkAcceptChildGuaranteedNodeTypes(this, newChild.get(), ec)) - return false; + auto checkAcceptResult = checkAcceptChildGuaranteedNodeTypes(*this, newChild); + if (checkAcceptResult.hasException()) + return checkAcceptResult.releaseException(); - InspectorInstrumentation::willInsertDOMNode(&document(), this); + InspectorInstrumentation::willInsertDOMNode(document(), *this); ChildListMutationScope mutation(*this); - for (auto it = targets.begin(), end = targets.end(); it != end; ++it) { - Node& child = it->get(); - + for (auto& child : targets) { // Due to arbitrary code running in response to a DOM mutation event it's // possible that "next" is no longer a child of "this". // It's also possible that "child" has been inserted elsewhere. // In either of those cases, we'll just stop. if (next->parentNode() != this) break; - if (child.parentNode()) + if (child->parentNode()) break; - treeScope().adoptIfNeeded(&child); + { + NoEventDispatchAssertion assertNoEventDispatch; - insertBeforeCommon(next.get(), child); + treeScope().adoptIfNeeded(child); + insertBeforeCommon(next, child); + } updateTreeAfterInsertion(child); } dispatchSubtreeModifiedEvent(); - return true; + return { }; } void ContainerNode::insertBeforeCommon(Node& nextChild, Node& newChild) @@ -342,145 +326,161 @@ void ContainerNode::insertBeforeCommon(Node& nextChild, Node& newChild) newChild.setNextSibling(&nextChild); } -void ContainerNode::notifyChildInserted(Node& child, ChildChangeSource source) +void ContainerNode::appendChildCommon(Node& child) { - ChildChange change; - change.type = child.isElementNode() ? ElementInserted : child.isTextNode() ? TextInserted : NonContentsChildChanged; - change.previousSiblingElement = ElementTraversal::previousSibling(&child); - change.nextSiblingElement = ElementTraversal::nextSibling(&child); - change.source = source; + NoEventDispatchAssertion assertNoEventDispatch; + + child.setParentNode(this); + + if (m_lastChild) { + child.setPreviousSibling(m_lastChild); + m_lastChild->setNextSibling(&child); + } else + m_firstChild = &child; + + m_lastChild = &child; +} + +inline auto ContainerNode::changeForChildInsertion(Node& child, ChildChangeSource source, ReplacedAllChildren replacedAllChildren) -> ChildChange +{ + if (replacedAllChildren == ReplacedAllChildren::Yes) + return { AllChildrenReplaced, nullptr, nullptr, source }; + + return { + child.isElementNode() ? ElementInserted : child.isTextNode() ? TextInserted : NonContentsChildInserted, + ElementTraversal::previousSibling(child), + ElementTraversal::nextSibling(child), + source + }; +} + +void ContainerNode::notifyChildInserted(Node& child, const ChildChange& change) +{ + ChildListMutationScope(*this).childAdded(child); + + NodeVector postInsertionNotificationTargets; + notifyChildNodeInserted(*this, child, postInsertionNotificationTargets); childrenChanged(change); + + for (auto& target : postInsertionNotificationTargets) + target->finishedInsertingSubtree(); } void ContainerNode::notifyChildRemoved(Node& child, Node* previousSibling, Node* nextSibling, ChildChangeSource source) { + NoEventDispatchAssertion assertNoEventDispatch; + notifyChildNodeRemoved(*this, child); + ChildChange change; - change.type = child.isElementNode() ? ElementRemoved : child.isTextNode() ? TextRemoved : NonContentsChildChanged; - change.previousSiblingElement = (!previousSibling || previousSibling->isElementNode()) ? toElement(previousSibling) : ElementTraversal::previousSibling(previousSibling); - change.nextSiblingElement = (!nextSibling || nextSibling->isElementNode()) ? toElement(nextSibling) : ElementTraversal::nextSibling(nextSibling); + change.type = is(child) ? ElementRemoved : is(child) ? TextRemoved : NonContentsChildRemoved; + change.previousSiblingElement = (!previousSibling || is(*previousSibling)) ? downcast(previousSibling) : ElementTraversal::previousSibling(*previousSibling); + change.nextSiblingElement = (!nextSibling || is(*nextSibling)) ? downcast(nextSibling) : ElementTraversal::nextSibling(*nextSibling); change.source = source; childrenChanged(change); } -void ContainerNode::parserInsertBefore(PassRefPtr newChild, Node* nextChild) +void ContainerNode::parserInsertBefore(Node& newChild, Node& nextChild) { - ASSERT(newChild); - ASSERT(nextChild); - ASSERT(nextChild->parentNode() == this); - ASSERT(!newChild->isDocumentFragment()); -#if ENABLE(TEMPLATE_ELEMENT) + ASSERT(nextChild.parentNode() == this); + ASSERT(!newChild.isDocumentFragment()); ASSERT(!hasTagName(HTMLNames::templateTag)); -#endif - if (nextChild->previousSibling() == newChild || nextChild == newChild) // nothing to do + if (nextChild.previousSibling() == &newChild || &nextChild == &newChild) // nothing to do return; - if (&document() != &newChild->document()) - document().adoptNode(newChild.get(), ASSERT_NO_EXCEPTION); - - insertBeforeCommon(*nextChild, *newChild.get()); + if (&document() != &newChild.document()) + document().adoptNode(newChild); - newChild->updateAncestorConnectedSubframeCountForInsertion(); + insertBeforeCommon(nextChild, newChild); - ChildListMutationScope(*this).childAdded(*newChild); + newChild.updateAncestorConnectedSubframeCountForInsertion(); - notifyChildInserted(*newChild, ChildChangeSourceParser); - - ChildNodeInsertionNotifier(*this).notify(*newChild); - - newChild->setNeedsStyleRecalc(ReconstructRenderTree); + notifyChildInserted(newChild, changeForChildInsertion(newChild, ChildChangeSourceParser)); } -bool ContainerNode::replaceChild(PassRefPtr newChild, Node* oldChild, ExceptionCode& ec) +ExceptionOr ContainerNode::replaceChild(Node& newChild, Node& oldChild) { // Check that this node is not "floating". // If it is, it can be deleted as a side effect of sending mutation events. ASSERT(refCount() || parentOrShadowHostNode()); - Ref protect(*this); - - ec = 0; - - if (oldChild == newChild) // nothing to do - return true; - - if (!oldChild) { - ec = NOT_FOUND_ERR; - return false; - } + Ref protectedThis(*this); // Make sure replacing the old child with the new is ok - if (!checkReplaceChild(this, newChild.get(), oldChild, ec)) - return false; + auto validityResult = checkPreReplacementValidity(*this, newChild, oldChild); + if (validityResult.hasException()) + return validityResult.releaseException(); // NOT_FOUND_ERR: Raised if oldChild is not a child of this node. - if (oldChild->parentNode() != this) { - ec = NOT_FOUND_ERR; - return false; - } + if (oldChild.parentNode() != this) + return Exception { NOT_FOUND_ERR }; - ChildListMutationScope mutation(*this); - - RefPtr next = oldChild->nextSibling(); + RefPtr refChild = oldChild.nextSibling(); + if (refChild.get() == &newChild) + refChild = refChild->nextSibling(); - // Remove the node we're replacing - Ref removedChild(*oldChild); - removeChild(oldChild, ec); - if (ec) - return false; + NodeVector targets; + { + ChildListMutationScope mutation(*this); + auto collectResult = collectChildrenAndRemoveFromOldParent(newChild, targets); + if (collectResult.hasException()) + return collectResult.releaseException(); + } - if (next && (next->previousSibling() == newChild || next == newChild)) // nothing to do - return true; + // Do this one more time because collectChildrenAndRemoveFromOldParent() fires a MutationEvent. + validityResult = checkPreReplacementValidity(*this, newChild, oldChild); + if (validityResult.hasException()) + return validityResult.releaseException(); - // Does this one more time because removeChild() fires a MutationEvent. - if (!checkReplaceChild(this, newChild.get(), oldChild, ec)) - return false; + // Remove the node we're replacing. + Ref protectOldChild(oldChild); - NodeVector targets; - collectChildrenAndRemoveFromOldParent(*newChild.get(), targets, ec); - if (ec) - return false; + ChildListMutationScope mutation(*this); - // Does this yet another check because collectChildrenAndRemoveFromOldParent() fires a MutationEvent. - if (!checkReplaceChild(this, newChild.get(), oldChild, ec)) - return false; + // If oldChild == newChild then oldChild no longer has a parent at this point. + if (oldChild.parentNode()) { + auto removeResult = removeChild(oldChild); + if (removeResult.hasException()) + return removeResult.releaseException(); - InspectorInstrumentation::willInsertDOMNode(&document(), this); + // Does this one more time because removeChild() fires a MutationEvent. + validityResult = checkPreReplacementValidity(*this, newChild, oldChild); + if (validityResult.hasException()) + return validityResult.releaseException(); + } - // Add the new child(ren) - for (auto it = targets.begin(), end = targets.end(); it != end; ++it) { - Node& child = it->get(); + InspectorInstrumentation::willInsertDOMNode(document(), *this); + // Add the new child(ren). + for (auto& child : targets) { // Due to arbitrary code running in response to a DOM mutation event it's - // possible that "next" is no longer a child of "this". + // possible that "refChild" is no longer a child of "this". // It's also possible that "child" has been inserted elsewhere. // In either of those cases, we'll just stop. - if (next && next->parentNode() != this) + if (refChild && refChild->parentNode() != this) break; - if (child.parentNode()) + if (child->parentNode()) break; - treeScope().adoptIfNeeded(&child); - - // Add child before "next". { NoEventDispatchAssertion assertNoEventDispatch; - if (next) - insertBeforeCommon(*next, child); + treeScope().adoptIfNeeded(child); + if (refChild) + insertBeforeCommon(*refChild, child.get()); else - appendChildToContainer(&child, *this); + appendChildCommon(child); } - updateTreeAfterInsertion(child); + updateTreeAfterInsertion(child.get()); } dispatchSubtreeModifiedEvent(); - return true; + return { }; } -void ContainerNode::willRemoveChild(Node& child) +static void willRemoveChild(ContainerNode& container, Node& child) { ASSERT(child.parentNode()); @@ -488,12 +488,11 @@ void ContainerNode::willRemoveChild(Node& child) child.notifyMutationObserversNodeWillDetach(); dispatchChildRemovalEvents(child); - if (child.parentNode() != this) + if (child.parentNode() != &container) return; - child.document().nodeWillBeRemoved(&child); // e.g. mutation event listener can create a new range. - if (child.isContainerNode()) - disconnectSubframesIfNeeded(toContainerNode(child), RootAndDescendants); + if (is(child)) + disconnectSubframesIfNeeded(downcast(child), RootAndDescendants); } static void willRemoveChildren(ContainerNode& container) @@ -502,17 +501,14 @@ static void willRemoveChildren(ContainerNode& container) getChildNodes(container, children); ChildListMutationScope mutation(container); - for (auto it = children.begin(); it != children.end(); ++it) { - Node& child = it->get(); - mutation.willRemoveChild(child); - child.notifyMutationObserversNodeWillDetach(); + for (auto& child : children) { + mutation.willRemoveChild(child.get()); + child->notifyMutationObserversNodeWillDetach(); // fire removed from document mutation events. - dispatchChildRemovalEvents(child); + dispatchChildRemovalEvents(child.get()); } - container.document().nodeChildrenWillBeRemoved(container); - disconnectSubframesIfNeeded(container, DescendantsOnly); } @@ -521,70 +517,48 @@ void ContainerNode::disconnectDescendantFrames() disconnectSubframesIfNeeded(*this, RootAndDescendants); } -bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec) +ExceptionOr ContainerNode::removeChild(Node& oldChild) { // Check that this node is not "floating". // If it is, it can be deleted as a side effect of sending mutation events. ASSERT(refCount() || parentOrShadowHostNode()); - Ref protect(*this); - - ec = 0; - - // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. - if (isReadOnlyNode()) { - ec = NO_MODIFICATION_ALLOWED_ERR; - return false; - } + Ref protectedThis(*this); // NOT_FOUND_ERR: Raised if oldChild is not a child of this node. - if (!oldChild || oldChild->parentNode() != this) { - ec = NOT_FOUND_ERR; - return false; - } - - Ref child(*oldChild); - - document().removeFocusedNodeOfSubtree(&child.get()); + if (oldChild.parentNode() != this) + return Exception { NOT_FOUND_ERR }; -#if ENABLE(FULLSCREEN_API) - document().removeFullScreenElementOfSubtree(&child.get()); -#endif - - // Events fired when blurring currently focused node might have moved this - // child into a different parent. - if (child->parentNode() != this) { - ec = NOT_FOUND_ERR; - return false; - } + Ref child(oldChild); - willRemoveChild(child.get()); + willRemoveChild(*this, child); - // Mutation events might have moved this child into a different parent. - if (child->parentNode() != this) { - ec = NOT_FOUND_ERR; - return false; - } + // Mutation events in willRemoveChild might have moved this child into a different parent. + if (child->parentNode() != this) + return Exception { NOT_FOUND_ERR }; { WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates; + NoEventDispatchAssertion assertNoEventDispatch; + + document().nodeWillBeRemoved(child); Node* prev = child->previousSibling(); Node* next = child->nextSibling(); - removeBetween(prev, next, child.get()); + removeBetween(prev, next, child); - notifyChildRemoved(child.get(), prev, next, ChildChangeSourceAPI); - - ChildNodeRemovalNotifier(*this).notify(child.get()); + notifyChildRemoved(child, prev, next, ChildChangeSourceAPI); } + + rebuildSVGExtensionsElementsIfNecessary(); dispatchSubtreeModifiedEvent(); - return true; + return { }; } void ContainerNode::removeBetween(Node* previousChild, Node* nextChild, Node& oldChild) { - InspectorInstrumentation::didRemoveDOMNode(&oldChild.document(), &oldChild); + InspectorInstrumentation::didRemoveDOMNode(oldChild.document(), oldChild); NoEventDispatchAssertion assertNoEventDispatch; @@ -592,40 +566,116 @@ void ContainerNode::removeBetween(Node* previousChild, Node* nextChild, Node& ol destroyRenderTreeIfNeeded(oldChild); - if (nextChild) + if (nextChild) { nextChild->setPreviousSibling(previousChild); - if (previousChild) + oldChild.setNextSibling(nullptr); + } else { + ASSERT(m_lastChild == &oldChild); + m_lastChild = previousChild; + } + if (previousChild) { previousChild->setNextSibling(nextChild); - if (m_firstChild == &oldChild) + oldChild.setPreviousSibling(nullptr); + } else { + ASSERT(m_firstChild == &oldChild); m_firstChild = nextChild; - if (m_lastChild == &oldChild) - m_lastChild = previousChild; + } - oldChild.setPreviousSibling(0); - oldChild.setNextSibling(0); - oldChild.setParentNode(0); + ASSERT(m_firstChild != &oldChild); + ASSERT(m_lastChild != &oldChild); + ASSERT(!oldChild.previousSibling()); + ASSERT(!oldChild.nextSibling()); + oldChild.setParentNode(nullptr); - document().adoptIfNeeded(&oldChild); + document().adoptIfNeeded(oldChild); } void ContainerNode::parserRemoveChild(Node& oldChild) { - ASSERT(oldChild.parentNode() == this); - ASSERT(!oldChild.isDocumentFragment()); + disconnectSubframesIfNeeded(*this, DescendantsOnly); + if (oldChild.parentNode() != this) + return; - Node* prev = oldChild.previousSibling(); - Node* next = oldChild.nextSibling(); + { + NoEventDispatchAssertion assertNoEventDispatch; - oldChild.updateAncestorConnectedSubframeCountForRemoval(); + document().nodeChildrenWillBeRemoved(*this); - ChildListMutationScope(*this).willRemoveChild(oldChild); - oldChild.notifyMutationObserversNodeWillDetach(); + ASSERT(oldChild.parentNode() == this); + ASSERT(!oldChild.isDocumentFragment()); - removeBetween(prev, next, oldChild); + Node* prev = oldChild.previousSibling(); + Node* next = oldChild.nextSibling(); - notifyChildRemoved(oldChild, prev, next, ChildChangeSourceParser); + ChildListMutationScope(*this).willRemoveChild(oldChild); + oldChild.notifyMutationObserversNodeWillDetach(); - ChildNodeRemovalNotifier(*this).notify(oldChild); + removeBetween(prev, next, oldChild); + + notifyChildRemoved(oldChild, prev, next, ChildChangeSourceParser); + } +} + +// https://dom.spec.whatwg.org/#concept-node-replace-all +void ContainerNode::replaceAllChildren(std::nullptr_t) +{ + ChildListMutationScope mutation(*this); + removeChildren(); +} + +// https://dom.spec.whatwg.org/#concept-node-replace-all +void ContainerNode::replaceAllChildren(Ref&& node) +{ + // This function assumes the input node is not a DocumentFragment and is parentless to decrease complexity. + ASSERT(!is(node)); + ASSERT(!node->parentNode()); + + if (!hasChildNodes()) { + // appendChildWithoutPreInsertionValidityCheck() can only throw when node has a parent and we already asserted it doesn't. + auto result = appendChildWithoutPreInsertionValidityCheck(node); + ASSERT_UNUSED(result, !result.hasException()); + return; + } + + Ref protectedThis(*this); + ChildListMutationScope mutation(*this); + + // If node is not null, adopt node into parent's node document. + treeScope().adoptIfNeeded(node); + + // Remove all parent's children, in tree order. + willRemoveChildren(*this); + + { + WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates; + { + NoEventDispatchAssertion assertNoEventDispatch; + + document().nodeChildrenWillBeRemoved(*this); + + while (RefPtr child = m_firstChild) { + removeBetween(nullptr, child->nextSibling(), *child); + notifyChildNodeRemoved(*this, *child); + } + + // If node is not null, insert node into parent before null. + ASSERT(!ensurePreInsertionValidity(node, nullptr).hasException()); + InspectorInstrumentation::willInsertDOMNode(document(), *this); + + appendChildCommon(node); + } + + updateTreeAfterInsertion(node, ReplacedAllChildren::Yes); + } + + rebuildSVGExtensionsElementsIfNecessary(); + dispatchSubtreeModifiedEvent(); +} + +inline void ContainerNode::rebuildSVGExtensionsElementsIfNecessary() +{ + if (document().svgExtensions() && !is(shadowHost())) + document().accessSVGExtensions().rebuildElements(); } // this differs from other remove functions because it forcibly removes all the children, @@ -636,187 +686,106 @@ void ContainerNode::removeChildren() return; // The container node can be removed from event handlers. - Ref protect(*this); - - // exclude this node when looking for removed focusedNode since only children will be removed - document().removeFocusedNodeOfSubtree(this, true); - -#if ENABLE(FULLSCREEN_API) - document().removeFullScreenElementOfSubtree(this, true); -#endif + Ref protectedThis(*this); // Do any prep work needed before actually starting to detach // and remove... e.g. stop loading frames, fire unload events. willRemoveChildren(*this); - NodeVector removedChildren; { WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates; - { - NoEventDispatchAssertion assertNoEventDispatch; - removedChildren.reserveInitialCapacity(childNodeCount()); - while (RefPtr n = m_firstChild) { - removedChildren.append(*m_firstChild); - removeBetween(0, m_firstChild->nextSibling(), *m_firstChild); - } + NoEventDispatchAssertion assertNoEventDispatch; + + document().nodeChildrenWillBeRemoved(*this); + + while (RefPtr child = m_firstChild) { + removeBetween(0, child->nextSibling(), *child); + notifyChildNodeRemoved(*this, *child); } ChildChange change = { AllChildrenRemoved, nullptr, nullptr, ChildChangeSourceAPI }; childrenChanged(change); - - for (size_t i = 0; i < removedChildren.size(); ++i) - ChildNodeRemovalNotifier(*this).notify(removedChildren[i].get()); } + rebuildSVGExtensionsElementsIfNecessary(); dispatchSubtreeModifiedEvent(); } -bool ContainerNode::appendChild(PassRefPtr newChild, ExceptionCode& ec) +ExceptionOr ContainerNode::appendChild(Node& newChild) { - Ref protect(*this); - // Check that this node is not "floating". // If it is, it can be deleted as a side effect of sending mutation events. ASSERT(refCount() || parentOrShadowHostNode()); - ec = 0; - // Make sure adding the new child is ok - if (!checkAddChild(this, newChild.get(), ec)) - return false; + auto validityCheckResult = ensurePreInsertionValidity(newChild, nullptr); + if (validityCheckResult.hasException()) + return validityCheckResult.releaseException(); + + return appendChildWithoutPreInsertionValidityCheck(newChild); +} - if (newChild == m_lastChild) // nothing to do - return newChild; +ExceptionOr ContainerNode::appendChildWithoutPreInsertionValidityCheck(Node& newChild) +{ + Ref protectedThis(*this); NodeVector targets; - collectChildrenAndRemoveFromOldParent(*newChild.get(), targets, ec); - if (ec) - return false; + auto removeResult = collectChildrenAndRemoveFromOldParent(newChild, targets); + if (removeResult.hasException()) + return removeResult.releaseException(); if (targets.isEmpty()) - return true; + return { }; // We need this extra check because collectChildrenAndRemoveFromOldParent() can fire mutation events. - if (!checkAcceptChildGuaranteedNodeTypes(this, newChild.get(), ec)) - return false; + auto nodeTypeResult = checkAcceptChildGuaranteedNodeTypes(*this, newChild); + if (nodeTypeResult.hasException()) + return nodeTypeResult.releaseException(); - InspectorInstrumentation::willInsertDOMNode(&document(), this); + InspectorInstrumentation::willInsertDOMNode(document(), *this); // Now actually add the child(ren) ChildListMutationScope mutation(*this); - for (auto it = targets.begin(), end = targets.end(); it != end; ++it) { - Node& child = it->get(); - + for (auto& child : targets) { // If the child has a parent again, just stop what we're doing, because // that means someone is doing something with DOM mutation -- can't re-parent // a child that already has a parent. - if (child.parentNode()) + if (child->parentNode()) break; - treeScope().adoptIfNeeded(&child); - // Append child to the end of the list { NoEventDispatchAssertion assertNoEventDispatch; - appendChildToContainer(&child, *this); + treeScope().adoptIfNeeded(child); + appendChildCommon(child); } - updateTreeAfterInsertion(child); + updateTreeAfterInsertion(child.get()); } dispatchSubtreeModifiedEvent(); - return true; + return { }; } -void ContainerNode::parserAppendChild(PassRefPtr newChild) +void ContainerNode::parserAppendChild(Node& newChild) { - ASSERT(newChild); - ASSERT(!newChild->parentNode()); // Use appendChild if you need to handle reparenting (and want DOM mutation events). - ASSERT(!newChild->isDocumentFragment()); -#if ENABLE(TEMPLATE_ELEMENT) + ASSERT(!newChild.parentNode()); // Use appendChild if you need to handle reparenting (and want DOM mutation events). + ASSERT(!newChild.isDocumentFragment()); ASSERT(!hasTagName(HTMLNames::templateTag)); -#endif - - if (&document() != &newChild->document()) - document().adoptNode(newChild.get(), ASSERT_NO_EXCEPTION); { NoEventDispatchAssertion assertNoEventDispatch; - // FIXME: This method should take a PassRefPtr. - appendChildToContainer(newChild.get(), *this); - treeScope().adoptIfNeeded(newChild.get()); - } - - newChild->updateAncestorConnectedSubframeCountForInsertion(); - - ChildListMutationScope(*this).childAdded(*newChild); - - notifyChildInserted(*newChild, ChildChangeSourceParser); - - ChildNodeInsertionNotifier(*this).notify(*newChild); - newChild->setNeedsStyleRecalc(ReconstructRenderTree); -} - -void ContainerNode::suspendPostAttachCallbacks(Document& document) -{ - if (!s_attachDepth) { - ASSERT(!s_shouldReEnableMemoryCacheCallsAfterAttach); - if (Page* page = document.page()) { - // FIXME: How can this call be specific to one Page, while the - // s_attachDepth is a global? Doesn't make sense. - if (page->areMemoryCacheClientCallsEnabled()) { - page->setMemoryCacheClientCallsEnabled(false); - s_shouldReEnableMemoryCacheCallsAfterAttach = true; - } - } - platformStrategies()->loaderStrategy()->resourceLoadScheduler()->suspendPendingRequests(); - } - ++s_attachDepth; -} + if (&document() != &newChild.document()) + document().adoptNode(newChild); -void ContainerNode::resumePostAttachCallbacks(Document& document) -{ - if (s_attachDepth == 1) { - Ref protect(document); - - if (s_postAttachCallbackQueue) - dispatchPostAttachCallbacks(); - if (s_shouldReEnableMemoryCacheCallsAfterAttach) { - s_shouldReEnableMemoryCacheCallsAfterAttach = false; - if (Page* page = document.page()) - page->setMemoryCacheClientCallsEnabled(true); - } - platformStrategies()->loaderStrategy()->resourceLoadScheduler()->resumePendingRequests(); + appendChildCommon(newChild); + treeScope().adoptIfNeeded(newChild); } - --s_attachDepth; -} -void ContainerNode::queuePostAttachCallback(NodeCallback callback, Node& node, unsigned callbackData) -{ - if (!s_postAttachCallbackQueue) - s_postAttachCallbackQueue = new NodeCallbackQueue; - - s_postAttachCallbackQueue->append(CallbackInfo(callback, CallbackParameters(&node, callbackData))); -} + newChild.updateAncestorConnectedSubframeCountForInsertion(); -bool ContainerNode::postAttachCallbacksAreSuspended() -{ - return s_attachDepth; -} - -void ContainerNode::dispatchPostAttachCallbacks() -{ - // We recalculate size() each time through the loop because a callback - // can add more callbacks to the end of the queue. - for (size_t i = 0; i < s_postAttachCallbackQueue->size(); ++i) { - const CallbackInfo& info = (*s_postAttachCallbackQueue)[i]; - NodeCallback callback = info.first; - CallbackParameters params = info.second; - - callback(*params.first, params.second); - } - s_postAttachCallbackQueue->clear(); + notifyChildInserted(newChild, changeForChildInsertion(newChild, ChildChangeSourceParser)); } void ContainerNode::childrenChanged(const ChildChange& change) @@ -827,182 +796,30 @@ void ContainerNode::childrenChanged(const ChildChange& change) invalidateNodeListAndCollectionCachesInAncestors(); } -inline static void cloneChildNodesAvoidingDeleteButton(ContainerNode* parent, ContainerNode* clonedParent, HTMLElement* deleteButtonContainerElement) -{ - ExceptionCode ec = 0; - for (Node* child = parent->firstChild(); child && !ec; child = child->nextSibling()) { - -#if ENABLE(DELETION_UI) - if (child == deleteButtonContainerElement) - continue; -#else - UNUSED_PARAM(deleteButtonContainerElement); -#endif - - RefPtr clonedChild = child->cloneNode(false); - clonedParent->appendChild(clonedChild, ec); - - if (!ec && child->isContainerNode()) - cloneChildNodesAvoidingDeleteButton(toContainerNode(child), toContainerNode(clonedChild.get()), deleteButtonContainerElement); - } -} - -void ContainerNode::cloneChildNodes(ContainerNode *clone) -{ -#if ENABLE(DELETION_UI) - HTMLElement* deleteButtonContainerElement = 0; - if (Frame* frame = document().frame()) - deleteButtonContainerElement = frame->editor().deleteButtonController().containerElement(); - cloneChildNodesAvoidingDeleteButton(this, clone, deleteButtonContainerElement); -#else - cloneChildNodesAvoidingDeleteButton(this, clone, 0); -#endif -} - -bool ContainerNode::getUpperLeftCorner(FloatPoint& point) const -{ - if (!renderer()) - return false; - // What is this code really trying to do? - RenderObject* o = renderer(); - RenderObject* p = o; - - if (!o->isInline() || o->isReplaced()) { - point = o->localToAbsolute(FloatPoint(), UseTransforms); - return true; - } - - // find the next text/image child, to get a position - while (o) { - p = o; - if (RenderObject* child = o->firstChildSlow()) - o = child; - else if (o->nextSibling()) - o = o->nextSibling(); - else { - RenderObject* next = 0; - while (!next && o->parent()) { - o = o->parent(); - next = o->nextSibling(); - } - o = next; - - if (!o) - break; - } - ASSERT(o); - - if (!o->isInline() || o->isReplaced()) { - point = o->localToAbsolute(FloatPoint(), UseTransforms); - return true; - } - - if (p->node() && p->node() == this && o->isText() && !toRenderText(o)->firstTextBox()) { - // do nothing - skip unrendered whitespace that is a child or next sibling of the anchor - } else if (o->isText() || o->isReplaced()) { - point = FloatPoint(); - if (o->isText() && toRenderText(o)->firstTextBox()) { - point.move(toRenderText(o)->linesBoundingBox().x(), toRenderText(o)->firstTextBox()->root().lineTop()); - } else if (o->isBox()) { - RenderBox* box = toRenderBox(o); - point.moveBy(box->location()); - } - point = o->container()->localToAbsolute(point, UseTransforms); - return true; - } - } - - // If the target doesn't have any children or siblings that could be used to calculate the scroll position, we must be - // at the end of the document. Scroll to the bottom. FIXME: who said anything about scrolling? - if (!o && document().view()) { - point = FloatPoint(0, document().view()->contentsHeight()); - return true; - } - return false; -} - -bool ContainerNode::getLowerRightCorner(FloatPoint& point) const +void ContainerNode::cloneChildNodes(ContainerNode& clone) { - if (!renderer()) - return false; - - RenderObject* o = renderer(); - if (!o->isInline() || o->isReplaced()) { - RenderBox* box = toRenderBox(o); - point = o->localToAbsolute(LayoutPoint(box->size()), UseTransforms); - return true; + Document& targetDocument = clone.document(); + for (Node* child = firstChild(); child; child = child->nextSibling()) { + auto clonedChild = child->cloneNodeInternal(targetDocument, CloningOperation::SelfWithTemplateContent); + if (!clone.appendChild(clonedChild).hasException() && is(*child)) + downcast(*child).cloneChildNodes(downcast(clonedChild.get())); } - - // find the last text/image child, to get a position - while (o) { - if (RenderObject* child = o->lastChildSlow()) - o = child; - else if (o->previousSibling()) - o = o->previousSibling(); - else { - RenderObject* prev = 0; - while (!prev) { - o = o->parent(); - if (!o) - return false; - prev = o->previousSibling(); - } - o = prev; - } - ASSERT(o); - if (o->isText() || o->isReplaced()) { - point = FloatPoint(); - if (o->isText()) { - RenderText* text = toRenderText(o); - IntRect linesBox = text->linesBoundingBox(); - if (!linesBox.maxX() && !linesBox.maxY()) - continue; - point.moveBy(linesBox.maxXMaxYCorner()); - } else { - RenderBox* box = toRenderBox(o); - point.moveBy(box->frameRect().maxXMaxYCorner()); - } - point = o->container()->localToAbsolute(point, UseTransforms); - return true; - } - } - return true; -} - -LayoutRect ContainerNode::boundingBox() const -{ - FloatPoint upperLeft, lowerRight; - bool foundUpperLeft = getUpperLeftCorner(upperLeft); - bool foundLowerRight = getLowerRightCorner(lowerRight); - - // If we've found one corner, but not the other, - // then we should just return a point at the corner that we did find. - if (foundUpperLeft != foundLowerRight) { - if (foundUpperLeft) - lowerRight = upperLeft; - else - upperLeft = lowerRight; - } - - return enclosingLayoutRect(FloatRect(upperLeft, lowerRight.expandedTo(upperLeft) - upperLeft)); } -unsigned ContainerNode::childNodeCount() const +unsigned ContainerNode::countChildNodes() const { unsigned count = 0; - Node *n; - for (n = firstChild(); n; n = n->nextSibling()) - count++; + for (Node* child = firstChild(); child; child = child->nextSibling()) + ++count; return count; } -Node *ContainerNode::childNode(unsigned index) const +Node* ContainerNode::traverseToChildAt(unsigned index) const { - unsigned i; - Node *n = firstChild(); - for (i = 0; n != 0 && i < index; i++) - n = n->nextSibling(); - return n; + Node* child = firstChild(); + for (; child && index > 0; --index) + child = child->nextSibling(); + return child; } static void dispatchChildInsertionEvents(Node& child) @@ -1010,7 +827,7 @@ static void dispatchChildInsertionEvents(Node& child) if (child.isInShadowTree()) return; - ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden()); + ASSERT_WITH_SECURITY_IMPLICATION(NoEventDispatchAssertion::isEventDispatchAllowedInSubtree(child)); RefPtr c = &child; Ref document(child.document()); @@ -1019,8 +836,8 @@ static void dispatchChildInsertionEvents(Node& child) c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeInsertedEvent, true, c->parentNode())); // dispatch the DOMNodeInsertedIntoDocument event to all descendants - if (c->inDocument() && document->hasListenerType(Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER)) { - for (; c; c = NodeTraversal::next(c.get(), &child)) + if (c->isConnected() && document->hasListenerType(Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER)) { + for (; c; c = NodeTraversal::next(*c, &child)) c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeInsertedIntoDocumentEvent, false)); } } @@ -1028,14 +845,14 @@ static void dispatchChildInsertionEvents(Node& child) static void dispatchChildRemovalEvents(Node& child) { if (child.isInShadowTree()) { - InspectorInstrumentation::willRemoveDOMNode(&child.document(), &child); + InspectorInstrumentation::willRemoveDOMNode(child.document(), child); return; } - ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden()); + ASSERT_WITH_SECURITY_IMPLICATION(NoEventDispatchAssertion::isEventDispatchAllowedInSubtree(child)); willCreatePossiblyOrphanedTreeByRemoval(&child); - InspectorInstrumentation::willRemoveDOMNode(&child.document(), &child); + InspectorInstrumentation::willRemoveDOMNode(child.document(), child); RefPtr c = &child; Ref document(child.document()); @@ -1045,93 +862,121 @@ static void dispatchChildRemovalEvents(Node& child) c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeRemovedEvent, true, c->parentNode())); // dispatch the DOMNodeRemovedFromDocument event to all descendants - if (c->inDocument() && document->hasListenerType(Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER)) { - for (; c; c = NodeTraversal::next(c.get(), &child)) + if (c->isConnected() && document->hasListenerType(Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER)) { + for (; c; c = NodeTraversal::next(*c, &child)) c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeRemovedFromDocumentEvent, false)); } } -void ContainerNode::updateTreeAfterInsertion(Node& child) +void ContainerNode::updateTreeAfterInsertion(Node& child, ReplacedAllChildren replacedAllChildren) { ASSERT(child.refCount()); - ChildListMutationScope(*this).childAdded(child); - - notifyChildInserted(child, ChildChangeSourceAPI); - - ChildNodeInsertionNotifier(*this).notify(child); - - child.setNeedsStyleRecalc(ReconstructRenderTree); + notifyChildInserted(child, changeForChildInsertion(child, ChildChangeSourceAPI, replacedAllChildren)); dispatchChildInsertionEvents(child); } -void ContainerNode::setAttributeEventListener(const AtomicString& eventType, const QualifiedName& attributeName, const AtomicString& attributeValue) +ExceptionOr ContainerNode::querySelector(const String& selectors) { - setAttributeEventListener(eventType, JSLazyEventListener::createForNode(*this, attributeName, attributeValue)); + auto query = document().selectorQueryForString(selectors); + if (query.hasException()) + return query.releaseException(); + return query.releaseReturnValue().queryFirst(*this); } -Element* ContainerNode::querySelector(const AtomicString& selectors, ExceptionCode& ec) +ExceptionOr> ContainerNode::querySelectorAll(const String& selectors) { - if (selectors.isEmpty()) { - ec = SYNTAX_ERR; - return nullptr; - } + auto query = document().selectorQueryForString(selectors); + if (query.hasException()) + return query.releaseException(); + return query.releaseReturnValue().queryAll(*this); +} - SelectorQuery* selectorQuery = document().selectorQueryCache().add(selectors, document(), ec); - if (!selectorQuery) - return nullptr; - return selectorQuery->queryFirst(*this); +Ref ContainerNode::getElementsByTagName(const AtomicString& qualifiedName) +{ + ASSERT(!qualifiedName.isNull()); + + if (qualifiedName == starAtom) + return ensureRareData().ensureNodeLists().addCachedCollection(*this, AllDescendants); + + if (document().isHTMLDocument()) + return ensureRareData().ensureNodeLists().addCachedCollection(*this, ByHTMLTag, qualifiedName); + return ensureRareData().ensureNodeLists().addCachedCollection(*this, ByTag, qualifiedName); } -RefPtr ContainerNode::querySelectorAll(const AtomicString& selectors, ExceptionCode& ec) +Ref ContainerNode::getElementsByTagNameNS(const AtomicString& namespaceURI, const AtomicString& localName) { - if (selectors.isEmpty()) { - ec = SYNTAX_ERR; - return nullptr; - } + ASSERT(!localName.isNull()); + return ensureRareData().ensureNodeLists().addCachedTagCollectionNS(*this, namespaceURI.isEmpty() ? nullAtom : namespaceURI, localName); +} + +Ref ContainerNode::getElementsByName(const String& elementName) +{ + return ensureRareData().ensureNodeLists().addCacheWithAtomicName(*this, elementName); +} - SelectorQuery* selectorQuery = document().selectorQueryCache().add(selectors, document(), ec); - if (!selectorQuery) - return nullptr; - return selectorQuery->queryAll(*this); +Ref ContainerNode::getElementsByClassName(const AtomicString& classNames) +{ + return ensureRareData().ensureNodeLists().addCachedCollection(*this, ByClass, classNames); } -PassRefPtr ContainerNode::getElementsByTagName(const AtomicString& localName) +Ref ContainerNode::radioNodeList(const AtomicString& name) { - if (localName.isNull()) - return 0; + ASSERT(hasTagName(HTMLNames::formTag) || hasTagName(HTMLNames::fieldsetTag)); + return ensureRareData().ensureNodeLists().addCacheWithAtomicName(*this, name); +} - if (document().isHTMLDocument()) - return ensureRareData().ensureNodeLists().addCacheWithAtomicName(*this, LiveNodeList::HTMLTagNodeListType, localName); - return ensureRareData().ensureNodeLists().addCacheWithAtomicName(*this, LiveNodeList::TagNodeListType, localName); +Ref ContainerNode::children() +{ + return ensureRareData().ensureNodeLists().addCachedCollection::traversalType>>(*this, NodeChildren); } -PassRefPtr ContainerNode::getElementsByTagNameNS(const AtomicString& namespaceURI, const AtomicString& localName) +Element* ContainerNode::firstElementChild() const { - if (localName.isNull()) - return 0; + return ElementTraversal::firstChild(*this); +} - if (namespaceURI == starAtom) - return getElementsByTagName(localName); +Element* ContainerNode::lastElementChild() const +{ + return ElementTraversal::lastChild(*this); +} - return ensureRareData().ensureNodeLists().addCacheWithQualifiedName(*this, namespaceURI.isEmpty() ? nullAtom : namespaceURI, localName); +unsigned ContainerNode::childElementCount() const +{ + auto children = childrenOfType(*this); + return std::distance(children.begin(), children.end()); } -PassRefPtr ContainerNode::getElementsByName(const String& elementName) +ExceptionOr ContainerNode::append(Vector&& vector) { - return ensureRareData().ensureNodeLists().addCacheWithAtomicName(*this, LiveNodeList::NameNodeListType, elementName); + auto result = convertNodesOrStringsIntoNode(WTFMove(vector)); + if (result.hasException()) + return result.releaseException(); + + auto node = result.releaseReturnValue(); + if (!node) + return { }; + + return appendChild(*node); } -PassRefPtr ContainerNode::getElementsByClassName(const String& classNames) +ExceptionOr ContainerNode::prepend(Vector&& vector) { - return ensureRareData().ensureNodeLists().addCacheWithName(*this, LiveNodeList::ClassNodeListType, classNames); + auto result = convertNodesOrStringsIntoNode(WTFMove(vector)); + if (result.hasException()) + return result.releaseException(); + + auto node = result.releaseReturnValue(); + if (!node) + return { }; + + return insertBefore(*node, firstChild()); } -PassRefPtr ContainerNode::radioNodeList(const AtomicString& name) +HTMLCollection* ContainerNode::cachedHTMLCollection(CollectionType type) { - ASSERT(hasTagName(HTMLNames::formTag) || hasTagName(HTMLNames::fieldsetTag)); - return ensureRareData().ensureNodeLists().addCacheWithAtomicName(*this, LiveNodeList::RadioNodeListType, name); + return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cachedCollection(type) : nullptr; } } // namespace WebCore diff --git a/Source/WebCore/dom/ContainerNode.h b/Source/WebCore/dom/ContainerNode.h index 163753026..8a8e0a2d7 100644 --- a/Source/WebCore/dom/ContainerNode.h +++ b/Source/WebCore/dom/ContainerNode.h @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2004-2015 Apple 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 @@ -21,222 +21,177 @@ * */ -#ifndef ContainerNode_h -#define ContainerNode_h +#pragma once -#include "ExceptionCodePlaceholder.h" +#include "CollectionType.h" #include "Node.h" -#include -#include - namespace WebCore { -class FloatPoint; +class HTMLCollection; +class RadioNodeList; class RenderElement; -typedef void (*NodeCallback)(Node&, unsigned); - -namespace Private { - template - void addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer&); -}; - -class NoEventDispatchAssertion { -public: - NoEventDispatchAssertion() - { -#ifndef NDEBUG - if (!isMainThread()) - return; - s_count++; -#endif - } - - ~NoEventDispatchAssertion() - { -#ifndef NDEBUG - if (!isMainThread()) - return; - ASSERT(s_count); - s_count--; -#endif - } - -#ifndef NDEBUG - static bool isEventDispatchForbidden() - { - if (!isMainThread()) - return false; - return s_count; - } -#endif - -private: -#ifndef NDEBUG - static unsigned s_count; -#endif -}; - class ContainerNode : public Node { - friend class PostAttachCallbackDisabler; public: virtual ~ContainerNode(); Node* firstChild() const { return m_firstChild; } + static ptrdiff_t firstChildMemoryOffset() { return OBJECT_OFFSETOF(ContainerNode, m_firstChild); } Node* lastChild() const { return m_lastChild; } + static ptrdiff_t lastChildMemoryOffset() { return OBJECT_OFFSETOF(ContainerNode, m_lastChild); } bool hasChildNodes() const { return m_firstChild; } + bool hasOneChild() const { return m_firstChild && !m_firstChild->nextSibling(); } + + bool directChildNeedsStyleRecalc() const { return getFlag(DirectChildNeedsStyleRecalcFlag); } + void setDirectChildNeedsStyleRecalc() { setFlag(DirectChildNeedsStyleRecalcFlag); } - unsigned childNodeCount() const; - Node* childNode(unsigned index) const; + WEBCORE_EXPORT unsigned countChildNodes() const; + WEBCORE_EXPORT Node* traverseToChildAt(unsigned) const; - bool insertBefore(PassRefPtr newChild, Node* refChild, ExceptionCode& = ASSERT_NO_EXCEPTION); - bool replaceChild(PassRefPtr newChild, Node* oldChild, ExceptionCode& = ASSERT_NO_EXCEPTION); - bool removeChild(Node* child, ExceptionCode& = ASSERT_NO_EXCEPTION); - bool appendChild(PassRefPtr newChild, ExceptionCode& = ASSERT_NO_EXCEPTION); + ExceptionOr insertBefore(Node& newChild, Node* refChild); + ExceptionOr replaceChild(Node& newChild, Node& oldChild); + WEBCORE_EXPORT ExceptionOr removeChild(Node& child); + WEBCORE_EXPORT ExceptionOr appendChild(Node& newChild); + void replaceAllChildren(Ref&&); + void replaceAllChildren(std::nullptr_t); // These methods are only used during parsing. // They don't send DOM mutation events or handle reparenting. // However, arbitrary code may be run by beforeload handlers. - void parserAppendChild(PassRefPtr); + void parserAppendChild(Node&); void parserRemoveChild(Node&); - void parserInsertBefore(PassRefPtr newChild, Node* refChild); + void parserInsertBefore(Node& newChild, Node& refChild); void removeChildren(); - void takeAllChildrenFrom(ContainerNode*); - void cloneChildNodes(ContainerNode* clone); + void takeAllChildrenFrom(ContainerNode*); - virtual LayoutRect boundingBox() const override; + void cloneChildNodes(ContainerNode& clone); - enum ChildChangeType { ElementInserted, ElementRemoved, TextInserted, TextRemoved, TextChanged, AllChildrenRemoved, NonContentsChildChanged }; + enum ChildChangeType { ElementInserted, ElementRemoved, TextInserted, TextRemoved, TextChanged, AllChildrenRemoved, NonContentsChildRemoved, NonContentsChildInserted, AllChildrenReplaced }; enum ChildChangeSource { ChildChangeSourceParser, ChildChangeSourceAPI }; struct ChildChange { ChildChangeType type; Element* previousSiblingElement; Element* nextSiblingElement; ChildChangeSource source; + + bool isInsertion() const + { + switch (type) { + case ElementInserted: + case TextInserted: + case NonContentsChildInserted: + case AllChildrenReplaced: + return true; + case ElementRemoved: + case TextRemoved: + case TextChanged: + case AllChildrenRemoved: + case NonContentsChildRemoved: + return false; + } + ASSERT_NOT_REACHED(); + return false; + } }; virtual void childrenChanged(const ChildChange&); void disconnectDescendantFrames(); - virtual bool childShouldCreateRenderer(const Node&) const { return true; } - - using Node::setAttributeEventListener; - void setAttributeEventListener(const AtomicString& eventType, const QualifiedName& attributeName, const AtomicString& value); - RenderElement* renderer() const; - Element* querySelector(const AtomicString& selectors, ExceptionCode&); - RefPtr querySelectorAll(const AtomicString& selectors, ExceptionCode&); + // Return a bounding box in absolute coordinates enclosing this node and all its descendants. + // This gives the area within which events may get handled by a hander registered on this node. + virtual LayoutRect absoluteEventHandlerBounds(bool& /* includesFixedPositionElements */) { return LayoutRect(); } - PassRefPtr getElementsByTagName(const AtomicString&); - PassRefPtr getElementsByTagNameNS(const AtomicString& namespaceURI, const AtomicString& localName); - PassRefPtr getElementsByName(const String& elementName); - PassRefPtr getElementsByClassName(const String& classNames); - PassRefPtr radioNodeList(const AtomicString&); + WEBCORE_EXPORT ExceptionOr querySelector(const String& selectors); + WEBCORE_EXPORT ExceptionOr> querySelectorAll(const String& selectors); -protected: - explicit ContainerNode(Document*, ConstructionType = CreateContainer); + WEBCORE_EXPORT Ref getElementsByTagName(const AtomicString&); + WEBCORE_EXPORT Ref getElementsByTagNameNS(const AtomicString& namespaceURI, const AtomicString& localName); + WEBCORE_EXPORT Ref getElementsByName(const String& elementName); + WEBCORE_EXPORT Ref getElementsByClassName(const AtomicString& classNames); + Ref radioNodeList(const AtomicString&); - static void queuePostAttachCallback(NodeCallback, Node&, unsigned = 0); - static bool postAttachCallbacksAreSuspended(); + // From the ParentNode interface - https://dom.spec.whatwg.org/#interface-parentnode + WEBCORE_EXPORT Ref children(); + WEBCORE_EXPORT Element* firstElementChild() const; + WEBCORE_EXPORT Element* lastElementChild() const; + WEBCORE_EXPORT unsigned childElementCount() const; + ExceptionOr append(Vector&&); + ExceptionOr prepend(Vector&&); - template - friend void appendChildToContainer(GenericNode* child, GenericNodeContainer&); + ExceptionOr ensurePreInsertionValidity(Node& newChild, Node* refChild); - template - friend void Private::addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer&); +protected: + explicit ContainerNode(Document&, ConstructionType = CreateContainer); + + friend void addChildNodesToDeletionQueue(Node*& head, Node*& tail, ContainerNode&); void removeDetachedChildren(); void setFirstChild(Node* child) { m_firstChild = child; } void setLastChild(Node* child) { m_lastChild = child; } + HTMLCollection* cachedHTMLCollection(CollectionType); + private: void removeBetween(Node* previousChild, Node* nextChild, Node& oldChild); + ExceptionOr appendChildWithoutPreInsertionValidityCheck(Node&); void insertBeforeCommon(Node& nextChild, Node& oldChild); + void appendChildCommon(Node&); - static void dispatchPostAttachCallbacks(); - static void suspendPostAttachCallbacks(Document&); - static void resumePostAttachCallbacks(Document&); - - bool getUpperLeftCorner(FloatPoint&) const; - bool getLowerRightCorner(FloatPoint&) const; - - void notifyChildInserted(Node& child, ChildChangeSource); + void notifyChildInserted(Node& child, const ChildChange&); void notifyChildRemoved(Node& child, Node* previousSibling, Node* nextSibling, ChildChangeSource); - void updateTreeAfterInsertion(Node& child); + enum class ReplacedAllChildren { No, Yes }; + void updateTreeAfterInsertion(Node& child, ReplacedAllChildren = ReplacedAllChildren::No); + static ChildChange changeForChildInsertion(Node& child, ChildChangeSource, ReplacedAllChildren = ReplacedAllChildren::No); + void rebuildSVGExtensionsElementsIfNecessary(); bool isContainerNode() const = delete; - void willRemoveChild(Node& child); - - Node* m_firstChild; - Node* m_lastChild; + Node* m_firstChild { nullptr }; + Node* m_lastChild { nullptr }; }; -inline bool isContainerNode(const Node& node) { return node.isContainerNode(); } -void isContainerNode(const ContainerNode&); // Catch unnecessary runtime check of type known at compile time. - -NODE_TYPE_CASTS(ContainerNode) - -inline ContainerNode::ContainerNode(Document* document, ConstructionType type) +inline ContainerNode::ContainerNode(Document& document, ConstructionType type) : Node(document, type) - , m_firstChild(0) - , m_lastChild(0) { } -inline unsigned Node::childNodeCount() const +inline unsigned Node::countChildNodes() const { - if (!isContainerNode()) + if (!is(*this)) return 0; - return toContainerNode(this)->childNodeCount(); + return downcast(*this).countChildNodes(); } -inline Node* Node::childNode(unsigned index) const +inline Node* Node::traverseToChildAt(unsigned index) const { - if (!isContainerNode()) - return 0; - return toContainerNode(this)->childNode(index); + if (!is(*this)) + return nullptr; + return downcast(*this).traverseToChildAt(index); } inline Node* Node::firstChild() const { - if (!isContainerNode()) - return 0; - return toContainerNode(this)->firstChild(); + if (!is(*this)) + return nullptr; + return downcast(*this).firstChild(); } inline Node* Node::lastChild() const { - if (!isContainerNode()) - return 0; - return toContainerNode(this)->lastChild(); -} - -inline Node* Node::highestAncestor() const -{ - Node* node = const_cast(this); - Node* highest = node; - for (; node; node = node->parentNode()) - highest = node; - return highest; -} - -inline bool Node::needsNodeRenderingTraversalSlowPath() const -{ - if (getFlag(NeedsNodeRenderingTraversalSlowPathFlag)) - return true; - ContainerNode* parent = parentOrShadowHostNode(); - return parent && parent->getFlag(NeedsNodeRenderingTraversalSlowPathFlag); + if (!is(*this)) + return nullptr; + return downcast(*this).lastChild(); } inline bool Node::isTreeScope() const { - return treeScope().rootNode() == this; + return &treeScope().rootNode() == this; } // This constant controls how much buffer is initially allocated @@ -259,45 +214,45 @@ public: explicit ChildNodesLazySnapshot(Node& parentNode) : m_currentNode(parentNode.firstChild()) , m_currentIndex(0) + , m_hasSnapshot(false) { m_nextSnapshot = latestSnapshot; latestSnapshot = this; } - ~ChildNodesLazySnapshot() + ALWAYS_INLINE ~ChildNodesLazySnapshot() { latestSnapshot = m_nextSnapshot; } // Returns 0 if there is no next Node. - PassRefPtr nextNode() + RefPtr nextNode() { if (LIKELY(!hasSnapshot())) { - RefPtr node = m_currentNode; + RefPtr node = WTFMove(m_currentNode); if (node) m_currentNode = node->nextSibling(); - return node.release(); + return node; } - Vector>& nodeVector = *m_childNodes; - if (m_currentIndex >= nodeVector.size()) - return 0; - return nodeVector[m_currentIndex++]; + if (m_currentIndex >= m_snapshot.size()) + return nullptr; + return m_snapshot[m_currentIndex++]; } void takeSnapshot() { if (hasSnapshot()) return; - m_childNodes = adoptPtr(new Vector>()); + m_hasSnapshot = true; Node* node = m_currentNode.get(); while (node) { - m_childNodes->append(node); + m_snapshot.append(node); node = node->nextSibling(); } } ChildNodesLazySnapshot* nextSnapshot() { return m_nextSnapshot; } - bool hasSnapshot() { return !!m_childNodes.get(); } + bool hasSnapshot() { return m_hasSnapshot; } static void takeChildNodesLazySnapshot() { @@ -313,10 +268,13 @@ private: RefPtr m_currentNode; unsigned m_currentIndex; - OwnPtr>> m_childNodes; // Lazily instantiated. + bool m_hasSnapshot; + Vector> m_snapshot; // Lazily instantiated. ChildNodesLazySnapshot* m_nextSnapshot; }; } // namespace WebCore -#endif // ContainerNode_h +SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ContainerNode) + static bool isType(const WebCore::Node& node) { return node.isContainerNode(); } +SPECIALIZE_TYPE_TRAITS_END() diff --git a/Source/WebCore/dom/ContainerNodeAlgorithms.cpp b/Source/WebCore/dom/ContainerNodeAlgorithms.cpp index 9750df147..2958ec28f 100644 --- a/Source/WebCore/dom/ContainerNodeAlgorithms.cpp +++ b/Source/WebCore/dom/ContainerNodeAlgorithms.cpp @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Apple Inc. All rights reserved. * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * Copyright (C) 2012 Google Inc. All rights reserved. @@ -26,75 +26,204 @@ #include "config.h" #include "ContainerNodeAlgorithms.h" +#include "HTMLFrameOwnerElement.h" +#include "HTMLTextAreaElement.h" +#include "InspectorInstrumentation.h" +#include "NoEventDispatchAssertion.h" +#include "ShadowRoot.h" namespace WebCore { -void ChildNodeInsertionNotifier::notifyDescendantInsertedIntoDocument(ContainerNode& node) +static void notifyNodeInsertedIntoTree(ContainerNode& insertionPoint, ContainerNode&, NodeVector& postInsertionNotificationTargets); +static void notifyNodeInsertedIntoDocument(ContainerNode& insertionPoint, Node&, NodeVector& postInsertionNotificationTargets); +static void notifyNodeRemovedFromTree(ContainerNode& insertionPoint, ContainerNode&); +static void notifyNodeRemovedFromDocument(ContainerNode& insertionPoint, Node&); + +static void notifyDescendantInsertedIntoDocument(ContainerNode& insertionPoint, ContainerNode& node, NodeVector& postInsertionNotificationTargets) { ChildNodesLazySnapshot snapshot(node); while (RefPtr child = snapshot.nextNode()) { // If we have been removed from the document during this loop, then // we don't want to tell the rest of our children that they've been // inserted into the document because they haven't. - if (node.inDocument() && child->parentNode() == &node) - notifyNodeInsertedIntoDocument(*child.get()); + if (node.isConnected() && child->parentNode() == &node) + notifyNodeInsertedIntoDocument(insertionPoint, *child, postInsertionNotificationTargets); } - if (!node.isElementNode()) + if (!is(node)) return; - if (RefPtr root = toElement(node).shadowRoot()) { - if (node.inDocument() && root->hostElement() == &node) - notifyNodeInsertedIntoDocument(*root.get()); + if (RefPtr root = downcast(node).shadowRoot()) { + if (node.isConnected() && root->host() == &node) + notifyNodeInsertedIntoDocument(insertionPoint, *root, postInsertionNotificationTargets); } } -void ChildNodeInsertionNotifier::notifyDescendantInsertedIntoTree(ContainerNode& node) +static void notifyDescendantInsertedIntoTree(ContainerNode& insertionPoint, ContainerNode& node, NodeVector& postInsertionNotificationTargets) { for (Node* child = node.firstChild(); child; child = child->nextSibling()) { - if (child->isContainerNode()) - notifyNodeInsertedIntoTree(*toContainerNode(child)); + if (is(*child)) + notifyNodeInsertedIntoTree(insertionPoint, downcast(*child), postInsertionNotificationTargets); } if (ShadowRoot* root = node.shadowRoot()) - notifyNodeInsertedIntoTree(*root); + notifyNodeInsertedIntoTree(insertionPoint, *root, postInsertionNotificationTargets); +} + +void notifyNodeInsertedIntoDocument(ContainerNode& insertionPoint, Node& node, NodeVector& postInsertionNotificationTargets) +{ + ASSERT(insertionPoint.isConnected()); + if (node.insertedInto(insertionPoint) == Node::InsertionShouldCallFinishedInsertingSubtree) + postInsertionNotificationTargets.append(node); + if (is(node)) + notifyDescendantInsertedIntoDocument(insertionPoint, downcast(node), postInsertionNotificationTargets); } -void ChildNodeRemovalNotifier::notifyDescendantRemovedFromDocument(ContainerNode& node) +void notifyNodeInsertedIntoTree(ContainerNode& insertionPoint, ContainerNode& node, NodeVector& postInsertionNotificationTargets) { + NoEventDispatchAssertion assertNoEventDispatch; + ASSERT(!insertionPoint.isConnected()); + + if (node.insertedInto(insertionPoint) == Node::InsertionShouldCallFinishedInsertingSubtree) + postInsertionNotificationTargets.append(node); + notifyDescendantInsertedIntoTree(insertionPoint, node, postInsertionNotificationTargets); +} + +void notifyChildNodeInserted(ContainerNode& insertionPoint, Node& node, NodeVector& postInsertionNotificationTargets) +{ + ASSERT_WITH_SECURITY_IMPLICATION(NoEventDispatchAssertion::isEventDispatchAllowedInSubtree(insertionPoint)); + + InspectorInstrumentation::didInsertDOMNode(node.document(), node); + + Ref protectDocument(node.document()); + Ref protectNode(node); + + if (insertionPoint.isConnected()) + notifyNodeInsertedIntoDocument(insertionPoint, node, postInsertionNotificationTargets); + else if (is(node)) + notifyNodeInsertedIntoTree(insertionPoint, downcast(node), postInsertionNotificationTargets); +} + +void notifyNodeRemovedFromDocument(ContainerNode& insertionPoint, Node& node) +{ + ASSERT(insertionPoint.isConnected()); + node.removedFrom(insertionPoint); + + if (!is(node)) + return; ChildNodesLazySnapshot snapshot(node); while (RefPtr child = snapshot.nextNode()) { // If we have been added to the document during this loop, then we // don't want to tell the rest of our children that they've been // removed from the document because they haven't. - if (!node.inDocument() && child->parentNode() == &node) - notifyNodeRemovedFromDocument(*child.get()); + if (!node.isConnected() && child->parentNode() == &node) + notifyNodeRemovedFromDocument(insertionPoint, *child.get()); } - if (!node.isElementNode()) + if (!is(node)) return; if (node.document().cssTarget() == &node) - node.document().setCSSTarget(0); + node.document().setCSSTarget(nullptr); - if (RefPtr root = toElement(node).shadowRoot()) { - if (!node.inDocument() && root->hostElement() == &node) - notifyNodeRemovedFromDocument(*root.get()); + if (RefPtr root = downcast(node).shadowRoot()) { + if (!node.isConnected() && root->host() == &node) + notifyNodeRemovedFromDocument(insertionPoint, *root.get()); } } -void ChildNodeRemovalNotifier::notifyDescendantRemovedFromTree(ContainerNode& node) +void notifyNodeRemovedFromTree(ContainerNode& insertionPoint, ContainerNode& node) { + NoEventDispatchAssertion assertNoEventDispatch; + ASSERT(!insertionPoint.isConnected()); + + node.removedFrom(insertionPoint); + for (Node* child = node.firstChild(); child; child = child->nextSibling()) { - if (child->isContainerNode()) - notifyNodeRemovedFromTree(*toContainerNode(child)); + if (is(*child)) + notifyNodeRemovedFromTree(insertionPoint, downcast(*child)); } - if (!node.isElementNode()) + if (!is(node)) return; - if (RefPtr root = toElement(node).shadowRoot()) - notifyNodeRemovedFromTree(*root.get()); + if (RefPtr root = downcast(node).shadowRoot()) + notifyNodeRemovedFromTree(insertionPoint, *root.get()); +} + +void notifyChildNodeRemoved(ContainerNode& insertionPoint, Node& child) +{ + if (!child.isConnected()) { + if (is(child)) + notifyNodeRemovedFromTree(insertionPoint, downcast(child)); + return; + } + notifyNodeRemovedFromDocument(insertionPoint, child); +} + +void addChildNodesToDeletionQueue(Node*& head, Node*& tail, ContainerNode& container) +{ + // We have to tell all children that their parent has died. + Node* next = nullptr; + for (auto* node = container.firstChild(); node; node = next) { + ASSERT(!node->m_deletionHasBegun); + + next = node->nextSibling(); + node->setNextSibling(nullptr); + node->setParentNode(nullptr); + container.setFirstChild(next); + if (next) + next->setPreviousSibling(nullptr); + + if (!node->refCount()) { +#ifndef NDEBUG + node->m_deletionHasBegun = true; +#endif + // Add the node to the list of nodes to be deleted. + // Reuse the nextSibling pointer for this purpose. + if (tail) + tail->setNextSibling(node); + else + head = node; + + tail = node; + } else { + Ref protect(*node); // removedFromDocument may remove remove all references to this node. + if (Document* containerDocument = container.ownerDocument()) + containerDocument->adoptIfNeeded(*node); + if (node->isInTreeScope()) + notifyChildNodeRemoved(container, *node); + } + } + + container.setLastChild(nullptr); +} + +void removeDetachedChildrenInContainer(ContainerNode& container) +{ + // List of nodes to be deleted. + Node* head = nullptr; + Node* tail = nullptr; + + addChildNodesToDeletionQueue(head, tail, container); + + Node* node; + Node* next; + while ((node = head)) { + ASSERT(node->m_deletionHasBegun); + + next = node->nextSibling(); + node->setNextSibling(nullptr); + + head = next; + if (!next) + tail = nullptr; + + if (is(*node)) + addChildNodesToDeletionQueue(head, tail, downcast(*node)); + + delete node; + } } #ifndef NDEBUG @@ -102,11 +231,11 @@ static unsigned assertConnectedSubrameCountIsConsistent(ContainerNode& node) { unsigned count = 0; - if (node.isElementNode()) { - if (node.isFrameOwnerElement() && toHTMLFrameOwnerElement(node).contentFrame()) - count++; + if (is(node)) { + if (is(node) && downcast(node).contentFrame()) + ++count; - if (ShadowRoot* root = toElement(node).shadowRoot()) + if (ShadowRoot* root = downcast(node).shadowRoot()) count += assertConnectedSubrameCountIsConsistent(*root); } @@ -138,8 +267,8 @@ static void collectFrameOwners(Vector>& frameOwners, continue; } - if (element.isHTMLElement() && element.isFrameOwnerElement()) - frameOwners.append(toHTMLFrameOwnerElement(element)); + if (is(element)) + frameOwners.append(downcast(element)); if (ShadowRoot* shadowRoot = element.shadowRoot()) collectFrameOwners(frameOwners, *shadowRoot); @@ -157,22 +286,26 @@ void disconnectSubframes(ContainerNode& root, SubframeDisconnectPolicy policy) Vector> frameOwners; if (policy == RootAndDescendants) { - if (root.isHTMLElement() && root.isFrameOwnerElement()) - frameOwners.append(toHTMLFrameOwnerElement(root)); + if (is(root)) + frameOwners.append(downcast(root)); } collectFrameOwners(frameOwners, root); + if (auto* shadowRoot = root.shadowRoot()) + collectFrameOwners(frameOwners, *shadowRoot); + // Must disable frame loading in the subtree so an unload handler cannot // insert more frames and create loaded frames in detached subtrees. - SubframeLoadingDisabler disabler(root); + SubframeLoadingDisabler disabler(&root); - for (unsigned i = 0; i < frameOwners.size(); ++i) { - auto& owner = frameOwners[i].get(); + bool isFirst = true; + for (auto& owner : frameOwners) { // Don't need to traverse up the tree for the first owner since no // script could have moved it. - if (!i || root.containsIncludingShadowDOM(&owner)) - owner.disconnectContentFrame(); + if (isFirst || root.containsIncludingShadowDOM(&owner.get())) + owner.get().disconnectContentFrame(); + isFirst = false; } } diff --git a/Source/WebCore/dom/ContainerNodeAlgorithms.h b/Source/WebCore/dom/ContainerNodeAlgorithms.h index cea04980a..611a0444b 100644 --- a/Source/WebCore/dom/ContainerNodeAlgorithms.h +++ b/Source/WebCore/dom/ContainerNodeAlgorithms.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2015 Apple Inc. All rights reserved. * (C) 2008 Nikolas Zimmermann * * This library is free software; you can redistribute it and/or @@ -19,248 +19,20 @@ * */ -#ifndef ContainerNodeAlgorithms_h -#define ContainerNodeAlgorithms_h +#pragma once #include "Document.h" #include "ElementIterator.h" #include "Frame.h" -#include "HTMLFrameOwnerElement.h" -#include "InspectorInstrumentation.h" #include "NodeTraversal.h" -#include "ShadowRoot.h" #include #include namespace WebCore { -class ChildNodeInsertionNotifier { -public: - explicit ChildNodeInsertionNotifier(ContainerNode& insertionPoint) - : m_insertionPoint(insertionPoint) - { - } - - void notify(Node&); - -private: - void notifyDescendantInsertedIntoDocument(ContainerNode&); - void notifyDescendantInsertedIntoTree(ContainerNode&); - void notifyNodeInsertedIntoDocument(Node&); - void notifyNodeInsertedIntoTree(ContainerNode&); - - ContainerNode& m_insertionPoint; - Vector> m_postInsertionNotificationTargets; -}; - -class ChildNodeRemovalNotifier { -public: - explicit ChildNodeRemovalNotifier(ContainerNode& insertionPoint) - : m_insertionPoint(insertionPoint) - { - } - - void notify(Node&); - -private: - void notifyDescendantRemovedFromDocument(ContainerNode&); - void notifyDescendantRemovedFromTree(ContainerNode&); - void notifyNodeRemovedFromDocument(Node&); - void notifyNodeRemovedFromTree(ContainerNode&); - - ContainerNode& m_insertionPoint; -}; - -namespace Private { - - template - void addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer&); - -} - -// Helper functions for TreeShared-derived classes, which have a 'Node' style interface -// This applies to 'ContainerNode' and 'SVGElementInstance' -template -inline void removeDetachedChildrenInContainer(GenericNodeContainer& container) -{ - // List of nodes to be deleted. - GenericNode* head = 0; - GenericNode* tail = 0; - - Private::addChildNodesToDeletionQueue(head, tail, container); - - GenericNode* n; - GenericNode* next; - while ((n = head) != 0) { - ASSERT(n->m_deletionHasBegun); - - next = n->nextSibling(); - n->setNextSibling(0); - - head = next; - if (next == 0) - tail = 0; - - if (n->hasChildNodes()) - Private::addChildNodesToDeletionQueue(head, tail, *static_cast(n)); - - delete n; - } -} - -template -inline void appendChildToContainer(GenericNode* child, GenericNodeContainer& container) -{ - child->setParentNode(&container); - - GenericNode* lastChild = container.lastChild(); - if (lastChild) { - child->setPreviousSibling(lastChild); - lastChild->setNextSibling(child); - } else - container.setFirstChild(child); - - container.setLastChild(child); -} - -// Helper methods for removeDetachedChildrenInContainer, hidden from WebCore namespace -namespace Private { - - template - struct NodeRemovalDispatcher { - static void dispatch(GenericNode&, GenericNodeContainer&) - { - // no-op, by default - } - }; - - template - struct NodeRemovalDispatcher { - static void dispatch(GenericNode& node, GenericNodeContainer& container) - { - // Clean up any TreeScope to a removed tree. - if (Document* containerDocument = container.ownerDocument()) - containerDocument->adoptIfNeeded(&node); - if (node.inDocument()) - ChildNodeRemovalNotifier(container).notify(node); - } - }; - - template - struct ShouldDispatchRemovalNotification { - static const bool value = false; - }; - - template<> - struct ShouldDispatchRemovalNotification { - static const bool value = true; - }; - - template - void addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer& container) - { - // We have to tell all children that their parent has died. - GenericNode* next = 0; - for (GenericNode* n = container.firstChild(); n != 0; n = next) { - ASSERT(!n->m_deletionHasBegun); - - next = n->nextSibling(); - n->setNextSibling(0); - n->setParentNode(0); - container.setFirstChild(next); - if (next) - next->setPreviousSibling(0); - - if (!n->refCount()) { -#ifndef NDEBUG - n->m_deletionHasBegun = true; -#endif - // Add the node to the list of nodes to be deleted. - // Reuse the nextSibling pointer for this purpose. - if (tail) - tail->setNextSibling(n); - else - head = n; - - tail = n; - } else { - Ref protect(*n); // removedFromDocument may remove remove all references to this node. - NodeRemovalDispatcher::value>::dispatch(*n, container); - } - } - - container.setLastChild(0); - } - -} // namespace Private - -inline void ChildNodeInsertionNotifier::notifyNodeInsertedIntoDocument(Node& node) -{ - ASSERT(m_insertionPoint.inDocument()); - Ref protect(node); - if (Node::InsertionShouldCallDidNotifySubtreeInsertions == node.insertedInto(m_insertionPoint)) - m_postInsertionNotificationTargets.append(node); - if (node.isContainerNode()) - notifyDescendantInsertedIntoDocument(toContainerNode(node)); -} - -inline void ChildNodeInsertionNotifier::notifyNodeInsertedIntoTree(ContainerNode& node) -{ - NoEventDispatchAssertion assertNoEventDispatch; - ASSERT(!m_insertionPoint.inDocument()); - - if (Node::InsertionShouldCallDidNotifySubtreeInsertions == node.insertedInto(m_insertionPoint)) - m_postInsertionNotificationTargets.append(node); - notifyDescendantInsertedIntoTree(node); -} - -inline void ChildNodeInsertionNotifier::notify(Node& node) -{ - ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden()); - -#if ENABLE(INSPECTOR) - InspectorInstrumentation::didInsertDOMNode(&node.document(), &node); -#endif - - Ref protectDocument(node.document()); - Ref protectNode(node); - - if (m_insertionPoint.inDocument()) - notifyNodeInsertedIntoDocument(node); - else if (node.isContainerNode()) - notifyNodeInsertedIntoTree(toContainerNode(node)); - - for (size_t i = 0; i < m_postInsertionNotificationTargets.size(); ++i) - m_postInsertionNotificationTargets[i]->didNotifySubtreeInsertions(&m_insertionPoint); -} - - -inline void ChildNodeRemovalNotifier::notifyNodeRemovedFromDocument(Node& node) -{ - ASSERT(m_insertionPoint.inDocument()); - node.removedFrom(m_insertionPoint); - - if (node.isContainerNode()) - notifyDescendantRemovedFromDocument(toContainerNode(node)); -} - -inline void ChildNodeRemovalNotifier::notifyNodeRemovedFromTree(ContainerNode& node) -{ - NoEventDispatchAssertion assertNoEventDispatch; - ASSERT(!m_insertionPoint.inDocument()); - - node.removedFrom(m_insertionPoint); - notifyDescendantRemovedFromTree(node); -} - -inline void ChildNodeRemovalNotifier::notify(Node& node) -{ - if (node.inDocument()) { - notifyNodeRemovedFromDocument(node); - node.document().notifyRemovePendingSheetIfNeeded(); - } else if (node.isContainerNode()) - notifyNodeRemovedFromTree(toContainerNode(node)); -} +void notifyChildNodeInserted(ContainerNode& insertionPoint, Node&, NodeVector& postInsertionNotificationTargets); +void notifyChildNodeRemoved(ContainerNode& insertionPoint, Node&); +void removeDetachedChildrenInContainer(ContainerNode&); enum SubframeDisconnectPolicy { RootAndDescendants, @@ -276,5 +48,3 @@ inline void disconnectSubframesIfNeeded(ContainerNode& root, SubframeDisconnectP } } // namespace WebCore - -#endif // ContainerNodeAlgorithms_h diff --git a/Source/WebCore/dom/ContextDestructionObserver.cpp b/Source/WebCore/dom/ContextDestructionObserver.cpp index a557dc7c0..a3339180e 100644 --- a/Source/WebCore/dom/ContextDestructionObserver.cpp +++ b/Source/WebCore/dom/ContextDestructionObserver.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -32,34 +32,34 @@ namespace WebCore { ContextDestructionObserver::ContextDestructionObserver(ScriptExecutionContext* scriptExecutionContext) - : m_scriptExecutionContext(0) + : m_scriptExecutionContext(nullptr) { observeContext(scriptExecutionContext); } ContextDestructionObserver::~ContextDestructionObserver() { - observeContext(0); + observeContext(nullptr); } void ContextDestructionObserver::observeContext(ScriptExecutionContext* scriptExecutionContext) { if (m_scriptExecutionContext) { ASSERT(m_scriptExecutionContext->isContextThread()); - m_scriptExecutionContext->willDestroyDestructionObserver(this); + m_scriptExecutionContext->willDestroyDestructionObserver(*this); } m_scriptExecutionContext = scriptExecutionContext; if (m_scriptExecutionContext) { ASSERT(m_scriptExecutionContext->isContextThread()); - m_scriptExecutionContext->didCreateDestructionObserver(this); + m_scriptExecutionContext->didCreateDestructionObserver(*this); } } void ContextDestructionObserver::contextDestroyed() { - m_scriptExecutionContext = 0; + m_scriptExecutionContext = nullptr; } } // namespace WebCore diff --git a/Source/WebCore/dom/ContextDestructionObserver.h b/Source/WebCore/dom/ContextDestructionObserver.h index ca956abc8..ebb8d3e78 100644 --- a/Source/WebCore/dom/ContextDestructionObserver.h +++ b/Source/WebCore/dom/ContextDestructionObserver.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -24,8 +24,9 @@ * */ -#ifndef ContextDestructionObserver_h -#define ContextDestructionObserver_h +#pragma once + +#include "PlatformExportMacros.h" namespace WebCore { @@ -33,18 +34,16 @@ class ScriptExecutionContext; class ContextDestructionObserver { public: - explicit ContextDestructionObserver(ScriptExecutionContext*); - virtual void contextDestroyed(); + WEBCORE_EXPORT explicit ContextDestructionObserver(ScriptExecutionContext*); + WEBCORE_EXPORT virtual void contextDestroyed(); ScriptExecutionContext* scriptExecutionContext() const { return m_scriptExecutionContext; } protected: - virtual ~ContextDestructionObserver(); + WEBCORE_EXPORT virtual ~ContextDestructionObserver(); void observeContext(ScriptExecutionContext*); ScriptExecutionContext* m_scriptExecutionContext; }; } // namespace WebCore - -#endif // ContextDestructionObserver_h diff --git a/Source/WebCore/dom/CrossThreadTask.h b/Source/WebCore/dom/CrossThreadTask.h deleted file mode 100644 index 6cc5f8421..000000000 --- a/Source/WebCore/dom/CrossThreadTask.h +++ /dev/null @@ -1,476 +0,0 @@ -/* - * Copyright (C) 2009-2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CrossThreadTask_h -#define CrossThreadTask_h - -#include "CrossThreadCopier.h" -#include "ScriptExecutionContext.h" -#include -#include -#include - -namespace WebCore { - -// Traits for the CrossThreadTask. -template struct CrossThreadTaskTraits { - typedef const T& ParamType; -}; - -template struct CrossThreadTaskTraits { - typedef T* ParamType; -}; - -template struct CrossThreadTaskTraits> { - typedef PassRefPtr ParamType; -}; - -template struct CrossThreadTaskTraits> { - typedef PassOwnPtr ParamType; -}; - -template -class CrossThreadTask1 : public ScriptExecutionContext::Task { -public: - typedef void (*Method)(ScriptExecutionContext*, MP1); - typedef CrossThreadTask1 CrossThreadTask; - typedef typename CrossThreadTaskTraits::ParamType Param1; - - static PassOwnPtr create(Method method, Param1 parameter1) - { - return adoptPtr(new CrossThreadTask(method, parameter1)); - } - -private: - CrossThreadTask1(Method method, Param1 parameter1) - : m_method(method) - , m_parameter1(parameter1) - { - } - - virtual void performTask(ScriptExecutionContext* context) - { - (*m_method)(context, m_parameter1); - } - -private: - Method m_method; - P1 m_parameter1; -}; - -template -class CrossThreadTask2 : public ScriptExecutionContext::Task { -public: - typedef void (*Method)(ScriptExecutionContext*, MP1, MP2); - typedef CrossThreadTask2 CrossThreadTask; - typedef typename CrossThreadTaskTraits::ParamType Param1; - typedef typename CrossThreadTaskTraits::ParamType Param2; - - static PassOwnPtr create(Method method, Param1 parameter1, Param2 parameter2) - { - return adoptPtr(new CrossThreadTask(method, parameter1, parameter2)); - } - -private: - CrossThreadTask2(Method method, Param1 parameter1, Param2 parameter2) - : m_method(method) - , m_parameter1(parameter1) - , m_parameter2(parameter2) - { - } - - virtual void performTask(ScriptExecutionContext* context) - { - (*m_method)(context, m_parameter1, m_parameter2); - } - -private: - Method m_method; - P1 m_parameter1; - P2 m_parameter2; -}; - -template -class CrossThreadTask3 : public ScriptExecutionContext::Task { -public: - typedef void (*Method)(ScriptExecutionContext*, MP1, MP2, MP3); - typedef CrossThreadTask3 CrossThreadTask; - typedef typename CrossThreadTaskTraits::ParamType Param1; - typedef typename CrossThreadTaskTraits::ParamType Param2; - typedef typename CrossThreadTaskTraits::ParamType Param3; - - static PassOwnPtr create(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3) - { - return adoptPtr(new CrossThreadTask(method, parameter1, parameter2, parameter3)); - } - -private: - CrossThreadTask3(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3) - : m_method(method) - , m_parameter1(parameter1) - , m_parameter2(parameter2) - , m_parameter3(parameter3) - { - } - - virtual void performTask(ScriptExecutionContext* context) - { - (*m_method)(context, m_parameter1, m_parameter2, m_parameter3); - } - -private: - Method m_method; - P1 m_parameter1; - P2 m_parameter2; - P3 m_parameter3; -}; - -template -class CrossThreadTask4 : public ScriptExecutionContext::Task { -public: - typedef void (*Method)(ScriptExecutionContext*, MP1, MP2, MP3, MP4); - typedef CrossThreadTask4 CrossThreadTask; - typedef typename CrossThreadTaskTraits::ParamType Param1; - typedef typename CrossThreadTaskTraits::ParamType Param2; - typedef typename CrossThreadTaskTraits::ParamType Param3; - typedef typename CrossThreadTaskTraits::ParamType Param4; - - static PassOwnPtr create(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4) - { - return adoptPtr(new CrossThreadTask(method, parameter1, parameter2, parameter3, parameter4)); - } - -private: - CrossThreadTask4(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4) - : m_method(method) - , m_parameter1(parameter1) - , m_parameter2(parameter2) - , m_parameter3(parameter3) - , m_parameter4(parameter4) - { - } - - virtual void performTask(ScriptExecutionContext* context) - { - (*m_method)(context, m_parameter1, m_parameter2, m_parameter3, m_parameter4); - } - -private: - Method m_method; - P1 m_parameter1; - P2 m_parameter2; - P3 m_parameter3; - P4 m_parameter4; -}; - -template -class CrossThreadTask5 : public ScriptExecutionContext::Task { -public: - typedef void (*Method)(ScriptExecutionContext*, MP1, MP2, MP3, MP4, MP5); - typedef CrossThreadTask5 CrossThreadTask; - typedef typename CrossThreadTaskTraits::ParamType Param1; - typedef typename CrossThreadTaskTraits::ParamType Param2; - typedef typename CrossThreadTaskTraits::ParamType Param3; - typedef typename CrossThreadTaskTraits::ParamType Param4; - typedef typename CrossThreadTaskTraits::ParamType Param5; - - static PassOwnPtr create(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4, Param5 parameter5) - { - return adoptPtr(new CrossThreadTask(method, parameter1, parameter2, parameter3, parameter4, parameter5)); - } - -private: - CrossThreadTask5(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4, Param5 parameter5) - : m_method(method) - , m_parameter1(parameter1) - , m_parameter2(parameter2) - , m_parameter3(parameter3) - , m_parameter4(parameter4) - , m_parameter5(parameter5) - { - } - - virtual void performTask(ScriptExecutionContext* context) - { - (*m_method)(context, m_parameter1, m_parameter2, m_parameter3, m_parameter4, m_parameter5); - } - -private: - Method m_method; - P1 m_parameter1; - P2 m_parameter2; - P3 m_parameter3; - P4 m_parameter4; - P5 m_parameter5; -}; - -template -class CrossThreadTask6 : public ScriptExecutionContext::Task { -public: - typedef void (*Method)(ScriptExecutionContext*, MP1, MP2, MP3, MP4, MP5, MP6); - typedef CrossThreadTask6 CrossThreadTask; - typedef typename CrossThreadTaskTraits::ParamType Param1; - typedef typename CrossThreadTaskTraits::ParamType Param2; - typedef typename CrossThreadTaskTraits::ParamType Param3; - typedef typename CrossThreadTaskTraits::ParamType Param4; - typedef typename CrossThreadTaskTraits::ParamType Param5; - typedef typename CrossThreadTaskTraits::ParamType Param6; - - static PassOwnPtr create(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4, Param5 parameter5, Param6 parameter6) - { - return adoptPtr(new CrossThreadTask(method, parameter1, parameter2, parameter3, parameter4, parameter5, parameter6)); - } - -private: - CrossThreadTask6(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4, Param5 parameter5, Param6 parameter6) - : m_method(method) - , m_parameter1(parameter1) - , m_parameter2(parameter2) - , m_parameter3(parameter3) - , m_parameter4(parameter4) - , m_parameter5(parameter5) - , m_parameter6(parameter6) - { - } - - virtual void performTask(ScriptExecutionContext* context) - { - (*m_method)(context, m_parameter1, m_parameter2, m_parameter3, m_parameter4, m_parameter5, m_parameter6); - } - -private: - Method m_method; - P1 m_parameter1; - P2 m_parameter2; - P3 m_parameter3; - P4 m_parameter4; - P5 m_parameter5; - P6 m_parameter6; -}; - -template -class CrossThreadTask7 : public ScriptExecutionContext::Task { -public: - typedef void (*Method)(ScriptExecutionContext*, MP1, MP2, MP3, MP4, MP5, MP6, MP7); - typedef CrossThreadTask7 CrossThreadTask; - typedef typename CrossThreadTaskTraits::ParamType Param1; - typedef typename CrossThreadTaskTraits::ParamType Param2; - typedef typename CrossThreadTaskTraits::ParamType Param3; - typedef typename CrossThreadTaskTraits::ParamType Param4; - typedef typename CrossThreadTaskTraits::ParamType Param5; - typedef typename CrossThreadTaskTraits::ParamType Param6; - typedef typename CrossThreadTaskTraits::ParamType Param7; - - static PassOwnPtr create(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4, Param5 parameter5, Param6 parameter6, Param7 parameter7) - { - return adoptPtr(new CrossThreadTask(method, parameter1, parameter2, parameter3, parameter4, parameter5, parameter6, parameter7)); - } - -private: - CrossThreadTask7(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4, Param5 parameter5, Param6 parameter6, Param7 parameter7) - : m_method(method) - , m_parameter1(parameter1) - , m_parameter2(parameter2) - , m_parameter3(parameter3) - , m_parameter4(parameter4) - , m_parameter5(parameter5) - , m_parameter6(parameter6) - , m_parameter7(parameter7) - { - } - - virtual void performTask(ScriptExecutionContext* context) - { - (*m_method)(context, m_parameter1, m_parameter2, m_parameter3, m_parameter4, m_parameter5, m_parameter6, m_parameter7); - } - -private: - Method m_method; - P1 m_parameter1; - P2 m_parameter2; - P3 m_parameter3; - P4 m_parameter4; - P5 m_parameter5; - P6 m_parameter6; - P7 m_parameter7; -}; - -template -class CrossThreadTask8 : public ScriptExecutionContext::Task { -public: - typedef void (*Method)(ScriptExecutionContext*, MP1, MP2, MP3, MP4, MP5, MP6, MP7, MP8); - typedef CrossThreadTask8 CrossThreadTask; - typedef typename CrossThreadTaskTraits::ParamType Param1; - typedef typename CrossThreadTaskTraits::ParamType Param2; - typedef typename CrossThreadTaskTraits::ParamType Param3; - typedef typename CrossThreadTaskTraits::ParamType Param4; - typedef typename CrossThreadTaskTraits::ParamType Param5; - typedef typename CrossThreadTaskTraits::ParamType Param6; - typedef typename CrossThreadTaskTraits::ParamType Param7; - typedef typename CrossThreadTaskTraits::ParamType Param8; - - static PassOwnPtr create(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4, Param5 parameter5, Param6 parameter6, Param7 parameter7, Param8 parameter8) - { - return adoptPtr(new CrossThreadTask(method, parameter1, parameter2, parameter3, parameter4, parameter5, parameter6, parameter7, parameter8)); - } - -private: - CrossThreadTask8(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4, Param5 parameter5, Param6 parameter6, Param7 parameter7, Param8 parameter8) - : m_method(method) - , m_parameter1(parameter1) - , m_parameter2(parameter2) - , m_parameter3(parameter3) - , m_parameter4(parameter4) - , m_parameter5(parameter5) - , m_parameter6(parameter6) - , m_parameter7(parameter7) - , m_parameter8(parameter8) - { - } - - virtual void performTask(ScriptExecutionContext* context) - { - (*m_method)(context, m_parameter1, m_parameter2, m_parameter3, m_parameter4, m_parameter5, m_parameter6, m_parameter7, m_parameter8); - } - -private: - Method m_method; - P1 m_parameter1; - P2 m_parameter2; - P3 m_parameter3; - P4 m_parameter4; - P5 m_parameter5; - P6 m_parameter6; - P7 m_parameter7; - P8 m_parameter8; -}; - -template -PassOwnPtr createCallbackTask( - void (*method)(ScriptExecutionContext*, MP1), - const P1& parameter1) -{ - return CrossThreadTask1::Type, MP1>::create( - method, - CrossThreadCopier::copy(parameter1)); -} - -template -PassOwnPtr createCallbackTask( - void (*method)(ScriptExecutionContext*, MP1, MP2), - const P1& parameter1, const P2& parameter2) -{ - return CrossThreadTask2::Type, MP1, typename CrossThreadCopier::Type, MP2>::create( - method, - CrossThreadCopier::copy(parameter1), CrossThreadCopier::copy(parameter2)); -} - -template -PassOwnPtr createCallbackTask( - void (*method)(ScriptExecutionContext*, MP1, MP2, MP3), - const P1& parameter1, const P2& parameter2, const P3& parameter3) -{ - return CrossThreadTask3::Type, MP1, typename CrossThreadCopier::Type, MP2, typename CrossThreadCopier::Type, MP3>::create( - method, - CrossThreadCopier::copy(parameter1), CrossThreadCopier::copy(parameter2), - CrossThreadCopier::copy(parameter3)); -} - -template -PassOwnPtr createCallbackTask( - void (*method)(ScriptExecutionContext*, MP1, MP2, MP3, MP4), - const P1& parameter1, const P2& parameter2, const P3& parameter3, const P4& parameter4) -{ - return CrossThreadTask4::Type, MP1, typename CrossThreadCopier::Type, MP2, typename CrossThreadCopier::Type, MP3, - typename CrossThreadCopier::Type, MP4>::create( - method, - CrossThreadCopier::copy(parameter1), CrossThreadCopier::copy(parameter2), - CrossThreadCopier::copy(parameter3), CrossThreadCopier::copy(parameter4)); -} - -template -PassOwnPtr createCallbackTask( - void (*method)(ScriptExecutionContext*, MP1, MP2, MP3, MP4, MP5), - const P1& parameter1, const P2& parameter2, const P3& parameter3, const P4& parameter4, const P5& parameter5) -{ - return CrossThreadTask5::Type, MP1, typename CrossThreadCopier::Type, MP2, typename CrossThreadCopier::Type, MP3, - typename CrossThreadCopier::Type, MP4, typename CrossThreadCopier::Type, MP5>::create( - method, - CrossThreadCopier::copy(parameter1), CrossThreadCopier::copy(parameter2), - CrossThreadCopier::copy(parameter3), CrossThreadCopier::copy(parameter4), - CrossThreadCopier::copy(parameter5)); -} - -template -PassOwnPtr createCallbackTask( - void (*method)(ScriptExecutionContext*, MP1, MP2, MP3, MP4, MP5, MP6), - const P1& parameter1, const P2& parameter2, const P3& parameter3, const P4& parameter4, const P5& parameter5, const P6& parameter6) -{ - return CrossThreadTask6::Type, MP1, typename CrossThreadCopier::Type, MP2, typename CrossThreadCopier::Type, MP3, - typename CrossThreadCopier::Type, MP4, typename CrossThreadCopier::Type, MP5, typename CrossThreadCopier::Type, MP6>::create( - method, - CrossThreadCopier::copy(parameter1), CrossThreadCopier::copy(parameter2), - CrossThreadCopier::copy(parameter3), CrossThreadCopier::copy(parameter4), - CrossThreadCopier::copy(parameter5), CrossThreadCopier::copy(parameter6)); -} - -template -PassOwnPtr createCallbackTask( - void (*method)(ScriptExecutionContext*, MP1, MP2, MP3, MP4, MP5, MP6, MP7), - const P1& parameter1, const P2& parameter2, const P3& parameter3, const P4& parameter4, const P5& parameter5, const P6& parameter6, const P7& parameter7) -{ - return CrossThreadTask7::Type, MP1, typename CrossThreadCopier::Type, MP2, typename CrossThreadCopier::Type, MP3, - typename CrossThreadCopier::Type, MP4, typename CrossThreadCopier::Type, MP5, typename CrossThreadCopier::Type, MP6, - typename CrossThreadCopier::Type, MP7>::create( - method, - CrossThreadCopier::copy(parameter1), CrossThreadCopier::copy(parameter2), - CrossThreadCopier::copy(parameter3), CrossThreadCopier::copy(parameter4), - CrossThreadCopier::copy(parameter5), CrossThreadCopier::copy(parameter6), - CrossThreadCopier::copy(parameter7)); -} - -template -PassOwnPtr createCallbackTask( - void (*method)(ScriptExecutionContext*, MP1, MP2, MP3, MP4, MP5, MP6, MP7, MP8), - const P1& parameter1, const P2& parameter2, const P3& parameter3, const P4& parameter4, const P5& parameter5, const P6& parameter6, const P7& parameter7, const P8& parameter8) -{ - return CrossThreadTask8::Type, MP1, typename CrossThreadCopier::Type, MP2, typename CrossThreadCopier::Type, MP3, - typename CrossThreadCopier::Type, MP4, typename CrossThreadCopier::Type, MP5, typename CrossThreadCopier::Type, MP6, - typename CrossThreadCopier::Type, MP7, typename CrossThreadCopier::Type, MP8>::create( - method, - CrossThreadCopier::copy(parameter1), CrossThreadCopier::copy(parameter2), - CrossThreadCopier::copy(parameter3), CrossThreadCopier::copy(parameter4), - CrossThreadCopier::copy(parameter5), CrossThreadCopier::copy(parameter6), - CrossThreadCopier::copy(parameter7), CrossThreadCopier::copy(parameter8)); -} - -} // namespace WebCore - -#endif // CrossThreadTask_h diff --git a/Source/WebCore/dom/CurrentScriptIncrementer.h b/Source/WebCore/dom/CurrentScriptIncrementer.h index a8ceca25d..d08902334 100644 --- a/Source/WebCore/dom/CurrentScriptIncrementer.h +++ b/Source/WebCore/dom/CurrentScriptIncrementer.h @@ -10,7 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -26,8 +26,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CurrentScriptIncrementer_h -#define CurrentScriptIncrementer_h +#pragma once #include "Document.h" #include "HTMLScriptElement.h" @@ -37,25 +36,27 @@ namespace WebCore { class CurrentScriptIncrementer { WTF_MAKE_NONCOPYABLE(CurrentScriptIncrementer); public: - CurrentScriptIncrementer(Document* document, Element* element) + CurrentScriptIncrementer(Document& document, Element& element) : m_document(document) - , m_isHTMLScriptElement(isHTMLScriptElement(element)) + , m_isHTMLScriptElement(is(element)) { - if (m_isHTMLScriptElement) - m_document->pushCurrentScript(toHTMLScriptElement(element)); + if (!m_isHTMLScriptElement) + return; + auto& scriptElement = downcast(element); + bool shouldPushNullForCurrentScript = scriptElement.isInShadowTree() || scriptElement.scriptType() == ScriptElement::ScriptType::Module; + m_document.pushCurrentScript(shouldPushNullForCurrentScript ? nullptr : &scriptElement); } ~CurrentScriptIncrementer() { - if (m_isHTMLScriptElement) - m_document->popCurrentScript(); + if (!m_isHTMLScriptElement) + return; + m_document.popCurrentScript(); } private: - Document* m_document; + Document& m_document; bool m_isHTMLScriptElement; }; -} - -#endif +} // namespace WebCore diff --git a/Source/WebCore/dom/CustomElementReactionQueue.cpp b/Source/WebCore/dom/CustomElementReactionQueue.cpp new file mode 100644 index 000000000..a7dab97ad --- /dev/null +++ b/Source/WebCore/dom/CustomElementReactionQueue.cpp @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2015, 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CustomElementReactionQueue.h" + +#include "CustomElementRegistry.h" +#include "DOMWindow.h" +#include "Document.h" +#include "Element.h" +#include "HTMLNames.h" +#include "JSCustomElementInterface.h" +#include "JSDOMBinding.h" +#include "Microtasks.h" +#include +#include +#include +#include + +namespace WebCore { + +class CustomElementReactionQueueItem { +public: + enum class Type { + ElementUpgrade, + Connected, + Disconnected, + Adopted, + AttributeChanged, + }; + + CustomElementReactionQueueItem(Type type) + : m_type(type) + { } + + CustomElementReactionQueueItem(Document& oldDocument, Document& newDocument) + : m_type(Type::Adopted) + , m_oldDocument(&oldDocument) + , m_newDocument(&newDocument) + { } + + CustomElementReactionQueueItem(const QualifiedName& attributeName, const AtomicString& oldValue, const AtomicString& newValue) + : m_type(Type::AttributeChanged) + , m_attributeName(attributeName) + , m_oldValue(oldValue) + , m_newValue(newValue) + { } + + void invoke(Element& element, JSCustomElementInterface& elementInterface) + { + switch (m_type) { + case Type::ElementUpgrade: + elementInterface.upgradeElement(element); + break; + case Type::Connected: + elementInterface.invokeConnectedCallback(element); + break; + case Type::Disconnected: + elementInterface.invokeDisconnectedCallback(element); + break; + case Type::Adopted: + elementInterface.invokeAdoptedCallback(element, *m_oldDocument, *m_newDocument); + break; + case Type::AttributeChanged: + ASSERT(m_attributeName); + elementInterface.invokeAttributeChangedCallback(element, m_attributeName.value(), m_oldValue, m_newValue); + break; + } + } + +private: + Type m_type; + RefPtr m_oldDocument; + RefPtr m_newDocument; + std::optional m_attributeName; + AtomicString m_oldValue; + AtomicString m_newValue; +}; + +CustomElementReactionQueue::CustomElementReactionQueue(JSCustomElementInterface& elementInterface) + : m_interface(elementInterface) +{ } + +CustomElementReactionQueue::~CustomElementReactionQueue() +{ + ASSERT(m_items.isEmpty()); +} + +void CustomElementReactionQueue::clear() +{ + m_items.clear(); +} + +void CustomElementReactionQueue::enqueueElementUpgrade(Element& element) +{ + auto& queue = CustomElementReactionStack::ensureCurrentQueue(element); + queue.m_items.append({CustomElementReactionQueueItem::Type::ElementUpgrade}); +} + +void CustomElementReactionQueue::enqueueElementUpgradeIfDefined(Element& element) +{ + ASSERT(element.isConnected()); + ASSERT(element.isCustomElementUpgradeCandidate()); + auto* window = element.document().domWindow(); + if (!window) + return; + + auto* registry = window->customElementRegistry(); + if (!registry) + return; + + auto* elementInterface = registry->findInterface(element); + if (!elementInterface) + return; + + element.enqueueToUpgrade(*elementInterface); +} + +void CustomElementReactionQueue::enqueueConnectedCallbackIfNeeded(Element& element) +{ + ASSERT(element.isDefinedCustomElement()); + ASSERT(element.document().refCount() > 0); + auto& queue = CustomElementReactionStack::ensureCurrentQueue(element); + if (queue.m_interface->hasConnectedCallback()) + queue.m_items.append({CustomElementReactionQueueItem::Type::Connected}); +} + +void CustomElementReactionQueue::enqueueDisconnectedCallbackIfNeeded(Element& element) +{ + ASSERT(element.isDefinedCustomElement()); + if (element.document().refCount() <= 0) + return; // Don't enqueue disconnectedCallback if the entire document is getting destructed. + auto& queue = CustomElementReactionStack::ensureCurrentQueue(element); + if (queue.m_interface->hasDisconnectedCallback()) + queue.m_items.append({CustomElementReactionQueueItem::Type::Disconnected}); +} + +void CustomElementReactionQueue::enqueueAdoptedCallbackIfNeeded(Element& element, Document& oldDocument, Document& newDocument) +{ + ASSERT(element.isDefinedCustomElement()); + ASSERT(element.document().refCount() > 0); + auto& queue = CustomElementReactionStack::ensureCurrentQueue(element); + if (queue.m_interface->hasAdoptedCallback()) + queue.m_items.append({oldDocument, newDocument}); +} + +void CustomElementReactionQueue::enqueueAttributeChangedCallbackIfNeeded(Element& element, const QualifiedName& attributeName, const AtomicString& oldValue, const AtomicString& newValue) +{ + ASSERT(element.isDefinedCustomElement()); + ASSERT(element.document().refCount() > 0); + auto& queue = CustomElementReactionStack::ensureCurrentQueue(element); + if (queue.m_interface->observesAttribute(attributeName.localName())) + queue.m_items.append({attributeName, oldValue, newValue}); +} + +void CustomElementReactionQueue::enqueuePostUpgradeReactions(Element& element) +{ + ASSERT(element.isCustomElementUpgradeCandidate()); + if (!element.hasAttributes() && !element.isConnected()) + return; + + auto* queue = element.reactionQueue(); + ASSERT(queue); + + if (element.hasAttributes()) { + for (auto& attribute : element.attributesIterator()) { + if (queue->m_interface->observesAttribute(attribute.localName())) + queue->m_items.append({attribute.name(), nullAtom, attribute.value()}); + } + } + + if (element.isConnected() && queue->m_interface->hasConnectedCallback()) + queue->m_items.append({CustomElementReactionQueueItem::Type::Connected}); +} + +bool CustomElementReactionQueue::observesStyleAttribute() const +{ + return m_interface->observesAttribute(HTMLNames::styleAttr.localName()); +} + +void CustomElementReactionQueue::invokeAll(Element& element) +{ + while (!m_items.isEmpty()) { + Vector items = WTFMove(m_items); + for (auto& item : items) + item.invoke(element, m_interface.get()); + } +} + +inline void CustomElementReactionStack::ElementQueue::add(Element& element) +{ + RELEASE_ASSERT(!m_invoking); + // FIXME: Avoid inserting the same element multiple times. + m_elements.append(element); +} + +inline void CustomElementReactionStack::ElementQueue::invokeAll() +{ + RELEASE_ASSERT(!m_invoking); + SetForScope invoking(m_invoking, true); + Vector> elements; + elements.swap(m_elements); + RELEASE_ASSERT(m_elements.isEmpty()); + for (auto& element : elements) { + auto* queue = element->reactionQueue(); + ASSERT(queue); + queue->invokeAll(element.get()); + } + RELEASE_ASSERT(m_elements.isEmpty()); +} + +CustomElementReactionQueue& CustomElementReactionStack::ensureCurrentQueue(Element& element) +{ + ASSERT(element.reactionQueue()); + if (!s_currentProcessingStack) { + auto& queue = CustomElementReactionStack::ensureBackupQueue(); + queue.add(element); + return *element.reactionQueue(); + } + + auto*& queue = s_currentProcessingStack->m_queue; + if (!queue) // We use a raw pointer to avoid genearing code to delete it in ~CustomElementReactionStack. + queue = new ElementQueue; + queue->add(element); + return *element.reactionQueue(); +} + +CustomElementReactionStack* CustomElementReactionStack::s_currentProcessingStack = nullptr; + +void CustomElementReactionStack::processQueue() +{ + ASSERT(m_queue); + m_queue->invokeAll(); + delete m_queue; + m_queue = nullptr; +} + +class BackupElementQueueMicrotask final : public Microtask { + WTF_MAKE_FAST_ALLOCATED; +private: + Result run() final + { + CustomElementReactionStack::processBackupQueue(); + return Result::Done; + } +}; + +static bool s_processingBackupElementQueue = false; + +CustomElementReactionStack::ElementQueue& CustomElementReactionStack::ensureBackupQueue() +{ + if (!s_processingBackupElementQueue) { + s_processingBackupElementQueue = true; + MicrotaskQueue::mainThreadQueue().append(std::make_unique()); + } + return backupElementQueue(); +} + +void CustomElementReactionStack::processBackupQueue() +{ + backupElementQueue().invokeAll(); + s_processingBackupElementQueue = false; +} + +CustomElementReactionStack::ElementQueue& CustomElementReactionStack::backupElementQueue() +{ + static NeverDestroyed queue; + return queue.get(); +} + +} diff --git a/Source/WebCore/dom/CustomElementReactionQueue.h b/Source/WebCore/dom/CustomElementReactionQueue.h new file mode 100644 index 000000000..0c9123dc2 --- /dev/null +++ b/Source/WebCore/dom/CustomElementReactionQueue.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2015, 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include + +namespace WebCore { + +class CustomElementReactionQueueItem; +class Document; +class Element; +class JSCustomElementInterface; +class QualifiedName; + +class CustomElementReactionQueue { + WTF_MAKE_NONCOPYABLE(CustomElementReactionQueue); +public: + CustomElementReactionQueue(JSCustomElementInterface&); + ~CustomElementReactionQueue(); + + static void enqueueElementUpgrade(Element&); + static void enqueueElementUpgradeIfDefined(Element&); + static void enqueueConnectedCallbackIfNeeded(Element&); + static void enqueueDisconnectedCallbackIfNeeded(Element&); + static void enqueueAdoptedCallbackIfNeeded(Element&, Document& oldDocument, Document& newDocument); + static void enqueueAttributeChangedCallbackIfNeeded(Element&, const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue); + static void enqueuePostUpgradeReactions(Element&); + + bool observesStyleAttribute() const; + void invokeAll(Element&); + void clear(); + +private: + Ref m_interface; + Vector m_items; +}; + +class CustomElementReactionStack { +public: + CustomElementReactionStack() + : m_previousProcessingStack(s_currentProcessingStack) + { + s_currentProcessingStack = this; + } + + ~CustomElementReactionStack() + { + if (UNLIKELY(m_queue)) + processQueue(); + s_currentProcessingStack = m_previousProcessingStack; + } + + static CustomElementReactionQueue& ensureCurrentQueue(Element&); + + static bool hasCurrentProcessingStack() { return s_currentProcessingStack; } + + static void processBackupQueue(); + +private: + class ElementQueue { + public: + void add(Element&); + void invokeAll(); + + private: + Vector> m_elements; + bool m_invoking { false }; + }; + + WEBCORE_EXPORT void processQueue(); + + static ElementQueue& ensureBackupQueue(); + static ElementQueue& backupElementQueue(); + + ElementQueue* m_queue { nullptr }; + CustomElementReactionStack* m_previousProcessingStack; + + WEBCORE_EXPORT static CustomElementReactionStack* s_currentProcessingStack; +}; + +} diff --git a/Source/WebCore/dom/CustomElementRegistry.cpp b/Source/WebCore/dom/CustomElementRegistry.cpp new file mode 100644 index 000000000..f2f108b80 --- /dev/null +++ b/Source/WebCore/dom/CustomElementRegistry.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2015, 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CustomElementRegistry.h" + +#include "CustomElementReactionQueue.h" +#include "DOMWindow.h" +#include "Document.h" +#include "Element.h" +#include "ElementTraversal.h" +#include "JSCustomElementInterface.h" +#include "MathMLNames.h" +#include "QualifiedName.h" +#include "ShadowRoot.h" +#include +#include + +namespace WebCore { + +Ref CustomElementRegistry::create(DOMWindow& window) +{ + return adoptRef(*new CustomElementRegistry(window)); +} + +CustomElementRegistry::CustomElementRegistry(DOMWindow& window) + : m_window(window) +{ } + +CustomElementRegistry::~CustomElementRegistry() +{ } + +// https://dom.spec.whatwg.org/#concept-shadow-including-tree-order +static void enqueueUpgradeInShadowIncludingTreeOrder(ContainerNode& node, JSCustomElementInterface& elementInterface) +{ + for (Element* element = ElementTraversal::firstWithin(node); element; element = ElementTraversal::next(*element)) { + if (element->isCustomElementUpgradeCandidate() && element->tagQName() == elementInterface.name()) + element->enqueueToUpgrade(elementInterface); + if (auto* shadowRoot = element->shadowRoot()) { + if (shadowRoot->mode() != ShadowRootMode::UserAgent) + enqueueUpgradeInShadowIncludingTreeOrder(*shadowRoot, elementInterface); + } + } +} + +void CustomElementRegistry::addElementDefinition(Ref&& elementInterface) +{ + AtomicString localName = elementInterface->name().localName(); + ASSERT(!m_nameMap.contains(localName)); + m_constructorMap.add(elementInterface->constructor(), elementInterface.ptr()); + m_nameMap.add(localName, elementInterface.copyRef()); + + if (auto* document = m_window.document()) + enqueueUpgradeInShadowIncludingTreeOrder(*document, elementInterface.get()); + + if (auto promise = m_promiseMap.take(localName)) + promise.value()->resolve(); +} + +JSCustomElementInterface* CustomElementRegistry::findInterface(const Element& element) const +{ + return findInterface(element.tagQName()); +} + +JSCustomElementInterface* CustomElementRegistry::findInterface(const QualifiedName& name) const +{ + if (name.namespaceURI() != HTMLNames::xhtmlNamespaceURI) + return nullptr; + return m_nameMap.get(name.localName()); +} + +JSCustomElementInterface* CustomElementRegistry::findInterface(const AtomicString& name) const +{ + return m_nameMap.get(name); +} + +JSCustomElementInterface* CustomElementRegistry::findInterface(const JSC::JSObject* constructor) const +{ + return m_constructorMap.get(constructor); +} + +bool CustomElementRegistry::containsConstructor(const JSC::JSObject* constructor) const +{ + return m_constructorMap.contains(constructor); +} + +JSC::JSValue CustomElementRegistry::get(const AtomicString& name) +{ + if (auto* elementInterface = m_nameMap.get(name)) + return elementInterface->constructor(); + return JSC::jsUndefined(); +} + +} diff --git a/Source/WebCore/dom/CustomElementRegistry.h b/Source/WebCore/dom/CustomElementRegistry.h new file mode 100644 index 000000000..112097b1c --- /dev/null +++ b/Source/WebCore/dom/CustomElementRegistry.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2015, 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "JSDOMPromise.h" +#include "QualifiedName.h" +#include +#include +#include +#include + +namespace JSC { + +class JSObject; +class JSValue; + +} + +namespace WebCore { + +class CustomElementRegistry; +class DOMWindow; +class Element; +class JSCustomElementInterface; +class QualifiedName; + +class CustomElementRegistry : public RefCounted { +public: + static Ref create(DOMWindow&); + ~CustomElementRegistry(); + + void addElementDefinition(Ref&&); + + bool& elementDefinitionIsRunning() { return m_elementDefinitionIsRunning; } + + JSCustomElementInterface* findInterface(const Element&) const; + JSCustomElementInterface* findInterface(const QualifiedName&) const; + JSCustomElementInterface* findInterface(const AtomicString&) const; + JSCustomElementInterface* findInterface(const JSC::JSObject*) const; + bool containsConstructor(const JSC::JSObject*) const; + + JSC::JSValue get(const AtomicString&); + + HashMap>& promiseMap() { return m_promiseMap; } + +private: + CustomElementRegistry(DOMWindow&); + + DOMWindow& m_window; + HashMap> m_nameMap; + HashMap m_constructorMap; + HashMap> m_promiseMap; + + bool m_elementDefinitionIsRunning { false }; + + friend class ElementDefinitionIsRunningSetForScope; +}; + +} diff --git a/Source/WebCore/dom/CustomElementRegistry.idl b/Source/WebCore/dom/CustomElementRegistry.idl new file mode 100644 index 000000000..c52533bf5 --- /dev/null +++ b/Source/WebCore/dom/CustomElementRegistry.idl @@ -0,0 +1,34 @@ +/* +* Copyright (C) 2016 Apple Inc. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +[ + EnabledAtRuntime=CustomElements, + ImplementationLacksVTable, + JSGenerateToNativeObject, +] interface CustomElementRegistry { + [CEReactions, Custom] void define(DOMString name, Function constructor); + any get(DOMString name); + [Custom, MayThrowException] Promise whenDefined(DOMString name); +}; diff --git a/Source/WebCore/dom/CustomEvent.cpp b/Source/WebCore/dom/CustomEvent.cpp index d5ef0bdee..080cab456 100644 --- a/Source/WebCore/dom/CustomEvent.cpp +++ b/Source/WebCore/dom/CustomEvent.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,21 +26,18 @@ #include "config.h" #include "CustomEvent.h" -#include "EventNames.h" +#include namespace WebCore { -CustomEventInit::CustomEventInit() +CustomEvent::CustomEvent(IsTrusted isTrusted) + : Event(isTrusted) { } -CustomEvent::CustomEvent() -{ -} - -CustomEvent::CustomEvent(const AtomicString& type, const CustomEventInit& initializer) - : Event(type, initializer) - , m_detail(initializer.detail) +CustomEvent::CustomEvent(JSC::ExecState& state, const AtomicString& type, const Init& initializer, IsTrusted isTrusted) + : Event(type, initializer, isTrusted) + , m_detail(state.vm(), initializer.detail) { } @@ -48,15 +45,25 @@ CustomEvent::~CustomEvent() { } -void CustomEvent::initCustomEvent(const AtomicString& type, bool canBubble, bool cancelable, const Deprecated::ScriptValue& detail) +void CustomEvent::initCustomEvent(JSC::ExecState& state, const AtomicString& type, bool canBubble, bool cancelable, JSC::JSValue detail) { - ASSERT(!m_serializedScriptValue.get()); - if (dispatched()) + if (isBeingDispatched()) return; initEvent(type, canBubble, cancelable); - m_detail = detail; + m_detail = { state.vm(), detail }; + m_serializedDetail = nullptr; + m_triedToSerialize = false; +} + +RefPtr CustomEvent::trySerializeDetail(JSC::ExecState& state) +{ + if (!m_triedToSerialize) { + m_serializedDetail = SerializedScriptValue::create(state, m_detail, SerializationErrorMode::NonThrowing); + m_triedToSerialize = true; + } + return m_serializedDetail; } EventInterface CustomEvent::eventInterface() const diff --git a/Source/WebCore/dom/CustomEvent.h b/Source/WebCore/dom/CustomEvent.h index 7f4c1cf04..483495f1e 100644 --- a/Source/WebCore/dom/CustomEvent.h +++ b/Source/WebCore/dom/CustomEvent.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CustomEvent_h -#define CustomEvent_h +#pragma once #include "Event.h" #include "SerializedScriptValue.h" @@ -32,41 +31,39 @@ namespace WebCore { -struct CustomEventInit : public EventInit { - CustomEventInit(); - - Deprecated::ScriptValue detail; -}; - -class CustomEvent : public Event { +class CustomEvent final : public Event { public: virtual ~CustomEvent(); - static PassRefPtr create() + static Ref create(IsTrusted isTrusted = IsTrusted::No) { - return adoptRef(new CustomEvent); + return adoptRef(*new CustomEvent(isTrusted)); } - static PassRefPtr create(const AtomicString& type, const CustomEventInit& initializer) + struct Init : EventInit { + JSC::JSValue detail; + }; + + static Ref create(JSC::ExecState& state, const AtomicString& type, const Init& initializer, IsTrusted isTrusted = IsTrusted::No) { - return adoptRef(new CustomEvent(type, initializer)); + return adoptRef(*new CustomEvent(state, type, initializer, isTrusted)); } - void initCustomEvent(const AtomicString& type, bool canBubble, bool cancelable, const Deprecated::ScriptValue& detail); + void initCustomEvent(JSC::ExecState&, const AtomicString& type, bool canBubble, bool cancelable, JSC::JSValue detail = JSC::JSValue::JSUndefined); - virtual EventInterface eventInterface() const; + EventInterface eventInterface() const override; - const Deprecated::ScriptValue& detail() const { return m_detail; } - PassRefPtr serializedScriptValue() { return m_serializedScriptValue; } + JSC::JSValue detail() const { return m_detail.jsValue(); } + + RefPtr trySerializeDetail(JSC::ExecState&); private: - CustomEvent(); - CustomEvent(const AtomicString& type, const CustomEventInit& initializer); + CustomEvent(IsTrusted); + CustomEvent(JSC::ExecState&, const AtomicString& type, const Init& initializer, IsTrusted); - Deprecated::ScriptValue m_detail; - RefPtr m_serializedScriptValue; + Deprecated::ScriptValue m_detail; // FIXME: Why is it OK to use a strong reference here? What prevents a reference cycle? + RefPtr m_serializedDetail; + bool m_triedToSerialize { false }; }; } // namespace WebCore - -#endif // CustomEvent_h diff --git a/Source/WebCore/dom/CustomEvent.idl b/Source/WebCore/dom/CustomEvent.idl index 17dce6f33..1866be4a2 100644 --- a/Source/WebCore/dom/CustomEvent.idl +++ b/Source/WebCore/dom/CustomEvent.idl @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,17 +23,17 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#if !defined(LANGUAGE_CPP) || !LANGUAGE_CPP // Introduced in DOM Level 3: +// FIXME: This should be exposed to workers as well. [ - ConstructorTemplate=Event, + Constructor(DOMString type, optional CustomEventInit eventInitDict), + ConstructorCallWith=ScriptState, ] interface CustomEvent : Event { - [InitializedByEventConstructor] readonly attribute any detail; + [CustomGetter] readonly attribute any detail; - void initCustomEvent([Default=Undefined] optional DOMString typeArg, - [Default=Undefined] optional boolean canBubbleArg, - [Default=Undefined] optional boolean cancelableArg, - [Default=Undefined] optional any detailArg); + [CallWith=ScriptState] void initCustomEvent(DOMString type, optional boolean bubbles = false, optional boolean cancelable = false, optional any detail = null); }; -#endif +dictionary CustomEventInit : EventInit { + any detail = null; +}; diff --git a/Source/WebCore/dom/DOMAllInOne.cpp b/Source/WebCore/dom/DOMAllInOne.cpp new file mode 100644 index 000000000..a9760ffcb --- /dev/null +++ b/Source/WebCore/dom/DOMAllInOne.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2010, 2011 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This all-in-one cpp file cuts down on template bloat to allow us to build our Windows release build. + +#include "ActiveDOMCallbackMicrotask.cpp" +#include "ActiveDOMObject.cpp" +#include "AnimationEvent.cpp" +#include "Attr.cpp" +#include "StyleScope.cpp" +#include "BeforeTextInsertedEvent.cpp" +#include "BeforeUnloadEvent.cpp" +#include "CDATASection.cpp" +#include "CharacterData.cpp" +#include "ChildListMutationScope.cpp" +#include "ChildNodeList.cpp" +#include "ClassCollection.cpp" +#include "ClientRect.cpp" +#include "ClientRectList.cpp" +#include "ClipboardEvent.cpp" +#include "CollectionIndexCache.cpp" +#include "Comment.cpp" +#include "ComposedTreeIterator.cpp" +#include "CompositionEvent.cpp" +#include "ContainerNode.cpp" +#include "ContainerNodeAlgorithms.cpp" +#include "ContextDestructionObserver.cpp" +#include "CustomEvent.cpp" +#include "DOMCoreException.cpp" +#include "DOMError.cpp" +#include "DOMImplementation.cpp" +#include "DOMNamedFlowCollection.cpp" +#include "DOMStringList.cpp" +#include "DataTransfer.cpp" +#include "DataTransferItem.cpp" +#include "DatasetDOMStringMap.cpp" +#include "DecodedDataDocumentParser.cpp" +#include "DeviceMotionController.cpp" +#include "DeviceMotionData.cpp" +#include "DeviceMotionEvent.cpp" +#include "DeviceOrientationController.cpp" +#include "DeviceOrientationData.cpp" +#include "DeviceOrientationEvent.cpp" +#include "Document.cpp" +#include "DocumentEventQueue.cpp" +#include "DocumentFragment.cpp" +#include "DocumentMarkerController.cpp" +#include "DocumentOrderedMap.cpp" +#include "DocumentParser.cpp" +#include "DocumentSharedObjectPool.cpp" +#include "DocumentType.cpp" +#include "Element.cpp" +#include "ElementData.cpp" +#include "ElementRareData.cpp" +#include "ErrorEvent.cpp" +#include "Event.cpp" +#include "EventContext.cpp" +#include "EventDispatcher.cpp" +#include "EventListenerMap.cpp" +#include "EventNames.cpp" +#include "EventPath.cpp" +#include "EventTarget.cpp" +#include "ExceptionBase.cpp" +#include "ExtensionStyleSheets.cpp" +#include "FocusEvent.cpp" +#include "GenericEventQueue.cpp" +#include "IdTargetObserver.cpp" +#include "IdTargetObserverRegistry.cpp" +#include "InlineStyleSheetOwner.cpp" +#include "InputEvent.cpp" +#include "KeyboardEvent.cpp" +#include "CustomElementReactionQueue.cpp" +#include "LiveNodeList.cpp" +#include "MessageChannel.cpp" +#include "MessageEvent.cpp" +#include "MessagePort.cpp" +#include "Microtasks.cpp" +#include "MouseEvent.cpp" +#include "MouseRelatedEvent.cpp" +#include "MutationEvent.cpp" +#include "MutationObserver.cpp" +#include "MutationObserverInterestGroup.cpp" +#include "MutationObserverRegistration.cpp" +#include "MutationRecord.cpp" +#include "NameNodeList.cpp" +#include "NamedFlowCollection.cpp" +#include "NamedNodeMap.cpp" +#include "Node.cpp" +#include "NodeFilterCondition.cpp" +#include "NodeIterator.cpp" +#include "NodeRareData.cpp" +#include "NodeTraversal.cpp" +#include "OverflowEvent.cpp" +#include "PageTransitionEvent.cpp" +#include "PendingScript.cpp" +#include "PopStateEvent.cpp" +#include "Position.cpp" +#include "PositionIterator.cpp" +#include "ProcessingInstruction.cpp" +#include "ProgressEvent.cpp" +#include "PseudoElement.cpp" +// Build error if adding QualifiedName.cpp to DOMAllInOne.cpp +// https://bugs.webkit.org/show_bug.cgi?id=146586 +// #include "QualifiedName.cpp" +#include "RadioButtonGroups.cpp" +#include "Range.cpp" +#include "ScopedEventQueue.cpp" +#include "ScriptElement.cpp" +#include "ScriptExecutionContext.cpp" +#include "ScriptRunner.cpp" +#include "ScriptableDocumentParser.cpp" +#include "ScriptedAnimationController.cpp" +#include "SecurityContext.cpp" +#include "SecurityOriginPolicy.cpp" +#include "SelectorQuery.cpp" +#include "ShadowRoot.cpp" +#include "SlotAssignment.cpp" +#include "SpaceSplitString.cpp" +#include "StaticNodeList.cpp" +#include "StaticRange.cpp" +#include "StringCallback.cpp" +#include "StyledElement.cpp" +#include "TagCollection.cpp" +#include "Text.cpp" +#include "TextEvent.cpp" +#include "TextNodeTraversal.cpp" +#include "Touch.cpp" +#include "TouchEvent.cpp" +#include "TouchList.cpp" +#include "TransformSourceLibxslt.cpp" +#include "TransitionEvent.cpp" +#include "Traversal.cpp" +#include "TreeScope.cpp" +#include "TreeScopeAdopter.cpp" +#include "TreeWalker.cpp" +#include "UIEvent.cpp" +#include "UIEventWithKeyState.cpp" +#include "UserActionElementSet.cpp" +#include "UserGestureIndicator.cpp" +#include "UserTypingGestureIndicator.cpp" +#include "ViewportArguments.cpp" +#include "VisitedLinkState.cpp" +#include "WebKitAnimationEvent.cpp" +#include "WebKitNamedFlow.cpp" +#include "WebKitTransitionEvent.cpp" +#include "WheelEvent.cpp" +#include "XMLDocumentParser.cpp" +#include "XMLDocumentParserScope.cpp" + diff --git a/Source/WebCore/dom/DOMCoreException.cpp b/Source/WebCore/dom/DOMCoreException.cpp index 6b1f0c507..3756c1b78 100644 --- a/Source/WebCore/dom/DOMCoreException.cpp +++ b/Source/WebCore/dom/DOMCoreException.cpp @@ -10,7 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -29,40 +29,73 @@ #include "config.h" #include "DOMCoreException.h" +#include "ExceptionCode.h" +#include "ExceptionCodeDescription.h" + namespace WebCore { -static struct CoreException { +// http://heycam.github.io/webidl/#idl-DOMException-error-names +static const struct CoreException { const char* const name; const char* const description; + ExceptionCode code; } coreExceptions[] = { - { "IndexSizeError", "Index or size was negative, or greater than the allowed value." }, - { 0, 0 }, // DOMStringSizeError - { "HierarchyRequestError", "A Node was inserted somewhere it doesn't belong." }, - { "WrongDocumentError", "A Node was used in a different document than the one that created it (that doesn't support it)." }, - { "InvalidCharacterError", "An invalid or illegal character was specified, such as in an XML name." }, - { 0, 0 }, // NoDataAllowedError - { "NoModificationAllowedError", "An attempt was made to modify an object where modifications are not allowed." }, - { "NotFoundError", "An attempt was made to reference a Node in a context where it does not exist." }, - { "NotSupportedError", "The implementation did not support the requested type of object or operation." }, - { "InUseAttributeError", "An attempt was made to add an attribute that is already in use elsewhere." }, - { "InvalidStateError", "An attempt was made to use an object that is not, or is no longer, usable." }, - { "SyntaxError", "An invalid or illegal string was specified." }, - { "InvalidModificationError", "An attempt was made to modify the type of the underlying object." }, - { "NamespaceError", "An attempt was made to create or change an object in a way which is incorrect with regard to namespaces." }, - { "InvalidAccessError", "A parameter or an operation was not supported by the underlying object." }, - { 0, 0 }, // ValidationError - { "TypeMismatchError", "The type of an object was incompatible with the expected type of the parameter associated to the object." }, - { "SecurityError", "An attempt was made to break through the security policy of the user agent." }, - // FIXME: Couldn't find a description in the HTML/DOM specifications for NETWORK_ERR, ABORT_ERR, URL_MISMATCH_ERR, and QUOTA_EXCEEDED_ERR - { "NetworkError", "A network error occurred." }, - { "AbortError", "The user aborted a request." }, - { "URLMismatchError", "A worker global scope represented an absolute URL that is not equal to the resulting absolute URL." }, - { "QuotaExceededError", "An attempt was made to add something to storage that exceeded the quota." }, - { "TimeoutError", "A timeout occurred." }, - { "InvalidNodeTypeError", "The supplied node is invalid or has an invalid ancestor for this operation." }, - { "DataCloneError", "An object could not be cloned." } + { "IndexSizeError", "The index is not in the allowed range.", 1 }, + { nullptr, nullptr, 0 }, // DOMStringSizeError + { "HierarchyRequestError", "The operation would yield an incorrect node tree.", 3 }, + { "WrongDocumentError", "The object is in the wrong document.", 4 }, + { "InvalidCharacterError", "The string contains invalid characters.", 5 }, + { nullptr, nullptr, 0 }, // NoDataAllowedError + { "NoModificationAllowedError", "The object can not be modified.", 7 }, + { "NotFoundError", "The object can not be found here.", 8 }, + { "NotSupportedError", "The operation is not supported.", 9 }, + { "InUseAttributeError", "The attribute is in use.", 10 }, + { "InvalidStateError", "The object is in an invalid state.", 11 }, + { "SyntaxError", "The string did not match the expected pattern.", 12 }, + { "InvalidModificationError", " The object can not be modified in this way.", 13 }, + { "NamespaceError", "The operation is not allowed by Namespaces in XML.", 14 }, + { "InvalidAccessError", "The object does not support the operation or argument.", 15 }, + { nullptr, nullptr, 0 }, // ValidationError + { "TypeMismatchError", "The type of an object was incompatible with the expected type of the parameter associated to the object.", 17 }, + { "SecurityError", "The operation is insecure.", 18 }, + { "NetworkError", " A network error occurred.", 19 }, + { "AbortError", "The operation was aborted.", 20 }, + { "URLMismatchError", "The given URL does not match another URL.", 21 }, + { "QuotaExceededError", "The quota has been exceeded.", 22 }, + { "TimeoutError", "The operation timed out.", 23 }, + { "InvalidNodeTypeError", "The supplied node is incorrect or has an incorrect ancestor for this operation.", 24 }, + { "DataCloneError", "The object can not be cloned.", 25 }, + { "EncodingError", "The encoding operation (either encoded or decoding) failed.", 0 }, + { "NotReadableError", "The I/O read operation failed.", 0 }, + { "UnknownError", "The operation failed for an unknown transient reason (e.g. out of memory).", 0 }, + { "ConstraintError", "A mutation operation in a transaction failed because a constraint was not satisfied.", 0 }, + { "DataError", "Provided data is inadequate.", 0 }, + { "TransactionInactiveError", "A request was placed against a transaction which is currently not active, or which is finished.", 0 }, + { "ReadOnlyError", "The mutating operation was attempted in a \"readonly\" transaction.", 0 }, + { "VersionError", "An attempt was made to open a database using a lower version than the existing version.", 0 }, + { "OperationError", "The operation failed for an operation-specific reason.", 0 }, + { "NotAllowedError", "The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.", 0 } }; +static ExceptionCode errorCodeFromName(const String& name) +{ + for (auto& entry : coreExceptions) { + if (entry.name == name) + return entry.code; + } + return 0; +} + +Ref DOMCoreException::create(const String& message, const String& name) +{ + return adoptRef(*new DOMCoreException(errorCodeFromName(name), message, name)); +} + +DOMCoreException::DOMCoreException(ExceptionCode ec, const String& message, const String& name) + : ExceptionBase(ec, name, message, ASCIILiteral("DOM")) +{ +} + bool DOMCoreException::initializeDescription(ExceptionCode ec, ExceptionCodeDescription* description) { description->typeName = "DOM"; diff --git a/Source/WebCore/dom/DOMCoreException.h b/Source/WebCore/dom/DOMCoreException.h index cc21a7a14..87b421d6c 100644 --- a/Source/WebCore/dom/DOMCoreException.h +++ b/Source/WebCore/dom/DOMCoreException.h @@ -10,7 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -26,8 +26,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DOMCoreException_h -#define DOMCoreException_h +#pragma once #include "ExceptionBase.h" @@ -35,14 +34,16 @@ namespace WebCore { class DOMCoreException : public ExceptionBase { public: - static PassRefPtr create(const ExceptionCodeDescription& description) + static Ref create(const ExceptionCodeDescription& description) { - return adoptRef(new DOMCoreException(description)); + return adoptRef(*new DOMCoreException(description)); } + static Ref create(const String& message, const String& name); static bool initializeDescription(ExceptionCode, ExceptionCodeDescription*); -private: +protected: + DOMCoreException(ExceptionCode, const String& message, const String& name); explicit DOMCoreException(const ExceptionCodeDescription& description) : ExceptionBase(description) { @@ -50,5 +51,3 @@ private: }; } // namespace WebCore - -#endif // DOMCoreException_h diff --git a/Source/WebCore/dom/DOMCoreException.idl b/Source/WebCore/dom/DOMCoreException.idl index 5215ed913..34d150f51 100644 --- a/Source/WebCore/dom/DOMCoreException.idl +++ b/Source/WebCore/dom/DOMCoreException.idl @@ -10,7 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -27,8 +27,9 @@ */ [ - JSNoStaticTables, + Constructor(optional DOMString message = "", optional DOMString name = "Error"), DoNotCheckConstants, + Exposed=(Window,Worker), InterfaceName=DOMException, ImplementationLacksVTable, ] exception DOMCoreException { @@ -37,47 +38,32 @@ readonly attribute DOMString name; readonly attribute DOMString message; -#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT - // Override in a Mozilla compatible format [NotEnumerable] DOMString toString(); -#endif // ExceptionCode - const unsigned short INDEX_SIZE_ERR = 1; - const unsigned short DOMSTRING_SIZE_ERR = 2; - const unsigned short HIERARCHY_REQUEST_ERR = 3; - const unsigned short WRONG_DOCUMENT_ERR = 4; - const unsigned short INVALID_CHARACTER_ERR = 5; - const unsigned short NO_DATA_ALLOWED_ERR = 6; - const unsigned short NO_MODIFICATION_ALLOWED_ERR = 7; - const unsigned short NOT_FOUND_ERR = 8; - const unsigned short NOT_SUPPORTED_ERR = 9; - const unsigned short INUSE_ATTRIBUTE_ERR = 10; - // Introduced in DOM Level 2: - const unsigned short INVALID_STATE_ERR = 11; - // Introduced in DOM Level 2: - const unsigned short SYNTAX_ERR = 12; - // Introduced in DOM Level 2: - const unsigned short INVALID_MODIFICATION_ERR = 13; - // Introduced in DOM Level 2: - const unsigned short NAMESPACE_ERR = 14; - // Introduced in DOM Level 2: - const unsigned short INVALID_ACCESS_ERR = 15; - // Introduced in DOM Level 3: - const unsigned short VALIDATION_ERR = 16; - // Introduced in DOM Level 3: - const unsigned short TYPE_MISMATCH_ERR = 17; - // Introduced as an XHR extension: - const unsigned short SECURITY_ERR = 18; - // Introduced in HTML5: - const unsigned short NETWORK_ERR = 19; - const unsigned short ABORT_ERR = 20; - const unsigned short URL_MISMATCH_ERR = 21; - const unsigned short QUOTA_EXCEEDED_ERR = 22; - // TIMEOUT_ERR is currently unused but was added for completeness. - const unsigned short TIMEOUT_ERR = 23; - // INVALID_NODE_TYPE_ERR is currently unused but was added for completeness. - const unsigned short INVALID_NODE_TYPE_ERR = 24; - const unsigned short DATA_CLONE_ERR = 25; + const unsigned short INDEX_SIZE_ERR = 1; + const unsigned short DOMSTRING_SIZE_ERR = 2; + const unsigned short HIERARCHY_REQUEST_ERR = 3; + const unsigned short WRONG_DOCUMENT_ERR = 4; + const unsigned short INVALID_CHARACTER_ERR = 5; + const unsigned short NO_DATA_ALLOWED_ERR = 6; + const unsigned short NO_MODIFICATION_ALLOWED_ERR = 7; + const unsigned short NOT_FOUND_ERR = 8; + const unsigned short NOT_SUPPORTED_ERR = 9; + const unsigned short INUSE_ATTRIBUTE_ERR = 10; + const unsigned short INVALID_STATE_ERR = 11; + const unsigned short SYNTAX_ERR = 12; + const unsigned short INVALID_MODIFICATION_ERR = 13; + const unsigned short NAMESPACE_ERR = 14; + const unsigned short INVALID_ACCESS_ERR = 15; + const unsigned short VALIDATION_ERR = 16; + const unsigned short TYPE_MISMATCH_ERR = 17; + const unsigned short SECURITY_ERR = 18; + const unsigned short NETWORK_ERR = 19; + const unsigned short ABORT_ERR = 20; + const unsigned short URL_MISMATCH_ERR = 21; + const unsigned short QUOTA_EXCEEDED_ERR = 22; + const unsigned short TIMEOUT_ERR = 23; + const unsigned short INVALID_NODE_TYPE_ERR = 24; + const unsigned short DATA_CLONE_ERR = 25; }; - diff --git a/Source/WebCore/dom/DOMError.cpp b/Source/WebCore/dom/DOMError.cpp index 58f8afab6..bb146c16e 100644 --- a/Source/WebCore/dom/DOMError.cpp +++ b/Source/WebCore/dom/DOMError.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2012 Google Inc. All Rights Reserved. + * Copyright (C) 2016 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,11 +27,11 @@ #include "config.h" #include "DOMError.h" - namespace WebCore { -DOMError::DOMError(const String& name) +DOMError::DOMError(const String& name, const String& message) : m_name(name) + , m_message(message) { } diff --git a/Source/WebCore/dom/DOMError.h b/Source/WebCore/dom/DOMError.h index e9f3d0b4a..d2495177c 100644 --- a/Source/WebCore/dom/DOMError.h +++ b/Source/WebCore/dom/DOMError.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2012 Google Inc. All Rights Reserved. + * Copyright (C) 2016 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,10 +24,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DOMError_h -#define DOMError_h +#pragma once -#include #include #include @@ -34,21 +33,21 @@ namespace WebCore { class DOMError : public RefCounted { public: - static PassRefPtr create(const String& name) + static Ref create(const String& name, const String& message = { }) { - return adoptRef(new DOMError(name)); + return adoptRef(*new DOMError(name, message)); } virtual ~DOMError() { } const String& name() const { return m_name; } + const String& message() const { return m_message; } protected: - explicit DOMError(const String& name); + explicit DOMError(const String& name, const String& message); private: - const String m_name; + String m_name; + String m_message; }; } // namespace WebCore - -#endif // DOMError_h diff --git a/Source/WebCore/dom/DOMError.idl b/Source/WebCore/dom/DOMError.idl index 539dc7e6b..0d38a72af 100644 --- a/Source/WebCore/dom/DOMError.idl +++ b/Source/WebCore/dom/DOMError.idl @@ -10,7 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -30,5 +30,6 @@ SkipVTableValidation ] interface DOMError { readonly attribute DOMString name; + readonly attribute DOMString message; }; diff --git a/Source/WebCore/dom/DOMExceptions.in b/Source/WebCore/dom/DOMExceptions.in index 6e824ff54..6148e8603 100644 --- a/Source/WebCore/dom/DOMExceptions.in +++ b/Source/WebCore/dom/DOMExceptions.in @@ -1,11 +1,8 @@ namespace=Exception DOMCoreException -EventException -FileException conditional=BLOB -RangeException -SQLException conditional=SQL_DATABASE -SVGException conditional=SVG -XMLHttpRequestException +FileException +SQLException +SVGException XPathException diff --git a/Source/WebCore/dom/DOMImplementation.cpp b/Source/WebCore/dom/DOMImplementation.cpp index 081c8560a..586fa1ccb 100644 --- a/Source/WebCore/dom/DOMImplementation.cpp +++ b/Source/WebCore/dom/DOMImplementation.cpp @@ -25,50 +25,46 @@ #include "config.h" #include "DOMImplementation.h" -#include "ContentType.h" #include "CSSStyleSheet.h" +#include "ContentType.h" #include "DocumentType.h" #include "Element.h" -#include "ExceptionCode.h" +#include "FTPDirectoryDocument.h" #include "Frame.h" #include "FrameLoader.h" #include "FrameLoaderClient.h" -#include "FTPDirectoryDocument.h" #include "HTMLDocument.h" -#include "HTMLViewSourceDocument.h" +#include "HTMLHeadElement.h" +#include "HTMLTitleElement.h" #include "Image.h" #include "ImageDocument.h" +#include "MIMETypeRegistry.h" +#include "MainFrame.h" #include "MediaDocument.h" #include "MediaList.h" -#include "MIMETypeRegistry.h" +#include "MediaPlayer.h" #include "Page.h" #include "PluginData.h" #include "PluginDocument.h" +#include "SVGDocument.h" +#include "SVGNames.h" #include "SecurityOrigin.h" +#include "SecurityOriginPolicy.h" #include "Settings.h" #include "StyleSheetContents.h" #include "SubframeLoader.h" +#include "Text.h" #include "TextDocument.h" -#include "XMLNames.h" +#include "XMLDocument.h" +#include #include -#if ENABLE(SVG) -#include "SVGNames.h" -#include "SVGDocument.h" -#endif - namespace WebCore { -typedef HashSet FeatureSet; - -#if ENABLE(SVG) -static void addString(FeatureSet& set, const char* string) -{ - set.add(string); -} -#endif +using namespace HTMLNames; #if ENABLE(VIDEO) + class DOMImplementationSupportsTypeClient : public MediaPlayerSupportsTypeClient { public: DOMImplementationSupportsTypeClient(bool needsHacks, const String& host) @@ -78,113 +74,13 @@ public: } private: - virtual bool mediaPlayerNeedsSiteSpecificHacks() const override { return m_needsHacks; } - virtual String mediaPlayerDocumentHost() const override { return m_host; } + bool mediaPlayerNeedsSiteSpecificHacks() const override { return m_needsHacks; } + String mediaPlayerDocumentHost() const override { return m_host; } bool m_needsHacks; String m_host; }; -#endif - -#if ENABLE(SVG) - -static bool isSupportedSVG10Feature(const String& feature, const String& version) -{ - if (!version.isEmpty() && version != "1.0") - return false; - - static bool initialized = false; - DEFINE_STATIC_LOCAL(FeatureSet, svgFeatures, ()); - if (!initialized) { -#if ENABLE(FILTERS) && ENABLE(SVG_FONTS) - addString(svgFeatures, "svg"); - addString(svgFeatures, "svg.static"); -#endif -// addString(svgFeatures, "svg.animation"); -// addString(svgFeatures, "svg.dynamic"); -// addString(svgFeatures, "svg.dom.animation"); -// addString(svgFeatures, "svg.dom.dynamic"); -#if ENABLE(FILTERS) && ENABLE(SVG_FONTS) - addString(svgFeatures, "dom"); - addString(svgFeatures, "dom.svg"); - addString(svgFeatures, "dom.svg.static"); -#endif -// addString(svgFeatures, "svg.all"); -// addString(svgFeatures, "dom.svg.all"); - initialized = true; - } - return feature.startsWith("org.w3c.", false) - && svgFeatures.contains(feature.right(feature.length() - 8)); -} - -static bool isSupportedSVG11Feature(const String& feature, const String& version) -{ - if (!version.isEmpty() && version != "1.1") - return false; - static bool initialized = false; - DEFINE_STATIC_LOCAL(FeatureSet, svgFeatures, ()); - if (!initialized) { - // Sadly, we cannot claim to implement any of the SVG 1.1 generic feature sets - // lack of Font and Filter support. - // http://bugs.webkit.org/show_bug.cgi?id=15480 -#if ENABLE(FILTERS) && ENABLE(SVG_FONTS) - addString(svgFeatures, "SVG"); - addString(svgFeatures, "SVGDOM"); - addString(svgFeatures, "SVG-static"); - addString(svgFeatures, "SVGDOM-static"); -#endif - addString(svgFeatures, "SVG-animation"); - addString(svgFeatures, "SVGDOM-animation"); -// addString(svgFeatures, "SVG-dynamic); -// addString(svgFeatures, "SVGDOM-dynamic); - addString(svgFeatures, "CoreAttribute"); - addString(svgFeatures, "Structure"); - addString(svgFeatures, "BasicStructure"); - addString(svgFeatures, "ContainerAttribute"); - addString(svgFeatures, "ConditionalProcessing"); - addString(svgFeatures, "Image"); - addString(svgFeatures, "Style"); - addString(svgFeatures, "ViewportAttribute"); - addString(svgFeatures, "Shape"); - addString(svgFeatures, "Text"); - addString(svgFeatures, "BasicText"); - addString(svgFeatures, "PaintAttribute"); - addString(svgFeatures, "BasicPaintAttribute"); - addString(svgFeatures, "OpacityAttribute"); - addString(svgFeatures, "GraphicsAttribute"); - addString(svgFeatures, "BaseGraphicsAttribute"); - addString(svgFeatures, "Marker"); -// addString(svgFeatures, "ColorProfile"); // requires color-profile, bug 6037 - addString(svgFeatures, "Gradient"); - addString(svgFeatures, "Pattern"); - addString(svgFeatures, "Clip"); - addString(svgFeatures, "BasicClip"); - addString(svgFeatures, "Mask"); -#if ENABLE(FILTERS) - addString(svgFeatures, "Filter"); - addString(svgFeatures, "BasicFilter"); -#endif - addString(svgFeatures, "DocumentEventsAttribute"); - addString(svgFeatures, "GraphicalEventsAttribute"); -// addString(svgFeatures, "AnimationEventsAttribute"); - addString(svgFeatures, "Cursor"); - addString(svgFeatures, "Hyperlinking"); - addString(svgFeatures, "XlinkAttribute"); - addString(svgFeatures, "ExternalResourcesRequired"); - addString(svgFeatures, "View"); - addString(svgFeatures, "Script"); - addString(svgFeatures, "Animation"); -#if ENABLE(SVG_FONTS) - addString(svgFeatures, "Font"); - addString(svgFeatures, "BasicFont"); -#endif - addString(svgFeatures, "Extensibility"); - initialized = true; - } - return feature.startsWith("http://www.w3.org/tr/svg11/feature#", false) - && svgFeatures.contains(feature.right(feature.length() - 35)); -} #endif DOMImplementation::DOMImplementation(Document& document) @@ -192,140 +88,81 @@ DOMImplementation::DOMImplementation(Document& document) { } -bool DOMImplementation::hasFeature(const String& feature, const String& version) -{ - if (feature.startsWith("http://www.w3.org/TR/SVG", false) - || feature.startsWith("org.w3c.dom.svg", false) - || feature.startsWith("org.w3c.svg", false)) { -#if ENABLE(SVG) - // FIXME: SVG 2.0 support? - return isSupportedSVG10Feature(feature, version) || isSupportedSVG11Feature(feature, version); -#else - UNUSED_PARAM(version); - return false; -#endif - } - - return true; -} - -PassRefPtr DOMImplementation::createDocumentType(const String& qualifiedName, - const String& publicId, const String& systemId, ExceptionCode& ec) +ExceptionOr> DOMImplementation::createDocumentType(const String& qualifiedName, const String& publicId, const String& systemId) { - String prefix, localName; - if (!Document::parseQualifiedName(qualifiedName, prefix, localName, ec)) - return 0; - + auto parseResult = Document::parseQualifiedName(qualifiedName); + if (parseResult.hasException()) + return parseResult.releaseException(); return DocumentType::create(m_document, qualifiedName, publicId, systemId); } -DOMImplementation* DOMImplementation::getInterface(const String& /*feature*/) +static inline Ref createXMLDocument(const String& namespaceURI) { - return 0; -} - -PassRefPtr DOMImplementation::createDocument(const String& namespaceURI, - const String& qualifiedName, DocumentType* doctype, ExceptionCode& ec) -{ - RefPtr doc; -#if ENABLE(SVG) if (namespaceURI == SVGNames::svgNamespaceURI) - doc = SVGDocument::create(0, URL()); - else -#endif + return SVGDocument::create(nullptr, URL()); if (namespaceURI == HTMLNames::xhtmlNamespaceURI) - doc = Document::createXHTML(0, URL()); - else - doc = Document::create(0, URL()); + return XMLDocument::createXHTML(nullptr, URL()); + return XMLDocument::create(nullptr, URL()); +} - doc->setSecurityOrigin(m_document.securityOrigin()); +ExceptionOr> DOMImplementation::createDocument(const String& namespaceURI, const String& qualifiedName, DocumentType* documentType) +{ + auto document = createXMLDocument(namespaceURI); + document->setContextDocument(m_document.contextDocument()); + document->setSecurityOriginPolicy(m_document.securityOriginPolicy()); - RefPtr documentElement; + RefPtr documentElement; if (!qualifiedName.isEmpty()) { - documentElement = doc->createElementNS(namespaceURI, qualifiedName, ec); - if (ec) - return 0; + ASSERT(!document->domWindow()); // If domWindow is not null, createElementNS could find CustomElementRegistry and arbitrary scripts. + auto result = document->createElementNS(namespaceURI, qualifiedName); + if (result.hasException()) + return result.releaseException(); + documentElement = result.releaseReturnValue(); } - if (doctype) - doc->appendChild(doctype); + if (documentType) + document->appendChild(*documentType); if (documentElement) - doc->appendChild(documentElement.release()); + document->appendChild(*documentElement); - return doc.release(); + return WTFMove(document); } -PassRefPtr DOMImplementation::createCSSStyleSheet(const String&, const String& media, ExceptionCode&) +Ref DOMImplementation::createCSSStyleSheet(const String&, const String& media) { // FIXME: Title should be set. // FIXME: Media could have wrong syntax, in which case we should generate an exception. auto sheet = CSSStyleSheet::create(StyleSheetContents::create()); - sheet.get().setMediaQueries(MediaQuerySet::createAllowingDescriptionSyntax(media)); - return std::move(sheet); -} - -static inline bool isValidXMLMIMETypeChar(UChar c) -{ - // Valid characters per RFCs 3023 and 2045: - // 0-9a-zA-Z_-+~!$^{}|.%'`#&* - return isASCIIAlphanumeric(c) || c == '!' || c == '#' || c == '$' || c == '%' || c == '&' || c == '\'' || c == '*' || c == '+' - || c == '-' || c == '.' || c == '^' || c == '_' || c == '`' || c == '{' || c == '|' || c == '}' || c == '~'; + sheet->setMediaQueries(MediaQuerySet::create(media)); + return sheet; } -bool DOMImplementation::isXMLMIMEType(const String& mimeType) +Ref DOMImplementation::createHTMLDocument(const String& title) { - if (mimeType == "text/xml" || mimeType == "application/xml" || mimeType == "text/xsl") - return true; - - if (!mimeType.endsWith("+xml")) - return false; - - size_t slashPosition = mimeType.find('/'); - // Take into account the '+xml' ending of mimeType. - if (slashPosition == notFound || !slashPosition || slashPosition == mimeType.length() - 5) - return false; - - // Again, mimeType ends with '+xml', no need to check the validity of that substring. - for (size_t i = 0; i < mimeType.length() - 4; ++i) { - if (!isValidXMLMIMETypeChar(mimeType[i]) && i != slashPosition) - return false; + auto document = HTMLDocument::create(nullptr, URL()); + document->open(); + document->write(""); + if (!title.isNull()) { + auto titleElement = HTMLTitleElement::create(titleTag, document); + titleElement->appendChild(document->createTextNode(title)); + ASSERT(document->head()); + document->head()->appendChild(titleElement); } - - return true; -} - -bool DOMImplementation::isTextMIMEType(const String& mimeType) -{ - if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType) - || mimeType == "application/json" // Render JSON as text/plain. - || (mimeType.startsWith("text/") && mimeType != "text/html" - && mimeType != "text/xml" && mimeType != "text/xsl")) - return true; - - return false; -} - -PassRefPtr DOMImplementation::createHTMLDocument(const String& title) -{ - RefPtr d = HTMLDocument::create(0, URL()); - d->open(); - d->write(""); - if (!title.isNull()) - d->setTitle(title); - d->setSecurityOrigin(m_document.securityOrigin()); - return d.release(); + document->setContextDocument(m_document.contextDocument()); + document->setSecurityOriginPolicy(m_document.securityOriginPolicy()); + return document; } -PassRefPtr DOMImplementation::createDocument(const String& type, Frame* frame, const URL& url, bool inViewSourceMode) +Ref DOMImplementation::createDocument(const String& type, Frame* frame, const URL& url) { - if (inViewSourceMode) - return HTMLViewSourceDocument::create(frame, url, type); + // FIXME: Confusing to have this here with public DOM APIs for creating documents. This is different enough that it should perhaps be moved. + // FIXME: This function is doing case insensitive comparisons on MIME types. Should do equalLettersIgnoringASCIICase instead. // Plugins cannot take HTML and XHTML from us, and we don't even need to initialize the plugin database for those. if (type == "text/html") return HTMLDocument::create(frame, url); if (type == "application/xhtml+xml") - return Document::createXHTML(frame, url); + return XMLDocument::createXHTML(frame, url); #if ENABLE(FTPDIR) // Plugins cannot take FTP from us either @@ -333,10 +170,14 @@ PassRefPtr DOMImplementation::createDocument(const String& type, Frame return FTPDirectoryDocument::create(frame, url); #endif - PluginData* pluginData = 0; - PluginData::AllowedPluginTypes allowedPluginTypes = PluginData::OnlyApplicationPlugins; + // If we want to useImageDocumentForSubframePDF, we'll let that override plugin support. + if (frame && !frame->isMainFrame() && MIMETypeRegistry::isPDFMIMEType(type) && frame->settings().useImageDocumentForSubframePDF()) + return ImageDocument::create(*frame, url); + + PluginData* pluginData = nullptr; + auto allowedPluginTypes = PluginData::OnlyApplicationPlugins; if (frame && frame->page()) { - if (frame->loader().subframeLoader().allowPlugins(NotAboutToInstantiatePlugin)) + if (frame->loader().subframeLoader().allowPlugins()) allowedPluginTypes = PluginData::AllPlugins; pluginData = &frame->page()->pluginData(); @@ -344,36 +185,35 @@ PassRefPtr DOMImplementation::createDocument(const String& type, Frame // PDF is one image type for which a plugin can override built-in support. // We do not want QuickTime to take over all image types, obviously. - if ((MIMETypeRegistry::isPDFOrPostScriptMIMEType(type)) && pluginData && pluginData->supportsMimeType(type, allowedPluginTypes)) + if (MIMETypeRegistry::isPDFOrPostScriptMIMEType(type) && pluginData && pluginData->supportsWebVisibleMimeType(type, allowedPluginTypes)) return PluginDocument::create(frame, url); if (Image::supportsType(type)) - return ImageDocument::create(frame, url); + return ImageDocument::create(*frame, url); -#if ENABLE(VIDEO) && !ENABLE(PLUGIN_PROXY_FOR_VIDEO) - // Check to see if the type can be played by our MediaPlayer, if so create a MediaDocument +#if ENABLE(VIDEO) + // Check to see if the type can be played by our MediaPlayer, if so create a MediaDocument // Key system is not applicable here. DOMImplementationSupportsTypeClient client(frame && frame->settings().needsSiteSpecificQuirks(), url.host()); MediaEngineSupportParameters parameters; parameters.type = type; parameters.url = url; if (MediaPlayer::supportsType(parameters, &client)) - return MediaDocument::create(frame, url); + return MediaDocument::create(frame, url); #endif // Everything else except text/plain can be overridden by plugins. In particular, Adobe SVG Viewer should be used for SVG, if installed. // Disallowing plug-ins to use text/plain prevents plug-ins from hijacking a fundamental type that the browser is expected to handle, // and also serves as an optimization to prevent loading the plug-in database in the common case. - if (type != "text/plain" && ((pluginData && pluginData->supportsMimeType(type, allowedPluginTypes)) || (frame && frame->loader().client().shouldAlwaysUsePluginDocument(type)))) + if (type != "text/plain" && ((pluginData && pluginData->supportsWebVisibleMimeType(type, allowedPluginTypes)) || (frame && frame->loader().client().shouldAlwaysUsePluginDocument(type)))) return PluginDocument::create(frame, url); - if (isTextMIMEType(type)) + if (MIMETypeRegistry::isTextMIMEType(type)) return TextDocument::create(frame, url); -#if ENABLE(SVG) if (type == "image/svg+xml") return SVGDocument::create(frame, url); -#endif - if (isXMLMIMEType(type)) - return Document::create(frame, url); + + if (MIMETypeRegistry::isXMLMIMEType(type)) + return XMLDocument::create(frame, url); return HTMLDocument::create(frame, url); } diff --git a/Source/WebCore/dom/DOMImplementation.h b/Source/WebCore/dom/DOMImplementation.h index 748057aa6..a40a2f691 100644 --- a/Source/WebCore/dom/DOMImplementation.h +++ b/Source/WebCore/dom/DOMImplementation.h @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2008, 2016 Apple 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 @@ -21,60 +21,32 @@ * */ -#ifndef DOMImplementation_h -#define DOMImplementation_h +#pragma once -#include "Document.h" -#include "MediaPlayer.h" -#include -#include -#include +#include "ExceptionOr.h" +#include "XMLDocument.h" namespace WebCore { -class CSSStyleSheet; -class Document; -class DocumentType; -class Frame; -class HTMLDocument; -class URL; - -typedef int ExceptionCode; - class DOMImplementation : public ScriptWrappable { WTF_MAKE_FAST_ALLOCATED; public: - static PassOwnPtr create(Document& document) { return adoptPtr(new DOMImplementation(document)); } - + explicit DOMImplementation(Document&); + void ref() { m_document.ref(); } void deref() { m_document.deref(); } - Document* document() { return &m_document; } - - // DOM methods & attributes for DOMImplementation - static bool hasFeature(const String& feature, const String& version); - PassRefPtr createDocumentType(const String& qualifiedName, const String& publicId, const String& systemId, ExceptionCode&); - PassRefPtr createDocument(const String& namespaceURI, const String& qualifiedName, DocumentType*, ExceptionCode&); - - DOMImplementation* getInterface(const String& feature); + Document& document() { return m_document; } - // From the DOMImplementationCSS interface - static PassRefPtr createCSSStyleSheet(const String& title, const String& media, ExceptionCode&); + WEBCORE_EXPORT ExceptionOr> createDocumentType(const String& qualifiedName, const String& publicId, const String& systemId); + WEBCORE_EXPORT ExceptionOr> createDocument(const String& namespaceURI, const String& qualifiedName, DocumentType*); + WEBCORE_EXPORT Ref createHTMLDocument(const String& title); + static bool hasFeature() { return true; } + WEBCORE_EXPORT static Ref createCSSStyleSheet(const String& title, const String& media); - // From the HTMLDOMImplementation interface - PassRefPtr createHTMLDocument(const String& title); - - // Other methods (not part of DOM) - static PassRefPtr createDocument(const String& MIMEType, Frame*, const URL&, bool inViewSourceMode); - - static bool isXMLMIMEType(const String& MIMEType); - static bool isTextMIMEType(const String& MIMEType); + static Ref createDocument(const String& MIMEType, Frame*, const URL&); private: - explicit DOMImplementation(Document&); - Document& m_document; }; } // namespace WebCore - -#endif diff --git a/Source/WebCore/dom/DOMImplementation.idl b/Source/WebCore/dom/DOMImplementation.idl index 3d0a33d39..f5b40e917 100644 --- a/Source/WebCore/dom/DOMImplementation.idl +++ b/Source/WebCore/dom/DOMImplementation.idl @@ -19,31 +19,16 @@ */ [ + ExportToWrappedFunction, GenerateIsReachable=ImplDocument, ImplementationLacksVTable, ] interface DOMImplementation { + [NewObject, MayThrowException] DocumentType createDocumentType(DOMString qualifiedName, DOMString publicId, DOMString systemId); + [NewObject, MayThrowException] XMLDocument createDocument(DOMString? namespaceURI, [TreatNullAs=EmptyString] DOMString qualifiedName, optional DocumentType? doctype = null); + [NewObject] HTMLDocument createHTMLDocument(optional DOMString title); - // DOM Level 1 + boolean hasFeature(); - [ObjCLegacyUnnamedParameters] boolean hasFeature([Default=Undefined] optional DOMString feature, - [TreatNullAs=NullString, Default=Undefined] optional DOMString version); - - // DOM Level 2 - - [ObjCLegacyUnnamedParameters, RaisesException] DocumentType createDocumentType([TreatNullAs=NullString, TreatUndefinedAs=NullString, Default=Undefined] optional DOMString qualifiedName, - [TreatNullAs=NullString, TreatUndefinedAs=NullString, Default=Undefined] optional DOMString publicId, - [TreatNullAs=NullString, TreatUndefinedAs=NullString, Default=Undefined] optional DOMString systemId); - [ObjCLegacyUnnamedParameters, RaisesException] Document createDocument([TreatNullAs=NullString, Default=Undefined] optional DOMString namespaceURI, - [TreatNullAs=NullString, Default=Undefined] optional DOMString qualifiedName, - [TreatNullAs=NullString, Default=Undefined] optional DocumentType doctype); - - // DOMImplementationCSS interface from DOM Level 2 CSS - - [ObjCLegacyUnnamedParameters, RaisesException] CSSStyleSheet createCSSStyleSheet([Default=Undefined] optional DOMString title, - [Default=Undefined] optional DOMString media); - - // HTMLDOMImplementation interface from DOM Level 2 HTML - - HTMLDocument createHTMLDocument([Default=NullString] optional DOMString title); + // FIXME: Using "undefined" as default parameter value is wrong. + CSSStyleSheet createCSSStyleSheet(optional DOMString title = "undefined", optional DOMString media = "undefined"); }; - diff --git a/Source/WebCore/dom/DOMNamedFlowCollection.cpp b/Source/WebCore/dom/DOMNamedFlowCollection.cpp index 39b3784bf..cdc1f73fb 100644 --- a/Source/WebCore/dom/DOMNamedFlowCollection.cpp +++ b/Source/WebCore/dom/DOMNamedFlowCollection.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. + * Copyright (C) 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,60 +27,67 @@ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ + #include "config.h" #include "DOMNamedFlowCollection.h" +#include "WebKitNamedFlow.h" +#include namespace WebCore { -DOMNamedFlowCollection::DOMNamedFlowCollection(const Vector& namedFlows) +inline DOMNamedFlowCollection::DOMNamedFlowCollection(Vector>&& flows) + : m_flows(WTFMove(flows)) { - for (Vector::const_iterator it = namedFlows.begin(); it != namedFlows.end(); ++it) - m_namedFlows.add(*it); } -unsigned long DOMNamedFlowCollection::length() const +Ref DOMNamedFlowCollection::create(Vector>&& flows) { - return m_namedFlows.size(); + return adoptRef(*new DOMNamedFlowCollection(WTFMove(flows))); } -PassRefPtr DOMNamedFlowCollection::item(unsigned long index) const +DOMNamedFlowCollection::~DOMNamedFlowCollection() { - if (index >= static_cast(m_namedFlows.size())) - return 0; - DOMNamedFlowSet::const_iterator it = m_namedFlows.begin(); - for (unsigned long i = 0; i < index; ++i) - ++it; - return *it; } -PassRefPtr DOMNamedFlowCollection::namedItem(const AtomicString& name) const +WebKitNamedFlow* DOMNamedFlowCollection::item(unsigned index) const { - DOMNamedFlowSet::const_iterator it = m_namedFlows.find(name); - if (it != m_namedFlows.end()) - return *it; - return 0; + if (index >= m_flows.size()) + return nullptr; + return const_cast(m_flows[index].ptr()); } -bool DOMNamedFlowCollection::hasNamedItem(const AtomicString& name) const -{ - return namedItem(name); -} +struct DOMNamedFlowCollection::HashFunctions { + static unsigned hash(const WebKitNamedFlow* key) { return AtomicStringHash::hash(key->name()); } + static bool equal(const WebKitNamedFlow* a, const WebKitNamedFlow* b) { return a->name() == b->name(); } + static const bool safeToCompareToEmptyOrDeleted = false; -// The HashFunctions object used by the HashSet to compare between RefPtr. -// It is safe to set safeToCompareToEmptyOrDeleted because the HashSet will never contain null pointers or deleted values. -struct DOMNamedFlowCollection::DOMNamedFlowHashFunctions { - static unsigned hash(PassRefPtr key) { return DefaultHash::Hash::hash(key->name()); } - static bool equal(PassRefPtr a, PassRefPtr b) { return a->name() == b->name(); } - static const bool safeToCompareToEmptyOrDeleted = true; + static unsigned hash(const AtomicString& key) { return AtomicStringHash::hash(key); } + static bool equal(const WebKitNamedFlow* a, const AtomicString& b) { return a->name() == b; } }; -// The HashTranslator is used to lookup a RefPtr in the set using a name. -struct DOMNamedFlowCollection::DOMNamedFlowHashTranslator { - static unsigned hash(const String& key) { return DefaultHash::Hash::hash(key); } - static bool equal(PassRefPtr a, const String& b) { return a->name() == b; } -}; -} // namespace WebCore - +WebKitNamedFlow* DOMNamedFlowCollection::namedItem(const AtomicString& name) const +{ + if (m_flowsByName.isEmpty()) { + // No need to optimize the case where m_flows is empty; will do nothing very quickly. + for (auto& flow : m_flows) + m_flowsByName.add(const_cast(flow.ptr())); + } + auto it = m_flowsByName.find(name); + if (it == m_flowsByName.end()) + return nullptr; + return *it; +} +const Vector& DOMNamedFlowCollection::supportedPropertyNames() +{ + if (m_flowNames.isEmpty()) { + // No need to optimize the case where m_flows is empty; will do nothing relatively quickly. + m_flowNames.reserveInitialCapacity(m_flows.size()); + for (auto& flow : m_flows) + m_flowNames.uncheckedAppend(flow->name()); + } + return m_flowNames; +} +} // namespace WebCore diff --git a/Source/WebCore/dom/DOMNamedFlowCollection.h b/Source/WebCore/dom/DOMNamedFlowCollection.h index 62c8ca022..bbd74a099 100644 --- a/Source/WebCore/dom/DOMNamedFlowCollection.h +++ b/Source/WebCore/dom/DOMNamedFlowCollection.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. + * Copyright (C) 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,42 +27,41 @@ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -#ifndef DOMNamedFlowCollection_h -#define DOMNamedFlowCollection_h -#include "NamedFlowCollection.h" -#include -#include +#pragma once + +#include +#include #include #include namespace WebCore { -class Document; class WebKitNamedFlow; class DOMNamedFlowCollection : public RefCounted { public: - static PassRefPtr create(const Vector& namedFlows) - { - return adoptRef(new DOMNamedFlowCollection(namedFlows)); - } - - unsigned long length() const; - PassRefPtr item(unsigned long index) const; - PassRefPtr namedItem(const AtomicString& name) const; + static Ref create(Vector>&&); + ~DOMNamedFlowCollection(); - bool hasNamedItem(const AtomicString& name) const; + unsigned length() const; + WebKitNamedFlow* item(unsigned index) const; + WebKitNamedFlow* namedItem(const AtomicString& name) const; + const Vector& supportedPropertyNames(); private: - struct DOMNamedFlowHashFunctions; - struct DOMNamedFlowHashTranslator; + struct HashFunctions; + + explicit DOMNamedFlowCollection(Vector>&&); - typedef ListHashSet, 1, DOMNamedFlowHashFunctions> DOMNamedFlowSet; - explicit DOMNamedFlowCollection(const Vector&); - DOMNamedFlowSet m_namedFlows; + const Vector> m_flows; + mutable HashSet m_flowsByName; + mutable Vector m_flowNames; }; -} // namespace WebCore -#endif +inline unsigned DOMNamedFlowCollection::length() const +{ + return m_flows.size(); +} +} // namespace WebCore diff --git a/Source/WebCore/dom/DOMNamedFlowCollection.idl b/Source/WebCore/dom/DOMNamedFlowCollection.idl index 01a1ba2ae..ea3dae5a5 100644 --- a/Source/WebCore/dom/DOMNamedFlowCollection.idl +++ b/Source/WebCore/dom/DOMNamedFlowCollection.idl @@ -28,13 +28,14 @@ */ [ - NoInterfaceObject, Conditional=CSS_REGIONS, + ImplementationLacksVTable, InterfaceName=WebKitNamedFlowCollection, JSGenerateToJSObject, - ImplementationLacksVTable, + LegacyUnenumerableNamedProperties, + NoInterfaceObject ] interface DOMNamedFlowCollection { readonly attribute unsigned long length; - getter WebKitNamedFlow item(unsigned long index); - getter WebKitNamedFlow namedItem(DOMString name); + getter WebKitNamedFlow? item(unsigned long index); + getter WebKitNamedFlow? namedItem(DOMString name); }; diff --git a/Source/WebCore/dom/DOMPoint.h b/Source/WebCore/dom/DOMPoint.h new file mode 100644 index 000000000..b7cadb99a --- /dev/null +++ b/Source/WebCore/dom/DOMPoint.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2014 Adobe Systems Incorporated. All rights reserved. + * Copyright (C) 2016 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "DOMPointReadOnly.h" + +namespace WebCore { + +class DOMPoint final : public DOMPointReadOnly { + WTF_MAKE_FAST_ALLOCATED; +public: + static Ref create(double x, double y, double z, double w) { return adoptRef(*new DOMPoint(x, y, z, w)); } + static Ref create(const DOMPointInit& init) { return create(init.x, init.y, init.z, init.w); } + static Ref fromPoint(const DOMPointInit& init) { return create(init.x, init.y, init.z, init.w); } + + void setX(double x) { m_x = x; } + void setY(double y) { m_y = y; } + void setZ(double z) { m_z = z; } + void setW(double w) { m_w = w; } + +private: + DOMPoint(double x, double y, double z, double w) + : DOMPointReadOnly(x, y, z, w) + { + } +}; + +} // namespace WebCore diff --git a/Source/WebCore/dom/DOMPoint.idl b/Source/WebCore/dom/DOMPoint.idl new file mode 100644 index 000000000..7ae41ace5 --- /dev/null +++ b/Source/WebCore/dom/DOMPoint.idl @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014 Adobe Systems Incorporated. All rights reserved. + * Copyright (C) 2016 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// The DOMPointInit constructor exists in https://www.w3.org/TR/geometry-1/ but is removed in https://drafts.fxtf.org/geometry/ +[ + Constructor(DOMPointInit point), + Constructor(optional unrestricted double x = 0, optional unrestricted double y = 0, + optional unrestricted double z = 0, optional unrestricted double w = 1), + Exposed=(Window,Worker), + ImplementationLacksVTable +] +interface DOMPoint : DOMPointReadOnly { + [NewObject] static DOMPoint fromPoint(optional DOMPointInit other); + + inherit attribute unrestricted double x; + inherit attribute unrestricted double y; + inherit attribute unrestricted double z; + inherit attribute unrestricted double w; +}; diff --git a/Source/WebCore/dom/DOMPointInit.h b/Source/WebCore/dom/DOMPointInit.h new file mode 100644 index 000000000..119e42d42 --- /dev/null +++ b/Source/WebCore/dom/DOMPointInit.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 Adobe Systems Incorporated. All rights reserved. + * Copyright (C) 2016 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +namespace WebCore { + +struct DOMPointInit { + double x { 0 }; + double y { 0 }; + double z { 0 }; + double w { 1 }; +}; + +} // namespace WebCore diff --git a/Source/WebCore/dom/DOMPointInit.idl b/Source/WebCore/dom/DOMPointInit.idl new file mode 100644 index 000000000..5f47f0701 --- /dev/null +++ b/Source/WebCore/dom/DOMPointInit.idl @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 Adobe Systems Incorporated. All rights reserved. + * Copyright (C) 2016 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +dictionary DOMPointInit { + unrestricted double x = 0; + unrestricted double y = 0; + unrestricted double z = 0; + unrestricted double w = 1; +}; diff --git a/Source/WebCore/dom/DOMPointReadOnly.h b/Source/WebCore/dom/DOMPointReadOnly.h new file mode 100644 index 000000000..1b98302ac --- /dev/null +++ b/Source/WebCore/dom/DOMPointReadOnly.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2014 Adobe Systems Incorporated. All rights reserved. + * Copyright (C) 2016 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "DOMPointInit.h" +#include "ScriptWrappable.h" +#include + +namespace WebCore { + +class DOMPointReadOnly : public ScriptWrappable, public RefCounted { + WTF_MAKE_FAST_ALLOCATED; +public: + static Ref create(double x, double y, double z, double w) { return adoptRef(*new DOMPointReadOnly(x, y, z, w)); } + static Ref create(const DOMPointInit& init) { return create(init.x, init.y, init.z, init.w); } + static Ref fromPoint(const DOMPointInit& init) { return create(init.x, init.y, init.z, init.w); } + + double x() const { return m_x; } + double y() const { return m_y; } + double z() const { return m_z; } + double w() const { return m_w; } + +protected: + DOMPointReadOnly(double x, double y, double z, double w) + : m_x(x) + , m_y(y) + , m_z(z) + , m_w(w) + { + } + + // Any of these can be NaN or Inf. + double m_x; + double m_y; + double m_z; + double m_w; +}; + +} // namespace WebCore + diff --git a/Source/WebCore/dom/DOMPointReadOnly.idl b/Source/WebCore/dom/DOMPointReadOnly.idl new file mode 100644 index 000000000..9a00b9f4f --- /dev/null +++ b/Source/WebCore/dom/DOMPointReadOnly.idl @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014 Adobe Systems Incorporated. All rights reserved. + * Copyright (C) 2016 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// The DOMPointInit constructor exists in https://www.w3.org/TR/geometry-1/ but is removed in https://drafts.fxtf.org/geometry/ +[ + Constructor(DOMPointInit point), + Constructor(optional unrestricted double x = 0, optional unrestricted double y = 0, + optional unrestricted double z = 0, optional unrestricted double w = 1), + Exposed=(Window,Worker), + ImplementationLacksVTable +] +interface DOMPointReadOnly { + [NewObject] static DOMPointReadOnly fromPoint(optional DOMPointInit other); + + readonly attribute unrestricted double x; + readonly attribute unrestricted double y; + readonly attribute unrestricted double z; + readonly attribute unrestricted double w; + + // FIXME: No support for DOMMatrix yet (webkit.org/b/110001) + // DOMPoint matrixTransform(optional DOMMatrixInit matrix); + + serializer = { attribute }; +}; diff --git a/Source/WebCore/dom/DOMRect.h b/Source/WebCore/dom/DOMRect.h new file mode 100644 index 000000000..92307422f --- /dev/null +++ b/Source/WebCore/dom/DOMRect.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "DOMRectReadOnly.h" + +namespace WebCore { + +class DOMRect : public DOMRectReadOnly { + WTF_MAKE_FAST_ALLOCATED; +public: + static Ref create(double x, double y, double width, double height) { return adoptRef(*new DOMRect(x, y, width, height)); } + static Ref fromRect(const DOMRectInit& init) { return create(init.x, init.y, init.width, init.height); } + + void setX(double x) { m_x = x; } + void setY(double y) { m_y = y; } + + void setWidth(double width) { m_width = width; } + void setHeight(double height) { m_height = height; } + +private: + DOMRect(double x, double y, double width, double height) + : DOMRectReadOnly(x, y, width, height) + { + } +}; + +} diff --git a/Source/WebCore/dom/DOMRect.idl b/Source/WebCore/dom/DOMRect.idl new file mode 100644 index 000000000..47fef35db --- /dev/null +++ b/Source/WebCore/dom/DOMRect.idl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// https://drafts.fxtf.org/geometry-1/#DOMRect + +[ + Constructor(optional unrestricted double x = 0, optional unrestricted double y = 0, + optional unrestricted double width = 0, optional unrestricted double height = 0), + Exposed=(Window,Worker), + ImplementationLacksVTable +] +interface DOMRect : DOMRectReadOnly { + [NewObject] static DOMRect fromRect(optional DOMRectInit other); + + inherit attribute unrestricted double x; + inherit attribute unrestricted double y; + inherit attribute unrestricted double width; + inherit attribute unrestricted double height; +}; diff --git a/Source/WebCore/dom/DOMRectInit.h b/Source/WebCore/dom/DOMRectInit.h new file mode 100644 index 000000000..65ca6fd91 --- /dev/null +++ b/Source/WebCore/dom/DOMRectInit.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +namespace WebCore { + +struct DOMRectInit { + double x { 0 }; + double y { 0 }; + double width { 0 }; + double height { 0 }; +}; + +} diff --git a/Source/WebCore/dom/DOMRectInit.idl b/Source/WebCore/dom/DOMRectInit.idl new file mode 100644 index 000000000..0a2fcc144 --- /dev/null +++ b/Source/WebCore/dom/DOMRectInit.idl @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// https://drafts.fxtf.org/geometry-1/#DOMRect + +dictionary DOMRectInit { + unrestricted double x = 0; + unrestricted double y = 0; + unrestricted double width = 0; + unrestricted double height = 0; +}; diff --git a/Source/WebCore/dom/DOMRectReadOnly.h b/Source/WebCore/dom/DOMRectReadOnly.h new file mode 100644 index 000000000..06a5252fe --- /dev/null +++ b/Source/WebCore/dom/DOMRectReadOnly.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "DOMRectInit.h" +#include "ScriptWrappable.h" +#include +#include +#include + +namespace WebCore { + +class DOMRectReadOnly : public ScriptWrappable, public RefCounted { + WTF_MAKE_FAST_ALLOCATED; +public: + static Ref create(double x, double y, double width, double height) { return adoptRef(*new DOMRectReadOnly(x, y, width, height)); } + static Ref fromRect(const DOMRectInit& init) { return create(init.x, init.y, init.width, init.height); } + + double x() const { return m_x; } + double y() const { return m_y; } + double width() const { return m_width; } + double height() const { return m_height; } + + // Model NaN handling after Math.min, Math.max. + double top() const { return WTF::nanPropagatingMin(m_y, m_y + m_height); } + double right() const { return WTF::nanPropagatingMax(m_x, m_x + m_width); } + double bottom() const { return WTF::nanPropagatingMax(m_y, m_y + m_height); } + double left() const { return WTF::nanPropagatingMin(m_x, m_x + m_width); } + +protected: + DOMRectReadOnly(double x, double y, double width, double height) + : m_x(x) + , m_y(y) + , m_width(width) + , m_height(height) + { + } + + // Any of these can be NaN or Inf. + double m_x; + double m_y; + double m_width; // Can be negative. + double m_height; // Can be negative. +}; + +} diff --git a/Source/WebCore/dom/DOMRectReadOnly.idl b/Source/WebCore/dom/DOMRectReadOnly.idl new file mode 100644 index 000000000..06b7dce8a --- /dev/null +++ b/Source/WebCore/dom/DOMRectReadOnly.idl @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +// https://drafts.fxtf.org/geometry-1/#DOMRect + +[ + Constructor(optional unrestricted double x = 0, optional unrestricted double y = 0, + optional unrestricted double width = 0, optional unrestricted double height = 0), + Exposed=(Window,Worker), + ImplementationLacksVTable +] +interface DOMRectReadOnly { + [NewObject] static DOMRectReadOnly fromRect(optional DOMRectInit other); + + readonly attribute unrestricted double x; + readonly attribute unrestricted double y; + readonly attribute unrestricted double width; + readonly attribute unrestricted double height; + readonly attribute unrestricted double top; + readonly attribute unrestricted double right; + readonly attribute unrestricted double bottom; + readonly attribute unrestricted double left; + + serializer = { attribute }; +}; diff --git a/Source/WebCore/dom/DOMStringList.cpp b/Source/WebCore/dom/DOMStringList.cpp index bcc0d23ba..8826b9344 100644 --- a/Source/WebCore/dom/DOMStringList.cpp +++ b/Source/WebCore/dom/DOMStringList.cpp @@ -40,9 +40,8 @@ bool DOMStringList::contains(const String& string) const // FIXME: Currently, all consumers of DOMStringList store fairly small lists and thus an O(n) // algorithm is OK. But this may need to be optimized if larger amounts of data are // stored in m_strings. - size_t count = m_strings.size(); - for (size_t i = 0; i < count; ++i) { - if (m_strings[i] == string) + for (auto& value : m_strings) { + if (value == string) return true; } return false; diff --git a/Source/WebCore/dom/DOMStringList.h b/Source/WebCore/dom/DOMStringList.h index d365799bc..69cb2d7f9 100644 --- a/Source/WebCore/dom/DOMStringList.h +++ b/Source/WebCore/dom/DOMStringList.h @@ -23,10 +23,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DOMStringList_h -#define DOMStringList_h +#pragma once -#include #include #include #include @@ -37,9 +35,9 @@ namespace WebCore { // than creating the list statically as is currently the only option. class DOMStringList : public RefCounted { public: - static PassRefPtr create() + static Ref create() { - return adoptRef(new DOMStringList()); + return adoptRef(*new DOMStringList); } bool isEmpty() const { return m_strings.isEmpty(); } @@ -61,6 +59,3 @@ private: }; } // namespace WebCore - -#endif // DOMStringList_h - diff --git a/Source/WebCore/dom/DOMStringList.idl b/Source/WebCore/dom/DOMStringList.idl index 9618e2437..b5e09e9cf 100644 --- a/Source/WebCore/dom/DOMStringList.idl +++ b/Source/WebCore/dom/DOMStringList.idl @@ -24,12 +24,11 @@ */ [ - JSCustomToNativeObject, - JSNoStaticTables, - ImplementationLacksVTable, + ImplementationLacksVTable ] interface DOMStringList { readonly attribute unsigned long length; - [TreatReturnedNullStringAs=Null] getter DOMString item([Default=Undefined] optional unsigned long index); - boolean contains([Default=Undefined] optional DOMString string); + getter DOMString? item(unsigned long index); + + boolean contains(DOMString string); }; diff --git a/Source/WebCore/dom/DOMStringMap.h b/Source/WebCore/dom/DOMStringMap.h index da1e41119..947e17bd3 100644 --- a/Source/WebCore/dom/DOMStringMap.h +++ b/Source/WebCore/dom/DOMStringMap.h @@ -23,15 +23,12 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DOMStringMap_h -#define DOMStringMap_h +#pragma once #include "DatasetDOMStringMap.h" namespace WebCore { -typedef DatasetDOMStringMap DOMStringMap; +using DOMStringMap = DatasetDOMStringMap; } // namespace WebCore - -#endif // DOMStringMap_h diff --git a/Source/WebCore/dom/DOMStringMap.idl b/Source/WebCore/dom/DOMStringMap.idl index 55db65d55..cbfa3fd5b 100644 --- a/Source/WebCore/dom/DOMStringMap.idl +++ b/Source/WebCore/dom/DOMStringMap.idl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,10 +26,14 @@ [ GenerateIsReachable=ImplElementRoot, CustomDeleteProperty, - CustomEnumerateProperty, CustomNamedSetter, + OverrideBuiltins, SkipVTableValidation, ] interface DOMStringMap { getter DOMString (DOMString name); + + // FIXME: Add support for the setter and deleter specials. + // [CEReactions] setter void (DOMString name, DOMString value); + // [CEReactions] deleter void (DOMString name); }; diff --git a/Source/WebCore/dom/DOMTimeStamp.h b/Source/WebCore/dom/DOMTimeStamp.h index ff615205c..ee21875a9 100644 --- a/Source/WebCore/dom/DOMTimeStamp.h +++ b/Source/WebCore/dom/DOMTimeStamp.h @@ -28,8 +28,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DOMTimeStamp_h -#define DOMTimeStamp_h +#pragma once namespace WebCore { @@ -46,5 +45,3 @@ inline double convertDOMTimeStampToSeconds(DOMTimeStamp milliseconds) } } // namespace WebCore - -#endif // DOMTimeStamp_h diff --git a/Source/WebCore/dom/DataTransfer.cpp b/Source/WebCore/dom/DataTransfer.cpp new file mode 100644 index 000000000..083d3967b --- /dev/null +++ b/Source/WebCore/dom/DataTransfer.cpp @@ -0,0 +1,447 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DataTransfer.h" + +#include "CachedImage.h" +#include "CachedImageClient.h" +#include "DragData.h" +#include "Editor.h" +#include "FileList.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "HTMLImageElement.h" +#include "Image.h" +#include "Pasteboard.h" +#include "StaticPasteboard.h" + +namespace WebCore { + +#if ENABLE(DRAG_SUPPORT) + +class DragImageLoader final : private CachedImageClient { + WTF_MAKE_NONCOPYABLE(DragImageLoader); WTF_MAKE_FAST_ALLOCATED; +public: + explicit DragImageLoader(DataTransfer*); + void startLoading(CachedResourceHandle&); + void stopLoading(CachedResourceHandle&); + +private: + void imageChanged(CachedImage*, const IntRect*) override; + DataTransfer* m_dataTransfer; +}; + +#endif + +DataTransfer::DataTransfer(DataTransferAccessPolicy policy, std::unique_ptr pasteboard, Type type, bool forFileDrag) + : m_policy(policy) + , m_pasteboard(WTFMove(pasteboard)) +#if ENABLE(DRAG_SUPPORT) + , m_forDrag(type == DragAndDrop) + , m_forFileDrag(forFileDrag) + , m_dropEffect(ASCIILiteral("uninitialized")) + , m_effectAllowed(ASCIILiteral("uninitialized")) + , m_shouldUpdateDragImage(false) +#endif +{ +#if !ENABLE(DRAG_SUPPORT) + ASSERT_UNUSED(type, type != DragAndDrop); + ASSERT_UNUSED(forFileDrag, !forFileDrag); +#endif +} + +Ref DataTransfer::createForCopyAndPaste(DataTransferAccessPolicy policy) +{ + return adoptRef(*new DataTransfer(policy, policy == DataTransferAccessPolicy::Writable ? Pasteboard::createPrivate() : Pasteboard::createForCopyAndPaste())); +} + +DataTransfer::~DataTransfer() +{ +#if ENABLE(DRAG_SUPPORT) + if (m_dragImageLoader && m_dragImage) + m_dragImageLoader->stopLoading(m_dragImage); +#endif +} + +void DataTransfer::setAccessPolicy(DataTransferAccessPolicy policy) +{ + // Once the dataTransfer goes numb, it can never go back. + ASSERT(m_policy != DataTransferAccessPolicy::Numb || policy == DataTransferAccessPolicy::Numb); + m_policy = policy; +} + +bool DataTransfer::canReadTypes() const +{ + return m_policy == DataTransferAccessPolicy::Readable || m_policy == DataTransferAccessPolicy::TypesReadable || m_policy == DataTransferAccessPolicy::Writable; +} + +bool DataTransfer::canReadData() const +{ + return m_policy == DataTransferAccessPolicy::Readable || m_policy == DataTransferAccessPolicy::Writable; +} + +bool DataTransfer::canWriteData() const +{ + return m_policy == DataTransferAccessPolicy::Writable; +} + +void DataTransfer::clearData(const String& type) +{ + if (!canWriteData()) + return; + + if (type.isNull()) + m_pasteboard->clear(); + else + m_pasteboard->clear(type); +} + +String DataTransfer::getData(const String& type) const +{ + if (!canReadData()) + return String(); + +#if ENABLE(DRAG_SUPPORT) + if (m_forFileDrag) + return String(); +#endif + + return m_pasteboard->readString(type); +} + +void DataTransfer::setData(const String& type, const String& data) +{ + if (!canWriteData()) + return; + +#if ENABLE(DRAG_SUPPORT) + if (m_forFileDrag) + return; +#endif + + m_pasteboard->writeString(type, data); +} + +Vector DataTransfer::types() const +{ + if (!canReadTypes()) + return { }; + + return m_pasteboard->types(); +} + +FileList& DataTransfer::files() const +{ + bool newlyCreatedFileList = !m_fileList; + if (!m_fileList) + m_fileList = FileList::create(); + + if (!canReadData()) { + m_fileList->clear(); + return *m_fileList; + } + +#if ENABLE(DRAG_SUPPORT) + if (m_forDrag && !m_forFileDrag) { + ASSERT(m_fileList->isEmpty()); + return *m_fileList; + } +#endif + + if (newlyCreatedFileList) { + for (const String& filename : m_pasteboard->readFilenames()) + m_fileList->append(File::create(filename)); + } + return *m_fileList; +} + +bool DataTransfer::hasFileOfType(const String& type) +{ + ASSERT_WITH_SECURITY_IMPLICATION(canReadTypes()); + + for (const String& path : m_pasteboard->readFilenames()) { + if (equalIgnoringASCIICase(File::contentTypeForFile(path), type)) + return true; + } + + return false; +} + +bool DataTransfer::hasStringOfType(const String& type) +{ + ASSERT_WITH_SECURITY_IMPLICATION(canReadTypes()); + + return !type.isNull() && types().contains(type); +} + +Ref DataTransfer::createForInputEvent(const String& plainText, const String& htmlText) +{ + TypeToStringMap typeToStringMap; + typeToStringMap.set(ASCIILiteral("text/plain"), plainText); + typeToStringMap.set(ASCIILiteral("text/html"), htmlText); + return adoptRef(*new DataTransfer(DataTransferAccessPolicy::Readable, StaticPasteboard::create(WTFMove(typeToStringMap)), InputEvent)); +} + +#if !ENABLE(DRAG_SUPPORT) + +String DataTransfer::dropEffect() const +{ + return ASCIILiteral("none"); +} + +void DataTransfer::setDropEffect(const String&) +{ +} + +String DataTransfer::effectAllowed() const +{ + return ASCIILiteral("uninitialized"); +} + +void DataTransfer::setEffectAllowed(const String&) +{ +} + +void DataTransfer::setDragImage(Element*, int, int) +{ +} + +#else + +Ref DataTransfer::createForDrag() +{ + return adoptRef(*new DataTransfer(DataTransferAccessPolicy::Writable, Pasteboard::createForDragAndDrop(), DragAndDrop)); +} + +Ref DataTransfer::createForDrop(DataTransferAccessPolicy policy, const DragData& dragData) +{ + return adoptRef(*new DataTransfer(policy, Pasteboard::createForDragAndDrop(dragData), DragAndDrop, dragData.containsFiles())); +} + +bool DataTransfer::canSetDragImage() const +{ + // Note that the spec doesn't actually allow drag image modification outside the dragstart + // event. This capability is maintained for backwards compatiblity for ports that have + // supported this in the past. On many ports, attempting to set a drag image outside the + // dragstart operation is a no-op anyway. + return m_forDrag && (m_policy == DataTransferAccessPolicy::ImageWritable || m_policy == DataTransferAccessPolicy::Writable); +} + +void DataTransfer::setDragImage(Element* element, int x, int y) +{ + if (!canSetDragImage()) + return; + + CachedImage* image = nullptr; + if (is(element) && !element->isConnected()) + image = downcast(*element).cachedImage(); + + m_dragLocation = IntPoint(x, y); + + if (m_dragImageLoader && m_dragImage) + m_dragImageLoader->stopLoading(m_dragImage); + m_dragImage = image; + if (m_dragImage) { + if (!m_dragImageLoader) + m_dragImageLoader = std::make_unique(this); + m_dragImageLoader->startLoading(m_dragImage); + } + + m_dragImageElement = image ? nullptr : element; + + updateDragImage(); +} + +void DataTransfer::updateDragImage() +{ + // Don't allow setting the image if we haven't started dragging yet; we'll rely on the dragging code + // to install this drag image as part of getting the drag kicked off. + if (!m_shouldUpdateDragImage) + return; + + IntPoint computedHotSpot; + auto computedImage = DragImage { createDragImage(computedHotSpot) }; + if (!computedImage) + return; + + m_pasteboard->setDragImage(WTFMove(computedImage), computedHotSpot); +} + +#if !PLATFORM(MAC) + +DragImageRef DataTransfer::createDragImage(IntPoint& location) const +{ + location = m_dragLocation; + + if (m_dragImage) + return createDragImageFromImage(m_dragImage->image(), ImageOrientationDescription()); + + if (m_dragImageElement) { + if (Frame* frame = m_dragImageElement->document().frame()) + return createDragImageForNode(*frame, *m_dragImageElement); + } + + // We do not have enough information to create a drag image, use the default icon. + return nullptr; +} + +#endif + +DragImageLoader::DragImageLoader(DataTransfer* dataTransfer) + : m_dataTransfer(dataTransfer) +{ +} + +void DragImageLoader::startLoading(CachedResourceHandle& image) +{ + // FIXME: Does this really trigger a load? Does it need to? + image->addClient(*this); +} + +void DragImageLoader::stopLoading(CachedResourceHandle& image) +{ + image->removeClient(*this); +} + +void DragImageLoader::imageChanged(CachedImage*, const IntRect*) +{ + m_dataTransfer->updateDragImage(); +} + +static DragOperation dragOpFromIEOp(const String& operation) +{ + if (operation == "uninitialized") + return DragOperationEvery; + if (operation == "none") + return DragOperationNone; + if (operation == "copy") + return DragOperationCopy; + if (operation == "link") + return DragOperationLink; + if (operation == "move") + return (DragOperation)(DragOperationGeneric | DragOperationMove); + if (operation == "copyLink") + return (DragOperation)(DragOperationCopy | DragOperationLink); + if (operation == "copyMove") + return (DragOperation)(DragOperationCopy | DragOperationGeneric | DragOperationMove); + if (operation == "linkMove") + return (DragOperation)(DragOperationLink | DragOperationGeneric | DragOperationMove); + if (operation == "all") + return DragOperationEvery; + return DragOperationPrivate; // really a marker for "no conversion" +} + +static const char* IEOpFromDragOp(DragOperation operation) +{ + bool isGenericMove = operation & (DragOperationGeneric | DragOperationMove); + + if ((isGenericMove && (operation & DragOperationCopy) && (operation & DragOperationLink)) || operation == DragOperationEvery) + return "all"; + if (isGenericMove && (operation & DragOperationCopy)) + return "copyMove"; + if (isGenericMove && (operation & DragOperationLink)) + return "linkMove"; + if ((operation & DragOperationCopy) && (operation & DragOperationLink)) + return "copyLink"; + if (isGenericMove) + return "move"; + if (operation & DragOperationCopy) + return "copy"; + if (operation & DragOperationLink) + return "link"; + return "none"; +} + +DragOperation DataTransfer::sourceOperation() const +{ + DragOperation operation = dragOpFromIEOp(m_effectAllowed); + ASSERT(operation != DragOperationPrivate); + return operation; +} + +DragOperation DataTransfer::destinationOperation() const +{ + DragOperation operation = dragOpFromIEOp(m_dropEffect); + ASSERT(operation == DragOperationCopy || operation == DragOperationNone || operation == DragOperationLink || operation == (DragOperation)(DragOperationGeneric | DragOperationMove) || operation == DragOperationEvery); + return operation; +} + +void DataTransfer::setSourceOperation(DragOperation operation) +{ + ASSERT_ARG(operation, operation != DragOperationPrivate); + m_effectAllowed = IEOpFromDragOp(operation); +} + +void DataTransfer::setDestinationOperation(DragOperation operation) +{ + ASSERT_ARG(operation, operation == DragOperationCopy || operation == DragOperationNone || operation == DragOperationLink || operation == DragOperationGeneric || operation == DragOperationMove || operation == (DragOperation)(DragOperationGeneric | DragOperationMove)); + m_dropEffect = IEOpFromDragOp(operation); +} + +String DataTransfer::dropEffect() const +{ + return m_dropEffect == "uninitialized" ? ASCIILiteral("none") : m_dropEffect; +} + +void DataTransfer::setDropEffect(const String& effect) +{ + if (!m_forDrag) + return; + + if (effect != "none" && effect != "copy" && effect != "link" && effect != "move") + return; + + // FIXME: The spec allows this in all circumstances. There is probably no value + // in ignoring attempts to change it. + if (!canReadTypes()) + return; + + m_dropEffect = effect; +} + +String DataTransfer::effectAllowed() const +{ + return m_effectAllowed; +} + +void DataTransfer::setEffectAllowed(const String& effect) +{ + if (!m_forDrag) + return; + + // Ignore any attempts to set it to an unknown value. + if (dragOpFromIEOp(effect) == DragOperationPrivate) + return; + + if (!canWriteData()) + return; + + m_effectAllowed = effect; +} + +#endif // ENABLE(DRAG_SUPPORT) + +} // namespace WebCore diff --git a/Source/WebCore/dom/DataTransfer.h b/Source/WebCore/dom/DataTransfer.h new file mode 100644 index 000000000..d24b9daaf --- /dev/null +++ b/Source/WebCore/dom/DataTransfer.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de) + * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) + * Copyright (C) 2003-2016 Apple 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. + * + */ + +#pragma once + +#include "CachedResourceHandle.h" +#include "DataTransferAccessPolicy.h" +#include "DragActions.h" +#include "DragImage.h" +#include "IntPoint.h" +#include + +namespace WebCore { + +class CachedImage; +class DragData; +class DragImageLoader; +class Element; +class FileList; +class Pasteboard; + +class DataTransfer : public RefCounted { +public: + static Ref createForCopyAndPaste(DataTransferAccessPolicy); + static Ref createForInputEvent(const String& plainText, const String& htmlText); + + WEBCORE_EXPORT ~DataTransfer(); + + String dropEffect() const; + void setDropEffect(const String&); + + String effectAllowed() const; + void setEffectAllowed(const String&); + + Vector types() const; + + FileList& files() const; + + void clearData(const String& type = String()); + + String getData(const String& type) const; + + void setData(const String& type, const String& data); + + void setDragImage(Element*, int x, int y); + + void setAccessPolicy(DataTransferAccessPolicy); + bool canReadTypes() const; + bool canReadData() const; + bool canWriteData() const; + + bool hasFileOfType(const String&); + bool hasStringOfType(const String&); + + Pasteboard& pasteboard() { return *m_pasteboard; } + +#if ENABLE(DRAG_SUPPORT) + static Ref createForDrag(); + static Ref createForDrop(DataTransferAccessPolicy, const DragData&); + + bool dropEffectIsUninitialized() const { return m_dropEffect == "uninitialized"; } + + DragOperation sourceOperation() const; + DragOperation destinationOperation() const; + void setSourceOperation(DragOperation); + void setDestinationOperation(DragOperation); + + void setDragHasStarted() { m_shouldUpdateDragImage = true; } + DragImageRef createDragImage(IntPoint& dragLocation) const; + void updateDragImage(); +#endif + +private: + enum Type { CopyAndPaste, DragAndDrop, InputEvent }; + DataTransfer(DataTransferAccessPolicy, std::unique_ptr, Type = CopyAndPaste, bool forFileDrag = false); + +#if ENABLE(DRAG_SUPPORT) + bool canSetDragImage() const; +#endif + + DataTransferAccessPolicy m_policy; + std::unique_ptr m_pasteboard; + + mutable RefPtr m_fileList; + +#if ENABLE(DRAG_SUPPORT) + bool m_forDrag; + bool m_forFileDrag; + String m_dropEffect; + String m_effectAllowed; + bool m_shouldUpdateDragImage; + IntPoint m_dragLocation; + CachedResourceHandle m_dragImage; + RefPtr m_dragImageElement; + std::unique_ptr m_dragImageLoader; +#endif +}; + +} // namespace WebCore diff --git a/Source/WebCore/dom/DataTransfer.idl b/Source/WebCore/dom/DataTransfer.idl new file mode 100644 index 000000000..fc415bb1b --- /dev/null +++ b/Source/WebCore/dom/DataTransfer.idl @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2008, 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +[ + SkipVTableValidation, +] interface DataTransfer { + attribute DOMString dropEffect; + attribute DOMString effectAllowed; + + // FIXME: items should use [SameObject] once that is supported. + [Conditional=DATA_TRANSFER_ITEMS] readonly attribute DataTransferItemList items; + + void setDragImage(Element? image, long x, long y); // FIXME: Element argument is not nullable in the HTML standard. + + readonly attribute FrozenArray types; + DOMString getData(DOMString format); + void setData(DOMString format, DOMString data); + void clearData(optional DOMString format); + // FIXME: files should use [SameObject] once that is supported. + readonly attribute FileList files; +}; diff --git a/Source/WebCore/dom/DataTransferAccessPolicy.h b/Source/WebCore/dom/DataTransferAccessPolicy.h new file mode 100644 index 000000000..a50e87aa9 --- /dev/null +++ b/Source/WebCore/dom/DataTransferAccessPolicy.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2006 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +namespace WebCore { + +enum class DataTransferAccessPolicy { + Numb, ImageWritable, Writable, TypesReadable, Readable +}; + +} // namespace WebCore diff --git a/Source/WebCore/dom/DataTransferItem.h b/Source/WebCore/dom/DataTransferItem.h index 11f58e979..d0e55e1d5 100644 --- a/Source/WebCore/dom/DataTransferItem.h +++ b/Source/WebCore/dom/DataTransferItem.h @@ -28,8 +28,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DataTransferItem_h -#define DataTransferItem_h +#pragma once #if ENABLE(DATA_TRANSFER_ITEMS) @@ -39,9 +38,7 @@ namespace WebCore { class Blob; -class File; class StringCallback; -class ScriptExecutionContext; class DataTransferItem : public RefCounted { public: @@ -53,12 +50,10 @@ public: virtual String kind() const = 0; virtual String type() const = 0; - virtual void getAsString(PassRefPtr) const = 0; - virtual PassRefPtr getAsFile() const = 0; + virtual void getAsString(RefPtr&&) const = 0; + virtual RefPtr getAsFile() const = 0; }; } // namespace WebCore #endif // ENABLE(DATA_TRANSFER_ITEMS) - -#endif // DataTransferItem_h diff --git a/Source/WebCore/dom/DataTransferItem.idl b/Source/WebCore/dom/DataTransferItem.idl index 3027eaf9b..fb722b8c6 100644 --- a/Source/WebCore/dom/DataTransferItem.idl +++ b/Source/WebCore/dom/DataTransferItem.idl @@ -36,7 +36,7 @@ readonly attribute DOMString kind; readonly attribute DOMString type; - void getAsString([Default=Undefined] optional StringCallback callback); + void getAsString(optional StringCallback? callback); Blob getAsFile(); }; diff --git a/Source/WebCore/dom/DataTransferItemList.h b/Source/WebCore/dom/DataTransferItemList.h index 58db06370..172a9b36e 100644 --- a/Source/WebCore/dom/DataTransferItemList.h +++ b/Source/WebCore/dom/DataTransferItemList.h @@ -28,8 +28,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DataTransferItemList_h -#define DataTransferItemList_h +#pragma once #if ENABLE(DATA_TRANSFER_ITEMS) @@ -39,25 +38,21 @@ namespace WebCore { -class Clipboard; class File; -typedef int ExceptionCode; - +// FIXME: Unclear why this need to be an abstract base class. class DataTransferItemList : public RefCounted { public: virtual ~DataTransferItemList() { } - virtual size_t length() const = 0; - virtual PassRefPtr item(unsigned long index) = 0; - virtual void deleteItem(unsigned long index, ExceptionCode&) = 0; + virtual unsigned length() const = 0; + virtual DataTransferItem* item(unsigned index) = 0; + virtual ExceptionOr deleteItem(unsigned index) = 0; virtual void clear() = 0; - virtual void add(const String& data, const String& type, ExceptionCode&) = 0; - virtual void add(PassRefPtr) = 0; + virtual ExceptionOr add(const String& data, const String& type) = 0; + virtual void add(RefPtr&&) = 0; }; } // namespace WebCore #endif // ENABLE(DATA_TRANSFER_ITEMS) - -#endif // DataTransferItemList_h diff --git a/Source/WebCore/dom/DataTransferItemList.idl b/Source/WebCore/dom/DataTransferItemList.idl index f60899310..bdf2a8700 100644 --- a/Source/WebCore/dom/DataTransferItemList.idl +++ b/Source/WebCore/dom/DataTransferItemList.idl @@ -35,11 +35,10 @@ ImplementationLacksVTable, ] interface DataTransferItemList { readonly attribute long length; - getter DataTransferItem item([Default=Undefined] optional unsigned long index); + getter DataTransferItem item(unsigned long index); void clear(); void add(File? file); - [RaisesException] void add([Default=Undefined] optional DOMString data, - [Default=Undefined] optional DOMString type); -}; + [MayThrowException] void add(optional DOMString data = "undefined", optional DOMString type = "undefined"); +}; diff --git a/Source/WebCore/dom/DatasetDOMStringMap.cpp b/Source/WebCore/dom/DatasetDOMStringMap.cpp index b4383dc2d..5f01ecf17 100644 --- a/Source/WebCore/dom/DatasetDOMStringMap.cpp +++ b/Source/WebCore/dom/DatasetDOMStringMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,6 +29,7 @@ #include "Element.h" #include "ExceptionCode.h" #include +#include #include namespace WebCore { @@ -105,22 +106,39 @@ static bool isValidPropertyName(const String& name) return true; } -static String convertPropertyNameToAttributeName(const String& name) +template +static inline AtomicString convertPropertyNameToAttributeName(const StringImpl& name) { - StringBuilder builder; - builder.append("data-"); + const CharacterType dataPrefix[] = { 'd', 'a', 't', 'a', '-' }; + + Vector buffer; unsigned length = name.length(); + buffer.reserveInitialCapacity(WTF_ARRAY_LENGTH(dataPrefix) + length); + + buffer.append(dataPrefix, WTF_ARRAY_LENGTH(dataPrefix)); + + const CharacterType* characters = name.characters(); for (unsigned i = 0; i < length; ++i) { - UChar character = name[i]; + CharacterType character = characters[i]; if (isASCIIUpper(character)) { - builder.append('-'); - builder.append(toASCIILower(character)); + buffer.append('-'); + buffer.append(toASCIILower(character)); } else - builder.append(character); + buffer.append(character); } + return AtomicString(buffer.data(), buffer.size()); +} - return builder.toString(); +static AtomicString convertPropertyNameToAttributeName(const String& name) +{ + if (name.isNull()) + return nullAtom; + + StringImpl* nameImpl = name.impl(); + if (nameImpl->is8Bit()) + return convertPropertyNameToAttributeName(*nameImpl); + return convertPropertyNameToAttributeName(*nameImpl); } void DatasetDOMStringMap::ref() @@ -133,61 +151,58 @@ void DatasetDOMStringMap::deref() m_element.deref(); } -void DatasetDOMStringMap::getNames(Vector& names) +Vector DatasetDOMStringMap::supportedPropertyNames() const { - if (!m_element.hasAttributes()) - return; + Vector names; - for (const Attribute& attribute : m_element.attributesIterator()) { - if (isValidAttributeName(attribute.localName())) - names.append(convertAttributeNameToPropertyName(attribute.localName())); + if (m_element.hasAttributes()) { + for (auto& attribute : m_element.attributesIterator()) { + if (isValidAttributeName(attribute.localName())) + names.append(convertAttributeNameToPropertyName(attribute.localName())); + } } + + return names; } -String DatasetDOMStringMap::item(const String& name) +std::optional DatasetDOMStringMap::item(const String& propertyName) const { - if (!m_element.hasAttributes()) - return String(); - - for (const Attribute& attribute : m_element.attributesIterator()) { - if (propertyNameMatchesAttributeName(name, attribute.localName())) - return attribute.value(); + if (m_element.hasAttributes()) { + AttributeIteratorAccessor attributeIteratorAccessor = m_element.attributesIterator(); + + if (attributeIteratorAccessor.attributeCount() == 1) { + // If the node has a single attribute, it is the dataset member accessed in most cases. + // Building a new AtomicString in that case is overkill so we do a direct character comparison. + const Attribute& attribute = *attributeIteratorAccessor.begin(); + if (propertyNameMatchesAttributeName(propertyName, attribute.localName())) + return attribute.value(); + } else { + AtomicString attributeName = convertPropertyNameToAttributeName(propertyName); + for (const Attribute& attribute : attributeIteratorAccessor) { + if (attribute.localName() == attributeName) + return attribute.value(); + } + } } - return String(); + return std::nullopt; } -bool DatasetDOMStringMap::contains(const String& name) +String DatasetDOMStringMap::namedItem(const AtomicString& name) const { - if (!m_element.hasAttributes()) - return false; - - for (const Attribute& attribute : m_element.attributesIterator()) { - if (propertyNameMatchesAttributeName(name, attribute.localName())) - return true; - } - - return false; + return item(name).value_or(String { }); } -void DatasetDOMStringMap::setItem(const String& name, const String& value, ExceptionCode& ec) +ExceptionOr DatasetDOMStringMap::setItem(const String& name, const String& value) { - if (!isValidPropertyName(name)) { - ec = SYNTAX_ERR; - return; - } - - m_element.setAttribute(convertPropertyNameToAttributeName(name), value, ec); + if (!isValidPropertyName(name)) + return Exception { SYNTAX_ERR }; + return m_element.setAttribute(convertPropertyNameToAttributeName(name), value); } -void DatasetDOMStringMap::deleteItem(const String& name, ExceptionCode& ec) +bool DatasetDOMStringMap::deleteItem(const String& name) { - if (!isValidPropertyName(name)) { - ec = SYNTAX_ERR; - return; - } - - m_element.removeAttribute(convertPropertyNameToAttributeName(name)); + return m_element.removeAttribute(convertPropertyNameToAttributeName(name)); } } // namespace WebCore diff --git a/Source/WebCore/dom/DatasetDOMStringMap.h b/Source/WebCore/dom/DatasetDOMStringMap.h index 3a4bfa843..a3914fd96 100644 --- a/Source/WebCore/dom/DatasetDOMStringMap.h +++ b/Source/WebCore/dom/DatasetDOMStringMap.h @@ -23,21 +23,17 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DatasetDOMStringMap_h -#define DatasetDOMStringMap_h +#pragma once +#include "ExceptionOr.h" #include "ScriptWrappable.h" -#include -#include -#include namespace WebCore { class Element; -typedef int ExceptionCode; class DatasetDOMStringMap final : public ScriptWrappable { - WTF_MAKE_NONCOPYABLE(DatasetDOMStringMap); WTF_MAKE_FAST_ALLOCATED; + WTF_MAKE_FAST_ALLOCATED; public: explicit DatasetDOMStringMap(Element& element) : m_element(element) @@ -47,18 +43,18 @@ public: void ref(); void deref(); - void getNames(Vector&); - String item(const String& name); - bool contains(const String& name); - void setItem(const String& name, const String& value, ExceptionCode&); - void deleteItem(const String& name, ExceptionCode&); + Vector supportedPropertyNames() const; - Element* element() { return &m_element; } + String namedItem(const AtomicString& name) const; + ExceptionOr setItem(const String& name, const String& value); + bool deleteItem(const String& name); + + Element& element() { return m_element; } private: + std::optional item(const String& name) const; + Element& m_element; }; } // namespace WebCore - -#endif // DatasetDOMStringMap_h diff --git a/Source/WebCore/dom/DecodedDataDocumentParser.h b/Source/WebCore/dom/DecodedDataDocumentParser.h index 34934ecba..bbb06a3e8 100644 --- a/Source/WebCore/dom/DecodedDataDocumentParser.h +++ b/Source/WebCore/dom/DecodedDataDocumentParser.h @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DecodedDataDocumentParser_h -#define DecodedDataDocumentParser_h +#pragma once #include "DocumentParser.h" @@ -41,13 +40,11 @@ protected: private: // append is used by DocumentWriter::replaceDocument. - virtual void append(PassRefPtr) = 0; + void append(RefPtr&&) override = 0; // appendBytes and flush are used by DocumentWriter (the loader). - virtual void appendBytes(DocumentWriter&, const char* bytes, size_t length) override; - virtual void flush(DocumentWriter&) override; + void appendBytes(DocumentWriter&, const char* bytes, size_t length) override; + void flush(DocumentWriter&) override; }; -} - -#endif // DecodedDataDocumentParser_h +} // namespace WebCore diff --git a/Source/WebCore/dom/DeviceMotionClient.h b/Source/WebCore/dom/DeviceMotionClient.h index 7533f6c60..dbe9abee8 100644 --- a/Source/WebCore/dom/DeviceMotionClient.h +++ b/Source/WebCore/dom/DeviceMotionClient.h @@ -24,8 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DeviceMotionClient_h -#define DeviceMotionClient_h +#pragma once #include "DeviceClient.h" #include @@ -49,5 +48,3 @@ public: void provideDeviceMotionTo(Page*, DeviceMotionClient*); } // namespace WebCore - -#endif // DeviceMotionClient_h diff --git a/Source/WebCore/dom/DeviceMotionController.cpp b/Source/WebCore/dom/DeviceMotionController.cpp index 89eb00262..1ca7aa72f 100644 --- a/Source/WebCore/dom/DeviceMotionController.cpp +++ b/Source/WebCore/dom/DeviceMotionController.cpp @@ -30,6 +30,7 @@ #include "DeviceMotionClient.h" #include "DeviceMotionData.h" #include "DeviceMotionEvent.h" +#include "EventNames.h" #include "Page.h" namespace WebCore { @@ -41,11 +42,6 @@ DeviceMotionController::DeviceMotionController(DeviceMotionClient* client) deviceMotionClient()->setController(this); } -PassOwnPtr DeviceMotionController::create(DeviceMotionClient* client) -{ - return adoptPtr(new DeviceMotionController(client)); -} - #if PLATFORM(IOS) // FIXME: We should look to reconcile the iOS and OpenSource differences with this class // so that we can either remove these methods or remove the PLATFORM(IOS)-guard. @@ -77,7 +73,7 @@ bool DeviceMotionController::hasLastData() return deviceMotionClient()->lastMotion(); } -PassRefPtr DeviceMotionController::getLastEvent() +RefPtr DeviceMotionController::getLastEvent() { return DeviceMotionEvent::create(eventNames().devicemotionEvent, deviceMotionClient()->lastMotion()); } @@ -101,7 +97,7 @@ bool DeviceMotionController::isActiveAt(Page* page) void provideDeviceMotionTo(Page* page, DeviceMotionClient* client) { - DeviceMotionController::provideTo(page, DeviceMotionController::supplementName(), DeviceMotionController::create(client)); + DeviceMotionController::provideTo(page, DeviceMotionController::supplementName(), std::make_unique(client)); } } // namespace WebCore diff --git a/Source/WebCore/dom/DeviceMotionController.h b/Source/WebCore/dom/DeviceMotionController.h index deb0620d1..8cd2e2946 100644 --- a/Source/WebCore/dom/DeviceMotionController.h +++ b/Source/WebCore/dom/DeviceMotionController.h @@ -24,8 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DeviceMotionController_h -#define DeviceMotionController_h +#pragma once #include "DeviceController.h" #include @@ -35,12 +34,11 @@ namespace WebCore { class DeviceMotionClient; class DeviceMotionData; -class DeviceMotionController : public DeviceController { +class DeviceMotionController final : public DeviceController { WTF_MAKE_NONCOPYABLE(DeviceMotionController); public: - ~DeviceMotionController() { }; - - static PassOwnPtr create(DeviceMotionClient*); + explicit DeviceMotionController(DeviceMotionClient*); + virtual ~DeviceMotionController() { } #if PLATFORM(IOS) // FIXME: We should look to reconcile the iOS and OpenSource differences with this class @@ -52,17 +50,12 @@ public: void didChangeDeviceMotion(DeviceMotionData*); DeviceMotionClient* deviceMotionClient(); - virtual bool hasLastData() override; - virtual PassRefPtr getLastEvent() override; + bool hasLastData() override; + RefPtr getLastEvent() override; static const char* supplementName(); static DeviceMotionController* from(Page*); static bool isActiveAt(Page*); - -private: - explicit DeviceMotionController(DeviceMotionClient*); }; } // namespace WebCore - -#endif // DeviceMotionController_h diff --git a/Source/WebCore/dom/DeviceMotionData.cpp b/Source/WebCore/dom/DeviceMotionData.cpp index 441c80d16..06816a6c8 100644 --- a/Source/WebCore/dom/DeviceMotionData.cpp +++ b/Source/WebCore/dom/DeviceMotionData.cpp @@ -28,64 +28,20 @@ namespace WebCore { -PassRefPtr DeviceMotionData::Acceleration::create(bool canProvideX, double x, - bool canProvideY, double y, - bool canProvideZ, double z) +Ref DeviceMotionData::create() { - return adoptRef(new DeviceMotionData::Acceleration(canProvideX, x, canProvideY, y, canProvideZ, z)); + return adoptRef(*new DeviceMotionData); } -DeviceMotionData::Acceleration::Acceleration(bool canProvideX, double x, bool canProvideY, double y, bool canProvideZ, double z) - : m_x(x) - , m_y(y) - , m_z(z) - , m_canProvideX(canProvideX) - , m_canProvideY(canProvideY) - , m_canProvideZ(canProvideZ) - -{ -} - -PassRefPtr DeviceMotionData::RotationRate::create(bool canProvideAlpha, double alpha, - bool canProvideBeta, double beta, - bool canProvideGamma, double gamma) -{ - return adoptRef(new DeviceMotionData::RotationRate(canProvideAlpha, alpha, canProvideBeta, beta, canProvideGamma, gamma)); -} - -DeviceMotionData::RotationRate::RotationRate(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma) - : m_alpha(alpha) - , m_beta(beta) - , m_gamma(gamma) - , m_canProvideAlpha(canProvideAlpha) - , m_canProvideBeta(canProvideBeta) - , m_canProvideGamma(canProvideGamma) -{ -} - -PassRefPtr DeviceMotionData::create() -{ - return adoptRef(new DeviceMotionData); -} - -PassRefPtr DeviceMotionData::create(PassRefPtr acceleration, PassRefPtr accelerationIncludingGravity, - PassRefPtr rotationRate, bool canProvideInterval, double interval) -{ - return adoptRef(new DeviceMotionData(acceleration, accelerationIncludingGravity, rotationRate, canProvideInterval, interval)); -} - -DeviceMotionData::DeviceMotionData() - : m_canProvideInterval(false) - , m_interval(0) +Ref DeviceMotionData::create(RefPtr&& acceleration, RefPtr&& accelerationIncludingGravity, RefPtr&& rotationRate, std::optional interval) { + return adoptRef(*new DeviceMotionData(WTFMove(acceleration), WTFMove(accelerationIncludingGravity), WTFMove(rotationRate), interval)); } -DeviceMotionData::DeviceMotionData(PassRefPtr acceleration, PassRefPtr accelerationIncludingGravity, - PassRefPtr rotationRate, bool canProvideInterval, double interval) - : m_acceleration(acceleration) - , m_accelerationIncludingGravity(accelerationIncludingGravity) - , m_rotationRate(rotationRate) - , m_canProvideInterval(canProvideInterval) +DeviceMotionData::DeviceMotionData(RefPtr&& acceleration, RefPtr&& accelerationIncludingGravity, RefPtr&& rotationRate, std::optional interval) + : m_acceleration(WTFMove(acceleration)) + , m_accelerationIncludingGravity(WTFMove(accelerationIncludingGravity)) + , m_rotationRate(WTFMove(rotationRate)) , m_interval(interval) { } diff --git a/Source/WebCore/dom/DeviceMotionData.h b/Source/WebCore/dom/DeviceMotionData.h index 1d53b531f..ccdb87a08 100644 --- a/Source/WebCore/dom/DeviceMotionData.h +++ b/Source/WebCore/dom/DeviceMotionData.h @@ -23,10 +23,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DeviceMotionData_h -#define DeviceMotionData_h +#pragma once -#include +#include #include #include @@ -36,74 +35,79 @@ class DeviceMotionData : public RefCounted { public: class Acceleration : public RefCounted { public: - static PassRefPtr create(bool canProvideX, double x, bool canProvideY, double y, bool canProvideZ, double z); - - bool canProvideX() const { return m_canProvideX; } - bool canProvideY() const { return m_canProvideY; } - bool canProvideZ() const { return m_canProvideZ; } - - double x() const { return m_x; } - double y() const { return m_y; } - double z() const { return m_z; } + static Ref create() + { + return adoptRef(*new Acceleration); + } + static Ref create(std::optional x, std::optional y, std::optional z) + { + return adoptRef(*new Acceleration(x, y, z)); + } + + std::optional x() const { return m_x; } + std::optional y() const { return m_y; } + std::optional z() const { return m_z; } private: - Acceleration(bool canProvideX, double x, bool canProvideY, double y, bool canProvideZ, double z); - - double m_x; - double m_y; - double m_z; - - bool m_canProvideX; - bool m_canProvideY; - bool m_canProvideZ; + Acceleration() = default; + Acceleration(std::optional x, std::optional y, std::optional z) + : m_x(x) + , m_y(y) + , m_z(z) + { + } + + std::optional m_x; + std::optional m_y; + std::optional m_z; }; class RotationRate : public RefCounted { public: - static PassRefPtr create(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma); - - bool canProvideAlpha() const { return m_canProvideAlpha; } - bool canProvideBeta() const { return m_canProvideBeta; } - bool canProvideGamma() const { return m_canProvideGamma; } - - double alpha() const { return m_alpha; } - double beta() const { return m_beta; } - double gamma() const { return m_gamma; } + static Ref create() + { + return adoptRef(*new RotationRate); + } + static Ref create(std::optional alpha, std::optional beta, std::optional gamma) + { + return adoptRef(*new RotationRate(alpha, beta, gamma)); + } + + std::optional alpha() const { return m_alpha; } + std::optional beta() const { return m_beta; } + std::optional gamma() const { return m_gamma; } private: - RotationRate(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma); - - double m_alpha; - double m_beta; - double m_gamma; - - bool m_canProvideAlpha; - bool m_canProvideBeta; - bool m_canProvideGamma; + RotationRate() = default; + RotationRate(std::optional alpha, std::optional beta, std::optional gamma) + : m_alpha(alpha) + , m_beta(beta) + , m_gamma(gamma) + { + } + + std::optional m_alpha; + std::optional m_beta; + std::optional m_gamma; }; - static PassRefPtr create(); - static PassRefPtr create(PassRefPtr acceleration, PassRefPtr accelerationIncludingGravity, - PassRefPtr rotationRate, bool canProvideInterval, double interval); + WEBCORE_EXPORT static Ref create(); + WEBCORE_EXPORT static Ref create(RefPtr&&, RefPtr&& accelerationIncludingGravity, RefPtr&&, std::optional interval); const Acceleration* acceleration() const { return m_acceleration.get(); } const Acceleration* accelerationIncludingGravity() const { return m_accelerationIncludingGravity.get(); } const RotationRate* rotationRate() const { return m_rotationRate.get(); } - double interval() const { return m_interval; } - bool canProvideInterval() const { return m_canProvideInterval; } + + std::optional interval() const { return m_interval; } private: - DeviceMotionData(); - DeviceMotionData(PassRefPtr acceleration, PassRefPtr accelerationIncludingGravity, - PassRefPtr rotationRate, bool canProvideInterval, double interval); + DeviceMotionData() = default; + DeviceMotionData(RefPtr&&, RefPtr&& accelerationIncludingGravity, RefPtr&&, std::optional interval); RefPtr m_acceleration; RefPtr m_accelerationIncludingGravity; RefPtr m_rotationRate; - bool m_canProvideInterval; - double m_interval; + std::optional m_interval; }; } // namespace WebCore - -#endif // DeviceMotionData_h diff --git a/Source/WebCore/dom/DeviceMotionEvent.cpp b/Source/WebCore/dom/DeviceMotionEvent.cpp index e0b49a8c3..d6c858ac8 100644 --- a/Source/WebCore/dom/DeviceMotionEvent.cpp +++ b/Source/WebCore/dom/DeviceMotionEvent.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -27,7 +27,6 @@ #include "DeviceMotionEvent.h" #include "DeviceMotionData.h" -#include "EventNames.h" namespace WebCore { @@ -46,13 +45,71 @@ DeviceMotionEvent::DeviceMotionEvent(const AtomicString& eventType, DeviceMotion { } -void DeviceMotionEvent::initDeviceMotionEvent(const AtomicString& type, bool bubbles, bool cancelable, DeviceMotionData* deviceMotionData) +static std::optional convert(const DeviceMotionData::Acceleration* acceleration) +{ + if (!acceleration) + return std::nullopt; + + return DeviceMotionEvent::Acceleration { acceleration->x(), acceleration->y(), acceleration->z() }; +} + +static std::optional convert(const DeviceMotionData::RotationRate* rotationRate) +{ + if (!rotationRate) + return std::nullopt; + + return DeviceMotionEvent::RotationRate { rotationRate->alpha(), rotationRate->beta(), rotationRate->gamma() }; +} + +static RefPtr convert(std::optional&& acceleration) +{ + if (!acceleration) + return nullptr; + + if (!acceleration->x && !acceleration->y && !acceleration->z) + return nullptr; + + return DeviceMotionData::Acceleration::create(acceleration->x, acceleration->y, acceleration->z); +} + +static RefPtr convert(std::optional&& rotationRate) +{ + if (!rotationRate) + return nullptr; + + if (!rotationRate->alpha && !rotationRate->beta && !rotationRate->gamma) + return nullptr; + + return DeviceMotionData::RotationRate::create(rotationRate->alpha, rotationRate->beta, rotationRate->gamma); +} + +std::optional DeviceMotionEvent::acceleration() const +{ + return convert(m_deviceMotionData->acceleration()); +} + +std::optional DeviceMotionEvent::accelerationIncludingGravity() const +{ + return convert(m_deviceMotionData->accelerationIncludingGravity()); +} + +std::optional DeviceMotionEvent::rotationRate() const +{ + return convert(m_deviceMotionData->rotationRate()); +} + +std::optional DeviceMotionEvent::interval() const +{ + return m_deviceMotionData->interval(); +} + +void DeviceMotionEvent::initDeviceMotionEvent(const AtomicString& type, bool bubbles, bool cancelable, std::optional&& acceleration, std::optional&& accelerationIncludingGravity, std::optional&& rotationRate, std::optional interval) { if (dispatched()) return; initEvent(type, bubbles, cancelable); - m_deviceMotionData = deviceMotionData; + m_deviceMotionData = DeviceMotionData::create(convert(WTFMove(acceleration)), convert(WTFMove(accelerationIncludingGravity)), convert(WTFMove(rotationRate)), interval); } EventInterface DeviceMotionEvent::eventInterface() const diff --git a/Source/WebCore/dom/DeviceMotionEvent.h b/Source/WebCore/dom/DeviceMotionEvent.h index 2f06d86b8..7a8e9a5a1 100644 --- a/Source/WebCore/dom/DeviceMotionEvent.h +++ b/Source/WebCore/dom/DeviceMotionEvent.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DeviceMotionEvent_h -#define DeviceMotionEvent_h +#pragma once #include "Event.h" @@ -32,31 +31,48 @@ namespace WebCore { class DeviceMotionData; -class DeviceMotionEvent : public Event { +class DeviceMotionEvent final : public Event { public: - ~DeviceMotionEvent(); - static PassRefPtr create() + virtual ~DeviceMotionEvent(); + + // FIXME: Merge this with DeviceMotionData::Acceleration + struct Acceleration { + std::optional x; + std::optional y; + std::optional z; + }; + + // FIXME: Merge this with DeviceMotionData::RotationRate + struct RotationRate { + std::optional alpha; + std::optional beta; + std::optional gamma; + }; + + static Ref create(const AtomicString& eventType, DeviceMotionData* deviceMotionData) { - return adoptRef(new DeviceMotionEvent); + return adoptRef(*new DeviceMotionEvent(eventType, deviceMotionData)); } - static PassRefPtr create(const AtomicString& eventType, DeviceMotionData* deviceMotionData) + + static Ref createForBindings() { - return adoptRef(new DeviceMotionEvent(eventType, deviceMotionData)); + return adoptRef(*new DeviceMotionEvent); } - void initDeviceMotionEvent(const AtomicString& type, bool bubbles, bool cancelable, DeviceMotionData*); + std::optional acceleration() const; + std::optional accelerationIncludingGravity() const; + std::optional rotationRate() const; + std::optional interval() const; - DeviceMotionData* deviceMotionData() const { return m_deviceMotionData.get(); } - - virtual EventInterface eventInterface() const override; + void initDeviceMotionEvent(const AtomicString& type, bool bubbles, bool cancelable, std::optional&&, std::optional&&, std::optional&&, std::optional); private: DeviceMotionEvent(); DeviceMotionEvent(const AtomicString& eventType, DeviceMotionData*); + EventInterface eventInterface() const override; + RefPtr m_deviceMotionData; }; } // namespace WebCore - -#endif // DeviceMotionEvent_h diff --git a/Source/WebCore/dom/DeviceMotionEvent.idl b/Source/WebCore/dom/DeviceMotionEvent.idl index 12e0df499..f2f5df20f 100644 --- a/Source/WebCore/dom/DeviceMotionEvent.idl +++ b/Source/WebCore/dom/DeviceMotionEvent.idl @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -24,18 +24,36 @@ */ [ - Conditional=DEVICE_ORIENTATION, + Conditional=DEVICE_ORIENTATION ] interface DeviceMotionEvent : Event { - [Custom] readonly attribute Acceleration acceleration; - [Custom] readonly attribute Acceleration accelerationIncludingGravity; - [Custom] readonly attribute RotationRate rotationRate; - [Custom] readonly attribute double interval; - [Custom] void initDeviceMotionEvent([Default=Undefined] optional DOMString type, - [Default=Undefined] optional boolean bubbles, - [Default=Undefined] optional boolean cancelable, - [Default=Undefined] optional Acceleration acceleration, - [Default=Undefined] optional Acceleration accelerationIncludingGravity, - [Default=Undefined] optional RotationRate rotationRate, - [Default=Undefined] optional double interval); + readonly attribute Acceleration? acceleration; + readonly attribute Acceleration? accelerationIncludingGravity; + readonly attribute RotationRate? rotationRate; + readonly attribute unrestricted double? interval; + + void initDeviceMotionEvent(optional DOMString type = "", + optional boolean bubbles = false, + optional boolean cancelable = false, + optional Acceleration? acceleration = null, + optional Acceleration? accelerationIncludingGravity = null, + optional RotationRate? rotationRate = null, + optional unrestricted double? interval = null); }; +[ + Conditional=DEVICE_ORIENTATION, + JSGenerateToJSObject +] dictionary Acceleration { + double? x; + double? y; + double? z; +}; + +[ + Conditional=DEVICE_ORIENTATION, + JSGenerateToJSObject +] dictionary RotationRate { + double? alpha; + double? beta; + double? gamma; +}; diff --git a/Source/WebCore/dom/DeviceOrientationClient.h b/Source/WebCore/dom/DeviceOrientationClient.h index 5b5d1768b..37763633b 100644 --- a/Source/WebCore/dom/DeviceOrientationClient.h +++ b/Source/WebCore/dom/DeviceOrientationClient.h @@ -24,10 +24,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DeviceOrientationClient_h -#define DeviceOrientationClient_h +#pragma once #include "DeviceClient.h" +#include "PlatformExportMacros.h" #include namespace WebCore { @@ -46,8 +46,6 @@ public: virtual void deviceOrientationControllerDestroyed() = 0; }; -void provideDeviceOrientationTo(Page*, DeviceOrientationClient*); +WEBCORE_EXPORT void provideDeviceOrientationTo(Page*, DeviceOrientationClient*); } // namespace WebCore - -#endif // DeviceOrientationClient_h diff --git a/Source/WebCore/dom/DeviceOrientationController.cpp b/Source/WebCore/dom/DeviceOrientationController.cpp index 5ce7c5dd2..072f71189 100644 --- a/Source/WebCore/dom/DeviceOrientationController.cpp +++ b/Source/WebCore/dom/DeviceOrientationController.cpp @@ -30,6 +30,7 @@ #include "DeviceOrientationClient.h" #include "DeviceOrientationData.h" #include "DeviceOrientationEvent.h" +#include "EventNames.h" #include "Page.h" namespace WebCore { @@ -49,11 +50,6 @@ DeviceOrientationController::DeviceOrientationController(DeviceOrientationClient #endif } -PassOwnPtr DeviceOrientationController::create(DeviceOrientationClient* client) -{ - return adoptPtr(new DeviceOrientationController(client)); -} - void DeviceOrientationController::didChangeDeviceOrientation(DeviceOrientationData* orientation) { dispatchDeviceEvent(DeviceOrientationEvent::create(eventNames().deviceorientationEvent, orientation)); @@ -84,7 +80,7 @@ bool DeviceOrientationController::hasLastData() return deviceOrientationClient()->lastOrientation(); } -PassRefPtr DeviceOrientationController::getLastEvent() +RefPtr DeviceOrientationController::getLastEvent() { return DeviceOrientationEvent::create(eventNames().deviceorientationEvent, deviceOrientationClient()->lastOrientation()); } @@ -109,7 +105,7 @@ bool DeviceOrientationController::isActiveAt(Page* page) void provideDeviceOrientationTo(Page* page, DeviceOrientationClient* client) { - DeviceOrientationController::provideTo(page, DeviceOrientationController::supplementName(), DeviceOrientationController::create(client)); + DeviceOrientationController::provideTo(page, DeviceOrientationController::supplementName(), std::make_unique(client)); } } // namespace WebCore diff --git a/Source/WebCore/dom/DeviceOrientationController.h b/Source/WebCore/dom/DeviceOrientationController.h index 56bae2d78..fb2c6bb58 100644 --- a/Source/WebCore/dom/DeviceOrientationController.h +++ b/Source/WebCore/dom/DeviceOrientationController.h @@ -24,11 +24,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DeviceOrientationController_h -#define DeviceOrientationController_h +#pragma once #include "DeviceController.h" -#include #include namespace WebCore { @@ -37,12 +35,11 @@ class DeviceOrientationClient; class DeviceOrientationData; class Page; -class DeviceOrientationController : public DeviceController { +class DeviceOrientationController final : public DeviceController { WTF_MAKE_NONCOPYABLE(DeviceOrientationController); public: - ~DeviceOrientationController() { }; - - static PassOwnPtr create(DeviceOrientationClient*); + explicit DeviceOrientationController(DeviceOrientationClient*); + virtual ~DeviceOrientationController() { } void didChangeDeviceOrientation(DeviceOrientationData*); DeviceOrientationClient* deviceOrientationClient(); @@ -53,18 +50,13 @@ public: void suspendUpdates(); void resumeUpdates(); #else - virtual bool hasLastData() override; - virtual PassRefPtr getLastEvent() override; + bool hasLastData() override; + RefPtr getLastEvent() override; #endif static const char* supplementName(); static DeviceOrientationController* from(Page*); static bool isActiveAt(Page*); - -private: - DeviceOrientationController(DeviceOrientationClient*); }; } // namespace WebCore - -#endif // DeviceOrientationController_h diff --git a/Source/WebCore/dom/DeviceOrientationData.cpp b/Source/WebCore/dom/DeviceOrientationData.cpp index d6a5f2cf4..885912600 100644 --- a/Source/WebCore/dom/DeviceOrientationData.cpp +++ b/Source/WebCore/dom/DeviceOrientationData.cpp @@ -28,134 +28,38 @@ namespace WebCore { -PassRefPtr DeviceOrientationData::create() -{ - return adoptRef(new DeviceOrientationData); -} - #if PLATFORM(IOS) -// FIXME: We should reconcile the iOS and OpenSource differences. -PassRefPtr DeviceOrientationData::create(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma, bool canProvideCompassHeading, double compassHeading, bool canProvideCompassAccuracy, double compassAccuracy) -{ - return adoptRef(new DeviceOrientationData(canProvideAlpha, alpha, canProvideBeta, beta, canProvideGamma, gamma, canProvideCompassHeading, compassHeading, canProvideCompassAccuracy, compassAccuracy)); -} -#else -PassRefPtr DeviceOrientationData::create(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma, bool canProvideAbsolute, bool absolute) -{ - return adoptRef(new DeviceOrientationData(canProvideAlpha, alpha, canProvideBeta, beta, canProvideGamma, gamma, canProvideAbsolute, absolute)); -} -#endif - -DeviceOrientationData::DeviceOrientationData() - : m_canProvideAlpha(false) - , m_canProvideBeta(false) - , m_canProvideGamma(false) -#if !PLATFORM(IOS) - , m_canProvideAbsolute(false) -#endif - , m_alpha(0) - , m_beta(0) - , m_gamma(0) -#if PLATFORM(IOS) - , m_canProvideCompassHeading(false) - , m_canProvideCompassAccuracy(false) -#else - , m_absolute(false) -#endif +// FIXME: We should reconcile the iOS and OpenSource differences. +Ref DeviceOrientationData::create(std::optional alpha, std::optional beta, std::optional gamma, std::optional compassHeading, std::optional compassAccuracy) { + return adoptRef(*new DeviceOrientationData(alpha, beta, gamma, compassHeading, compassAccuracy)); } -#if PLATFORM(IOS) -DeviceOrientationData::DeviceOrientationData(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma, bool canProvideCompassHeading, double compassHeading, bool canProvideCompassAccuracy, double compassAccuracy) - : m_canProvideAlpha(canProvideAlpha) - , m_canProvideBeta(canProvideBeta) - , m_canProvideGamma(canProvideGamma) - , m_alpha(alpha) +DeviceOrientationData::DeviceOrientationData(std::optional alpha, std::optional beta, std::optional gamma, std::optional compassHeading, std::optional compassAccuracy) + : m_alpha(alpha) , m_beta(beta) , m_gamma(gamma) - , m_canProvideCompassHeading(canProvideCompassHeading) - , m_canProvideCompassAccuracy(canProvideCompassAccuracy) , m_compassHeading(compassHeading) , m_compassAccuracy(compassAccuracy) -#else -DeviceOrientationData::DeviceOrientationData(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma, bool canProvideAbsolute, bool absolute) - : m_canProvideAlpha(canProvideAlpha) - , m_canProvideBeta(canProvideBeta) - , m_canProvideGamma(canProvideGamma) - , m_canProvideAbsolute(canProvideAbsolute) - , m_alpha(alpha) - , m_beta(beta) - , m_gamma(gamma) - , m_absolute(absolute) -#endif { } -double DeviceOrientationData::alpha() const -{ - return m_alpha; -} - -double DeviceOrientationData::beta() const -{ - return m_beta; -} - -double DeviceOrientationData::gamma() const -{ - return m_gamma; -} - -#if !PLATFORM(IOS) -bool DeviceOrientationData::absolute() const -{ - return m_absolute; -} -#endif - -bool DeviceOrientationData::canProvideAlpha() const -{ - return m_canProvideAlpha; -} - -bool DeviceOrientationData::canProvideBeta() const -{ - return m_canProvideBeta; -} - -bool DeviceOrientationData::canProvideGamma() const -{ - return m_canProvideGamma; -} - -#if PLATFORM(IOS) -double DeviceOrientationData::compassHeading() const -{ - return m_compassHeading; -} - -double DeviceOrientationData::compassAccuracy() const -{ - return m_compassAccuracy; -} +#else -bool DeviceOrientationData::canProvideCompassHeading() const +Ref DeviceOrientationData::create(std::optional alpha, std::optional beta, std::optional gamma, std::optional absolute) { - return m_canProvideCompassHeading; + return adoptRef(*new DeviceOrientationData(alpha, beta, gamma, absolute)); } -bool DeviceOrientationData::canProvideCompassAccuracy() const +DeviceOrientationData::DeviceOrientationData(std::optional alpha, std::optional beta, std::optional gamma, std::optional absolute) + : m_alpha(alpha) + , m_beta(beta) + , m_gamma(gamma) + , m_absolute(absolute) { - return m_canProvideCompassAccuracy; } -#endif -#if !PLATFORM(IOS) -bool DeviceOrientationData::canProvideAbsolute() const -{ - return m_canProvideAbsolute; -} #endif } // namespace WebCore diff --git a/Source/WebCore/dom/DeviceOrientationData.h b/Source/WebCore/dom/DeviceOrientationData.h index facf91709..818faddd6 100644 --- a/Source/WebCore/dom/DeviceOrientationData.h +++ b/Source/WebCore/dom/DeviceOrientationData.h @@ -23,67 +23,55 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DeviceOrientationData_h -#define DeviceOrientationData_h +#pragma once -#include +#include "PlatformExportMacros.h" +#include +#include #include namespace WebCore { class DeviceOrientationData : public RefCounted { public: - static PassRefPtr create(); + static Ref create() + { + return adoptRef(*new DeviceOrientationData); + } + #if PLATFORM(IOS) - static PassRefPtr create(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma, bool canProvideCompassHeading, double compassHeading, bool canProvideCompassAccuracy, double compassAccuracy); + WEBCORE_EXPORT static Ref create(std::optional alpha, std::optional beta, std::optional gamma, std::optional compassHeading, std::optional compassAccuracy); #else - static PassRefPtr create(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma, bool canProvideAbsolute = false, bool absolute = false); + WEBCORE_EXPORT static Ref create(std::optional alpha, std::optional beta, std::optional gamma, std::optional absolute); #endif - double alpha() const; - double beta() const; - double gamma() const; - bool absolute() const; - bool canProvideAlpha() const; - bool canProvideBeta() const; - bool canProvideGamma() const; - bool canProvideAbsolute() const; - + std::optional alpha() const { return m_alpha; } + std::optional beta() const { return m_beta; } + std::optional gamma() const { return m_gamma; } #if PLATFORM(IOS) - double compassHeading() const; - double compassAccuracy() const; - bool canProvideCompassHeading() const; - bool canProvideCompassAccuracy() const; + std::optional compassHeading() const { return m_compassHeading; } + std::optional compassAccuracy() const { return m_compassAccuracy; } +#else + std::optional absolute() const { return m_absolute; } #endif private: - DeviceOrientationData(); + DeviceOrientationData() = default; #if PLATFORM(IOS) - DeviceOrientationData(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma, bool canProvideCompassHeading, double compassHeading, bool canProvideCompassAccuracy, double compassAccuracy); + DeviceOrientationData(std::optional alpha, std::optional beta, std::optional gamma, std::optional compassHeading, std::optional compassAccuracy); #else - DeviceOrientationData(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma, bool canProvideAbsolute, bool absolute); + DeviceOrientationData(std::optional alpha, std::optional beta, std::optional gamma, std::optional absolute); #endif - bool m_canProvideAlpha; - bool m_canProvideBeta; - bool m_canProvideGamma; -#if !PLATFORM(IOS) - bool m_canProvideAbsolute; -#endif - double m_alpha; - double m_beta; - double m_gamma; - + std::optional m_alpha; + std::optional m_beta; + std::optional m_gamma; #if PLATFORM(IOS) - bool m_canProvideCompassHeading; - bool m_canProvideCompassAccuracy; - double m_compassHeading; - double m_compassAccuracy; + std::optional m_compassHeading; + std::optional m_compassAccuracy; #else - bool m_absolute; + std::optional m_absolute; #endif }; } // namespace WebCore - -#endif // DeviceOrientationData_h diff --git a/Source/WebCore/dom/DeviceOrientationEvent.cpp b/Source/WebCore/dom/DeviceOrientationEvent.cpp index 97b919e59..e06ec3170 100644 --- a/Source/WebCore/dom/DeviceOrientationEvent.cpp +++ b/Source/WebCore/dom/DeviceOrientationEvent.cpp @@ -27,7 +27,6 @@ #include "DeviceOrientationEvent.h" #include "DeviceOrientationData.h" -#include "EventNames.h" namespace WebCore { @@ -46,15 +45,60 @@ DeviceOrientationEvent::DeviceOrientationEvent(const AtomicString& eventType, De { } -void DeviceOrientationEvent::initDeviceOrientationEvent(const AtomicString& type, bool bubbles, bool cancelable, DeviceOrientationData* orientation) +std::optional DeviceOrientationEvent::alpha() const +{ + return m_orientation->alpha(); +} + +std::optional DeviceOrientationEvent::beta() const +{ + return m_orientation->beta(); +} + +std::optional DeviceOrientationEvent::gamma() const +{ + return m_orientation->gamma(); +} + +#if PLATFORM(IOS) + +std::optional DeviceOrientationEvent::compassHeading() const +{ + return m_orientation->compassHeading(); +} + +std::optional DeviceOrientationEvent::compassAccuracy() const +{ + return m_orientation->compassAccuracy(); +} + +void DeviceOrientationEvent::initDeviceOrientationEvent(const AtomicString& type, bool bubbles, bool cancelable, std::optional alpha, std::optional beta, std::optional gamma, std::optional compassHeading, std::optional compassAccuracy) { if (dispatched()) return; initEvent(type, bubbles, cancelable); - m_orientation = orientation; + m_orientation = DeviceOrientationData::create(alpha, beta, gamma, compassHeading, compassAccuracy); +} + +#else + +std::optional DeviceOrientationEvent::absolute() const +{ + return m_orientation->absolute(); } +void DeviceOrientationEvent::initDeviceOrientationEvent(const AtomicString& type, bool bubbles, bool cancelable, std::optional alpha, std::optional beta, std::optional gamma, std::optional absolute) +{ + if (dispatched()) + return; + + initEvent(type, bubbles, cancelable); + m_orientation = DeviceOrientationData::create(alpha, beta, gamma, absolute); +} + +#endif + EventInterface DeviceOrientationEvent::eventInterface() const { #if ENABLE(DEVICE_ORIENTATION) diff --git a/Source/WebCore/dom/DeviceOrientationEvent.h b/Source/WebCore/dom/DeviceOrientationEvent.h index d69ddbf95..a5d70316c 100644 --- a/Source/WebCore/dom/DeviceOrientationEvent.h +++ b/Source/WebCore/dom/DeviceOrientationEvent.h @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DeviceOrientationEvent_h -#define DeviceOrientationEvent_h +#pragma once #include "Event.h" @@ -32,31 +31,42 @@ namespace WebCore { class DeviceOrientationData; -class DeviceOrientationEvent : public Event { +class DeviceOrientationEvent final : public Event { public: - ~DeviceOrientationEvent(); - static PassRefPtr create() + static Ref create(const AtomicString& eventType, DeviceOrientationData* orientation) { - return adoptRef(new DeviceOrientationEvent); + return adoptRef(*new DeviceOrientationEvent(eventType, orientation)); } - static PassRefPtr create(const AtomicString& eventType, DeviceOrientationData* orientation) + + static Ref createForBindings() { - return adoptRef(new DeviceOrientationEvent(eventType, orientation)); + return adoptRef(*new DeviceOrientationEvent); } - void initDeviceOrientationEvent(const AtomicString& type, bool bubbles, bool cancelable, DeviceOrientationData*); + virtual ~DeviceOrientationEvent(); + + std::optional alpha() const; + std::optional beta() const; + std::optional gamma() const; + +#if PLATFORM(IOS) + std::optional compassHeading() const; + std::optional compassAccuracy() const; - DeviceOrientationData* orientation() const { return m_orientation.get(); } + void initDeviceOrientationEvent(const AtomicString& type, bool bubbles, bool cancelable, std::optional alpha, std::optional beta, std::optional gamma, std::optional compassHeading, std::optional compassAccuracy); +#else + std::optional absolute() const; - virtual EventInterface eventInterface() const override; + void initDeviceOrientationEvent(const AtomicString& type, bool bubbles, bool cancelable, std::optional alpha, std::optional beta, std::optional gamma, std::optional absolute); +#endif private: DeviceOrientationEvent(); DeviceOrientationEvent(const AtomicString& eventType, DeviceOrientationData*); + EventInterface eventInterface() const override; + RefPtr m_orientation; }; } // namespace WebCore - -#endif // DeviceOrientationEvent_h diff --git a/Source/WebCore/dom/DeviceOrientationEvent.idl b/Source/WebCore/dom/DeviceOrientationEvent.idl index 2ab8ffafb..f349490d9 100644 --- a/Source/WebCore/dom/DeviceOrientationEvent.idl +++ b/Source/WebCore/dom/DeviceOrientationEvent.idl @@ -26,32 +26,32 @@ [ Conditional=DEVICE_ORIENTATION, ] interface DeviceOrientationEvent : Event { - [Custom] readonly attribute double alpha; - [Custom] readonly attribute double beta; - [Custom] readonly attribute double gamma; + readonly attribute unrestricted double? alpha; + readonly attribute unrestricted double? beta; + readonly attribute unrestricted double? gamma; // FIXME: Consider defining an ENABLE macro for iOS device orientation code and/or modifying // the bindings scripts to support generating more complicated conditional code. #if defined(WTF_PLATFORM_IOS) && WTF_PLATFORM_IOS - [Custom] readonly attribute double webkitCompassHeading; - [Custom] readonly attribute double webkitCompassAccuracy; - [Custom] void initDeviceOrientationEvent([Default=Undefined] optional DOMString type, - [Default=Undefined] optional boolean bubbles, - [Default=Undefined] optional boolean cancelable, - [Default=Undefined] optional double alpha, - [Default=Undefined] optional double beta, - [Default=Undefined] optional double gamma, - [Default=Undefined] optional double compassHeading, - [Default=Undefined] optional double compassAccuracy); + [ImplementedAs=compassHeading] readonly attribute unrestricted double? webkitCompassHeading; + [ImplementedAs=compassAccuracy] readonly attribute unrestricted double? webkitCompassAccuracy; + void initDeviceOrientationEvent(optional DOMString type = "", + optional boolean bubbles = false, + optional boolean cancelable = false, + optional unrestricted double? alpha = null, + optional unrestricted double? beta = null, + optional unrestricted double? gamma = null, + optional unrestricted double? compassHeading = null, + optional unrestricted double? compassAccuracy = null); #else - [Custom] readonly attribute boolean absolute; - [Custom] void initDeviceOrientationEvent([Default=Undefined] optional DOMString type, - [Default=Undefined] optional boolean bubbles, - [Default=Undefined] optional boolean cancelable, - [Default=Undefined] optional double alpha, - [Default=Undefined] optional double beta, - [Default=Undefined] optional double gamma, - [Default=Undefined] optional boolean absolute); + readonly attribute boolean? absolute; + void initDeviceOrientationEvent(optional DOMString type = "", + optional boolean bubbles = false, + optional boolean cancelable = false, + optional unrestricted double? alpha = null, + optional unrestricted double? beta = null, + optional unrestricted double? gamma = null, + optional boolean? absolute = null); #endif }; diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp index 1e677dc90..f9e0bf272 100644 --- a/Source/WebCore/dom/Document.cpp +++ b/Source/WebCore/dom/Document.cpp @@ -3,7 +3,7 @@ * (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, 2011, 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2004-2017 Apple Inc. All rights reserved. * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * Copyright (C) 2008, 2009, 2011, 2012 Google Inc. All rights reserved. * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) @@ -29,117 +29,163 @@ #include "Document.h" #include "AXObjectCache.h" -#include "AnimationController.h" #include "Attr.h" #include "CDATASection.h" +#include "CSSAnimationController.h" +#include "CSSFontSelector.h" #include "CSSStyleDeclaration.h" #include "CSSStyleSheet.h" #include "CachedCSSStyleSheet.h" +#include "CachedFrame.h" #include "CachedResourceLoader.h" #include "Chrome.h" #include "ChromeClient.h" #include "Comment.h" +#include "CommonVM.h" +#include "CompositionEvent.h" #include "ContentSecurityPolicy.h" #include "CookieJar.h" +#include "CustomElementReactionQueue.h" +#include "CustomElementRegistry.h" +#include "CustomEvent.h" #include "DOMImplementation.h" #include "DOMNamedFlowCollection.h" #include "DOMWindow.h" #include "DateComponents.h" -#include "Dictionary.h" +#include "DebugPageOverlays.h" #include "DocumentLoader.h" #include "DocumentMarkerController.h" #include "DocumentSharedObjectPool.h" #include "DocumentType.h" #include "Editor.h" #include "ElementIterator.h" -#include "EntityReference.h" -#include "EventFactory.h" #include "EventHandler.h" -#include "FontLoader.h" +#include "ExtensionStyleSheets.h" +#include "FocusController.h" +#include "FontFaceSet.h" #include "FormController.h" #include "FrameLoader.h" #include "FrameLoaderClient.h" #include "FrameView.h" -#include "HashChangeEvent.h" -#include "HistogramSupport.h" -#include "History.h" +#include "GenericCachedHTMLCollection.h" #include "HTMLAllCollection.h" #include "HTMLAnchorElement.h" #include "HTMLBaseElement.h" #include "HTMLBodyElement.h" #include "HTMLCanvasElement.h" -#include "HTMLCollection.h" #include "HTMLDocument.h" #include "HTMLElementFactory.h" #include "HTMLFormControlElement.h" #include "HTMLFrameOwnerElement.h" #include "HTMLFrameSetElement.h" #include "HTMLHeadElement.h" -#include "HTMLIFrameElement.h" +#include "HTMLHtmlElement.h" #include "HTMLImageElement.h" +#include "HTMLInputElement.h" #include "HTMLLinkElement.h" #include "HTMLMediaElement.h" #include "HTMLNameCollection.h" #include "HTMLParserIdioms.h" +#include "HTMLPictureElement.h" #include "HTMLPlugInElement.h" #include "HTMLScriptElement.h" #include "HTMLStyleElement.h" #include "HTMLTitleElement.h" +#include "HTMLUnknownElement.h" +#include "HTTPHeaderNames.h" #include "HTTPParsers.h" +#include "HashChangeEvent.h" +#include "History.h" #include "HitTestResult.h" #include "IconController.h" #include "ImageLoader.h" #include "InspectorInstrumentation.h" +#include "JSCustomElementInterface.h" #include "JSLazyEventListener.h" +#include "KeyboardEvent.h" #include "Language.h" #include "LoaderStrategy.h" #include "Logging.h" #include "MainFrame.h" #include "MediaCanStartListener.h" +#include "MediaProducer.h" #include "MediaQueryList.h" #include "MediaQueryMatcher.h" +#include "MessageEvent.h" #include "MouseEventWithHitTestResults.h" +#include "MutationEvent.h" #include "NameNodeList.h" +#include "NamedFlowCollection.h" #include "NestingLevelIncrementer.h" +#include "NoEventDispatchAssertion.h" #include "NodeIterator.h" #include "NodeRareData.h" #include "NodeWithIndex.h" -#include "PageConsole.h" +#include "OriginAccessEntry.h" +#include "OverflowEvent.h" +#include "PageConsoleClient.h" #include "PageGroup.h" #include "PageTransitionEvent.h" #include "PlatformLocale.h" +#include "PlatformMediaSessionManager.h" +#include "PlatformScreen.h" #include "PlatformStrategies.h" #include "PlugInsResources.h" #include "PluginDocument.h" #include "PointerLockController.h" #include "PopStateEvent.h" #include "ProcessingInstruction.h" +#include "RenderChildIterator.h" +#include "RenderLayerCompositor.h" +#include "RenderTreeUpdater.h" #include "RenderView.h" #include "RenderWidget.h" -#include "ResourceLoadScheduler.h" -#include "ResourceLoader.h" +#include "RequestAnimationFrameCallback.h" +#include "ResourceLoadObserver.h" #include "RuntimeEnabledFeatures.h" +#include "SVGDocumentExtensions.h" +#include "SVGElement.h" +#include "SVGElementFactory.h" +#include "SVGNames.h" +#include "SVGSVGElement.h" +#include "SVGTitleElement.h" +#include "SVGZoomEvent.h" #include "SchemeRegistry.h" #include "ScopedEventQueue.h" -#include "ScriptCallStack.h" #include "ScriptController.h" +#include "ScriptModuleLoader.h" #include "ScriptRunner.h" #include "ScriptSourceCode.h" +#include "ScriptedAnimationController.h" #include "ScrollingCoordinator.h" #include "SecurityOrigin.h" +#include "SecurityOriginData.h" +#include "SecurityOriginPolicy.h" #include "SecurityPolicy.h" #include "SegmentedString.h" #include "SelectorQuery.h" #include "Settings.h" #include "ShadowRoot.h" +#include "SocketProvider.h" +#include "StorageEvent.h" #include "StyleProperties.h" +#include "StyleResolveForDocument.h" #include "StyleResolver.h" +#include "StyleScope.h" #include "StyleSheetContents.h" #include "StyleSheetList.h" -#include "TextResourceDecoder.h" +#include "StyleTreeResolver.h" +#include "SubresourceLoader.h" +#include "TextAutoSizing.h" +#include "TextEvent.h" +#include "TextNodeTraversal.h" #include "TransformSource.h" #include "TreeWalker.h" +#include "ValidationMessageClient.h" #include "VisitedLinkState.h" +#include "WheelEvent.h" +#include "WindowFeatures.h" +#include "XMLDocument.h" #include "XMLDocumentParser.h" #include "XMLNSNames.h" #include "XMLNames.h" @@ -148,31 +194,27 @@ #include "XPathNSResolver.h" #include "XPathResult.h" #include "htmlediting.h" +#include +#include #include -#include +#include +#include +#include #include +#include -#if USE(ACCELERATED_COMPOSITING) -#include "RenderLayerCompositor.h" -#endif - -#if ENABLE(SHARED_WORKERS) -#include "SharedWorkerRepository.h" -#endif - -#if ENABLE(XSLT) -#include "XSLTProcessor.h" +#if ENABLE(DEVICE_ORIENTATION) +#include "DeviceMotionEvent.h" +#include "DeviceOrientationEvent.h" #endif -#if ENABLE(SVG) -#include "SVGDocumentExtensions.h" -#include "SVGElementFactory.h" -#include "SVGNames.h" -#include "SVGSVGElement.h" +#if ENABLE(FULLSCREEN_API) +#include "RenderFullScreen.h" #endif -#if ENABLE(TOUCH_EVENTS) -#include "TouchList.h" +#if ENABLE(INDEXED_DATABASE) +#include "IDBConnectionProxy.h" +#include "IDBOpenDBRequest.h" #endif #if PLATFORM(IOS) @@ -198,29 +240,35 @@ #include "MathMLNames.h" #endif -#if ENABLE(FULLSCREEN_API) -#include "RenderFullScreen.h" +#if ENABLE(MEDIA_SESSION) +#include "MediaSession.h" #endif -#if ENABLE(REQUEST_ANIMATION_FRAME) -#include "RequestAnimationFrameCallback.h" -#include "ScriptedAnimationController.h" +#if USE(QUICK_LOOK) +#include "QuickLook.h" #endif -#if ENABLE(IOS_TEXT_AUTOSIZING) -#include "TextAutoSizing.h" +#if ENABLE(TOUCH_EVENTS) +#include "TouchEvent.h" +#include "TouchList.h" #endif -#if ENABLE(TEXT_AUTOSIZING) -#include "TextAutosizer.h" +#if ENABLE(VIDEO_TRACK) +#include "CaptionUserPreferences.h" #endif -#if ENABLE(CSP_NEXT) -#include "DOMSecurityPolicy.h" +#if ENABLE(WEB_REPLAY) +#include "WebReplayInputs.h" +#include +#include #endif -#if ENABLE(VIDEO_TRACK) -#include "CaptionUserPreferences.h" +#if ENABLE(WIRELESS_PLAYBACK_TARGET) +#include "MediaPlaybackTargetClient.h" +#endif + +#if ENABLE(XSLT) +#include "XSLTProcessor.h" #endif using namespace WTF; @@ -230,9 +278,8 @@ namespace WebCore { using namespace HTMLNames; -// #define INSTRUMENT_LAYOUT_SCHEDULING 1 - static const unsigned cMaxWriteRecursionDepth = 21; +bool Document::hasEverCreatedAnAXObjectCache = false; // DOM Level 2 says (letters added): // @@ -305,27 +352,14 @@ static inline bool isValidNamePart(UChar32 c) return true; } -static bool shouldInheritSecurityOriginFromOwner(const URL& url) -{ - // http://www.whatwg.org/specs/web-apps/current-work/#origin-0 - // - // If a Document has the address "about:blank" - // The origin of the Document is the origin it was assigned when its browsing context was created. - // - // Note: We generalize this to all "blank" URLs and invalid URLs because we - // treat all of these URLs as about:blank. - // - return url.isEmpty() || url.isBlankURL(); -} - static Widget* widgetForElement(Element* focusedElement) { if (!focusedElement) return nullptr; - auto renderer = focusedElement->renderer(); - if (!renderer || !renderer->isWidget()) + auto* renderer = focusedElement->renderer(); + if (!is(renderer)) return nullptr; - return toRenderWidget(renderer)->widget(); + return downcast(*renderer).widget(); } static bool acceptsEditingFocus(Node* node) @@ -338,31 +372,31 @@ static bool acceptsEditingFocus(Node* node) if (!frame || !root) return false; - return frame->editor().shouldBeginEditing(rangeOfContents(*root).get()); + return frame->editor().shouldBeginEditing(rangeOfContents(*root).ptr()); } -static bool canAccessAncestor(const SecurityOrigin* activeSecurityOrigin, Frame* targetFrame) +static bool canAccessAncestor(const SecurityOrigin& activeSecurityOrigin, Frame* targetFrame) { // targetFrame can be 0 when we're trying to navigate a top-level frame // that has a 0 opener. if (!targetFrame) return false; - const bool isLocalActiveOrigin = activeSecurityOrigin->isLocal(); + const bool isLocalActiveOrigin = activeSecurityOrigin.isLocal(); for (Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ancestorFrame->tree().parent()) { Document* ancestorDocument = ancestorFrame->document(); // FIXME: Should be an ASSERT? Frames should alway have documents. if (!ancestorDocument) return true; - const SecurityOrigin* ancestorSecurityOrigin = ancestorDocument->securityOrigin(); - if (activeSecurityOrigin->canAccess(ancestorSecurityOrigin)) + const SecurityOrigin& ancestorSecurityOrigin = ancestorDocument->securityOrigin(); + if (activeSecurityOrigin.canAccess(ancestorSecurityOrigin)) return true; // Allow file URL descendant navigation even when allowFileAccessFromFileURLs is false. // FIXME: It's a bit strange to special-case local origins here. Should we be doing // something more general instead? - if (isLocalActiveOrigin && ancestorSecurityOrigin->isLocal()) + if (isLocalActiveOrigin && ancestorSecurityOrigin.isLocal()) return true; } @@ -377,73 +411,73 @@ static void printNavigationErrorMessage(Frame* frame, const URL& activeURL, cons frame->document()->domWindow()->printErrorMessage(message); } -uint64_t Document::s_globalTreeVersion = 0; - -static const double timeBeforeThrowingAwayStyleResolverAfterLastUseInSeconds = 30; +#if ENABLE(TEXT_AUTOSIZING) -#if ENABLE(IOS_TEXT_AUTOSIZING) void TextAutoSizingTraits::constructDeletedValue(TextAutoSizingKey& slot) { - new (&slot) TextAutoSizingKey(TextAutoSizingKey::deletedKeyStyle(), TextAutoSizingKey::deletedKeyDoc()); + new (NotNull, &slot) TextAutoSizingKey(TextAutoSizingKey::Deleted); } bool TextAutoSizingTraits::isDeletedValue(const TextAutoSizingKey& value) { - return value.style() == TextAutoSizingKey::deletedKeyStyle() && value.doc() == TextAutoSizingKey::deletedKeyDoc(); + return value.isDeleted(); } + #endif +uint64_t Document::s_globalTreeVersion = 0; + +HashSet& Document::allDocuments() +{ + static NeverDestroyed> documents; + return documents; +} + Document::Document(Frame* frame, const URL& url, unsigned documentClasses, unsigned constructionFlags) - : ContainerNode(nullptr, CreateDocument) - , TreeScope(this) -#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS) - , m_handlingTouchEvent(false) - , m_touchEventRegionsDirty(false) - , m_touchEventsChangedTimer(this, &Document::touchEventsChangedTimerFired) + : ContainerNode(*this, CreateDocument) + , TreeScope(*this) + , FrameDestructionObserver(frame) +#if ENABLE(IOS_TOUCH_EVENTS) + , m_touchEventsChangedTimer(*this, &Document::touchEventsChangedTimerFired) #endif - , m_styleResolverThrowawayTimer(this, &Document::styleResolverThrowawayTimerFired, timeBeforeThrowingAwayStyleResolverAfterLastUseInSeconds) - , m_didCalculateStyleResolver(false) + , m_referencingNodeCount(0) + , m_settings(frame ? Ref(frame->settings()) : Settings::create(nullptr)) , m_hasNodesWithPlaceholderStyle(false) - , m_needsNotifyRemoveAllPendingStylesheet(false) , m_ignorePendingStylesheets(false) , m_pendingSheetLayout(NoLayoutWithPendingSheets) - , m_frame(frame) + , m_cachedResourceLoader(m_frame ? Ref(m_frame->loader().activeDocumentLoader()->cachedResourceLoader()) : CachedResourceLoader::create(nullptr)) , m_activeParserCount(0) , m_wellFormed(false) , m_printing(false) , m_paginatedForScreen(false) - , m_ignoreAutofocus(false) - , m_compatibilityMode(NoQuirksMode) + , m_compatibilityMode(DocumentCompatibilityMode::NoQuirksMode) , m_compatibilityModeLocked(false) , m_textColor(Color::black) , m_domTreeVersion(++s_globalTreeVersion) , m_listenerTypes(0) , m_mutationObserverTypes(0) - , m_styleSheetCollection(*this) - , m_visitedLinkState(VisitedLinkState::create(*this)) + , m_styleScope(std::make_unique(*this)) + , m_extensionStyleSheets(std::make_unique(*this)) + , m_visitedLinkState(std::make_unique(*this)) , m_visuallyOrdered(false) , m_readyState(Complete) , m_bParsing(false) - , m_optimizedStyleSheetUpdateTimer(this, &Document::optimizedStyleSheetUpdateTimerFired) - , m_styleRecalcTimer(this, &Document::styleRecalcTimerFired) + , m_styleRecalcTimer(*this, &Document::updateStyleIfNeeded) , m_pendingStyleRecalcShouldForce(false) , m_inStyleRecalc(false) , m_closeAfterStyleRecalc(false) , m_gotoAnchorNeededAfterStylesheetsLoad(false) , m_frameElementsShouldIgnoreScrolling(false) - , m_containsValidityStyleRules(false) - , m_updateFocusAppearanceRestoresSelection(false) - , m_ignoreDestructiveWriteCount(0) - , m_titleSetExplicitly(false) - , m_markers(adoptPtr(new DocumentMarkerController)) - , m_updateFocusAppearanceTimer(this, &Document::updateFocusAppearanceTimerFired) - , m_resetHiddenFocusElementTimer(this, &Document::resetHiddenFocusElementTimer) + , m_updateFocusAppearanceRestoresSelection(SelectionRestorationMode::SetDefault) + , m_markers(std::make_unique(*this)) + , m_updateFocusAppearanceTimer(*this, &Document::updateFocusAppearanceTimerFired) , m_cssTarget(nullptr) , m_processingLoadEvent(false) , m_loadEventFinished(false) - , m_startTime(std::chrono::steady_clock::now()) + , m_documentCreationTime(MonotonicTime::now()) , m_overMinimumLayoutThreshold(false) , m_scriptRunner(std::make_unique(*this)) + , m_moduleLoader(std::make_unique(*this)) , m_xmlVersion(ASCIILiteral("1.0")) , m_xmlStandalone(StandaloneUnspecified) , m_hasXMLDeclaration(false) @@ -453,56 +487,61 @@ Document::Document(Frame* frame, const URL& url, unsigned documentClasses, unsig , m_annotatedRegionsDirty(false) #endif , m_createRenderers(true) - , m_inPageCache(false) , m_accessKeyMapValid(false) , m_documentClasses(documentClasses) , m_isSynthesized(constructionFlags & Synthesized) , m_isNonRenderedPlaceholder(constructionFlags & NonRenderedPlaceholder) - , m_isViewSource(false) , m_sawElementsInKnownNamespaces(false) , m_isSrcdocDocument(false) , m_eventQueue(*this) , m_weakFactory(this) - , m_idAttributeName(idAttr) #if ENABLE(FULLSCREEN_API) , m_areKeysEnabledInFullScreen(0) , m_fullScreenRenderer(nullptr) - , m_fullScreenChangeDelayTimer(this, &Document::fullScreenChangeDelayTimerFired) + , m_fullScreenChangeDelayTimer(*this, &Document::fullScreenChangeDelayTimerFired) , m_isAnimatingFullScreen(false) #endif , m_loadEventDelayCount(0) - , m_loadEventDelayTimer(this, &Document::loadEventDelayTimerFired) - , m_referrerPolicy(ReferrerPolicyDefault) - , m_directionSetOnDocumentElement(false) - , m_writingModeSetOnDocumentElement(false) + , m_loadEventDelayTimer(*this, &Document::loadEventDelayTimerFired) + , m_referrerPolicy(ReferrerPolicy::Default) , m_writeRecursionIsTooDeep(false) , m_writeRecursionDepth(0) - , m_wheelEventHandlerCount(0) , m_lastHandledUserGestureTimestamp(0) #if PLATFORM(IOS) #if ENABLE(DEVICE_ORIENTATION) - , m_deviceMotionClient(DeviceMotionClientIOS::create()) - , m_deviceMotionController(DeviceMotionController::create(m_deviceMotionClient.get())) - , m_deviceOrientationClient(DeviceOrientationClientIOS::create()) - , m_deviceOrientationController(DeviceOrientationController::create(m_deviceOrientationClient.get())) + , m_deviceMotionClient(std::make_unique()) + , m_deviceMotionController(std::make_unique(m_deviceMotionClient.get())) + , m_deviceOrientationClient(std::make_unique()) + , m_deviceOrientationController(std::make_unique(m_deviceOrientationClient.get())) +#endif #endif +#if ENABLE(TELEPHONE_NUMBER_DETECTION) , m_isTelephoneNumberParsingAllowed(true) #endif - , m_pendingTasksTimer(this, &Document::pendingTasksTimerFired) + , m_pendingTasksTimer(*this, &Document::pendingTasksTimerFired) , m_scheduledTasksAreSuspended(false) , m_visualUpdatesAllowed(true) - , m_visualUpdatesSuppressionTimer(this, &Document::visualUpdatesSuppressionTimerFired) - , m_sharedObjectPoolClearTimer(this, &Document::sharedObjectPoolClearTimerFired) + , m_visualUpdatesSuppressionTimer(*this, &Document::visualUpdatesSuppressionTimerFired) + , m_sharedObjectPoolClearTimer(*this, &Document::clearSharedObjectPool) #ifndef NDEBUG , m_didDispatchViewportPropertiesChanged(false) #endif -#if ENABLE(TEMPLATE_ELEMENT) , m_templateDocumentHost(nullptr) + , m_fontSelector(CSSFontSelector::create(*this)) +#if ENABLE(WEB_REPLAY) + , m_inputCursor(EmptyInputCursor::create()) #endif - , m_didAssociateFormControlsTimer(this, &Document::didAssociateFormControlsTimerFired) + , m_didAssociateFormControlsTimer(*this, &Document::didAssociateFormControlsTimerFired) + , m_cookieCacheExpiryTimer(*this, &Document::invalidateDOMCookieCache) + , m_disabledFieldsetElementsCount(0) , m_hasInjectedPlugInsScript(false) - , m_renderTreeBeingDestroyed(false) + , m_hasStyleWithViewportUnits(false) +#if ENABLE(WEB_SOCKETS) + , m_socketProvider(page() ? &page()->socketProvider() : nullptr) +#endif { + allDocuments().add(this); + // We depend on the url getting immediately set in subframes, but we // also depend on the url NOT getting immediately set in opened windows. // See fast/dom/early-frame-url.html @@ -511,16 +550,8 @@ Document::Document(Frame* frame, const URL& url, unsigned documentClasses, unsig if ((frame && frame->ownerElement()) || !url.isEmpty()) setURL(url); - if (m_frame) - m_cachedResourceLoader = &m_frame->loader().activeDocumentLoader()->cachedResourceLoader(); - if (!m_cachedResourceLoader) - m_cachedResourceLoader = CachedResourceLoader::create(nullptr); m_cachedResourceLoader->setDocument(this); -#if ENABLE(TEXT_AUTOSIZING) - m_textAutosizer = TextAutosizer::create(this); -#endif - resetLinkColor(); resetVisitedLinkColor(); resetActiveLinkColor(); @@ -528,23 +559,14 @@ Document::Document(Frame* frame, const URL& url, unsigned documentClasses, unsig initSecurityContext(); initDNSPrefetch(); - for (unsigned i = 0; i < WTF_ARRAY_LENGTH(m_nodeListAndCollectionCounts); ++i) - m_nodeListAndCollectionCounts[i] = 0; - - InspectorCounters::incrementCounter(InspectorCounters::DocumentCounter); -} + m_fontSelector->registerForInvalidationCallbacks(*this); -static void histogramMutationEventUsage(const unsigned short& listenerTypes) -{ - HistogramSupport::histogramEnumeration("DOMAPI.PerDocumentMutationEventUsage.DOMSubtreeModified", static_cast(listenerTypes & Document::DOMSUBTREEMODIFIED_LISTENER), 2); - HistogramSupport::histogramEnumeration("DOMAPI.PerDocumentMutationEventUsage.DOMNodeInserted", static_cast(listenerTypes & Document::DOMNODEINSERTED_LISTENER), 2); - HistogramSupport::histogramEnumeration("DOMAPI.PerDocumentMutationEventUsage.DOMNodeRemoved", static_cast(listenerTypes & Document::DOMNODEREMOVED_LISTENER), 2); - HistogramSupport::histogramEnumeration("DOMAPI.PerDocumentMutationEventUsage.DOMNodeRemovedFromDocument", static_cast(listenerTypes & Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER), 2); - HistogramSupport::histogramEnumeration("DOMAPI.PerDocumentMutationEventUsage.DOMNodeInsertedIntoDocument", static_cast(listenerTypes & Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER), 2); - HistogramSupport::histogramEnumeration("DOMAPI.PerDocumentMutationEventUsage.DOMCharacterDataModified", static_cast(listenerTypes & Document::DOMCHARACTERDATAMODIFIED_LISTENER), 2); + for (auto& nodeListAndCollectionCount : m_nodeListAndCollectionCounts) + nodeListAndCollectionCount = 0; } #if ENABLE(FULLSCREEN_API) + static bool isAttributeOnAllOwners(const WebCore::QualifiedName& attribute, const WebCore::QualifiedName& prefixedAttribute, const HTMLFrameOwnerElement* owner) { if (!owner) @@ -555,32 +577,42 @@ static bool isAttributeOnAllOwners(const WebCore::QualifiedName& attribute, cons } while ((owner = owner->document().ownerElement())); return true; } + #endif +Ref Document::create(Document& contextDocument) +{ + auto document = adoptRef(*new Document(nullptr, URL())); + document->setContextDocument(contextDocument); + document->setSecurityOriginPolicy(contextDocument.securityOriginPolicy()); + return document; +} + Document::~Document() { + allDocuments().remove(this); + ASSERT(!renderView()); - ASSERT(!m_inPageCache); + ASSERT(m_pageCacheState != InPageCache); ASSERT(m_ranges.isEmpty()); ASSERT(!m_parentTreeScope); + ASSERT(!m_disabledFieldsetElementsCount); + ASSERT(m_inDocumentShadowRoots.isEmpty()); #if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS) m_deviceMotionClient->deviceMotionControllerDestroyed(); m_deviceOrientationClient->deviceOrientationControllerDestroyed(); #endif - -#if ENABLE(TEMPLATE_ELEMENT) + if (m_templateDocument) m_templateDocument->setTemplateDocumentHost(nullptr); // balanced in templateDocument(). -#endif // FIXME: Should we reset m_domWindow when we detach from the Frame? if (m_domWindow) - m_domWindow->resetUnlessSuspendedForPageCache(); + m_domWindow->resetUnlessSuspendedForDocumentSuspension(); m_scriptRunner = nullptr; - - histogramMutationEventUsage(m_listenerTypes); + m_moduleLoader = nullptr; removeAllEventListeners(); @@ -601,18 +633,22 @@ Document::~Document() if (m_styleSheetList) m_styleSheetList->detachFromDocument(); - if (m_elementSheet) - m_elementSheet->detachFromDocument(); - m_styleSheetCollection.detachFromDocument(); + extensionStyleSheets().detachFromDocument(); - clearStyleResolver(); // We need to destroy CSSFontSelector before destroying m_cachedResourceLoader. + styleScope().clearResolver(); // We need to destroy CSSFontSelector before destroying m_cachedResourceLoader. + m_fontSelector->clearDocument(); + m_fontSelector->unregisterForInvalidationCallbacks(*this); // It's possible for multiple Documents to end up referencing the same CachedResourceLoader (e.g., SVGImages // load the initial empty document and the SVGDocument with the same DocumentLoader). if (m_cachedResourceLoader->document() == this) m_cachedResourceLoader->setDocument(nullptr); - m_cachedResourceLoader.clear(); +#if ENABLE(VIDEO) + if (auto* platformMediaSessionManager = PlatformMediaSessionManager::sharedManagerIfExists()) + platformMediaSessionManager->stopAllMediaPlaybackForDocument(this); +#endif + // We must call clearRareData() here since a Document class inherits TreeScope // as well as Node. See a comment on TreeScope.h for the reason. if (hasRareData()) @@ -623,56 +659,68 @@ Document::~Document() for (unsigned i = 0; i < WTF_ARRAY_LENGTH(m_nodeListAndCollectionCounts); ++i) ASSERT(!m_nodeListAndCollectionCounts[i]); - - clearDocumentScope(); - - InspectorCounters::decrementCounter(InspectorCounters::DocumentCounter); } -void Document::dropChildren() +void Document::removedLastRef() { ASSERT(!m_deletionHasBegun); - - // We must make sure not to be retaining any of our children through - // these extra pointers or we will create a reference cycle. - m_focusedElement = nullptr; - m_hoveredElement = nullptr; - m_activeElement = nullptr; - m_titleElement = nullptr; - m_documentElement = nullptr; - m_userActionElements.documentDidRemoveLastRef(); + if (m_referencingNodeCount) { + // If removing a child removes the last node reference, we don't want the scope to be destroyed + // until after removeDetachedChildren returns, so we protect ourselves. + incrementReferencingNodeCount(); + + RELEASE_ASSERT(!hasLivingRenderTree()); + // We must make sure not to be retaining any of our children through + // these extra pointers or we will create a reference cycle. + m_focusedElement = nullptr; + m_hoveredElement = nullptr; + m_activeElement = nullptr; + m_titleElement = nullptr; + m_documentElement = nullptr; + m_focusNavigationStartingNode = nullptr; + m_userActionElements.documentDidRemoveLastRef(); #if ENABLE(FULLSCREEN_API) - m_fullScreenElement = nullptr; - m_fullScreenElementStack.clear(); + m_fullScreenElement = nullptr; + m_fullScreenElementStack.clear(); #endif + m_associatedFormControls.clear(); - detachParser(); - - // removeDetachedChildren() doesn't always unregister IDs, - // so tear down scope information up front to avoid having - // stale references in the map. + detachParser(); - destroyTreeScopeData(); - removeDetachedChildren(); - m_formController.clear(); + // removeDetachedChildren() doesn't always unregister IDs, + // so tear down scope information up front to avoid having + // stale references in the map. - m_markers->detach(); - - m_cssCanvasElements.clear(); + destroyTreeScopeData(); + removeDetachedChildren(); + m_formController = nullptr; + + m_markers->detach(); + + m_cssCanvasElements.clear(); + + commonTeardown(); - commonTeardown(); +#ifndef NDEBUG + // We need to do this right now since selfOnlyDeref() can delete this. + m_inRemovedLastRefFunction = false; +#endif + decrementReferencingNodeCount(); + } else { +#ifndef NDEBUG + m_inRemovedLastRefFunction = false; + m_deletionHasBegun = true; +#endif + delete this; + } } void Document::commonTeardown() { -#if ENABLE(SVG) if (svgExtensions()) - accessSVGExtensions()->pauseAnimations(); -#endif + accessSVGExtensions().pauseAnimations(); -#if ENABLE(REQUEST_ANIMATION_FRAME) clearScriptedAnimationController(); -#endif } Element* Document::getElementByAccessKey(const String& key) @@ -689,9 +737,8 @@ Element* Document::getElementByAccessKey(const String& key) void Document::buildAccessKeyMap(TreeScope* scope) { ASSERT(scope); - ContainerNode* rootNode = scope->rootNode(); - for (auto& element : descendantsOfType(*rootNode)) { - const AtomicString& accessKey = element.fastGetAttribute(accesskeyAttr); + for (auto& element : descendantsOfType(scope->rootNode())) { + const AtomicString& accessKey = element.attributeWithoutSynchronization(accesskeyAttr); if (!accessKey.isEmpty()) m_elementsByAccessKey.set(accessKey.impl(), &element); @@ -706,49 +753,55 @@ void Document::invalidateAccessKeyMap() m_elementsByAccessKey.clear(); } -void Document::addImageElementByLowercasedUsemap(const AtomicStringImpl& name, HTMLImageElement& element) +void Document::addImageElementByUsemap(const AtomicStringImpl& name, HTMLImageElement& element) { return m_imagesByUsemap.add(name, element, *this); } -void Document::removeImageElementByLowercasedUsemap(const AtomicStringImpl& name, HTMLImageElement& element) +void Document::removeImageElementByUsemap(const AtomicStringImpl& name, HTMLImageElement& element) { return m_imagesByUsemap.remove(name, element); } -HTMLImageElement* Document::imageElementByLowercasedUsemap(const AtomicStringImpl& name) const +HTMLImageElement* Document::imageElementByUsemap(const AtomicStringImpl& name) const { - return m_imagesByUsemap.getElementByLowercasedUsemap(name, *this); + return m_imagesByUsemap.getElementByUsemap(name, *this); } -SelectorQueryCache& Document::selectorQueryCache() +ExceptionOr Document::selectorQueryForString(const String& selectorString) { + if (selectorString.isEmpty()) + return Exception { SYNTAX_ERR }; if (!m_selectorQueryCache) - m_selectorQueryCache = adoptPtr(new SelectorQueryCache()); - return *m_selectorQueryCache; + m_selectorQueryCache = std::make_unique(); + return m_selectorQueryCache->add(selectorString, *this); +} + +void Document::clearSelectorQueryCache() +{ + m_selectorQueryCache = nullptr; } MediaQueryMatcher& Document::mediaQueryMatcher() { if (!m_mediaQueryMatcher) - m_mediaQueryMatcher = MediaQueryMatcher::create(this); + m_mediaQueryMatcher = MediaQueryMatcher::create(*this); return *m_mediaQueryMatcher; } -void Document::setCompatibilityMode(CompatibilityMode mode) +void Document::setCompatibilityMode(DocumentCompatibilityMode mode) { if (m_compatibilityModeLocked || mode == m_compatibilityMode) return; bool wasInQuirksMode = inQuirksMode(); m_compatibilityMode = mode; - if (m_selectorQueryCache) - m_selectorQueryCache->invalidate(); + clearSelectorQueryCache(); if (inQuirksMode() != wasInQuirksMode) { // All user stylesheets have to reparse using the different mode. - m_styleSheetCollection.clearPageUserSheet(); - m_styleSheetCollection.invalidateInjectedStyleSheetCache(); + extensionStyleSheets().clearPageUserSheet(); + extensionStyleSheets().invalidateInjectedStyleSheetCache(); } } @@ -769,19 +822,19 @@ void Document::resetVisitedLinkColor() void Document::resetActiveLinkColor() { - m_activeLinkColor.setNamedColor("red"); + m_activeLinkColor = Color(255, 0, 0); } -DOMImplementation* Document::implementation() +DOMImplementation& Document::implementation() { if (!m_implementation) - m_implementation = DOMImplementation::create(*this); - return m_implementation.get(); + m_implementation = std::make_unique(*this); + return *m_implementation; } bool Document::hasManifest() const { - return documentElement() && documentElement()->hasTagName(htmlTag) && documentElement()->hasAttribute(manifestAttr); + return documentElement() && documentElement()->hasTagName(htmlTag) && documentElement()->hasAttributeWithoutSynchronization(manifestAttr); } DocumentType* Document::doctype() const @@ -797,235 +850,188 @@ void Document::childrenChanged(const ChildChange& change) { ContainerNode::childrenChanged(change); - // NOTE: Per DOM, dynamically inserting/removing doctype nodes doesn't affect compatibility mode. - -#if ENABLE(LEGACY_VIEWPORT_ADAPTION) - // FIXME: It's a little strange to add these rules when a DocumentType with this prefix is added, - // but not remove these rules when a DocumentType with this prefix is removed. It seems this should - // be handled more the way the compatibility mode is, by fetching the doctype at the appropriate time, - // rather than by responding when a document type node is inserted. - if (DocumentType* documentType = doctype()) { - if (documentType->publicId().startsWith("-//wapforum//dtd xhtml mobile 1.", /* caseSensitive */ false)) - processViewport("width=device-width, height=device-height", ViewportArguments::XHTMLMobileProfile); - } -#endif + // FIXME: Chrome::didReceiveDocType() used to be called only when the doctype changed. We need to check the + // impact of calling this systematically. If the overhead is negligible, we need to rename didReceiveDocType, + // otherwise, we need to detect the doc type changes before updating the viewport. + if (Page* page = this->page()) + page->chrome().didReceiveDocType(*frame()); Element* newDocumentElement = childrenOfType(*this).first(); - if (newDocumentElement == m_documentElement) return; m_documentElement = newDocumentElement; // The root style used for media query matching depends on the document element. - clearStyleResolver(); + styleScope().clearResolver(); } -PassRefPtr Document::createElement(const AtomicString& name, ExceptionCode& ec) +static ALWAYS_INLINE Ref createUpgradeCandidateElement(Document& document, const QualifiedName& name) { - if (!isValidName(name)) { - ec = INVALID_CHARACTER_ERR; - return nullptr; + if (!RuntimeEnabledFeatures::sharedFeatures().customElementsEnabled() + || Document::validateCustomElementName(name.localName()) != CustomElementNameValidationStatus::Valid) + return HTMLUnknownElement::create(name, document); + + auto element = HTMLElement::create(name, document); + element->setIsCustomElementUpgradeCandidate(); + return element; +} + +static ALWAYS_INLINE Ref createUpgradeCandidateElement(Document& document, const AtomicString& localName) +{ + return createUpgradeCandidateElement(document, QualifiedName { nullAtom, localName, xhtmlNamespaceURI }); +} + +static inline bool isValidHTMLElementName(const AtomicString& localName) +{ + return Document::isValidName(localName); +} + +static inline bool isValidHTMLElementName(const QualifiedName& name) +{ + return Document::isValidName(name.localName()); +} + +template +static ExceptionOr> createHTMLElementWithNameValidation(Document& document, const NameType& name) +{ + auto element = HTMLElementFactory::createKnownElement(name, document); + if (LIKELY(element)) + return Ref { element.releaseNonNull() }; + + if (auto* window = document.domWindow()) { + auto* registry = window->customElementRegistry(); + if (UNLIKELY(registry)) { + if (auto* elementInterface = registry->findInterface(name)) + return elementInterface->constructElementWithFallback(document, name); + } } + if (UNLIKELY(!isValidHTMLElementName(name))) + return Exception { INVALID_CHARACTER_ERR }; + + return Ref { createUpgradeCandidateElement(document, name) }; +} + +ExceptionOr> Document::createElementForBindings(const AtomicString& name) +{ + if (isHTMLDocument()) + return createHTMLElementWithNameValidation(*this, name.convertToASCIILowercase()); + if (isXHTMLDocument()) - return HTMLElementFactory::createElement(QualifiedName(nullAtom, name, xhtmlNamespaceURI), *this); + return createHTMLElementWithNameValidation(*this, name); + + if (!isValidName(name)) + return Exception { INVALID_CHARACTER_ERR }; return createElement(QualifiedName(nullAtom, name, nullAtom), false); } -PassRefPtr Document::createDocumentFragment() +Ref Document::createDocumentFragment() { return DocumentFragment::create(document()); } -PassRefPtr Document::createTextNode(const String& data) +Ref Document::createTextNode(const String& data) { return Text::create(*this, data); } -PassRefPtr Document::createComment(const String& data) +Ref Document::createComment(const String& data) { return Comment::create(*this, data); } -PassRefPtr Document::createCDATASection(const String& data, ExceptionCode& ec) +ExceptionOr> Document::createCDATASection(const String& data) { - if (isHTMLDocument()) { - ec = NOT_SUPPORTED_ERR; - return nullptr; - } + if (isHTMLDocument()) + return Exception { NOT_SUPPORTED_ERR }; return CDATASection::create(*this, data); } -PassRefPtr Document::createProcessingInstruction(const String& target, const String& data, ExceptionCode& ec) +ExceptionOr> Document::createProcessingInstruction(const String& target, const String& data) { - if (!isValidName(target)) { - ec = INVALID_CHARACTER_ERR; - return nullptr; - } - if (isHTMLDocument()) { - ec = NOT_SUPPORTED_ERR; - return nullptr; - } - return ProcessingInstruction::create(*this, target, data); -} + if (!isValidName(target)) + return Exception { INVALID_CHARACTER_ERR }; -PassRefPtr Document::createEntityReference(const String& name, ExceptionCode& ec) -{ - if (!isValidName(name)) { - ec = INVALID_CHARACTER_ERR; - return nullptr; - } - if (isHTMLDocument()) { - ec = NOT_SUPPORTED_ERR; - return nullptr; - } - return EntityReference::create(*this, name); + if (data.contains("?>")) + return Exception { INVALID_CHARACTER_ERR }; + + return ProcessingInstruction::create(*this, target, data); } -PassRefPtr Document::createEditingTextNode(const String& text) +Ref Document::createEditingTextNode(const String& text) { return Text::createEditingText(*this, text); } -PassRefPtr Document::createCSSStyleDeclaration() +Ref Document::createCSSStyleDeclaration() { Ref propertySet(MutableStyleProperties::create()); - return propertySet->ensureCSSStyleDeclaration(); + return *propertySet->ensureCSSStyleDeclaration(); } -PassRefPtr Document::importNode(Node* importedNode, bool deep, ExceptionCode& ec) +ExceptionOr> Document::importNode(Node& nodeToImport, bool deep) { - ec = 0; - - if (!importedNode) { - ec = NOT_SUPPORTED_ERR; - return nullptr; - } - - switch (importedNode->nodeType()) { + switch (nodeToImport.nodeType()) { + case DOCUMENT_FRAGMENT_NODE: + if (nodeToImport.isShadowRoot()) + break; + FALLTHROUGH; + case ELEMENT_NODE: case TEXT_NODE: - return createTextNode(importedNode->nodeValue()); case CDATA_SECTION_NODE: - return createCDATASection(importedNode->nodeValue(), ec); - case ENTITY_REFERENCE_NODE: - return createEntityReference(importedNode->nodeName(), ec); case PROCESSING_INSTRUCTION_NODE: - return createProcessingInstruction(importedNode->nodeName(), importedNode->nodeValue(), ec); case COMMENT_NODE: - return createComment(importedNode->nodeValue()); - case ELEMENT_NODE: { - Element& oldElement = toElement(*importedNode); - // FIXME: The following check might be unnecessary. Is it possible that - // oldElement has mismatched prefix/namespace? - if (!hasValidNamespaceForElements(oldElement.tagQName())) { - ec = NAMESPACE_ERR; - return nullptr; - } - - RefPtr newElement = createElement(oldElement.tagQName(), false); - newElement->cloneDataFromElement(oldElement); - - if (deep) { - for (Node* oldChild = oldElement.firstChild(); oldChild; oldChild = oldChild->nextSibling()) { - RefPtr newChild = importNode(oldChild, true, ec); - if (ec) - return nullptr; - newElement->appendChild(newChild.release(), ec); - if (ec) - return nullptr; - } - } + return nodeToImport.cloneNodeInternal(document(), deep ? CloningOperation::Everything : CloningOperation::OnlySelf); - return newElement.release(); - } case ATTRIBUTE_NODE: - return Attr::create(*this, QualifiedName(nullAtom, toAttr(*importedNode).name(), nullAtom), toAttr(*importedNode).value()); - case DOCUMENT_FRAGMENT_NODE: { - if (importedNode->isShadowRoot()) { - // ShadowRoot nodes should not be explicitly importable. - // Either they are imported along with their host node, or created implicitly. - break; - } - DocumentFragment& oldFragment = toDocumentFragment(*importedNode); - RefPtr newFragment = createDocumentFragment(); - if (deep) { - for (Node* oldChild = oldFragment.firstChild(); oldChild; oldChild = oldChild->nextSibling()) { - RefPtr newChild = importNode(oldChild, true, ec); - if (ec) - return nullptr; - newFragment->appendChild(newChild.release(), ec); - if (ec) - return nullptr; - } - } - - return newFragment.release(); - } - case ENTITY_NODE: - case NOTATION_NODE: - // 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. - // Ability to add these imported nodes to a DocumentType will be considered for addition to a future release of the DOM. - case DOCUMENT_NODE: - case DOCUMENT_TYPE_NODE: - case XPATH_NAMESPACE_NODE: + // FIXME: This will "Attr::normalize" child nodes of Attr. + return Ref { Attr::create(*this, QualifiedName(nullAtom, downcast(nodeToImport).name(), nullAtom), downcast(nodeToImport).value()) }; + + case DOCUMENT_NODE: // Can't import a document into another document. + case DOCUMENT_TYPE_NODE: // FIXME: Support cloning a DocumentType node per DOM4. break; } - ec = NOT_SUPPORTED_ERR; - return nullptr; + + return Exception { NOT_SUPPORTED_ERR }; } -PassRefPtr Document::adoptNode(PassRefPtr source, ExceptionCode& ec) +ExceptionOr> Document::adoptNode(Node& source) { - if (!source) { - ec = NOT_SUPPORTED_ERR; - return nullptr; - } - - if (source->isReadOnlyNode()) { - ec = NO_MODIFICATION_ALLOWED_ERR; - return nullptr; - } - EventQueueScope scope; - switch (source->nodeType()) { - case ENTITY_NODE: - case NOTATION_NODE: + switch (source.nodeType()) { case DOCUMENT_NODE: - case DOCUMENT_TYPE_NODE: - case XPATH_NAMESPACE_NODE: - ec = NOT_SUPPORTED_ERR; - return nullptr; - case ATTRIBUTE_NODE: { - Attr& attr = toAttr(*source); - if (attr.ownerElement()) - attr.ownerElement()->removeAttributeNode(&attr, ec); + return Exception { NOT_SUPPORTED_ERR }; + case ATTRIBUTE_NODE: { + auto& attr = downcast(source); + if (auto* element = attr.ownerElement()) { + auto result = element->removeAttributeNode(attr); + if (result.hasException()) + return result.releaseException(); + } break; } default: - if (source->isShadowRoot()) { + if (source.isShadowRoot()) { // ShadowRoot cannot disconnect itself from the host node. - ec = HIERARCHY_REQUEST_ERR; - return nullptr; - } - if (source->isFrameOwnerElement()) { - HTMLFrameOwnerElement& frameOwnerElement = toHTMLFrameOwnerElement(*source); - if (frame() && frame()->tree().isDescendantOf(frameOwnerElement.contentFrame())) { - ec = HIERARCHY_REQUEST_ERR; - return nullptr; - } + return Exception { HIERARCHY_REQUEST_ERR }; } - if (source->parentNode()) { - source->parentNode()->removeChild(source.get(), ec); - if (ec) - return nullptr; + if (is(source)) { + auto& frameOwnerElement = downcast(source); + if (frame() && frame()->tree().isDescendantOf(frameOwnerElement.contentFrame())) + return Exception { HIERARCHY_REQUEST_ERR }; } + auto result = source.remove(); + if (result.hasException()) + return result.releaseException(); + ASSERT_WITH_SECURITY_IMPLICATION(!source.isConnected()); + ASSERT_WITH_SECURITY_IMPLICATION(!source.parentNode()); } - adoptIfNeeded(source.get()); + adoptIfNeeded(source); - return source; + return Ref { source }; } bool Document::hasValidNamespaceForElements(const QualifiedName& qName) @@ -1050,18 +1056,34 @@ bool Document::hasValidNamespaceForAttributes(const QualifiedName& qName) return hasValidNamespaceForElements(qName); } +static Ref createFallbackHTMLElement(Document& document, const QualifiedName& name) +{ + if (auto* window = document.domWindow()) { + auto* registry = window->customElementRegistry(); + if (UNLIKELY(registry)) { + if (auto* elementInterface = registry->findInterface(name)) { + auto element = HTMLElement::create(name, document); + element->enqueueToUpgrade(*elementInterface); + return element; + } + } + } + // FIXME: Should we also check the equality of prefix between the custom element and name? + return createUpgradeCandidateElement(document, name); +} + // FIXME: This should really be in a possible ElementFactory class. -PassRefPtr Document::createElement(const QualifiedName& name, bool createdByParser) +Ref Document::createElement(const QualifiedName& name, bool createdByParser) { RefPtr element; // FIXME: Use registered namespaces and look up in a hash to find the right factory. - if (name.namespaceURI() == xhtmlNamespaceURI) - element = HTMLElementFactory::createElement(name, *this, nullptr, createdByParser); -#if ENABLE(SVG) - else if (name.namespaceURI() == SVGNames::svgNamespaceURI) + if (name.namespaceURI() == xhtmlNamespaceURI) { + element = HTMLElementFactory::createKnownElement(name, *this, nullptr, createdByParser); + if (UNLIKELY(!element)) + element = createFallbackHTMLElement(*this, name); + } else if (name.namespaceURI() == SVGNames::svgNamespaceURI) element = SVGElementFactory::createElement(name, *this, createdByParser); -#endif #if ENABLE(MATHML) else if (name.namespaceURI() == MathMLNames::mathmlNamespaceURI) element = MathMLElementFactory::createElement(name, *this, createdByParser); @@ -1075,76 +1097,88 @@ PassRefPtr Document::createElement(const QualifiedName& name, bool crea // uses imgTag so we need a special rule. ASSERT((name.matches(imageTag) && element->tagQName().matches(imgTag) && element->tagQName().prefix() == name.prefix()) || name == element->tagQName()); - return element.release(); + return element.releaseNonNull(); } -bool Document::regionBasedColumnsEnabled() const +CustomElementNameValidationStatus Document::validateCustomElementName(const AtomicString& localName) { - return settings() && settings()->regionBasedColumnsEnabled(); -} + bool containsHyphen = false; + for (auto character : StringView(localName).codeUnits()) { + if (isASCIIUpper(character)) + return CustomElementNameValidationStatus::ContainsUpperCase; + if (character == '-') + containsHyphen = true; + } -bool Document::cssStickyPositionEnabled() const -{ - return settings() && settings()->cssStickyPositionEnabled(); -} + if (!containsHyphen) + return CustomElementNameValidationStatus::NoHyphen; -bool Document::cssRegionsEnabled() const -{ - return RuntimeEnabledFeatures::sharedFeatures().cssRegionsEnabled(); -} +#if ENABLE(MATHML) + const auto& annotationXmlLocalName = MathMLNames::annotation_xmlTag.localName(); +#else + static NeverDestroyed annotationXmlLocalName("annotation-xml", AtomicString::ConstructFromLiteral); +#endif -bool Document::cssCompositingEnabled() const -{ - return RuntimeEnabledFeatures::sharedFeatures().cssCompositingEnabled(); + if (localName == SVGNames::color_profileTag.localName() + || localName == SVGNames::font_faceTag.localName() + || localName == SVGNames::font_face_formatTag.localName() + || localName == SVGNames::font_face_nameTag.localName() + || localName == SVGNames::font_face_srcTag.localName() + || localName == SVGNames::font_face_uriTag.localName() + || localName == SVGNames::missing_glyphTag.localName() + || localName == annotationXmlLocalName) + return CustomElementNameValidationStatus::ConflictsWithBuiltinNames; + + return CustomElementNameValidationStatus::Valid; } -bool Document::cssGridLayoutEnabled() const +bool Document::isCSSGridLayoutEnabled() const { - return settings() && settings()->cssGridLayoutEnabled(); + return RuntimeEnabledFeatures::sharedFeatures().isCSSGridLayoutEnabled(); } #if ENABLE(CSS_REGIONS) -PassRefPtr Document::webkitGetNamedFlows() +RefPtr Document::webkitGetNamedFlows() { - if (!cssRegionsEnabled() || !renderView()) + if (!renderView()) return nullptr; updateStyleIfNeeded(); - return namedFlows()->createCSSOMSnapshot(); + return namedFlows().createCSSOMSnapshot(); } #endif -NamedFlowCollection* Document::namedFlows() +NamedFlowCollection& Document::namedFlows() { if (!m_namedFlows) m_namedFlows = NamedFlowCollection::create(this); - return m_namedFlows.get(); + return *m_namedFlows; } -PassRefPtr Document::createElementNS(const String& namespaceURI, const String& qualifiedName, ExceptionCode& ec) +ExceptionOr> Document::createElementNS(const AtomicString& namespaceURI, const String& qualifiedName) { - String prefix, localName; - if (!parseQualifiedName(qualifiedName, prefix, localName, ec)) - return nullptr; + auto parseResult = parseQualifiedName(namespaceURI, qualifiedName); + if (parseResult.hasException()) + return parseResult.releaseException(); + QualifiedName parsedName { parseResult.releaseReturnValue() }; + if (!hasValidNamespaceForElements(parsedName)) + return Exception { NAMESPACE_ERR }; - QualifiedName qName(prefix, localName, namespaceURI); - if (!hasValidNamespaceForElements(qName)) { - ec = NAMESPACE_ERR; - return nullptr; - } + if (parsedName.namespaceURI() == xhtmlNamespaceURI) + return createHTMLElementWithNameValidation(*this, parsedName); - return createElement(qName, false); + return createElement(parsedName, false); } String Document::readyState() const { - DEFINE_STATIC_LOCAL(const String, loading, (ASCIILiteral("loading"))); - DEFINE_STATIC_LOCAL(const String, interactive, (ASCIILiteral("interactive"))); - DEFINE_STATIC_LOCAL(const String, complete, (ASCIILiteral("complete"))); + static NeverDestroyed loading(ASCIILiteral("loading")); + static NeverDestroyed interactive(ASCIILiteral("interactive")); + static NeverDestroyed complete(ASCIILiteral("complete")); switch (m_readyState) { case Loading: @@ -1168,15 +1202,15 @@ void Document::setReadyState(ReadyState readyState) switch (readyState) { case Loading: if (!m_documentTiming.domLoading) - m_documentTiming.domLoading = monotonicallyIncreasingTime(); + m_documentTiming.domLoading = MonotonicTime::now(); break; case Interactive: if (!m_documentTiming.domInteractive) - m_documentTiming.domInteractive = monotonicallyIncreasingTime(); + m_documentTiming.domInteractive = MonotonicTime::now(); break; case Complete: if (!m_documentTiming.domComplete) - m_documentTiming.domComplete = monotonicallyIncreasingTime(); + m_documentTiming.domComplete = MonotonicTime::now(); break; } #endif @@ -1184,13 +1218,13 @@ void Document::setReadyState(ReadyState readyState) m_readyState = readyState; dispatchEvent(Event::create(eventNames().readystatechangeEvent, false, false)); - if (settings() && settings()->suppressesIncrementalRendering()) + if (settings().suppressesIncrementalRendering()) setVisualUpdatesAllowed(readyState); } void Document::setVisualUpdatesAllowed(ReadyState readyState) { - ASSERT(settings() && settings()->suppressesIncrementalRendering()); + ASSERT(settings().suppressesIncrementalRendering()); switch (readyState) { case Loading: ASSERT(!m_visualUpdatesSuppressionTimer.isActive()); @@ -1224,7 +1258,7 @@ void Document::setVisualUpdatesAllowed(bool visualUpdatesAllowed) if (visualUpdatesAllowed) m_visualUpdatesSuppressionTimer.stop(); else - m_visualUpdatesSuppressionTimer.startOneShot(settings()->incrementalRenderingSuppressionTimeoutInSeconds()); + m_visualUpdatesSuppressionTimer.startOneShot(settings().incrementalRenderingSuppressionTimeoutInSeconds()); if (!visualUpdatesAllowed) return; @@ -1238,14 +1272,12 @@ void Document::setVisualUpdatesAllowed(bool visualUpdatesAllowed) if (frame()->isMainFrame()) { frameView->addPaintPendingMilestones(DidFirstPaintAfterSuppressedIncrementalRendering); if (page->requestedLayoutMilestones() & DidFirstLayoutAfterSuppressedIncrementalRendering) - frame()->loader().didLayout(DidFirstLayoutAfterSuppressedIncrementalRendering); + frame()->loader().didReachLayoutMilestone(DidFirstLayoutAfterSuppressedIncrementalRendering); } } -#if USE(ACCELERATED_COMPOSITING) if (view()) view()->updateCompositingLayersAfterLayout(); -#endif if (RenderView* renderView = this->renderView()) renderView->repaintViewAndCompositedLayers(); @@ -1254,7 +1286,7 @@ void Document::setVisualUpdatesAllowed(bool visualUpdatesAllowed) frame->loader().forcePageTransitionIfNeeded(); } -void Document::visualUpdatesSuppressionTimerFired(Timer&) +void Document::visualUpdatesSuppressionTimerFired() { ASSERT(!m_visualUpdatesAllowed); @@ -1275,18 +1307,19 @@ void Document::setVisualUpdatesAllowedByClient(bool visualUpdatesAllowedByClient setVisualUpdatesAllowed(true); } -String Document::encoding() const +String Document::characterSetWithUTF8Fallback() const { - if (TextResourceDecoder* d = decoder()) - return d->encoding().domName(); - return String(); + AtomicString name = encoding(); + if (!name.isNull()) + return name; + return UTF8Encoding().domName(); } -String Document::defaultCharset() const +String Document::defaultCharsetForLegacyBindings() const { - if (Settings* settings = this->settings()) - return settings->defaultTextEncodingName(); - return String(); + if (!frame()) + UTF8Encoding().domName(); + return settings().defaultTextEncodingName(); } void Document::setCharset(const String& charset) @@ -1303,31 +1336,20 @@ void Document::setContentLanguage(const String& language) m_contentLanguage = language; // Recalculate style so language is used when selecting the initial font. - styleResolverChanged(DeferRecalcStyle); + m_styleScope->didChangeStyleSheetEnvironment(); } -void Document::setXMLVersion(const String& version, ExceptionCode& ec) +ExceptionOr Document::setXMLVersion(const String& version) { - if (!implementation()->hasFeature("XML", String())) { - ec = NOT_SUPPORTED_ERR; - return; - } - - if (!XMLDocumentParser::supportsXMLVersion(version)) { - ec = NOT_SUPPORTED_ERR; - return; - } + if (!XMLDocumentParser::supportsXMLVersion(version)) + return Exception { NOT_SUPPORTED_ERR }; m_xmlVersion = version; + return { }; } -void Document::setXMLStandalone(bool standalone, ExceptionCode& ec) +void Document::setXMLStandalone(bool standalone) { - if (!implementation()->hasFeature("XML", String())) { - ec = NOT_SUPPORTED_ERR; - return; - } - m_xmlStandalone = standalone ? Standalone : NotStandalone; } @@ -1338,11 +1360,6 @@ void Document::setDocumentURI(const String& uri) updateBaseURL(); } -URL Document::baseURI() const -{ - return m_baseURL; -} - void Document::setContent(const String& content) { open(); @@ -1369,99 +1386,102 @@ String Document::suggestedMIMEType() const return String(); } -Element* Document::elementFromPoint(int x, int y) const +void Document::overrideMIMEType(const String& mimeType) { - if (!hasLivingRenderTree()) - return nullptr; + m_overriddenMIMEType = mimeType; +} + +String Document::contentType() const +{ + if (!m_overriddenMIMEType.isNull()) + return m_overriddenMIMEType; + + if (DocumentLoader* documentLoader = loader()) + return documentLoader->currentContentType(); - return TreeScope::elementFromPoint(x, y); + String mimeType = suggestedMIMEType(); + if (!mimeType.isNull()) + return mimeType; + + return ASCIILiteral("application/xml"); +} + +RefPtr Document::caretRangeFromPoint(int x, int y) +{ + return caretRangeFromPoint(LayoutPoint(x, y)); } -PassRefPtr Document::caretRangeFromPoint(int x, int y) +RefPtr Document::caretRangeFromPoint(const LayoutPoint& clientPoint) { if (!hasLivingRenderTree()) return nullptr; + LayoutPoint localPoint; - Node* node = nodeFromPoint(this, x, y, &localPoint); + Node* node = nodeFromPoint(clientPoint, &localPoint); if (!node) return nullptr; - Node* shadowAncestorNode = ancestorInThisScope(node); - if (shadowAncestorNode != node) { - unsigned offset = shadowAncestorNode->nodeIndex(); - ContainerNode* container = shadowAncestorNode->parentNode(); - return Range::create(*this, container, offset, container, offset); - } - RenderObject* renderer = node->renderer(); if (!renderer) return nullptr; - VisiblePosition visiblePosition = renderer->positionForPoint(localPoint); - if (visiblePosition.isNull()) + Position rangeCompliantPosition = renderer->positionForPoint(localPoint).parentAnchoredEquivalent(); + if (rangeCompliantPosition.isNull()) return nullptr; - Position rangeCompliantPosition = visiblePosition.deepEquivalent().parentAnchoredEquivalent(); - return Range::create(*this, rangeCompliantPosition, rangeCompliantPosition); + unsigned offset = rangeCompliantPosition.offsetInContainerNode(); + node = &retargetToScope(*rangeCompliantPosition.containerNode()); + if (node != rangeCompliantPosition.containerNode()) + offset = 0; + + return Range::create(*this, node, offset, node, offset); } -/* - * Performs three operations: - * 1. Convert control characters to spaces - * 2. Trim leading and trailing spaces - * 3. Collapse internal whitespace. - */ -template -static inline StringWithDirection canonicalizedTitle(Document* document, const StringWithDirection& titleWithDirection) +Element* Document::scrollingElement() { - const String& title = titleWithDirection.string(); - const CharacterType* characters = title.getCharacters(); - unsigned length = title.length(); - unsigned i; + // FIXME: When we fix https://bugs.webkit.org/show_bug.cgi?id=106133, this should be replaced with the full implementation + // of Document.scrollingElement() as specified at http://dev.w3.org/csswg/cssom-view/#dom-document-scrollingelement. - StringBuffer buffer(length); - unsigned builderIndex = 0; + return body(); +} - // Skip leading spaces and leading characters that would convert to spaces - for (i = 0; i < length; ++i) { - CharacterType c = characters[i]; - if (!(c <= 0x20 || c == 0x7F)) - break; - } +template static inline String canonicalizedTitle(Document& document, const String& title) +{ + // FIXME: Compiling a separate copy of this for LChar and UChar is likely unnecessary. + // FIXME: Missing an optimized case for when title is fine as-is. This unnecessarily allocates + // and keeps around a new copy, and it's even the less optimal type of StringImpl with a separate buffer. + // Could probably just use StringBuilder instead. - if (i == length) - return StringWithDirection(); + auto* characters = title.characters(); + unsigned length = title.length(); - // Replace control characters with spaces, and backslashes with currency symbols, and collapse whitespace. - bool previousCharWasWS = false; - for (; i < length; ++i) { - CharacterType c = characters[i]; - if (c <= 0x20 || c == 0x7F || (U_GET_GC_MASK(c) & (U_GC_ZL_MASK | U_GC_ZP_MASK))) { - if (previousCharWasWS) - continue; - buffer[builderIndex++] = ' '; - previousCharWasWS = true; - } else { - buffer[builderIndex++] = c; - previousCharWasWS = false; - } - } + StringBuffer buffer { length }; + unsigned bufferLength = 0; - // Strip trailing spaces - while (builderIndex > 0) { - --builderIndex; - if (buffer[builderIndex] != ' ') - break; - } + auto* decoder = document.decoder(); + auto backslashAsCurrencySymbol = decoder ? decoder->encoding().backslashAsCurrencySymbol() : '\\'; - if (!builderIndex && buffer[builderIndex] == ' ') - return StringWithDirection(); - - buffer.shrink(builderIndex + 1); + // Collapse runs of HTML spaces into single space characters. + // Strip leading and trailing spaces. + // Replace backslashes with currency symbols. + bool previousCharacterWasHTMLSpace = false; + for (unsigned i = 0; i < length; ++i) { + auto character = characters[i]; + if (isHTMLSpace(character)) + previousCharacterWasHTMLSpace = true; + else { + if (character == '\\') + character = backslashAsCurrencySymbol; + if (previousCharacterWasHTMLSpace && bufferLength) + buffer[bufferLength++] = ' '; + buffer[bufferLength++] = character; + previousCharacterWasHTMLSpace = false; + } + } + if (!bufferLength) + return { }; - // Replace the backslashes with currency symbols if the encoding requires it. - document->displayBufferModifiedByEncoding(buffer.characters(), buffer.length()); - - return StringWithDirection(String::adopt(buffer), titleWithDirection.direction()); + buffer.shrink(bufferLength); + return String::adopt(WTFMove(buffer)); } void Document::updateTitle(const StringWithDirection& title) @@ -1470,71 +1490,104 @@ void Document::updateTitle(const StringWithDirection& title) return; m_rawTitle = title; + m_title = title; - if (m_rawTitle.string().isEmpty()) - m_title = StringWithDirection(); - else { - if (m_rawTitle.string().is8Bit()) - m_title = canonicalizedTitle(this, m_rawTitle); + if (!m_title.string.isEmpty()) { + if (m_title.string.is8Bit()) + m_title.string = canonicalizedTitle(*this, m_title.string); else - m_title = canonicalizedTitle(this, m_rawTitle); + m_title.string = canonicalizedTitle(*this, m_title.string); } - if (DocumentLoader* loader = this->loader()) + + if (auto* loader = this->loader()) loader->setTitle(m_title); } +void Document::updateTitleFromTitleElement() +{ + if (!m_titleElement) { + updateTitle({ }); + return; + } + + if (is(*m_titleElement)) + updateTitle(downcast(*m_titleElement).textWithDirection()); + else if (is(*m_titleElement)) { + // FIXME: Does the SVG title element have a text direction? + updateTitle({ downcast(*m_titleElement).textContent(), LTR }); + } +} + void Document::setTitle(const String& title) { - // Title set by JavaScript -- overrides any title elements. - m_titleSetExplicitly = true; - if (!isHTMLDocument() && !isXHTMLDocument()) - m_titleElement = nullptr; - else if (!m_titleElement) { - if (HTMLElement* headElement = head()) { - m_titleElement = createElement(titleTag, false); - headElement->appendChild(m_titleElement, ASSERT_NO_EXCEPTION); + if (!m_titleElement) { + if (isHTMLDocument() || isXHTMLDocument()) { + auto* headElement = head(); + if (!headElement) + return; + m_titleElement = HTMLTitleElement::create(HTMLNames::titleTag, *this); + headElement->appendChild(*m_titleElement); + } else if (isSVGDocument()) { + auto* element = documentElement(); + if (!is(element)) + return; + m_titleElement = SVGTitleElement::create(SVGNames::titleTag, *this); + element->insertBefore(*m_titleElement, element->firstChild()); } + } else if (!isHTMLDocument() && !isXHTMLDocument() && !isSVGDocument()) { + // FIXME: What exactly is the point of this? This seems like a strange moment + // in time to demote something from being m_titleElement, when setting the + // value of the title attribute. Do we have test coverage for this? + m_titleElement = nullptr; } - // The DOM API has no method of specifying direction, so assume LTR. - updateTitle(StringWithDirection(title, LTR)); - - if (m_titleElement && isHTMLTitleElement(m_titleElement.get())) - toHTMLTitleElement(m_titleElement.get())->setText(title); + if (is(m_titleElement.get())) + downcast(*m_titleElement).setTextContent(title); + else if (is(m_titleElement.get())) + downcast(*m_titleElement).setTextContent(title); + else + updateTitle({ title, LTR }); } -void Document::setTitleElement(const StringWithDirection& title, Element* titleElement) +void Document::updateTitleElement(Element* newTitleElement) { - if (titleElement != m_titleElement) { - if (m_titleElement || m_titleSetExplicitly) { - // Only allow the first title element to change the title -- others have no effect. - return; - } - m_titleElement = titleElement; + if (is(documentElement())) + m_titleElement = childrenOfType(*documentElement()).first(); + else { + if (m_titleElement) { + if (isHTMLDocument() || isXHTMLDocument()) + m_titleElement = descendantsOfType(*this).first(); + } else + m_titleElement = newTitleElement; } - updateTitle(title); + updateTitleFromTitleElement(); +} + +void Document::titleElementAdded(Element& titleElement) +{ + if (m_titleElement == &titleElement) + return; + + updateTitleElement(&titleElement); } -void Document::removeTitle(Element* titleElement) +void Document::titleElementRemoved(Element& titleElement) { - if (m_titleElement != titleElement) + if (m_titleElement != &titleElement) return; - m_titleElement = nullptr; - m_titleSetExplicitly = false; + updateTitleElement(nullptr); +} - // Update title based on first title element in the head, if one exists. - if (HTMLElement* headElement = head()) { - if (auto firstTitle = childrenOfType(*headElement).first()) - setTitleElement(firstTitle->textWithDirection(), firstTitle); - } +void Document::titleElementTextChanged(Element& titleElement) +{ + if (m_titleElement != &titleElement) + return; - if (!m_titleElement) - updateTitle(StringWithDirection()); + updateTitleFromTitleElement(); } -#if ENABLE(PAGE_VISIBILITY_API) void Document::registerForVisibilityStateChangedCallbacks(Element* element) { m_visibilityStateCallbackElements.add(element); @@ -1548,44 +1601,49 @@ void Document::unregisterForVisibilityStateChangedCallbacks(Element* element) void Document::visibilityStateChanged() { dispatchEvent(Event::create(eventNames().visibilitychangeEvent, false, false)); - for (auto it = m_visibilityStateCallbackElements.begin(); it != m_visibilityStateCallbackElements.end(); ++it) - (*it)->visibilityStateChanged(); + for (auto* element : m_visibilityStateCallbackElements) + element->visibilityStateChanged(); } -PageVisibilityState Document::pageVisibilityState() const +auto Document::visibilityState() const -> VisibilityState { // The visibility of the document is inherited from the visibility of the // page. If there is no page associated with the document, we will assume // that the page is hidden, as specified by the spec: // http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html#dom-document-hidden if (!m_frame || !m_frame->page()) - return PageVisibilityStateHidden; + return VisibilityState::Hidden; return m_frame->page()->visibilityState(); } -String Document::visibilityState() const +bool Document::hidden() const { - return pageVisibilityStateString(pageVisibilityState()); + return visibilityState() != VisibilityState::Visible; } -bool Document::hidden() const +#if ENABLE(VIDEO) + +void Document::registerForAllowsMediaDocumentInlinePlaybackChangedCallbacks(HTMLMediaElement& element) { - return pageVisibilityState() != PageVisibilityStateVisible; + m_allowsMediaDocumentInlinePlaybackElements.add(&element); +} + +void Document::unregisterForAllowsMediaDocumentInlinePlaybackChangedCallbacks(HTMLMediaElement& element) +{ + m_allowsMediaDocumentInlinePlaybackElements.remove(&element); } -#endif -#if ENABLE(CSP_NEXT) -DOMSecurityPolicy* Document::securityPolicy() +void Document::allowsMediaDocumentInlinePlaybackChanged() { - if (!m_domSecurityPolicy) - m_domSecurityPolicy = DOMSecurityPolicy::create(this); - return m_domSecurityPolicy.get(); + for (auto* element : m_allowsMediaDocumentInlinePlaybackElements) + element->allowsMediaDocumentInlinePlaybackChanged(); } + #endif String Document::nodeName() const { - return "#document"; + return ASCIILiteral("#document"); } Node::NodeType Document::nodeType() const @@ -1596,7 +1654,7 @@ Node::NodeType Document::nodeType() const FormController& Document::formController() { if (!m_formController) - m_formController = FormController::create(); + m_formController = std::make_unique(); return *m_formController; } @@ -1624,34 +1682,19 @@ Page* Document::page() const return m_frame ? m_frame->page() : nullptr; } -Settings* Document::settings() const -{ - return m_frame ? &m_frame->settings() : nullptr; -} - -PassRefPtr Document::createRange() +Ref Document::createRange() { return Range::create(*this); } -PassRefPtr Document::createNodeIterator(Node* root, unsigned whatToShow, - PassRefPtr filter, bool expandEntityReferences, ExceptionCode& ec) +Ref Document::createNodeIterator(Node& root, unsigned long whatToShow, RefPtr&& filter, bool) { - if (!root) { - ec = NOT_SUPPORTED_ERR; - return nullptr; - } - return NodeIterator::create(root, whatToShow, filter, expandEntityReferences); + return NodeIterator::create(root, whatToShow, WTFMove(filter)); } -PassRefPtr Document::createTreeWalker(Node* root, unsigned whatToShow, - PassRefPtr filter, bool expandEntityReferences, ExceptionCode& ec) +Ref Document::createTreeWalker(Node& root, unsigned long whatToShow, RefPtr&& filter, bool) { - if (!root) { - ec = NOT_SUPPORTED_ERR; - return nullptr; - } - return TreeWalker::create(root, whatToShow, filter, expandEntityReferences); + return TreeWalker::create(root, whatToShow, WTFMove(filter)); } void Document::scheduleForcedStyleRecalc() @@ -1662,14 +1705,9 @@ void Document::scheduleForcedStyleRecalc() void Document::scheduleStyleRecalc() { - if (shouldDisplaySeamlesslyWithParent()) { - // When we're seamless, our parent document manages our style recalcs. - ownerElement()->setNeedsStyleRecalc(); - ownerElement()->document().scheduleStyleRecalc(); - return; - } + ASSERT(!m_renderView || !m_renderView->inHitTesting()); - if (m_styleRecalcTimer.isActive() || inPageCache()) + if (m_styleRecalcTimer.isActive() || pageCacheState() != NotInPageCache) return; ASSERT(childNeedsStyleRecalc() || m_pendingStyleRecalcShouldForce); @@ -1679,7 +1717,7 @@ void Document::scheduleStyleRecalc() m_styleRecalcTimer.startOneShot(0); - InspectorInstrumentation::didScheduleStyleRecalculation(this); + InspectorInstrumentation::didScheduleStyleRecalculation(*this); } void Document::unscheduleStyleRecalc() @@ -1700,11 +1738,6 @@ bool Document::hasPendingForcedStyleRecalc() const return m_styleRecalcTimer.isActive() && m_pendingStyleRecalcShouldForce; } -void Document::styleRecalcTimerFired(Timer&) -{ - updateStyleIfNeeded(); -} - void Document::recalcStyle(Style::Change change) { ASSERT(!view() || !view()->isPainting()); @@ -1714,13 +1747,17 @@ void Document::recalcStyle(Style::Change change) return; FrameView& frameView = m_renderView->frameView(); + Ref protect(frameView); if (frameView.isPainting()) return; if (m_inStyleRecalc) return; // Guard against re-entrancy. -dwh + TraceScope tracingScope(StyleRecalcStart, StyleRecalcEnd); + RenderView::RepaintRegionAccumulator repaintRegionAccumulator(renderView()); + AnimationUpdateBlock animationUpdateBlock(&m_frame->animation()); // FIXME: We should update style on our ancestor chain before proceeding (especially for seamless), // however doing so currently causes several tests to crash, as Frame::setDocument calls Document::attach @@ -1729,16 +1766,16 @@ void Document::recalcStyle(Style::Change change) // re-attaching our containing iframe, which when asked HTMLFrameElementBase::isURLAllowed // hits a null-dereference due to security code always assuming the document has a SecurityOrigin. - m_styleSheetCollection.flushPendingUpdates(); + styleScope().flushPendingUpdate(); - InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRecalculateStyle(this); + frameView.willRecalcStyle(); - if (m_elementSheet && m_elementSheet->contents().usesRemUnits()) - m_styleSheetCollection.setUsesRemUnit(true); + InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRecalculateStyle(*this); m_inStyleRecalc = true; + bool updatedCompositingLayers = false; { - PostAttachCallbackDisabler disabler(*this); + Style::PostResolutionCallbackDisabler disabler(*this); WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates; if (m_pendingStyleRecalcShouldForce) @@ -1747,23 +1784,38 @@ void Document::recalcStyle(Style::Change change) if (change == Style::Force) { // This may get set again during style resolve. m_hasNodesWithPlaceholderStyle = false; + + auto documentStyle = Style::resolveForDocument(*this); + + // Inserting the pictograph font at the end of the font fallback list is done by the + // font selector, so set a font selector if needed. + if (settings().fontFallbackPrefersPictographs()) + documentStyle.fontCascade().update(&fontSelector()); + + auto documentChange = Style::determineChange(documentStyle, m_renderView->style()); + if (documentChange != Style::NoChange) + renderView()->setStyle(WTFMove(documentStyle)); } - Style::resolveTree(*this, change); + Style::TreeResolver resolver(*this); + auto styleUpdate = resolver.resolve(change); -#if USE(ACCELERATED_COMPOSITING) - frameView.updateCompositingLayersAfterStyleChange(); -#endif + m_lastStyleUpdateSizeForTesting = styleUpdate ? styleUpdate->size() : 0; - clearNeedsStyleRecalc(); + setHasValidStyle(); clearChildNeedsStyleRecalc(); unscheduleStyleRecalc(); m_inStyleRecalc = false; - // Pseudo element removal and similar may only work with these flags still set. Reset them after the style recalc. - if (m_styleResolver) - m_styleSheetCollection.resetCSSFeatureFlags(); + if (styleUpdate) { + SetForScope inRenderTreeUpdate(m_inRenderTreeUpdate, true); + + RenderTreeUpdater updater(*this); + updater.commit(WTFMove(styleUpdate)); + } + + updatedCompositingLayers = frameView.updateCompositingLayersAfterStyleChange(); } // If we wanted to call implicitClose() during recalcStyle, do so now that we're finished. @@ -1771,17 +1823,39 @@ void Document::recalcStyle(Style::Change change) m_closeAfterStyleRecalc = false; implicitClose(); } + + ++m_styleRecalcCount; InspectorInstrumentation::didRecalculateStyle(cookie); + // Some animated images may now be inside the viewport due to style recalc, + // resume them if necessary if there is no layout pending. Otherwise, we'll + // check if they need to be resumed after layout. + if (updatedCompositingLayers && !frameView.needsLayout()) + frameView.viewportContentsChanged(); + + // Usually this is handled by post-layout. + if (!frameView.needsLayout()) + frameView.frame().selection().scheduleAppearanceUpdateAfterStyleChange(); + // As a result of the style recalculation, the currently hovered element might have been // detached (for example, by setting display:none in the :hover style), schedule another mouseMove event // to check if any other elements ended up under the mouse pointer due to re-layout. if (m_hoveredElement && !m_hoveredElement->renderer()) - frameView.frame().eventHandler().dispatchFakeMouseMoveEventSoon(); + frameView.frame().mainFrame().eventHandler().dispatchFakeMouseMoveEventSoon(); + + if (m_gotoAnchorNeededAfterStylesheetsLoad && !styleScope().hasPendingSheets()) + frameView.scrollToFragment(m_url); + + // FIXME: Ideally we would ASSERT(!needsStyleRecalc()) here but we have some cases where it is not true. +} - // Style change may reset the focus, e.g. display: none, visibility: hidden. - resetHiddenFocusElementSoon(); +bool Document::needsStyleRecalc() const +{ + if (pageCacheState() != NotInPageCache) + return false; + + return m_pendingStyleRecalcShouldForce || childNeedsStyleRecalc() || styleScope().hasPendingUpdate(); } void Document::updateStyleIfNeeded() @@ -1789,17 +1863,15 @@ void Document::updateStyleIfNeeded() ASSERT(isMainThread()); ASSERT(!view() || !view()->isPainting()); - if (!view() || view()->isInLayout()) + if (!view() || view()->isInRenderTreeLayout()) return; - if (m_optimizedStyleSheetUpdateTimer.isActive()) - styleResolverChanged(RecalcStyleIfNeeded); + styleScope().flushPendingUpdate(); - if ((!m_pendingStyleRecalcShouldForce && !childNeedsStyleRecalc()) || inPageCache()) + if (!needsStyleRecalc()) return; - AnimationUpdateBlock animationUpdateBlock(m_frame ? &m_frame->animation() : nullptr); - recalcStyle(Style::NoChange); + recalcStyle(); } void Document::updateLayout() @@ -1807,7 +1879,7 @@ void Document::updateLayout() ASSERT(isMainThread()); FrameView* frameView = view(); - if (frameView && frameView->isInLayout()) { + if (frameView && frameView->isInRenderTreeLayout()) { // View layout should not be re-entrant. ASSERT_NOT_REACHED(); return; @@ -1815,8 +1887,8 @@ void Document::updateLayout() RenderView::RepaintRegionAccumulator repaintRegionAccumulator(renderView()); - if (Element* oe = ownerElement()) - oe->document().updateLayout(); + if (HTMLFrameOwnerElement* owner = ownerElement()) + owner->document().updateLayout(); updateStyleIfNeeded(); @@ -1825,9 +1897,6 @@ void Document::updateLayout() // Only do a layout if changes have occurred that make it necessary. if (frameView && renderView() && (frameView->layoutPending() || renderView()->needsLayout())) frameView->layout(); - - // Active focus element's isFocusable() state may change after Layout. e.g. width: 0px or height: 0px. - resetHiddenFocusElementSoon(); } // FIXME: This is a bad idea and needs to be removed eventually. @@ -1848,10 +1917,11 @@ void Document::updateLayoutIgnorePendingStylesheets(Document::RunPostLayoutTasks // moment. If it were more refined, we might be able to do something better.) // It's worth noting though that this entire method is a hack, since what we really want to do is // suspend JS instead of doing a layout with inaccurate information. - HTMLElement* bodyElement = body(); + HTMLElement* bodyElement = bodyOrFrameset(); if (bodyElement && !bodyElement->renderer() && m_pendingSheetLayout == NoLayoutWithPendingSheets) { m_pendingSheetLayout = DidLayoutWithPendingSheets; - styleResolverChanged(RecalcStyleImmediately); + styleScope().didChangeActiveStyleSheetCandidates(); + recalcStyle(Style::Force); } else if (m_hasNodesWithPlaceholderStyle) // If new nodes have been added or style recalc has been done with style sheets still pending, some nodes // may not have had their real style calculated yet. Normally this gets cleaned when style sheets arrive @@ -1861,33 +1931,141 @@ void Document::updateLayoutIgnorePendingStylesheets(Document::RunPostLayoutTasks updateLayout(); - if (runPostLayoutTasks == RunPostLayoutTasksSynchronously && view()) + if (runPostLayoutTasks == RunPostLayoutTasks::Synchronously && view()) view()->flushAnyPendingPostLayoutTasks(); m_ignorePendingStylesheets = oldIgnore; } -PassRef Document::styleForElementIgnoringPendingStylesheets(Element* element) +std::unique_ptr Document::styleForElementIgnoringPendingStylesheets(Element& element, const RenderStyle* parentStyle) { - ASSERT_ARG(element, &element->document() == this); + ASSERT(&element.document() == this); // On iOS request delegates called during styleForElement may result in re-entering WebKit and killing the style resolver. - ResourceLoadScheduler::Suspender suspender(*platformStrategies()->loaderStrategy()->resourceLoadScheduler()); + Style::PostResolutionCallbackDisabler disabler(*this); + + SetForScope change(m_ignorePendingStylesheets, true); + auto elementStyle = element.resolveStyle(parentStyle); + + if (elementStyle.relations) { + Style::Update emptyUpdate(*this); + Style::commitRelations(WTFMove(elementStyle.relations), emptyUpdate); + } + + return WTFMove(elementStyle.renderStyle); +} + +bool Document::updateLayoutIfDimensionsOutOfDate(Element& element, DimensionsCheck dimensionsCheck) +{ + ASSERT(isMainThread()); + + // If the stylesheets haven't loaded, just give up and do a full layout ignoring pending stylesheets. + if (!haveStylesheetsLoaded()) { + updateLayoutIgnorePendingStylesheets(); + return true; + } + + // Check for re-entrancy and assert (same code that is in updateLayout()). + FrameView* frameView = view(); + if (frameView && frameView->isInRenderTreeLayout()) { + // View layout should not be re-entrant. + ASSERT_NOT_REACHED(); + return true; + } + + RenderView::RepaintRegionAccumulator repaintRegionAccumulator(renderView()); + + // Mimic the structure of updateLayout(), but at each step, see if we have been forced into doing a full + // layout. + bool requireFullLayout = false; + if (HTMLFrameOwnerElement* owner = ownerElement()) { + if (owner->document().updateLayoutIfDimensionsOutOfDate(*owner)) + requireFullLayout = true; + } + + updateStyleIfNeeded(); + + RenderObject* renderer = element.renderer(); + if (!renderer || renderer->needsLayout() || element.renderNamedFlowFragment()) { + // If we don't have a renderer or if the renderer needs layout for any reason, give up. + // Named flows can have auto height, so don't try to enforce the optimization in this case. + // The 2-pass nature of auto height named flow layout means the region may not be dirty yet. + requireFullLayout = true; + } + + bool isVertical = renderer && !renderer->isHorizontalWritingMode(); + bool checkingLogicalWidth = ((dimensionsCheck & WidthDimensionsCheck) && !isVertical) || ((dimensionsCheck & HeightDimensionsCheck) && isVertical); + bool checkingLogicalHeight = ((dimensionsCheck & HeightDimensionsCheck) && !isVertical) || ((dimensionsCheck & WidthDimensionsCheck) && isVertical); + bool hasSpecifiedLogicalHeight = renderer && renderer->style().logicalMinHeight() == Length(0, Fixed) && renderer->style().logicalHeight().isFixed() && renderer->style().logicalMaxHeight().isAuto(); + + if (!requireFullLayout) { + RenderBox* previousBox = nullptr; + RenderBox* currentBox = nullptr; + + // Check our containing block chain. If anything in the chain needs a layout, then require a full layout. + for (RenderObject* currRenderer = element.renderer(); currRenderer && !currRenderer->isRenderView(); currRenderer = currRenderer->container()) { + + // Require the entire container chain to be boxes. + if (!is(currRenderer)) { + requireFullLayout = true; + break; + } + + previousBox = currentBox; + currentBox = downcast(currRenderer); + + // If a box needs layout for itself or if a box has changed children and sizes its width to + // its content, then require a full layout. + if (currentBox->selfNeedsLayout() || + (checkingLogicalWidth && currRenderer->needsLayout() && currentBox->sizesLogicalWidthToFitContent(MainOrPreferredSize))) { + requireFullLayout = true; + break; + } + + // If a block contains floats and the child's height isn't specified, then + // give up also, since our height could end up being influenced by the floats. + if (checkingLogicalHeight && !hasSpecifiedLogicalHeight && currentBox->isRenderBlockFlow()) { + RenderBlockFlow* currentBlockFlow = downcast(currentBox); + if (currentBlockFlow->containsFloats() && previousBox && !previousBox->isFloatingOrOutOfFlowPositioned()) { + requireFullLayout = true; + break; + } + } + + if (!currentBox->isRenderBlockFlow() || currentBox->flowThreadContainingBlock() || currentBox->isWritingModeRoot()) { + // FIXME: For now require only block flows all the way back to the root. This limits the optimization + // for now, and we'll expand it in future patches to apply to more and more scenarios. + // Disallow regions/columns from having the optimization. + // Give up if the writing mode changes at all in the containing block chain. + requireFullLayout = true; + break; + } + + if (currRenderer == frameView->layoutRoot()) + break; + } + } + + StackStats::LayoutCheckPoint layoutCheckPoint; - TemporaryChange change(m_ignorePendingStylesheets, true); - return ensureStyleResolver().styleForElement(element, element->parentNode() ? element->parentNode()->computedStyle() : nullptr); + // Only do a layout if changes have occurred that make it necessary. + if (requireFullLayout && frameView && renderView() && (frameView->layoutPending() || renderView()->needsLayout())) + frameView->layout(); + + return requireFullLayout; } bool Document::isPageBoxVisible(int pageIndex) { - Ref pageStyle(ensureStyleResolver().styleForPage(pageIndex)); + updateStyleIfNeeded(); + std::unique_ptr pageStyle(styleScope().resolver().styleForPage(pageIndex)); return pageStyle->visibility() != HIDDEN; // display property doesn't apply to @page. } void Document::pageSizeAndMarginsInPixels(int pageIndex, IntSize& pageSize, int& marginTop, int& marginRight, int& marginBottom, int& marginLeft) { - RefPtr style = ensureStyleResolver().styleForPage(pageIndex); - RenderView* view = renderView(); + updateStyleIfNeeded(); + auto style = styleScope().resolver().styleForPage(pageIndex); int width = pageSize.width(); int height = pageSize.height(); @@ -1903,11 +2081,11 @@ void Document::pageSizeAndMarginsInPixels(int pageIndex, IntSize& pageSize, int& std::swap(width, height); break; case PAGE_SIZE_RESOLVED: { - LengthSize size = style->pageSize(); - ASSERT(size.width().isFixed()); - ASSERT(size.height().isFixed()); - width = valueForLength(size.width(), 0, view); - height = valueForLength(size.height(), 0, view); + auto& size = style->pageSize(); + ASSERT(size.width.isFixed()); + ASSERT(size.height.isFixed()); + width = valueForLength(size.width, 0); + height = valueForLength(size.height, 0); break; } default: @@ -1917,39 +2095,39 @@ void Document::pageSizeAndMarginsInPixels(int pageIndex, IntSize& pageSize, int& // The percentage is calculated with respect to the width even for margin top and bottom. // http://www.w3.org/TR/CSS2/box.html#margin-properties - marginTop = style->marginTop().isAuto() ? marginTop : intValueForLength(style->marginTop(), width, view); - marginRight = style->marginRight().isAuto() ? marginRight : intValueForLength(style->marginRight(), width, view); - marginBottom = style->marginBottom().isAuto() ? marginBottom : intValueForLength(style->marginBottom(), width, view); - marginLeft = style->marginLeft().isAuto() ? marginLeft : intValueForLength(style->marginLeft(), width, view); + marginTop = style->marginTop().isAuto() ? marginTop : intValueForLength(style->marginTop(), width); + marginRight = style->marginRight().isAuto() ? marginRight : intValueForLength(style->marginRight(), width); + marginBottom = style->marginBottom().isAuto() ? marginBottom : intValueForLength(style->marginBottom(), width); + marginLeft = style->marginLeft().isAuto() ? marginLeft : intValueForLength(style->marginLeft(), width); } -void Document::setIsViewSource(bool isViewSource) +StyleResolver& Document::userAgentShadowTreeStyleResolver() { - m_isViewSource = isViewSource; - if (!m_isViewSource) - return; - - setSecurityOrigin(SecurityOrigin::createUnique()); + if (!m_userAgentShadowTreeStyleResolver) + m_userAgentShadowTreeStyleResolver = std::make_unique(*this); + return *m_userAgentShadowTreeStyleResolver; } -void Document::createStyleResolver() +void Document::fontsNeedUpdate(FontSelector&) { - bool matchAuthorAndUserStyles = true; - if (Settings* settings = this->settings()) - matchAuthorAndUserStyles = settings->authorAndUserStylesEnabled(); - m_styleResolver = adoptPtr(new StyleResolver(*this, matchAuthorAndUserStyles)); - m_styleSheetCollection.combineCSSFeatureFlags(); + if (auto* resolver = styleScope().resolverIfExists()) + resolver->invalidateMatchedPropertiesCache(); + if (pageCacheState() != NotInPageCache || !renderView()) + return; + scheduleForcedStyleRecalc(); } -void Document::clearStyleResolver() +void Document::didClearStyleResolver() { - m_styleResolver.clear(); + m_userAgentShadowTreeStyleResolver = nullptr; + + m_fontSelector->buildStarted(); } void Document::createRenderTree() { ASSERT(!renderView()); - ASSERT(!m_inPageCache); + ASSERT(m_pageCacheState != InPageCache); ASSERT(!m_axObjectCache || this != &topDocument()); if (m_isNonRenderedPlaceholder) @@ -1959,23 +2137,11 @@ void Document::createRenderTree() m_renderView = createRenderer(*this, RenderStyle::create()); Node::setRenderer(m_renderView.get()); -#if USE(ACCELERATED_COMPOSITING) renderView()->setIsInWindow(true); -#endif recalcStyle(Style::Force); } -static void pageWheelEventHandlerCountChanged(Page& page) -{ - unsigned count = 0; - for (const Frame* frame = &page.mainFrame(); frame; frame = frame->tree().traverseNext()) { - if (Document* document = frame->document()) - count += document->wheelEventHandlerCount(); - } - page.chrome().client().numWheelEventHandlersChanged(count); -} - void Document::didBecomeCurrentDocumentInFrame() { // FIXME: Are there cases where the document can be dislodged from the frame during the event handling below? @@ -1996,52 +2162,71 @@ void Document::didBecomeCurrentDocumentInFrame() // subframes' documents have no wheel event handlers, then the count did not change, // unless the documents they are replacing had wheel event handlers. if (page() && m_frame->isMainFrame()) - pageWheelEventHandlerCountChanged(*page()); - -#if ENABLE(TOUCH_EVENTS) - // FIXME: Doing this only for the main frame is insufficient. - // A subframe could have touch event handlers. - if (hasTouchEventHandlers() && page() && m_frame->isMainFrame()) - page()->chrome().client().needTouchEvents(true); -#endif - -#if PLATFORM(IOS) - // Ensure that document scheduled task state matches frame timer state. It can be out of sync - // if timers state changed while the document was not in the frame (possibly in page cache, - // or simply newly created). - // FIXME: How does this interact with cross-platform code below? - if (m_frame->timersPaused()) - suspendScheduledTasks(ActiveDOMObject::DocumentWillBePaused); - else - resumeScheduledTasks(ActiveDOMObject::DocumentWillBePaused); -#endif + wheelEventHandlersChanged(); + // Ensure that the scheduled task state of the document matches the DOM suspension state of the frame. It can + // be out of sync if the DOM suspension state changed while the document was not in the frame (possibly in the + // page cache, or simply newly created). if (m_frame->activeDOMObjectsAndAnimationsSuspended()) { - suspendScriptedAnimationControllerCallbacks(); m_frame->animation().suspendAnimationsForDocument(this); - suspendActiveDOMObjects(ActiveDOMObject::PageWillBeSuspended); + suspendScheduledTasks(ActiveDOMObject::PageWillBeSuspended); + } else { + resumeScheduledTasks(ActiveDOMObject::PageWillBeSuspended); + m_frame->animation().resumeAnimationsForDocument(this); } } -void Document::disconnectFromFrame() +void Document::frameDestroyed() +{ + // detachFromFrame() must be called before destroying the Frame. + ASSERT_WITH_SECURITY_IMPLICATION(!m_frame); + FrameDestructionObserver::frameDestroyed(); +} + +void Document::didBecomeCurrentDocumentInView() +{ + ASSERT(view()); + if (!hasLivingRenderTree()) + createRenderTree(); +} + +void Document::attachToCachedFrame(CachedFrameBase& cachedFrame) +{ + ASSERT_WITH_SECURITY_IMPLICATION(cachedFrame.document() == this); + ASSERT(cachedFrame.view()); + ASSERT(m_pageCacheState == Document::InPageCache); + observeFrame(&cachedFrame.view()->frame()); +} + +void Document::detachFromCachedFrame(CachedFrameBase& cachedFrame) { - m_frame = nullptr; + ASSERT_UNUSED(cachedFrame, cachedFrame.view()); + ASSERT_WITH_SECURITY_IMPLICATION(cachedFrame.document() == this); + ASSERT(m_frame == &cachedFrame.view()->frame()); + ASSERT(m_pageCacheState == Document::InPageCache); + detachFromFrame(); } void Document::destroyRenderTree() { ASSERT(hasLivingRenderTree()); - ASSERT(!m_inPageCache); + ASSERT(frame()); + ASSERT(page()); + + FrameView* frameView = frame()->document() == this ? frame()->view() : nullptr; + + // Prevent Widget tree changes from committing until the RenderView is dead and gone. + WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates; - TemporaryChange change(m_renderTreeBeingDestroyed, true); + SetForScope change(m_renderTreeBeingDestroyed, true); if (this == &topDocument()) clearAXObjectCache(); documentWillBecomeInactive(); - if (FrameView* frameView = view()) - frameView->detachCustomScrollbars(); + if (frameView) + frameView->willDestroyRenderTree(); #if ENABLE(FULLSCREEN_API) if (m_fullScreenRenderer) @@ -2051,9 +2236,10 @@ void Document::destroyRenderTree() m_hoveredElement = nullptr; m_focusedElement = nullptr; m_activeElement = nullptr; + m_focusNavigationStartingNode = nullptr; if (m_documentElement) - Style::detachRenderTree(*m_documentElement); + RenderTreeUpdater::tearDownRenderers(*m_documentElement); clearChildNeedsStyleRecalc(); @@ -2062,32 +2248,61 @@ void Document::destroyRenderTree() m_renderView = nullptr; Node::setRenderer(nullptr); -#if ENABLE(IOS_TEXT_AUTOSIZING) +#if ENABLE(TEXT_AUTOSIZING) // Do this before the arena is cleared, which is needed to deref the RenderStyle on TextAutoSizingKey. m_textAutoSizedNodes.clear(); #endif + + if (frameView) + frameView->didDestroyRenderTree(); } void Document::prepareForDestruction() { -#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS) - clearTouchEventListeners(); + if (m_hasPreparedForDestruction) + return; + + if (m_frame) + m_frame->animation().detachFromDocument(this); + +#if ENABLE(IOS_TOUCH_EVENTS) + clearTouchEventHandlersAndListeners(); +#endif + +#if HAVE(ACCESSIBILITY) + // Sub-frames need to cleanup Nodes in the text marker cache when the Document disappears. + if (this != &topDocument()) { + if (AXObjectCache* cache = existingAXObjectCache()) + cache->clearTextMarkerNodesInUse(this); + } #endif - disconnectDescendantFrames(); + { + NavigationDisabler navigationDisabler; + disconnectDescendantFrames(); + } + if (m_domWindow && m_frame) m_domWindow->willDetachDocumentFromFrame(); - destroyRenderTree(); + if (hasLivingRenderTree()) + destroyRenderTree(); - if (isPluginDocument()) - toPluginDocument(this)->detachFromPluginElement(); + if (is(*this)) + downcast(*this).detachFromPluginElement(); #if ENABLE(POINTER_LOCK) if (page()) - page()->pointerLockController()->documentDetached(this); + page()->pointerLockController().documentDetached(*this); #endif + if (auto* page = this->page()) { + if (auto* validationMessageClient = page->validationMessageClient()) + validationMessageClient->documentDetached(*this); + } + + InspectorInstrumentation::documentDetached(*this); + stopActiveDOMObjects(); m_eventQueue.close(); #if ENABLE(FULLSCREEN_API) @@ -2097,19 +2312,34 @@ void Document::prepareForDestruction() commonTeardown(); -#if ENABLE(SHARED_WORKERS) - SharedWorkerRepository::documentDetached(this); -#endif - #if ENABLE(TOUCH_EVENTS) if (m_touchEventTargets && m_touchEventTargets->size() && parentDocument()) - parentDocument()->didRemoveEventTargetNode(this); + parentDocument()->didRemoveEventTargetNode(*this); #endif + if (m_wheelEventTargets && m_wheelEventTargets->size() && parentDocument()) + parentDocument()->didRemoveEventTargetNode(*this); + if (m_mediaQueryMatcher) m_mediaQueryMatcher->documentDestroyed(); - disconnectFromFrame(); +#if ENABLE(WIRELESS_PLAYBACK_TARGET) + if (!m_clientToIDMap.isEmpty() && page()) { + Vector clients; + copyKeysToVector(m_clientToIDMap, clients); + for (auto* client : clients) + removePlaybackTargetPickerClient(*client); + } +#endif + + detachFromFrame(); + + m_hasPreparedForDestruction = true; + + // Note that m_pageCacheState can be Document::AboutToEnterPageCache if our frame + // was removed in an onpagehide event handler fired when the top-level frame is + // about to enter the page cache. + ASSERT_WITH_SECURITY_IMPLICATION(m_pageCacheState != Document::InPageCache); } void Document::removeAllEventListeners() @@ -2118,27 +2348,63 @@ void Document::removeAllEventListeners() if (m_domWindow) m_domWindow->removeAllEventListeners(); -#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS) - clearTouchEventListeners(); +#if ENABLE(IOS_TOUCH_EVENTS) + clearTouchEventHandlersAndListeners(); #endif - for (Node* node = firstChild(); node; node = NodeTraversal::next(node)) + for (Node* node = firstChild(); node; node = NodeTraversal::next(*node)) node->removeAllEventListeners(); + +#if ENABLE(TOUCH_EVENTS) + m_touchEventTargets = nullptr; +#endif + m_wheelEventTargets = nullptr; } -void Document::platformSuspendOrStopActiveDOMObjects() +void Document::suspendDeviceMotionAndOrientationUpdates() { -#if PLATFORM(IOS) -#if ENABLE(DEVICE_ORIENTATION) + if (m_areDeviceMotionAndOrientationUpdatesSuspended) + return; + m_areDeviceMotionAndOrientationUpdatesSuspended = true; +#if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS) if (m_deviceMotionController) m_deviceMotionController->suspendUpdates(); if (m_deviceOrientationController) m_deviceOrientationController->suspendUpdates(); #endif +} + +void Document::resumeDeviceMotionAndOrientationUpdates() +{ + if (!m_areDeviceMotionAndOrientationUpdatesSuspended) + return; + m_areDeviceMotionAndOrientationUpdatesSuspended = false; +#if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS) + if (m_deviceMotionController) + m_deviceMotionController->resumeUpdates(); + if (m_deviceOrientationController) + m_deviceOrientationController->resumeUpdates(); +#endif +} + +bool Document::shouldBypassMainWorldContentSecurityPolicy() const +{ + JSC::CallFrame* callFrame = commonVM().topCallFrame; + if (callFrame == JSC::CallFrame::noCaller()) + return false; + DOMWrapperWorld& domWrapperWorld = currentWorld(callFrame); + if (domWrapperWorld.isNormal()) + return false; + return true; +} +void Document::platformSuspendOrStopActiveDOMObjects() +{ +#if PLATFORM(IOS) if (WebThreadCountOfObservedContentModifiers() > 0) { - Frame* frame = this->frame(); - if (Page* page = frame ? frame->page() : nullptr) - page->chrome().client().clearContentChangeObservers(frame); + if (auto* frame = this->frame()) { + if (auto* page = frame->page()) + page->chrome().client().clearContentChangeObservers(*frame); + } } #endif } @@ -2146,19 +2412,14 @@ void Document::platformSuspendOrStopActiveDOMObjects() void Document::suspendActiveDOMObjects(ActiveDOMObject::ReasonForSuspension why) { ScriptExecutionContext::suspendActiveDOMObjects(why); + suspendDeviceMotionAndOrientationUpdates(); platformSuspendOrStopActiveDOMObjects(); } void Document::resumeActiveDOMObjects(ActiveDOMObject::ReasonForSuspension why) { ScriptExecutionContext::resumeActiveDOMObjects(why); - -#if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS) - if (m_deviceMotionController) - m_deviceMotionController->resumeUpdates(); - if (m_deviceOrientationController) - m_deviceOrientationController->resumeUpdates(); -#endif + resumeDeviceMotionAndOrientationUpdates(); // FIXME: For iOS, do we need to add content change observers that were removed in Document::suspendActiveDOMObjects()? } @@ -2173,11 +2434,12 @@ void Document::clearAXObjectCache() ASSERT(&topDocument() == this); // Clear the cache member variable before calling delete because attempts // are made to access it during destruction. - m_axObjectCache.clear(); + m_axObjectCache = nullptr; } -AXObjectCache* Document::existingAXObjectCache() const +AXObjectCache* Document::existingAXObjectCacheSlow() const { + ASSERT(hasEverCreatedAnAXObjectCache); Document& topDocument = this->topDocument(); if (!topDocument.hasLivingRenderTree()) return nullptr; @@ -2200,8 +2462,10 @@ AXObjectCache* Document::axObjectCache() const return nullptr; ASSERT(&topDocument == this || !m_axObjectCache); - if (!topDocument.m_axObjectCache) - topDocument.m_axObjectCache = adoptPtr(new AXObjectCache(topDocument)); + if (!topDocument.m_axObjectCache) { + topDocument.m_axObjectCache = std::make_unique(topDocument); + hasEverCreatedAnAXObjectCache = true; + } return topDocument.m_axObjectCache.get(); } @@ -2209,10 +2473,10 @@ void Document::setVisuallyOrdered() { m_visuallyOrdered = true; if (renderView()) - renderView()->style().setRTLOrdering(VisualOrder); + renderView()->mutableStyle().setRTLOrdering(VisualOrder); } -PassRefPtr Document::createParser() +Ref Document::createParser() { // FIXME: this should probably pass the frame instead return XMLDocumentParser::create(*this, view()); @@ -2225,10 +2489,13 @@ ScriptableDocumentParser* Document::scriptableDocumentParser() const void Document::open(Document* ownerDocument) { + if (m_ignoreOpensDuringUnloadCount) + return; + if (ownerDocument) { setURL(ownerDocument->url()); - m_cookieURL = ownerDocument->cookieURL(); - setSecurityOrigin(ownerDocument->securityOrigin()); + setCookieURL(ownerDocument->cookieURL()); + setSecurityOriginPolicy(ownerDocument->securityOriginPolicy()); } if (m_frame) { @@ -2261,7 +2528,7 @@ void Document::detachParser() if (!m_parser) return; m_parser->detach(); - m_parser.clear(); + m_parser = nullptr; } void Document::cancelParsing() @@ -2279,57 +2546,61 @@ void Document::cancelParsing() void Document::implicitOpen() { - cancelParsing(); - removeChildren(); - setCompatibilityMode(NoQuirksMode); - - // Documents rendered seamlessly should start out requiring a stylesheet - // collection update in order to ensure they inherit all the relevant data - // from their parent. - if (shouldDisplaySeamlesslyWithParent()) - styleResolverChanged(DeferRecalcStyle); + setCompatibilityMode(DocumentCompatibilityMode::NoQuirksMode); + cancelParsing(); m_parser = createParser(); setParsing(true); setReadyState(Loading); } -HTMLElement* Document::body() const +HTMLBodyElement* Document::body() const { - // If the document element contains both a frameset and a body, the frameset wins. - auto element = documentElement(); + auto* element = documentElement(); if (!element) return nullptr; - if (auto frameset = childrenOfType(*element).first()) - return frameset; return childrenOfType(*element).first(); } -void Document::setBody(PassRefPtr prpNewBody, ExceptionCode& ec) +HTMLElement* Document::bodyOrFrameset() const { - RefPtr newBody = prpNewBody; - - if (!newBody || !documentElement() || !newBody->hasTagName(bodyTag)) { - ec = HIERARCHY_REQUEST_ERR; - return; + // Return the first body or frameset child of the html element. + auto* element = documentElement(); + if (!is(element)) + return nullptr; + for (auto& child : childrenOfType(*element)) { + if (is(child) || is(child)) + return &child; } + return nullptr; +} - if (&newBody->document() != this) { - ec = 0; - RefPtr node = importNode(newBody.get(), true, ec); - if (ec) - return; - - newBody = toHTMLElement(node.get()); - } +ExceptionOr Document::setBodyOrFrameset(RefPtr&& newBody) +{ + if (!is(newBody.get()) && !is(newBody.get())) + return Exception { HIERARCHY_REQUEST_ERR }; - HTMLElement* b = body(); - if (!b) - documentElement()->appendChild(newBody.release(), ec); - else - documentElement()->replaceChild(newBody.release(), b, ec); + auto* currentBody = bodyOrFrameset(); + if (newBody == currentBody) + return { }; + + if (!m_documentElement) + return Exception { HIERARCHY_REQUEST_ERR }; + + if (currentBody) + return m_documentElement->replaceChild(*newBody, *currentBody); + return m_documentElement->appendChild(*newBody); +} + +Location* Document::location() const +{ + auto* window = domWindow(); + if (!window) + return nullptr; + + return window->location(); } HTMLHeadElement* Document::head() @@ -2363,7 +2634,7 @@ void Document::explicitClose() return; } - m_frame->loader().checkCompleted(); + checkCompleted(); } void Document::implicitClose() @@ -2381,7 +2652,7 @@ void Document::implicitClose() return; // Call to dispatchWindowLoadEvent can blow us from underneath. - Ref protect(*this); + Ref protectedThis(*this); m_processingLoadEvent = true; @@ -2400,35 +2671,37 @@ void Document::implicitClose() // ramifications, and we need to decide what is the Right Thing To Do(tm) Frame* f = frame(); if (f) { - f->loader().icon().startLoader(); + if (f->loader().client().useIconLoadingClient()) { + if (auto* documentLoader = loader()) + documentLoader->startIconLoading(); + } else + f->loader().icon().startLoader(); + f->animation().startAnimationsIfNotSuspended(this); - } - ImageLoader::dispatchPendingBeforeLoadEvents(); - ImageLoader::dispatchPendingLoadEvents(); - ImageLoader::dispatchPendingErrorEvents(); + // FIXME: We shouldn't be dispatching pending events globally on all Documents here. + // For now, only do this when there is a Frame, otherwise this could cause JS reentrancy + // below SVG font parsing, for example. + ImageLoader::dispatchPendingBeforeLoadEvents(); + ImageLoader::dispatchPendingLoadEvents(); + ImageLoader::dispatchPendingErrorEvents(); + HTMLLinkElement::dispatchPendingLoadEvents(); + HTMLStyleElement::dispatchPendingLoadEvents(); - HTMLLinkElement::dispatchPendingLoadEvents(); - HTMLStyleElement::dispatchPendingLoadEvents(); - -#if ENABLE(SVG) - // To align the HTML load event and the SVGLoad event for the outermost element, fire it from - // here, instead of doing it from SVGElement::finishedParsingChildren (if externalResourcesRequired="false", - // which is the default, for ='true' its fired at a later time, once all external resources finished loading). - if (svgExtensions()) - accessSVGExtensions()->dispatchSVGLoadEventToOutermostSVGElements(); -#endif + // To align the HTML load event and the SVGLoad event for the outermost element, fire it from + // here, instead of doing it from SVGElement::finishedParsingChildren (if externalResourcesRequired="false", + // which is the default, for ='true' its fired at a later time, once all external resources finished loading). + if (svgExtensions()) + accessSVGExtensions().dispatchSVGLoadEventToOutermostSVGElements(); + } dispatchWindowLoadEvent(); - enqueuePageshowEvent(PageshowEventNotPersisted); - enqueuePopstateEvent(m_pendingStateObject ? m_pendingStateObject.release() : SerializedScriptValue::nullValue()); - + dispatchPageshowEvent(PageshowEventNotPersisted); + if (m_pendingStateObject) + dispatchPopstateEvent(WTFMove(m_pendingStateObject)); + if (f) - f->loader().handledOnloadEvents(); -#ifdef INSTRUMENT_LAYOUT_SCHEDULING - if (!ownerElement()) - printf("onload fired at %lld\n", elapsedTime().count()); -#endif + f->loader().dispatchOnloadEvents(); // An event handler may have removed the frame if (!frame()) { @@ -2440,7 +2713,7 @@ void Document::implicitClose() // fires. This will improve onload scores, and other browsers do it. // If they wanna cheat, we can too. -dwh - if (frame()->navigationScheduler().locationChangePending() && elapsedTime() < settings()->layoutInterval()) { + if (frame()->navigationScheduler().locationChangePending() && timeSinceDocumentCreation() < settings().layoutInterval()) { // Just bail out. Before or during the onload we were shifted to another page. // The old i-Bench suite does this. When this happens don't bother painting or laying out. m_processingLoadEvent = false; @@ -2464,15 +2737,19 @@ void Document::implicitClose() m_processingLoadEvent = false; -#if PLATFORM(MAC) || PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(EFL) +#if PLATFORM(COCOA) || PLATFORM(WIN) || PLATFORM(GTK) if (f && hasLivingRenderTree() && AXObjectCache::accessibilityEnabled()) { // The AX cache may have been cleared at this point, but we need to make sure it contains an // AX object to send the notification to. getOrCreate will make sure that an valid AX object // exists in the cache (we ignore the return value because we don't need it here). This is - // only safe to call when a layout is not in progress, so it can not be used in postNotification. + // only safe to call when a layout is not in progress, so it can not be used in postNotification. + // + // This notification is now called AXNewDocumentLoadComplete because there are other handlers that will + // catch new AND page history loads, and that uses AXLoadComplete + axObjectCache()->getOrCreate(renderView()); if (this == &topDocument()) - axObjectCache()->postNotification(renderView(), AXObjectCache::AXLoadComplete); + axObjectCache()->postNotification(renderView(), AXObjectCache::AXNewDocumentLoadComplete); else { // AXLoadComplete can only be posted on the top document, so if it's a document // in an iframe that just finished loading, post AXLayoutComplete instead. @@ -2481,10 +2758,8 @@ void Document::implicitClose() } #endif -#if ENABLE(SVG) if (svgExtensions()) - accessSVGExtensions()->startAnimations(); -#endif + accessSVGExtensions().startAnimations(); } void Document::setParsing(bool b) @@ -2492,15 +2767,10 @@ void Document::setParsing(bool b) m_bParsing = b; if (m_bParsing && !m_sharedObjectPool) - m_sharedObjectPool = DocumentSharedObjectPool::create(); - - if (!m_bParsing && view()) - view()->scheduleRelayout(); + m_sharedObjectPool = std::make_unique(); -#ifdef INSTRUMENT_LAYOUT_SCHEDULING - if (!ownerElement() && !m_bParsing) - printf("Parsing finished at %lld\n", elapsedTime().count()); -#endif + if (!m_bParsing && view() && !view()->needsLayout()) + view()->fireLayoutRelatedMilestonesIfNeeded(); } bool Document::shouldScheduleLayout() @@ -2511,35 +2781,33 @@ bool Document::shouldScheduleLayout() // (a) Only schedule a layout once the stylesheets are loaded. // (b) Only schedule layout once we have a body element. - return (haveStylesheetsLoaded() && body()) - || (documentElement() && !documentElement()->hasTagName(htmlTag)); + return (haveStylesheetsLoaded() && bodyOrFrameset()) + || (documentElement() && !is(*documentElement())); } bool Document::isLayoutTimerActive() { - return view() && view()->layoutPending() && !minimumLayoutDelay().count(); + return view() && view()->layoutPending() && !minimumLayoutDelay(); } -std::chrono::milliseconds Document::minimumLayoutDelay() +Seconds Document::minimumLayoutDelay() { if (m_overMinimumLayoutThreshold) - return std::chrono::milliseconds(0); + return 0_s; - std::chrono::milliseconds elapsed = elapsedTime(); - m_overMinimumLayoutThreshold = elapsed > settings()->layoutInterval(); + auto elapsed = timeSinceDocumentCreation(); + m_overMinimumLayoutThreshold = elapsed > settings().layoutInterval(); // We'll want to schedule the timer to fire at the minimum layout threshold. - return std::max(std::chrono::milliseconds(0), settings()->layoutInterval() - elapsed); + return std::max(0_s, settings().layoutInterval() - elapsed); } -std::chrono::milliseconds Document::elapsedTime() const +Seconds Document::timeSinceDocumentCreation() const { - auto elapsedTime = std::chrono::steady_clock::now() - m_startTime; - - return std::chrono::duration_cast(elapsedTime); + return MonotonicTime::now() - m_documentCreationTime; } -void Document::write(const SegmentedString& text, Document* ownerDocument) +void Document::write(SegmentedString&& text, Document* ownerDocument) { NestingLevelIncrementer nestingLevelIncrementer(m_writeRecursionDepth); @@ -2547,54 +2815,60 @@ void Document::write(const SegmentedString& text, Document* ownerDocument) m_writeRecursionIsTooDeep = (m_writeRecursionDepth > cMaxWriteRecursionDepth) || m_writeRecursionIsTooDeep; if (m_writeRecursionIsTooDeep) - return; - -#ifdef INSTRUMENT_LAYOUT_SCHEDULING - if (!ownerElement()) - printf("Beginning a document.write at %lld\n", elapsedTime().count()); -#endif + return; bool hasInsertionPoint = m_parser && m_parser->hasInsertionPoint(); - if (!hasInsertionPoint && m_ignoreDestructiveWriteCount) + if (!hasInsertionPoint && (m_ignoreOpensDuringUnloadCount || m_ignoreDestructiveWriteCount)) return; if (!hasInsertionPoint) open(ownerDocument); ASSERT(m_parser); - m_parser->insert(text); - -#ifdef INSTRUMENT_LAYOUT_SCHEDULING - if (!ownerElement()) - printf("Ending a document.write at %lld\n", elapsedTime().count()); -#endif + m_parser->insert(WTFMove(text)); } void Document::write(const String& text, Document* ownerDocument) { - write(SegmentedString(text), ownerDocument); + write(SegmentedString { text }, ownerDocument); } void Document::writeln(const String& text, Document* ownerDocument) { - write(text, ownerDocument); - write("\n", ownerDocument); + SegmentedString textWithNewline { text }; + textWithNewline.append(String { "\n" }); + write(WTFMove(textWithNewline), ownerDocument); } -double Document::minimumTimerInterval() const +std::chrono::milliseconds Document::minimumTimerInterval() const { - Page* p = page(); - if (!p) + auto* page = this->page(); + if (!page) return ScriptExecutionContext::minimumTimerInterval(); - return p->settings().minDOMTimerInterval(); + return page->settings().minimumDOMTimerInterval(); +} + +void Document::setTimerThrottlingEnabled(bool shouldThrottle) +{ + if (m_isTimerThrottlingEnabled == shouldThrottle) + return; + + m_isTimerThrottlingEnabled = shouldThrottle; + didChangeTimerAlignmentInterval(); } -double Document::timerAlignmentInterval() const +std::chrono::milliseconds Document::timerAlignmentInterval(bool hasReachedMaxNestingLevel) const { - Page* p = page(); - if (!p) - return ScriptExecutionContext::timerAlignmentInterval(); - return p->settings().domTimerAlignmentInterval(); + auto alignmentInterval = ScriptExecutionContext::timerAlignmentInterval(hasReachedMaxNestingLevel); + + // Apply Document-level DOMTimer throttling only if timers have reached their maximum nesting level as the Page may still be visible. + if (m_isTimerThrottlingEnabled && hasReachedMaxNestingLevel) + alignmentInterval = std::max(alignmentInterval, DOMTimer::hiddenPageAlignmentInterval()); + + if (Page* page = this->page()) + alignmentInterval = std::max(alignmentInterval, page->domTimerAlignmentInterval()); + + return alignmentInterval; } EventTarget* Document::errorEventTarget() @@ -2602,9 +2876,9 @@ EventTarget* Document::errorEventTarget() return m_domWindow.get(); } -void Document::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtr callStack) +void Document::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, RefPtr&& callStack) { - addMessage(JSMessageSource, ErrorMessageLevel, errorMessage, sourceURL, lineNumber, columnNumber, callStack); + addMessage(MessageSource::JS, MessageLevel::Error, errorMessage, sourceURL, lineNumber, columnNumber, WTFMove(callStack)); } void Document::setURL(const URL& url) @@ -2635,21 +2909,11 @@ void Document::updateBaseURL() m_baseURL = URL(ParsedURLString, documentURI()); } - if (m_selectorQueryCache) - m_selectorQueryCache->invalidate(); + clearSelectorQueryCache(); if (!m_baseURL.isValid()) m_baseURL = URL(); - if (m_elementSheet) { - // Element sheet is silly. It never contains anything. - ASSERT(!m_elementSheet->contents().ruleCount()); - bool usesRemUnits = m_elementSheet->contents().usesRemUnits(); - m_elementSheet = CSSStyleSheet::createInline(*this, m_baseURL); - // FIXME: So we are not really the parser. The right fix is to eliminate the element sheet completely. - m_elementSheet->contents().parserSetUsesRemUnits(usesRemUnits); - } - if (!equalIgnoringFragmentIdentifier(oldBaseURL, m_baseURL)) { // Base URL change changes any relative visited links. // 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. @@ -2670,16 +2934,22 @@ void Document::processBaseElement() const AtomicString* href = nullptr; const AtomicString* target = nullptr; auto baseDescendants = descendantsOfType(*this); - for (auto base = baseDescendants.begin(), end = baseDescendants.end(); base != end && (!href || !target); ++base) { + for (auto& base : baseDescendants) { if (!href) { - const AtomicString& value = base->fastGetAttribute(hrefAttr); - if (!value.isNull()) + const AtomicString& value = base.attributeWithoutSynchronization(hrefAttr); + if (!value.isNull()) { href = &value; + if (target) + break; + } } if (!target) { - const AtomicString& value = base->fastGetAttribute(targetAttr); - if (!value.isNull()) + const AtomicString& value = base.attributeWithoutSynchronization(targetAttr); + if (!value.isNull()) { target = &value; + if (href) + break; + } } } @@ -2711,6 +2981,30 @@ void Document::disableEval(const String& errorMessage) frame()->script().disableEval(errorMessage); } +#if ENABLE(INDEXED_DATABASE) + +IDBClient::IDBConnectionProxy* Document::idbConnectionProxy() +{ + if (!m_idbConnectionProxy) { + Page* currentPage = page(); + if (!currentPage) + return nullptr; + m_idbConnectionProxy = ¤tPage->idbConnection().proxy(); + } + return m_idbConnectionProxy.get(); +} + +#endif + +#if ENABLE(WEB_SOCKETS) + +SocketProvider* Document::socketProvider() +{ + return m_socketProvider.get(); +} + +#endif + bool Document::canNavigate(Frame* targetFrame) { if (!m_frame) @@ -2780,7 +3074,7 @@ Frame* Document::findUnsafeParentScrollPropagationBoundary() Frame* ancestorFrame = currentFrame->tree().parent(); while (ancestorFrame) { - if (!ancestorFrame->document()->securityOrigin()->canAccess(securityOrigin())) + if (!ancestorFrame->document()->securityOrigin().canAccess(securityOrigin())) return currentFrame; currentFrame = ancestorFrame; ancestorFrame = ancestorFrame->tree().parent(); @@ -2788,159 +3082,141 @@ Frame* Document::findUnsafeParentScrollPropagationBoundary() return nullptr; } - -void Document::seamlessParentUpdatedStylesheets() -{ - styleResolverChanged(RecalcStyleImmediately); -} - void Document::didRemoveAllPendingStylesheet() { - m_needsNotifyRemoveAllPendingStylesheet = false; - - styleResolverChanged(DeferRecalcStyleIfNeeded); - if (m_pendingSheetLayout == DidLayoutWithPendingSheets) { + // Painting is disabled when doing layouts with pending sheets to avoid FOUC. + // We need to force paint when coming out from this state. + // FIXME: This is not very elegant. m_pendingSheetLayout = IgnoreLayoutWithPendingSheets; if (renderView()) renderView()->repaintViewAndCompositedLayers(); } - if (ScriptableDocumentParser* parser = scriptableDocumentParser()) - parser->executeScriptsWaitingForStylesheets(); + if (auto* parser = scriptableDocumentParser()) + parser->executeScriptsWaitingForStylesheetsSoon(); +} + +bool Document::usesStyleBasedEditability() const +{ + if (m_hasElementUsingStyleBasedEditability) + return true; + + ASSERT(!m_renderView || !m_renderView->frameView().isPainting()); + ASSERT(!m_inStyleRecalc); - if (m_gotoAnchorNeededAfterStylesheetsLoad && view()) - view()->scrollToFragment(m_url); + auto& styleScope = const_cast(this->styleScope()); + styleScope.flushPendingUpdate(); + return styleScope.usesStyleBasedEditability(); } -CSSStyleSheet& Document::elementSheet() +void Document::setHasElementUsingStyleBasedEditability() { - if (!m_elementSheet) - m_elementSheet = CSSStyleSheet::createInline(*this, m_baseURL); - return *m_elementSheet; + m_hasElementUsingStyleBasedEditability = true; } -void Document::processHttpEquiv(const String& equiv, const String& content) +void Document::processHttpEquiv(const String& equiv, const String& content, bool isInDocumentHead) { - ASSERT(!equiv.isNull() && !content.isNull()); + ASSERT(!equiv.isNull()); + ASSERT(!content.isNull()); + + HttpEquivPolicy policy = httpEquivPolicy(); + if (policy != HttpEquivPolicy::Enabled) { + String reason; + switch (policy) { + case HttpEquivPolicy::Enabled: + ASSERT_NOT_REACHED(); + break; + case HttpEquivPolicy::DisabledBySettings: + reason = "by the embedder."; + break; + case HttpEquivPolicy::DisabledByContentDispositionAttachmentSandbox: + reason = "for documents with Content-Disposition: attachment."; + break; + } + String message = "http-equiv '" + equiv + "' is disabled " + reason; + addConsoleMessage(MessageSource::Security, MessageLevel::Error, message); + return; + } Frame* frame = this->frame(); - if (equalIgnoringCase(equiv, "default-style")) { - // The preferred style set has been overridden as per section + HTTPHeaderName headerName; + if (!findHTTPHeaderName(equiv, headerName)) + return; + + switch (headerName) { + case HTTPHeaderName::DefaultStyle: + // The preferred style set has been overridden as per section // 14.3.2 of the HTML4.0 specification. We need to update the - // sheet used variable and then update our style selector. + // sheet used variable and then update our style selector. // For more info, see the test at: // http://www.hixie.ch/tests/evil/css/import/main/preferred.html // -dwh - m_styleSheetCollection.setSelectedStylesheetSetName(content); - m_styleSheetCollection.setPreferredStylesheetSetName(content); - styleResolverChanged(DeferRecalcStyle); - } else if (equalIgnoringCase(equiv, "refresh")) { + styleScope().setSelectedStylesheetSetName(content); + styleScope().setPreferredStylesheetSetName(content); + break; + + case HTTPHeaderName::Refresh: { double delay; - String url; - if (frame && parseHTTPRefresh(content, true, delay, url)) { - if (url.isEmpty()) - url = m_url.string(); + String urlString; + if (frame && parseMetaHTTPEquivRefresh(content, delay, urlString)) { + URL completedURL; + if (urlString.isEmpty()) + completedURL = m_url; else - url = completeURL(url).string(); - if (!protocolIsJavaScript(url)) - frame->navigationScheduler().scheduleRedirect(delay, url); + completedURL = completeURL(urlString); + if (!protocolIsJavaScript(completedURL)) + frame->navigationScheduler().scheduleRedirect(*this, delay, completedURL); else { String message = "Refused to refresh " + m_url.stringCenterEllipsizedToLength() + " to a javascript: URL"; - addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message); + addConsoleMessage(MessageSource::Security, MessageLevel::Error, message); } } - } else if (equalIgnoringCase(equiv, "set-cookie")) { + + break; + } + + case HTTPHeaderName::SetCookie: // FIXME: make setCookie work on XML documents too; e.g. in case of - if (isHTMLDocument()) { + if (is(*this)) { // Exception (for sandboxed documents) ignored. - toHTMLDocument(this)->setCookie(content, IGNORE_EXCEPTION); + downcast(*this).setCookie(content); } - } else if (equalIgnoringCase(equiv, "content-language")) + break; + + case HTTPHeaderName::ContentLanguage: setContentLanguage(content); - else if (equalIgnoringCase(equiv, "x-dns-prefetch-control")) + break; + + case HTTPHeaderName::XDNSPrefetchControl: parseDNSPrefetchControlHeader(content); - else if (equalIgnoringCase(equiv, "x-frame-options")) { + break; + + case HTTPHeaderName::XFrameOptions: if (frame) { FrameLoader& frameLoader = frame->loader(); unsigned long requestIdentifier = 0; if (frameLoader.activeDocumentLoader() && frameLoader.activeDocumentLoader()->mainResourceLoader()) requestIdentifier = frameLoader.activeDocumentLoader()->mainResourceLoader()->identifier(); - if (frameLoader.shouldInterruptLoadForXFrameOptions(content, url(), requestIdentifier)) { - String message = "Refused to display '" + url().stringCenterEllipsizedToLength() + "' in a frame because it set 'X-Frame-Options' to '" + content + "'."; - frameLoader.stopAllLoaders(); - // Stopping the loader isn't enough, as we're already parsing the document; to honor the header's - // intent, we must navigate away from the possibly partially-rendered document to a location that - // doesn't inherit the parent's SecurityOrigin. - frame->navigationScheduler().scheduleLocationChange(securityOrigin(), SecurityOrigin::urlWithUniqueSecurityOrigin(), String()); - addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message, requestIdentifier); - } - } - } else if (equalIgnoringCase(equiv, "content-security-policy")) - contentSecurityPolicy()->didReceiveHeader(content, ContentSecurityPolicy::Enforce); - else if (equalIgnoringCase(equiv, "content-security-policy-report-only")) - contentSecurityPolicy()->didReceiveHeader(content, ContentSecurityPolicy::Report); - else if (equalIgnoringCase(equiv, "x-webkit-csp")) - contentSecurityPolicy()->didReceiveHeader(content, ContentSecurityPolicy::PrefixedEnforce); - else if (equalIgnoringCase(equiv, "x-webkit-csp-report-only")) - contentSecurityPolicy()->didReceiveHeader(content, ContentSecurityPolicy::PrefixedReport); -} - -// Though isspace() considers \t and \v to be whitespace, Win IE doesn't. -static bool isSeparator(UChar c) -{ - return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '=' || c == ',' || c == '\0'; -} - -void Document::processArguments(const String& features, void* data, ArgumentsCallback callback) -{ - // Tread lightly in this code -- it was specifically designed to mimic Win IE's parsing behavior. - int keyBegin, keyEnd; - int valueBegin, valueEnd; - - int i = 0; - int length = features.length(); - String buffer = features.lower(); - while (i < length) { - // skip to first non-separator, but don't skip past the end of the string - while (isSeparator(buffer[i])) { - if (i >= length) - break; - i++; - } - keyBegin = i; - - // skip to first separator - while (!isSeparator(buffer[i])) - i++; - keyEnd = i; - - // skip to first '=', but don't skip past a ',' or the end of the string - while (buffer[i] != '=') { - if (buffer[i] == ',' || i >= length) - break; - i++; - } - // skip to first non-separator, but don't skip past a ',' or the end of the string - while (isSeparator(buffer[i])) { - if (buffer[i] == ',' || i >= length) - break; - i++; + String message = "The X-Frame-Option '" + content + "' supplied in a element was ignored. X-Frame-Options may only be provided by an HTTP header sent with the document."; + addConsoleMessage(MessageSource::Security, MessageLevel::Error, message, requestIdentifier); } - valueBegin = i; + break; - // skip to first separator - while (!isSeparator(buffer[i])) - i++; - valueEnd = i; + case HTTPHeaderName::ContentSecurityPolicy: + if (isInDocumentHead) + contentSecurityPolicy()->didReceiveHeader(content, ContentSecurityPolicyHeaderType::Enforce, ContentSecurityPolicy::PolicyFrom::HTTPEquivMeta); + break; - ASSERT_WITH_SECURITY_IMPLICATION(i <= length); + case HTTPHeaderName::XWebKitCSP: + if (isInDocumentHead) + contentSecurityPolicy()->didReceiveHeader(content, ContentSecurityPolicyHeaderType::PrefixedEnforce, ContentSecurityPolicy::PolicyFrom::HTTPEquivMeta); + break; - String keyString = buffer.substring(keyBegin, keyEnd - keyBegin); - String valueString = buffer.substring(valueBegin, valueEnd - valueBegin); - callback(keyString, valueString, this, data); + default: + break; } } @@ -2952,15 +3228,10 @@ void Document::processViewport(const String& features, ViewportArguments::Type o return; m_viewportArguments = ViewportArguments(origin); - processArguments(features, (void*)&m_viewportArguments, &setViewportFeature); -#if PLATFORM(IOS) - // FIXME: Investigate moving to ToT WebKit's extended Viewport Implementation - // Moving to ToT's implementation would mean calling findConfigurationForViewportData, which does - // bounds checking and determining concrete values for ValueAuto which we already do in UIKit. - // To maintain old behavior, we just need to update a few values, leaving Auto's for UIKit. - finalizeViewportArguments(m_viewportArguments); -#endif + processFeaturesString(features, [this](StringView key, StringView value) { + setViewportFeature(m_viewportArguments, *this, key, value); + }); updateViewportArguments(); } @@ -2972,24 +3243,19 @@ void Document::updateViewportArguments() m_didDispatchViewportPropertiesChanged = true; #endif page()->chrome().dispatchViewportPropertiesDidChange(m_viewportArguments); -#if PLATFORM(IOS) - page()->chrome().didReceiveDocType(frame()); -#endif + page()->chrome().didReceiveDocType(*frame()); } } #if PLATFORM(IOS) -// FIXME: Find a better place for this functionality. -void setParserFeature(const String& key, const String& value, Document* document, void*) -{ - if (key == "telephone" && equalIgnoringCase(value, "no")) - document->setIsTelephoneNumberParsingAllowed(false); -} void Document::processFormatDetection(const String& features) { - ASSERT(!features.isNull()); - processArguments(features, nullptr, &setParserFeature); + // FIXME: Find a better place for this function. + processFeaturesString(features, [this](StringView key, StringView value) { + if (equalLettersIgnoringASCIICase(key, "telephone") && equalLettersIgnoringASCIICase(value, "no")) + setIsTelephoneNumberParsingAllowed(false); + }); } void Document::processWebAppOrientations() @@ -2997,20 +3263,37 @@ void Document::processWebAppOrientations() if (Page* page = this->page()) page->chrome().client().webAppOrientationsUpdated(); } + #endif void Document::processReferrerPolicy(const String& policy) { ASSERT(!policy.isNull()); - m_referrerPolicy = ReferrerPolicyDefault; + // Documents in a Content-Disposition: attachment sandbox should never send a Referer header, + // even if the document has a meta tag saying otherwise. + if (shouldEnforceContentDispositionAttachmentSandbox()) + return; + +#if USE(QUICK_LOOK) + if (shouldEnforceQuickLookSandbox()) + return; +#endif - if (equalIgnoringCase(policy, "never")) - m_referrerPolicy = ReferrerPolicyNever; - else if (equalIgnoringCase(policy, "always")) - m_referrerPolicy = ReferrerPolicyAlways; - else if (equalIgnoringCase(policy, "origin")) - m_referrerPolicy = ReferrerPolicyOrigin; + // Note that we're supporting both the standard and legacy keywords for referrer + // policies, as defined by http://www.w3.org/TR/referrer-policy/#referrer-policy-delivery-meta + if (equalLettersIgnoringASCIICase(policy, "no-referrer") || equalLettersIgnoringASCIICase(policy, "never")) + setReferrerPolicy(ReferrerPolicy::Never); + else if (equalLettersIgnoringASCIICase(policy, "unsafe-url") || equalLettersIgnoringASCIICase(policy, "always")) + setReferrerPolicy(ReferrerPolicy::Always); + else if (equalLettersIgnoringASCIICase(policy, "origin")) + setReferrerPolicy(ReferrerPolicy::Origin); + else if (equalLettersIgnoringASCIICase(policy, "no-referrer-when-downgrade") || equalLettersIgnoringASCIICase(policy, "default")) + setReferrerPolicy(ReferrerPolicy::Default); + else { + addConsoleMessage(MessageSource::Rendering, MessageLevel::Error, "Failed to set referrer policy: The value '" + policy + "' is not one of 'no-referrer', 'origin', 'no-referrer-when-downgrade', or 'unsafe-url'. Defaulting to 'no-referrer'."); + setReferrerPolicy(ReferrerPolicy::Never); + } } MouseEventWithHitTestResults Document::prepareMouseEvent(const HitTestRequest& request, const LayoutPoint& documentPoint, const PlatformMouseEvent& event) @@ -3022,7 +3305,7 @@ MouseEventWithHitTestResults Document::prepareMouseEvent(const HitTestRequest& r renderView()->hitTest(request, result); if (!request.readOnly()) - updateHoverActiveState(request, result.innerElement(), &event); + updateHoverActiveState(request, result.targetElement()); return MouseEventWithHitTestResults(event, result); } @@ -3035,11 +3318,7 @@ bool Document::childTypeAllowed(NodeType type) const case CDATA_SECTION_NODE: case DOCUMENT_FRAGMENT_NODE: case DOCUMENT_NODE: - case ENTITY_NODE: - case ENTITY_REFERENCE_NODE: - case NOTATION_NODE: case TEXT_NODE: - case XPATH_NAMESPACE_NODE: return false; case COMMENT_NODE: case PROCESSING_INSTRUCTION_NODE: @@ -3056,103 +3335,97 @@ bool Document::childTypeAllowed(NodeType type) const return false; } -bool Document::canReplaceChild(Node* newChild, Node* oldChild) +bool Document::canAcceptChild(const Node& newChild, const Node* refChild, AcceptChildOperation operation) const { - if (!oldChild) - // ContainerNode::replaceChild will raise a NOT_FOUND_ERR. + if (operation == AcceptChildOperation::Replace && refChild->nodeType() == newChild.nodeType()) return true; - if (oldChild->nodeType() == newChild->nodeType()) + switch (newChild.nodeType()) { + case ATTRIBUTE_NODE: + case CDATA_SECTION_NODE: + case DOCUMENT_NODE: + case TEXT_NODE: + return false; + case COMMENT_NODE: + case PROCESSING_INSTRUCTION_NODE: return true; - - int numDoctypes = 0; - int numElements = 0; - - // First, check how many doctypes and elements we have, not counting - // the child we're about to remove. - for (Node* c = firstChild(); c; c = c->nextSibling()) { - if (c == oldChild) - continue; - - switch (c->nodeType()) { - case DOCUMENT_TYPE_NODE: - numDoctypes++; - break; - case ELEMENT_NODE: - numElements++; - break; - default: - break; + case DOCUMENT_FRAGMENT_NODE: { + bool hasSeenElementChild = false; + for (auto* node = downcast(newChild).firstChild(); node; node = node->nextSibling()) { + if (is(*node)) { + if (hasSeenElementChild) + return false; + hasSeenElementChild = true; + } + if (!canAcceptChild(*node, refChild, operation)) + return false; } + break; } - - // Then, see how many doctypes and elements might be added by the new child. - if (newChild->isDocumentFragment()) { - for (Node* c = newChild->firstChild(); c; c = c->nextSibling()) { - switch (c->nodeType()) { - case ATTRIBUTE_NODE: - case CDATA_SECTION_NODE: - case DOCUMENT_FRAGMENT_NODE: - case DOCUMENT_NODE: - case ENTITY_NODE: - case ENTITY_REFERENCE_NODE: - case NOTATION_NODE: - case TEXT_NODE: - case XPATH_NAMESPACE_NODE: + case DOCUMENT_TYPE_NODE: { + auto* existingDocType = childrenOfType(*this).first(); + if (operation == AcceptChildOperation::Replace) { + // parent has a doctype child that is not child, or an element is preceding child. + if (existingDocType && existingDocType != refChild) return false; - case COMMENT_NODE: - case PROCESSING_INSTRUCTION_NODE: - break; - case DOCUMENT_TYPE_NODE: - numDoctypes++; - break; - case ELEMENT_NODE: - numElements++; - break; + if (refChild->previousElementSibling()) + return false; + } else { + ASSERT(operation == AcceptChildOperation::InsertOrAdd); + if (existingDocType) + return false; + if ((refChild && refChild->previousElementSibling()) || (!refChild && firstElementChild())) + return false; + } + break; + } + case ELEMENT_NODE: { + auto* existingElementChild = firstElementChild(); + if (operation == AcceptChildOperation::Replace) { + if (existingElementChild && existingElementChild != refChild) + return false; + for (auto* child = refChild->nextSibling(); child; child = child->nextSibling()) { + if (is(*child)) + return false; + } + } else { + ASSERT(operation == AcceptChildOperation::InsertOrAdd); + if (existingElementChild) + return false; + for (auto* child = refChild; child; child = child->nextSibling()) { + if (is(*child)) + return false; } } - } else { - switch (newChild->nodeType()) { - case ATTRIBUTE_NODE: - case CDATA_SECTION_NODE: - case DOCUMENT_FRAGMENT_NODE: - case DOCUMENT_NODE: - case ENTITY_NODE: - case ENTITY_REFERENCE_NODE: - case NOTATION_NODE: - case TEXT_NODE: - case XPATH_NAMESPACE_NODE: - return false; - case COMMENT_NODE: - case PROCESSING_INSTRUCTION_NODE: - return true; - case DOCUMENT_TYPE_NODE: - numDoctypes++; - break; - case ELEMENT_NODE: - numElements++; - break; - } + break; + } } - - if (numElements > 1 || numDoctypes > 1) - return false; - return true; } -PassRefPtr Document::cloneNode(bool deep) +Ref Document::cloneNodeInternal(Document&, CloningOperation type) { - RefPtr clone = cloneDocumentWithoutChildren(); + Ref clone = cloneDocumentWithoutChildren(); clone->cloneDataFromDocument(*this); - if (deep) - cloneChildNodes(clone.get()); - return clone.release(); + switch (type) { + case CloningOperation::OnlySelf: + case CloningOperation::SelfWithTemplateContent: + break; + case CloningOperation::Everything: + cloneChildNodes(clone); + break; + } + return WTFMove(clone); } -PassRefPtr Document::cloneDocumentWithoutChildren() const +Ref Document::cloneDocumentWithoutChildren() const { - return isXHTMLDocument() ? createXHTML(nullptr, url()) : create(nullptr, url()); + if (isXMLDocument()) { + if (isXHTMLDocument()) + return XMLDocument::createXHTML(nullptr, url()); + return XMLDocument::create(nullptr, url()); + } + return create(nullptr, url()); } void Document::cloneDataFromDocument(const Document& other) @@ -3162,144 +3435,147 @@ void Document::cloneDataFromDocument(const Document& other) m_baseURLOverride = other.baseURLOverride(); m_documentURI = other.documentURI(); - setCompatibilityMode(other.compatibilityMode()); - setSecurityOrigin(other.securityOrigin()); + setCompatibilityMode(other.m_compatibilityMode); + setContextDocument(other.contextDocument()); + setSecurityOriginPolicy(other.securityOriginPolicy()); + overrideMIMEType(other.contentType()); setDecoder(other.decoder()); } -StyleSheetList* Document::styleSheets() +StyleSheetList& Document::styleSheets() { if (!m_styleSheetList) m_styleSheetList = StyleSheetList::create(this); - return m_styleSheetList.get(); + return *m_styleSheetList; } String Document::preferredStylesheetSet() const { - return m_styleSheetCollection.preferredStylesheetSetName(); + return styleScope().preferredStylesheetSetName(); } String Document::selectedStylesheetSet() const { - return m_styleSheetCollection.selectedStylesheetSetName(); + return styleScope().selectedStylesheetSetName(); } void Document::setSelectedStylesheetSet(const String& aString) { - m_styleSheetCollection.setSelectedStylesheetSetName(aString); - styleResolverChanged(DeferRecalcStyle); + styleScope().setSelectedStylesheetSetName(aString); } void Document::evaluateMediaQueryList() { if (m_mediaQueryMatcher) m_mediaQueryMatcher->styleResolverChanged(); + + checkViewportDependentPictures(); } -void Document::optimizedStyleSheetUpdateTimerFired(Timer&) +void Document::checkViewportDependentPictures() { - styleResolverChanged(RecalcStyleIfNeeded); + Vector changedPictures; + HashSet::iterator end = m_viewportDependentPictures.end(); + for (HashSet::iterator it = m_viewportDependentPictures.begin(); it != end; ++it) { + if ((*it)->viewportChangeAffectedPicture()) + changedPictures.append(*it); + } + for (auto* picture : changedPictures) + picture->sourcesChanged(); } -void Document::scheduleOptimizedStyleSheetUpdate() +void Document::updateViewportUnitsOnResize() { - if (m_optimizedStyleSheetUpdateTimer.isActive()) + if (!hasStyleWithViewportUnits()) return; - m_styleSheetCollection.setPendingUpdateType(DocumentStyleSheetCollection::OptimizedUpdate); - m_optimizedStyleSheetUpdateTimer.startOneShot(0); -} -void Document::styleResolverChanged(StyleResolverUpdateFlag updateFlag) -{ - if (m_optimizedStyleSheetUpdateTimer.isActive()) - m_optimizedStyleSheetUpdateTimer.stop(); + styleScope().resolver().clearCachedPropertiesAffectedByViewportUnits(); - // Don't bother updating, since we haven't loaded all our style info yet - // and haven't calculated the style selector for the first time. - if (!hasLivingRenderTree() || (!m_didCalculateStyleResolver && !haveStylesheetsLoaded())) { - m_styleResolver.clear(); - return; + // FIXME: Ideally, we should save the list of elements that have viewport units and only iterate over those. + for (Element* element = ElementTraversal::firstWithin(rootNode()); element; element = ElementTraversal::nextIncludingPseudo(*element)) { + auto* renderer = element->renderer(); + if (renderer && renderer->style().hasViewportUnits()) + element->invalidateStyle(); } - m_didCalculateStyleResolver = true; - -#ifdef INSTRUMENT_LAYOUT_SCHEDULING - if (!ownerElement()) - printf("Beginning update of style selector at time %lld.\n", elapsedTime().count()); -#endif +} - DocumentStyleSheetCollection::UpdateFlag styleSheetUpdate = (updateFlag == RecalcStyleIfNeeded || updateFlag == DeferRecalcStyleIfNeeded) - ? DocumentStyleSheetCollection::OptimizedUpdate - : DocumentStyleSheetCollection::FullUpdate; - bool stylesheetChangeRequiresStyleRecalc = m_styleSheetCollection.updateActiveStyleSheets(styleSheetUpdate); +void Document::addAudioProducer(MediaProducer* audioProducer) +{ + m_audioProducers.add(audioProducer); + updateIsPlayingMedia(); +} - if (updateFlag == DeferRecalcStyle) { - scheduleForcedStyleRecalc(); - return; - } +void Document::removeAudioProducer(MediaProducer* audioProducer) +{ + m_audioProducers.remove(audioProducer); + updateIsPlayingMedia(); +} - if (updateFlag == DeferRecalcStyleIfNeeded) { - if (stylesheetChangeRequiresStyleRecalc) - scheduleForcedStyleRecalc(); - return; - } +void Document::updateIsPlayingMedia(uint64_t sourceElementID) +{ + MediaProducer::MediaStateFlags state = MediaProducer::IsNotPlaying; + for (auto* audioProducer : m_audioProducers) + state |= audioProducer->mediaState(); - if (!stylesheetChangeRequiresStyleRecalc) - return; +#if ENABLE(MEDIA_SESSION) + if (HTMLMediaElement* sourceElement = HTMLMediaElement::elementWithID(sourceElementID)) { + if (sourceElement->isPlaying()) + state |= MediaProducer::IsSourceElementPlaying; - // This recalcStyle initiates a new recalc cycle. We need to bracket it to - // make sure animations get the correct update time - { - AnimationUpdateBlock animationUpdateBlock(m_frame ? &m_frame->animation() : nullptr); - recalcStyle(Style::Force); + if (auto* session = sourceElement->session()) { + if (auto* controls = session->controls()) { + if (controls->previousTrackEnabled()) + state |= MediaProducer::IsPreviousTrackControlEnabled; + if (controls->nextTrackEnabled()) + state |= MediaProducer::IsNextTrackControlEnabled; + } + } } - -#ifdef INSTRUMENT_LAYOUT_SCHEDULING - if (!ownerElement()) - printf("Finished update of style selector at time %lld\n", elapsedTime().count()); #endif - if (renderView()) { - renderView()->setNeedsLayoutAndPrefWidthsRecalc(); - if (view()) - view()->scheduleRelayout(); - } + if (state == m_mediaState) + return; - evaluateMediaQueryList(); + m_mediaState = state; + + if (page()) + page()->updateIsPlayingMedia(sourceElementID); } -void Document::notifySeamlessChildDocumentsOfStylesheetUpdate() const +void Document::pageMutedStateDidChange() { - // If we're not in a frame yet any potential child documents won't have a StyleResolver to update. - if (!frame()) - return; + for (auto* audioProducer : m_audioProducers) + audioProducer->pageMutedStateDidChange(); +} - // Seamless child frames are expected to notify their seamless children recursively, so we only do direct children. - for (Frame* child = frame()->tree().firstChild(); child; child = child->tree().nextSibling()) { - Document* childDocument = child->document(); - if (childDocument->shouldDisplaySeamlesslyWithParent()) { - ASSERT(&childDocument->seamlessParentIFrame()->document() == this); - childDocument->seamlessParentUpdatedStylesheets(); - } - } +static bool isNodeInSubtree(Node& node, Node& container, bool amongChildrenOnly) +{ + if (amongChildrenOnly) + return node.isDescendantOf(container); + else + return &node == &container || node.isDescendantOf(container); } -void Document::removeFocusedNodeOfSubtree(Node* node, bool amongChildrenOnly) +void Document::removeFocusedNodeOfSubtree(Node& node, bool amongChildrenOnly) { - if (!m_focusedElement || this->inPageCache()) // If the document is in the page cache, then we don't need to clear out the focused node. + if (!m_focusedElement || pageCacheState() != NotInPageCache) // If the document is in the page cache, then we don't need to clear out the focused node. return; - Element* focusedElement = node->treeScope().focusedElement(); + Element* focusedElement = node.treeScope().focusedElementInScope(); if (!focusedElement) return; - - bool nodeInSubtree = false; - if (amongChildrenOnly) - nodeInSubtree = focusedElement->isDescendantOf(node); - else - nodeInSubtree = (focusedElement == node) || focusedElement->isDescendantOf(node); - if (nodeInSubtree) - setFocusedElement(nullptr); + if (isNodeInSubtree(*focusedElement, node, amongChildrenOnly)) { + // FIXME: We should avoid synchronously updating the style inside setFocusedElement. + // FIXME: Object elements should avoid loading a frame synchronously in a post style recalc callback. + SubframeLoadingDisabler disabler(is(node) ? &downcast(node) : nullptr); + setFocusedElement(nullptr, FocusDirectionNone, FocusRemovalEventsMode::DoNotDispatch); + // Set the focus navigation starting node to the previous focused element so that + // we can fallback to the siblings or parent node for the next search. + // Also we need to call removeFocusNavigationNodeOfSubtree after this function because + // setFocusedElement(nullptr) will reset m_focusNavigationStartingNode. + setFocusNavigationStartingNode(focusedElement); + } } void Document::hoveredElementDidDetach(Element* element) @@ -3325,6 +3601,7 @@ void Document::elementInActiveChainDidDetach(Element* element) } #if ENABLE(DASHBOARD_SUPPORT) + const Vector& Document::annotatedRegions() const { return m_annotatedRegions; @@ -3335,12 +3612,12 @@ void Document::setAnnotatedRegions(const Vector& regions) m_annotatedRegions = regions; setAnnotatedRegionsDirty(false); } + #endif -bool Document::setFocusedElement(PassRefPtr prpNewFocusedElement, FocusDirection direction) +bool Document::setFocusedElement(Element* element, FocusDirection direction, FocusRemovalEventsMode eventsMode) { - RefPtr newFocusedElement = prpNewFocusedElement; - + RefPtr newFocusedElement = element; // Make sure newFocusedElement is actually in this document if (newFocusedElement && (&newFocusedElement->document() != this)) return true; @@ -3348,46 +3625,53 @@ bool Document::setFocusedElement(PassRefPtr prpNewFocusedElement, Focus if (m_focusedElement == newFocusedElement) return true; - if (m_inPageCache) + if (pageCacheState() != NotInPageCache) return false; bool focusChangeBlocked = false; - RefPtr oldFocusedElement = m_focusedElement.release(); + RefPtr oldFocusedElement = WTFMove(m_focusedElement); // Remove focus from the existing focus node (if any) if (oldFocusedElement) { - if (oldFocusedElement->active()) - oldFocusedElement->setActive(false); - oldFocusedElement->setFocus(false); + setFocusNavigationStartingNode(nullptr); + + if (eventsMode == FocusRemovalEventsMode::Dispatch) { + // Dispatch a change event for form control elements that have been edited. + if (is(*oldFocusedElement)) { + HTMLFormControlElement& formControlElement = downcast(*oldFocusedElement); + if (formControlElement.wasChangedSinceLastFormControlChangeEvent()) + formControlElement.dispatchFormControlChangeEvent(); + } - // Dispatch a change event for form control elements that have been edited. - if (oldFocusedElement->isFormControlElement()) { - HTMLFormControlElement* formControlElement = toHTMLFormControlElement(oldFocusedElement.get()); - if (formControlElement->wasChangedSinceLastFormControlChangeEvent()) - formControlElement->dispatchFormControlChangeEvent(); - } + // Dispatch the blur event and let the node do any other blur related activities (important for text fields) + oldFocusedElement->dispatchBlurEvent(newFocusedElement.copyRef()); - // Dispatch the blur event and let the node do any other blur related activities (important for text fields) - oldFocusedElement->dispatchBlurEvent(newFocusedElement); + if (m_focusedElement) { + // handler shifted focus + focusChangeBlocked = true; + newFocusedElement = nullptr; + } - if (m_focusedElement) { - // handler shifted focus - focusChangeBlocked = true; - newFocusedElement = nullptr; - } - - oldFocusedElement->dispatchFocusOutEvent(eventNames().focusoutEvent, newFocusedElement); // DOM level 3 name for the bubbling blur event. - // FIXME: We should remove firing DOMFocusOutEvent event when we are sure no content depends - // on it, probably when is resolved. - oldFocusedElement->dispatchFocusOutEvent(eventNames().DOMFocusOutEvent, newFocusedElement); // DOM level 2 name for compatibility. + oldFocusedElement->dispatchFocusOutEvent(eventNames().focusoutEvent, newFocusedElement.copyRef()); // DOM level 3 name for the bubbling blur event. + // FIXME: We should remove firing DOMFocusOutEvent event when we are sure no content depends + // on it, probably when is resolved. + oldFocusedElement->dispatchFocusOutEvent(eventNames().DOMFocusOutEvent, newFocusedElement.copyRef()); // DOM level 2 name for compatibility. - if (m_focusedElement) { - // handler shifted focus - focusChangeBlocked = true; - newFocusedElement = nullptr; + if (m_focusedElement) { + // handler shifted focus + focusChangeBlocked = true; + newFocusedElement = nullptr; + } + } else { + // Match the order in HTMLTextFormControlElement::dispatchBlurEvent. + if (is(*oldFocusedElement)) + downcast(*oldFocusedElement).endEditing(); + if (page()) + page()->chrome().client().elementDidBlur(*oldFocusedElement); + ASSERT(!m_focusedElement); } - + if (oldFocusedElement->isRootEditableElement()) frame()->editor().didEndEditing(); @@ -3407,9 +3691,10 @@ bool Document::setFocusedElement(PassRefPtr prpNewFocusedElement, Focus } // Set focus on the new node m_focusedElement = newFocusedElement; + setFocusNavigationStartingNode(m_focusedElement.get()); // Dispatch the focus event and let the node do any other focus related activities (important for text fields) - m_focusedElement->dispatchFocusEvent(oldFocusedElement, direction); + m_focusedElement->dispatchFocusEvent(oldFocusedElement.copyRef(), direction); if (m_focusedElement != newFocusedElement) { // handler shifted focus @@ -3417,7 +3702,7 @@ bool Document::setFocusedElement(PassRefPtr prpNewFocusedElement, Focus goto SetFocusedNodeDone; } - m_focusedElement->dispatchFocusInEvent(eventNames().focusinEvent, oldFocusedElement); // DOM level 3 bubbling focus event. + m_focusedElement->dispatchFocusInEvent(eventNames().focusinEvent, oldFocusedElement.copyRef()); // DOM level 3 bubbling focus event. if (m_focusedElement != newFocusedElement) { // handler shifted focus @@ -3427,7 +3712,7 @@ bool Document::setFocusedElement(PassRefPtr prpNewFocusedElement, Focus // FIXME: We should remove firing DOMFocusInEvent event when we are sure no content depends // on it, probably when is m. - m_focusedElement->dispatchFocusInEvent(eventNames().DOMFocusInEvent, oldFocusedElement); // DOM level 2 for compatibility. + m_focusedElement->dispatchFocusInEvent(eventNames().DOMFocusInEvent, oldFocusedElement.copyRef()); // DOM level 2 for compatibility. if (m_focusedElement != newFocusedElement) { // handler shifted focus @@ -3473,34 +3758,93 @@ SetFocusedNodeDone: return !focusChangeBlocked; } -void Document::setCSSTarget(Element* n) +static bool shouldResetFocusNavigationStartingNode(Node& node) +{ + // Setting focus navigation starting node to the following nodes means that we should start + // the search from the beginning of the document. + return is(node) || is(node); +} + +void Document::setFocusNavigationStartingNode(Node* node) +{ + if (!m_frame) + return; + + m_focusNavigationStartingNodeIsRemoved = false; + if (!node || shouldResetFocusNavigationStartingNode(*node)) { + m_focusNavigationStartingNode = nullptr; + return; + } + + m_focusNavigationStartingNode = node; +} + +Element* Document::focusNavigationStartingNode(FocusDirection direction) const +{ + if (m_focusedElement) { + if (!m_focusNavigationStartingNode || !m_focusNavigationStartingNode->isDescendantOf(m_focusedElement.get())) + return m_focusedElement.get(); + } + + if (!m_focusNavigationStartingNode) + return nullptr; + + Node* node = m_focusNavigationStartingNode.get(); + + // When the node was removed from the document tree. This case is not specified in the spec: + // https://html.spec.whatwg.org/multipage/interaction.html#sequential-focus-navigation-starting-point + // Current behaivor is to move the sequential navigation node to / after (based on the focus direction) + // the previous sibling of the removed node. + if (m_focusNavigationStartingNodeIsRemoved) { + Node* nextNode = NodeTraversal::next(*node); + if (!nextNode) + nextNode = node; + if (direction == FocusDirectionForward) + return ElementTraversal::previous(*nextNode); + if (is(*nextNode)) + return downcast(nextNode); + return ElementTraversal::next(*nextNode); + } + + if (is(*node)) + return downcast(node); + if (Element* elementBeforeNextFocusableElement = direction == FocusDirectionForward ? ElementTraversal::previous(*node) : ElementTraversal::next(*node)) + return elementBeforeNextFocusableElement; + return node->parentOrShadowHostElement(); +} + +void Document::setCSSTarget(Element* targetNode) { if (m_cssTarget) - m_cssTarget->didAffectSelector(AffectedSelectorTarget); - m_cssTarget = n; - if (n) - n->didAffectSelector(AffectedSelectorTarget); + m_cssTarget->invalidateStyleForSubtree(); + m_cssTarget = targetNode; + if (targetNode) + targetNode->invalidateStyleForSubtree(); } -void Document::registerNodeList(LiveNodeList& list) +void Document::registerNodeListForInvalidation(LiveNodeList& list) { m_nodeListAndCollectionCounts[list.invalidationType()]++; - if (list.isRootedAtDocument()) - m_listsInvalidatedAtDocument.add(&list); + if (!list.isRootedAtDocument()) + return; + ASSERT(!list.isRegisteredForInvalidationAtDocument()); + list.setRegisteredForInvalidationAtDocument(true); + m_listsInvalidatedAtDocument.add(&list); } -void Document::unregisterNodeList(LiveNodeList& list) +void Document::unregisterNodeListForInvalidation(LiveNodeList& list) { m_nodeListAndCollectionCounts[list.invalidationType()]--; - if (list.isRootedAtDocument()) { - ASSERT(m_listsInvalidatedAtDocument.contains(&list)); - m_listsInvalidatedAtDocument.remove(&list); - } + if (!list.isRegisteredForInvalidationAtDocument()) + return; + + list.setRegisteredForInvalidationAtDocument(false); + ASSERT(m_listsInvalidatedAtDocument.contains(&list)); + m_listsInvalidatedAtDocument.remove(&list); } void Document::registerCollection(HTMLCollection& collection) { - m_nodeListAndCollectionCounts[InvalidateOnIdNameAttrChange]++; m_nodeListAndCollectionCounts[collection.invalidationType()]++; if (collection.isRootedAtDocument()) m_collectionsInvalidatedAtDocument.add(&collection); @@ -3508,12 +3852,25 @@ void Document::registerCollection(HTMLCollection& collection) void Document::unregisterCollection(HTMLCollection& collection) { - m_nodeListAndCollectionCounts[InvalidateOnIdNameAttrChange]--; + ASSERT(m_nodeListAndCollectionCounts[collection.invalidationType()]); m_nodeListAndCollectionCounts[collection.invalidationType()]--; - if (collection.isRootedAtDocument()) { - ASSERT(m_collectionsInvalidatedAtDocument.contains(&collection)); - m_collectionsInvalidatedAtDocument.remove(&collection); - } + if (!collection.isRootedAtDocument()) + return; + + m_collectionsInvalidatedAtDocument.remove(&collection); +} + +void Document::collectionCachedIdNameMap(const HTMLCollection& collection) +{ + ASSERT_UNUSED(collection, collection.hasNamedElementCache()); + m_nodeListAndCollectionCounts[InvalidateOnIdNameAttrChange]++; +} + +void Document::collectionWillClearIdNameMap(const HTMLCollection& collection) +{ + ASSERT_UNUSED(collection, collection.hasNamedElementCache()); + ASSERT(m_nodeListAndCollectionCounts[InvalidateOnIdNameAttrChange]); + m_nodeListAndCollectionCounts[InvalidateOnIdNameAttrChange]--; } void Document::attachNodeIterator(NodeIterator* ni) @@ -3528,72 +3885,105 @@ void Document::detachNodeIterator(NodeIterator* ni) m_nodeIterators.remove(ni); } -void Document::moveNodeIteratorsToNewDocument(Node* node, Document* newDocument) +void Document::moveNodeIteratorsToNewDocument(Node& node, Document& newDocument) { - HashSet nodeIteratorsList = m_nodeIterators; - HashSet::const_iterator nodeIteratorsEnd = nodeIteratorsList.end(); - for (HashSet::const_iterator it = nodeIteratorsList.begin(); it != nodeIteratorsEnd; ++it) { - if ((*it)->root() == node) { - detachNodeIterator(*it); - newDocument->attachNodeIterator(*it); + Vector nodeIterators; + copyToVector(m_nodeIterators, nodeIterators); + for (auto* it : nodeIterators) { + if (&it->root() == &node) { + detachNodeIterator(it); + newDocument.attachNodeIterator(it); } } } void Document::updateRangesAfterChildrenChanged(ContainerNode& container) { - if (!m_ranges.isEmpty()) { - for (auto it = m_ranges.begin(), end = m_ranges.end(); it != end; ++it) - (*it)->nodeChildrenChanged(container); - } + for (auto* range : m_ranges) + range->nodeChildrenChanged(container); } void Document::nodeChildrenWillBeRemoved(ContainerNode& container) { - if (!m_ranges.isEmpty()) { - for (auto it = m_ranges.begin(), end = m_ranges.end(); it != end; ++it) - (*it)->nodeChildrenWillBeRemoved(container); - } + NoEventDispatchAssertion assertNoEventDispatch; + + removeFocusedNodeOfSubtree(container, true /* amongChildrenOnly */); + removeFocusNavigationNodeOfSubtree(container, true /* amongChildrenOnly */); + +#if ENABLE(FULLSCREEN_API) + removeFullScreenElementOfSubtree(container, true /* amongChildrenOnly */); +#endif - for (auto it = m_nodeIterators.begin(), end = m_nodeIterators.end(); it != end; ++it) { + for (auto* range : m_ranges) + range->nodeChildrenWillBeRemoved(container); + + for (auto* it : m_nodeIterators) { for (Node* n = container.firstChild(); n; n = n->nextSibling()) - (*it)->nodeWillBeRemoved(n); + it->nodeWillBeRemoved(*n); } if (Frame* frame = this->frame()) { for (Node* n = container.firstChild(); n; n = n->nextSibling()) { - frame->eventHandler().nodeWillBeRemoved(n); - frame->selection().nodeWillBeRemoved(n); - frame->page()->dragCaretController().nodeWillBeRemoved(n); + frame->eventHandler().nodeWillBeRemoved(*n); + frame->selection().nodeWillBeRemoved(*n); + frame->page()->dragCaretController().nodeWillBeRemoved(*n); } } + + if (m_markers->hasMarkers()) { + for (Text* textNode = TextNodeTraversal::firstChild(container); textNode; textNode = TextNodeTraversal::nextSibling(*textNode)) + m_markers->removeMarkers(textNode); + } } -void Document::nodeWillBeRemoved(Node* n) +void Document::nodeWillBeRemoved(Node& node) { - HashSet::const_iterator nodeIteratorsEnd = m_nodeIterators.end(); - for (HashSet::const_iterator it = m_nodeIterators.begin(); it != nodeIteratorsEnd; ++it) - (*it)->nodeWillBeRemoved(n); + NoEventDispatchAssertion assertNoEventDispatch; - if (!m_ranges.isEmpty()) { - HashSet::const_iterator rangesEnd = m_ranges.end(); - for (HashSet::const_iterator it = m_ranges.begin(); it != rangesEnd; ++it) - (*it)->nodeWillBeRemoved(n); - } + removeFocusedNodeOfSubtree(node); + removeFocusNavigationNodeOfSubtree(node); + +#if ENABLE(FULLSCREEN_API) + removeFullScreenElementOfSubtree(node); +#endif + + for (auto* it : m_nodeIterators) + it->nodeWillBeRemoved(node); + + for (auto* range : m_ranges) + range->nodeWillBeRemoved(node); if (Frame* frame = this->frame()) { - frame->eventHandler().nodeWillBeRemoved(n); - frame->selection().nodeWillBeRemoved(n); - frame->page()->dragCaretController().nodeWillBeRemoved(n); + frame->eventHandler().nodeWillBeRemoved(node); + frame->selection().nodeWillBeRemoved(node); + frame->page()->dragCaretController().nodeWillBeRemoved(node); + } + + if (is(node)) + m_markers->removeMarkers(&node); +} + +static Node* fallbackFocusNavigationStartingNodeAfterRemoval(Node& node) +{ + return node.previousSibling() ? node.previousSibling() : node.parentNode(); +} + +void Document::removeFocusNavigationNodeOfSubtree(Node& node, bool amongChildrenOnly) +{ + if (!m_focusNavigationStartingNode) + return; + + if (isNodeInSubtree(*m_focusNavigationStartingNode, node, amongChildrenOnly)) { + m_focusNavigationStartingNode = amongChildrenOnly ? &node : fallbackFocusNavigationStartingNodeAfterRemoval(node); + m_focusNavigationStartingNodeIsRemoved = true; } } void Document::textInserted(Node* text, unsigned offset, unsigned length) { if (!m_ranges.isEmpty()) { - HashSet::const_iterator end = m_ranges.end(); - for (HashSet::const_iterator it = m_ranges.begin(); it != end; ++it) - (*it)->textInserted(text, offset, length); + for (auto* range : m_ranges) + range->textInserted(text, offset, length); } // Update the markers for spelling and grammar checking. @@ -3603,9 +3993,8 @@ void Document::textInserted(Node* text, unsigned offset, unsigned length) void Document::textRemoved(Node* text, unsigned offset, unsigned length) { if (!m_ranges.isEmpty()) { - HashSet::const_iterator end = m_ranges.end(); - for (HashSet::const_iterator it = m_ranges.begin(); it != end; ++it) - (*it)->textRemoved(text, offset, length); + for (auto* range : m_ranges) + range->textRemoved(text, offset, length); } // Update the markers for spelling and grammar checking. @@ -3617,9 +4006,8 @@ void Document::textNodesMerged(Text* oldNode, unsigned offset) { if (!m_ranges.isEmpty()) { NodeWithIndex oldNodeWithIndex(oldNode); - HashSet::const_iterator end = m_ranges.end(); - for (HashSet::const_iterator it = m_ranges.begin(); it != end; ++it) - (*it)->textNodesMerged(oldNodeWithIndex, offset); + for (auto* range : m_ranges) + range->textNodesMerged(oldNodeWithIndex, offset); } // FIXME: This should update markers for spelling and grammar checking. @@ -3627,11 +4015,8 @@ void Document::textNodesMerged(Text* oldNode, unsigned offset) void Document::textNodeSplit(Text* oldNode) { - if (!m_ranges.isEmpty()) { - HashSet::const_iterator end = m_ranges.end(); - for (HashSet::const_iterator it = m_ranges.begin(); it != end; ++it) - (*it)->textNodeSplit(oldNode); - } + for (auto* range : m_ranges) + range->textNodeSplit(oldNode); // FIXME: This should update markers for spelling and grammar checking. } @@ -3641,7 +4026,7 @@ void Document::createDOMWindow() ASSERT(m_frame); ASSERT(!m_domWindow); - m_domWindow = DOMWindow::create(this); + m_domWindow = DOMWindow::create(*this); ASSERT(m_domWindow->document() == this); ASSERT(m_domWindow->frame() == m_frame); @@ -3653,39 +4038,51 @@ void Document::takeDOMWindowFrom(Document* document) ASSERT(!m_domWindow); ASSERT(document->m_domWindow); // A valid DOMWindow is needed by CachedFrame for its documents. - ASSERT(!document->inPageCache()); + ASSERT(pageCacheState() == NotInPageCache); - m_domWindow = document->m_domWindow.release(); - m_domWindow->didSecureTransitionTo(this); + m_domWindow = WTFMove(document->m_domWindow); + m_domWindow->didSecureTransitionTo(*this); ASSERT(m_domWindow->document() == this); ASSERT(m_domWindow->frame() == m_frame); } -void Document::setWindowAttributeEventListener(const AtomicString& eventType, PassRefPtr listener) +Document& Document::contextDocument() const +{ + if (m_contextDocument) + return *m_contextDocument.get(); + return const_cast(*this); +} + +void Document::setAttributeEventListener(const AtomicString& eventType, const QualifiedName& attributeName, const AtomicString& attributeValue, DOMWrapperWorld& isolatedWorld) +{ + setAttributeEventListener(eventType, JSLazyEventListener::create(*this, attributeName, attributeValue), isolatedWorld); +} + +void Document::setWindowAttributeEventListener(const AtomicString& eventType, RefPtr&& listener, DOMWrapperWorld& isolatedWorld) { if (!m_domWindow) return; - m_domWindow->setAttributeEventListener(eventType, listener); + m_domWindow->setAttributeEventListener(eventType, WTFMove(listener), isolatedWorld); } -void Document::setWindowAttributeEventListener(const AtomicString& eventType, const QualifiedName& attributeName, const AtomicString& attributeValue) +void Document::setWindowAttributeEventListener(const AtomicString& eventType, const QualifiedName& attributeName, const AtomicString& attributeValue, DOMWrapperWorld& isolatedWorld) { - if (!m_frame) + if (!m_domWindow) return; - setWindowAttributeEventListener(eventType, JSLazyEventListener::createForDOMWindow(*m_frame, attributeName, attributeValue)); + setWindowAttributeEventListener(eventType, JSLazyEventListener::create(*m_domWindow, attributeName, attributeValue), isolatedWorld); } -EventListener* Document::getWindowAttributeEventListener(const AtomicString& eventType) +EventListener* Document::getWindowAttributeEventListener(const AtomicString& eventType, DOMWrapperWorld& isolatedWorld) { if (!m_domWindow) return nullptr; - return m_domWindow->getAttributeEventListener(eventType); + return m_domWindow->attributeEventListener(eventType, isolatedWorld); } -void Document::dispatchWindowEvent(PassRefPtr event, PassRefPtr target) +void Document::dispatchWindowEvent(Event& event, EventTarget* target) { - ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden()); + ASSERT_WITH_SECURITY_IMPLICATION(NoEventDispatchAssertion::isEventAllowedInMainThread()); if (!m_domWindow) return; m_domWindow->dispatchEvent(event, target); @@ -3693,38 +4090,117 @@ void Document::dispatchWindowEvent(PassRefPtr event, PassRefPtrdispatchLoadEvent(); m_loadEventFinished = true; + m_cachedResourceLoader->documentDidFinishLoadEvent(); } -void Document::enqueueWindowEvent(PassRefPtr event) +void Document::enqueueWindowEvent(Ref&& event) { event->setTarget(m_domWindow.get()); - m_eventQueue.enqueueEvent(event); + m_eventQueue.enqueueEvent(WTFMove(event)); } -void Document::enqueueDocumentEvent(PassRefPtr event) +void Document::enqueueDocumentEvent(Ref&& event) { event->setTarget(this); - m_eventQueue.enqueueEvent(event); + m_eventQueue.enqueueEvent(WTFMove(event)); } -void Document::enqueueOverflowEvent(PassRefPtr event) +void Document::enqueueOverflowEvent(Ref&& event) { - m_eventQueue.enqueueEvent(event); + m_eventQueue.enqueueEvent(WTFMove(event)); } -PassRefPtr Document::createEvent(const String& eventType, ExceptionCode& ec) +ExceptionOr> Document::createEvent(const String& type) { - RefPtr event = EventFactory::create(eventType); - if (event) - return event.release(); + // Please do *not* add new event classes to this function unless they are + // required for compatibility of some actual legacy web content. - ec = NOT_SUPPORTED_ERR; - return nullptr; + // This mechanism is superceded by use of event constructors. + // That is what we should use for any new event classes. + + // The following strings are the ones from the DOM specification + // . + + if (equalLettersIgnoringASCIICase(type, "customevent")) + return Ref { CustomEvent::create() }; + if (equalLettersIgnoringASCIICase(type, "event") || equalLettersIgnoringASCIICase(type, "events") || equalLettersIgnoringASCIICase(type, "htmlevents")) + return Event::createForBindings(); + if (equalLettersIgnoringASCIICase(type, "keyboardevent") || equalLettersIgnoringASCIICase(type, "keyboardevents")) + return Ref { KeyboardEvent::createForBindings() }; + if (equalLettersIgnoringASCIICase(type, "messageevent")) + return Ref { MessageEvent::createForBindings() }; + if (equalLettersIgnoringASCIICase(type, "mouseevent") || equalLettersIgnoringASCIICase(type, "mouseevents")) + return Ref { MouseEvent::createForBindings() }; + if (equalLettersIgnoringASCIICase(type, "uievent") || equalLettersIgnoringASCIICase(type, "uievents")) + return Ref { UIEvent::createForBindings() }; + if (equalLettersIgnoringASCIICase(type, "popstateevent")) + return Ref { PopStateEvent::createForBindings() }; + +#if ENABLE(TOUCH_EVENTS) + if (equalLettersIgnoringASCIICase(type, "touchevent")) + return Ref { TouchEvent::createForBindings() }; +#endif + + // The following string comes from the SVG specifications + // + // . + // However, since there is no provision for initializing the event once it is created, + // there is no practical value in this feature. + + if (equalLettersIgnoringASCIICase(type, "svgzoomevents")) + return Ref { SVGZoomEvent::createForBindings() }; + + // The following strings are for event classes where WebKit supplies an init function. + // These strings are not part of the DOM specification and we would like to eliminate them. + // However, we currently include these because we have concerns about backward compatibility. + + // FIXME: For each of the strings below, prove there is no content depending on it and remove + // both the string and the corresponding init function for that class. + + if (equalLettersIgnoringASCIICase(type, "compositionevent")) + return Ref { CompositionEvent::createForBindings() }; + if (equalLettersIgnoringASCIICase(type, "hashchangeevent")) + return Ref { HashChangeEvent::createForBindings() }; + if (equalLettersIgnoringASCIICase(type, "mutationevent") || equalLettersIgnoringASCIICase(type, "mutationevents")) + return Ref { MutationEvent::createForBindings() }; + if (equalLettersIgnoringASCIICase(type, "overflowevent")) + return Ref { OverflowEvent::createForBindings() }; + if (equalLettersIgnoringASCIICase(type, "storageevent")) + return Ref { StorageEvent::createForBindings() }; + if (equalLettersIgnoringASCIICase(type, "textevent")) + return Ref { TextEvent::createForBindings() }; + if (equalLettersIgnoringASCIICase(type, "wheelevent")) + return Ref { WheelEvent::createForBindings() }; + +#if ENABLE(DEVICE_ORIENTATION) + if (equalLettersIgnoringASCIICase(type, "devicemotionevent")) + return Ref { DeviceMotionEvent::createForBindings() }; + if (equalLettersIgnoringASCIICase(type, "deviceorientationevent")) + return Ref { DeviceOrientationEvent::createForBindings() }; +#endif + + return Exception { NOT_SUPPORTED_ERR }; +} + +bool Document::hasListenerTypeForEventType(PlatformEvent::Type eventType) const +{ + switch (eventType) { + case PlatformEvent::MouseForceChanged: + return m_listenerTypes & Document::FORCECHANGED_LISTENER; + case PlatformEvent::MouseForceDown: + return m_listenerTypes & Document::FORCEDOWN_LISTENER; + case PlatformEvent::MouseForceUp: + return m_listenerTypes & Document::FORCEUP_LISTENER; + case PlatformEvent::MouseScroll: + return m_listenerTypes & Document::SCROLL_LISTENER; + default: + return false; + } } void Document::addListenerTypeIfNeeded(const AtomicString& eventType) @@ -3743,11 +4219,11 @@ void Document::addListenerTypeIfNeeded(const AtomicString& eventType) addListenerType(DOMCHARACTERDATAMODIFIED_LISTENER); else if (eventType == eventNames().overflowchangedEvent) addListenerType(OVERFLOWCHANGED_LISTENER); - else if (eventType == eventNames().webkitAnimationStartEvent) + else if (eventType == eventNames().webkitAnimationStartEvent || eventType == eventNames().animationstartEvent) addListenerType(ANIMATIONSTART_LISTENER); - else if (eventType == eventNames().webkitAnimationEndEvent) + else if (eventType == eventNames().webkitAnimationEndEvent || eventType == eventNames().animationendEvent) addListenerType(ANIMATIONEND_LISTENER); - else if (eventType == eventNames().webkitAnimationIterationEvent) + else if (eventType == eventNames().webkitAnimationIterationEvent || eventType == eventNames().animationiterationEvent) addListenerType(ANIMATIONITERATION_LISTENER); else if (eventType == eventNames().webkitTransitionEndEvent || eventType == eventNames().transitionendEvent) addListenerType(TRANSITIONEND_LISTENER); @@ -3755,6 +4231,14 @@ void Document::addListenerTypeIfNeeded(const AtomicString& eventType) addListenerType(BEFORELOAD_LISTENER); else if (eventType == eventNames().scrollEvent) addListenerType(SCROLL_LISTENER); + else if (eventType == eventNames().webkitmouseforcewillbeginEvent) + addListenerType(FORCEWILLBEGIN_LISTENER); + else if (eventType == eventNames().webkitmouseforcechangedEvent) + addListenerType(FORCECHANGED_LISTENER); + else if (eventType == eventNames().webkitmouseforcedownEvent) + addListenerType(FORCEDOWN_LISTENER); + else if (eventType == eventNames().webkitmouseforceupEvent) + addListenerType(FORCEUP_LISTENER); } CSSStyleDeclaration* Document::getOverrideStyle(Element*, const String&) @@ -3769,7 +4253,7 @@ HTMLFrameOwnerElement* Document::ownerElement() const return frame()->ownerElement(); } -String Document::cookie(ExceptionCode& ec) const +ExceptionOr Document::cookie() { if (page() && !page()->settings().cookieEnabled()) return String(); @@ -3778,37 +4262,38 @@ String Document::cookie(ExceptionCode& ec) const // INVALID_STATE_ERR exception on getting if the Document has no // browsing context. - if (!securityOrigin()->canAccessCookies()) { - ec = SECURITY_ERR; - return String(); - } + if (!securityOrigin().canAccessCookies()) + return Exception { SECURITY_ERR }; URL cookieURL = this->cookieURL(); if (cookieURL.isEmpty()) return String(); - return cookies(this, cookieURL); + if (!isDOMCookieCacheValid()) + setCachedDOMCookies(cookies(*this, cookieURL)); + + return String { cachedDOMCookies() }; } -void Document::setCookie(const String& value, ExceptionCode& ec) +ExceptionOr Document::setCookie(const String& value) { if (page() && !page()->settings().cookieEnabled()) - return; + return { }; // FIXME: The HTML5 DOM spec states that this attribute can raise an // INVALID_STATE_ERR exception on setting if the Document has no // browsing context. - if (!securityOrigin()->canAccessCookies()) { - ec = SECURITY_ERR; - return; - } + if (!securityOrigin().canAccessCookies()) + return Exception { SECURITY_ERR }; URL cookieURL = this->cookieURL(); if (cookieURL.isEmpty()) - return; + return { }; - setCookies(this, cookieURL, value); + invalidateDOMCookieCache(); + setCookies(*this, cookieURL, value); + return { }; } String Document::referrer() const @@ -3818,80 +4303,94 @@ String Document::referrer() const return String(); } +String Document::origin() const +{ + return securityOrigin().toString(); +} + String Document::domain() const { - return securityOrigin()->domain(); + return securityOrigin().domain(); } -void Document::setDomain(const String& newDomain, ExceptionCode& ec) +ExceptionOr Document::setDomain(const String& newDomain) { - if (SchemeRegistry::isDomainRelaxationForbiddenForURLScheme(securityOrigin()->protocol())) { - ec = SECURITY_ERR; - return; - } + if (SchemeRegistry::isDomainRelaxationForbiddenForURLScheme(securityOrigin().protocol())) + return Exception { SECURITY_ERR }; // Both NS and IE specify that changing the domain is only allowed when // the new domain is a suffix of the old domain. // FIXME: We should add logging indicating why a domain was not allowed. + String oldDomain = domain(); + // If the new domain is the same as the old domain, still call - // securityOrigin()->setDomainForDOM. This will change the + // securityOrigin().setDomainForDOM. This will change the // security check behavior. For example, if a page loaded on port 8000 // assigns its current domain using document.domain, the page will // allow other pages loaded on different ports in the same domain that // have also assigned to access this page. - if (equalIgnoringCase(domain(), newDomain)) { - securityOrigin()->setDomainFromDOM(newDomain); - return; + if (equalIgnoringASCIICase(oldDomain, newDomain)) { + securityOrigin().setDomainFromDOM(newDomain); + return { }; } - int oldLength = domain().length(); - int newLength = newDomain.length(); // e.g. newDomain = webkit.org (10) and domain() = www.webkit.org (14) - if (newLength >= oldLength) { - ec = SECURITY_ERR; - return; - } + unsigned oldLength = oldDomain.length(); + unsigned newLength = newDomain.length(); + if (newLength >= oldLength) + return Exception { SECURITY_ERR }; - String test = domain(); - // Check that it's a subdomain, not e.g. "ebkit.org" - if (test[oldLength - newLength - 1] != '.') { - ec = SECURITY_ERR; - return; - } + auto ipAddressSetting = settings().treatIPAddressAsDomain() ? OriginAccessEntry::TreatIPAddressAsDomain : OriginAccessEntry::TreatIPAddressAsIPAddress; + OriginAccessEntry accessEntry { securityOrigin().protocol(), newDomain, OriginAccessEntry::AllowSubdomains, ipAddressSetting }; + if (!accessEntry.matchesOrigin(securityOrigin())) + return Exception { SECURITY_ERR }; - // Now test is "webkit.org" from domain() - // and we check that it's the same thing as newDomain - test.remove(0, oldLength - newLength); - if (test != newDomain) { - ec = SECURITY_ERR; - return; - } + if (oldDomain[oldLength - newLength - 1] != '.') + return Exception { SECURITY_ERR }; + if (StringView { oldDomain }.substring(oldLength - newLength) != newDomain) + return Exception { SECURITY_ERR }; - securityOrigin()->setDomainFromDOM(newDomain); + securityOrigin().setDomainFromDOM(newDomain); + return { }; } // http://www.whatwg.org/specs/web-apps/current-work/#dom-document-lastmodified -String Document::lastModified() const +String Document::lastModified() { - DateComponents date; - bool foundDate = false; - if (m_frame) { - String httpLastModified; - if (DocumentLoader* documentLoader = loader()) - httpLastModified = documentLoader->response().httpHeaderField("Last-Modified"); - if (!httpLastModified.isEmpty()) { - date.setMillisecondsSinceEpochForDateTime(parseDate(httpLastModified)); - foundDate = true; - } - } + using namespace std::chrono; + std::optional dateTime; + if (m_frame && loader()) + dateTime = loader()->response().lastModified(); + // FIXME: If this document came from the file system, the HTML5 - // specificiation tells us to read the last modification date from the file + // specification tells us to read the last modification date from the file // system. - if (!foundDate) - date.setMillisecondsSinceEpochForDateTime(currentTimeMS()); - return String::format("%02d/%02d/%04d %02d:%02d:%02d", date.month() + 1, date.monthDay(), date.fullYear(), date.hour(), date.minute(), date.second()); + if (!dateTime) { + dateTime = system_clock::now(); +#if ENABLE(WEB_REPLAY) + auto& cursor = inputCursor(); + if (cursor.isCapturing()) + cursor.appendInput(duration_cast(dateTime.value().time_since_epoch()).count()); + else if (cursor.isReplaying()) { + if (auto* input = cursor.fetchInput()) + dateTime = system_clock::time_point(milliseconds(static_cast(input->fallbackValue()))); + } +#endif + } + + auto ctime = system_clock::to_time_t(dateTime.value()); + auto localDateTime = std::localtime(&ctime); + return String::format("%02d/%02d/%04d %02d:%02d:%02d", localDateTime->tm_mon + 1, localDateTime->tm_mday, 1900 + localDateTime->tm_year, localDateTime->tm_hour, localDateTime->tm_min, localDateTime->tm_sec); +} + +void Document::setCookieURL(const URL& url) +{ + if (m_cookieURL == url) + return; + m_cookieURL = url; + invalidateDOMCookieCache(); } static bool isValidNameNonASCII(const LChar* characters, unsigned length) @@ -3964,68 +4463,57 @@ bool Document::isValidName(const String& name) return isValidNameNonASCII(characters, length); } -bool Document::parseQualifiedName(const String& qualifiedName, String& prefix, String& localName, ExceptionCode& ec) +ExceptionOr> Document::parseQualifiedName(const String& qualifiedName) { unsigned length = qualifiedName.length(); - if (!length) { - ec = INVALID_CHARACTER_ERR; - return false; - } + if (!length) + return Exception { INVALID_CHARACTER_ERR }; bool nameStart = true; bool sawColon = false; - int colonPos = 0; + unsigned colonPosition = 0; - const UChar* s = qualifiedName.deprecatedCharacters(); - for (unsigned i = 0; i < length;) { + for (unsigned i = 0; i < length; ) { UChar32 c; - U16_NEXT(s, i, length, c) + U16_NEXT(qualifiedName, i, length, c) if (c == ':') { - if (sawColon) { - ec = NAMESPACE_ERR; - return false; // multiple colons: not allowed - } + if (sawColon) + return Exception { NAMESPACE_ERR }; nameStart = true; sawColon = true; - colonPos = i - 1; + colonPosition = i - 1; } else if (nameStart) { - if (!isValidNameStart(c)) { - ec = INVALID_CHARACTER_ERR; - return false; - } + if (!isValidNameStart(c)) + return Exception { INVALID_CHARACTER_ERR }; nameStart = false; } else { - if (!isValidNamePart(c)) { - ec = INVALID_CHARACTER_ERR; - return false; - } + if (!isValidNamePart(c)) + return Exception { INVALID_CHARACTER_ERR }; } } - if (!sawColon) { - prefix = String(); - localName = qualifiedName; - } else { - prefix = qualifiedName.substring(0, colonPos); - if (prefix.isEmpty()) { - ec = NAMESPACE_ERR; - return false; - } - localName = qualifiedName.substring(colonPos + 1); - } + if (!sawColon) + return std::pair { { }, { qualifiedName } }; - if (localName.isEmpty()) { - ec = NAMESPACE_ERR; - return false; - } + if (!colonPosition || length - colonPosition <= 1) + return Exception { NAMESPACE_ERR }; - return true; + return std::pair { StringView { qualifiedName }.substring(0, colonPosition).toAtomicString(), StringView { qualifiedName }.substring(colonPosition + 1).toAtomicString() }; } -void Document::setDecoder(PassRefPtr decoder) +ExceptionOr Document::parseQualifiedName(const AtomicString& namespaceURI, const String& qualifiedName) { - m_decoder = decoder; + auto parseResult = parseQualifiedName(qualifiedName); + if (parseResult.hasException()) + return parseResult.releaseException(); + auto parsedPieces = parseResult.releaseReturnValue(); + return QualifiedName { parsedPieces.first, parsedPieces.second, namespaceURI }; +} + +void Document::setDecoder(RefPtr&& decoder) +{ + m_decoder = WTFMove(decoder); } URL Document::completeURL(const String& url, const URL& baseURLOverride) const @@ -4046,20 +4534,18 @@ URL Document::completeURL(const String& url) const return completeURL(url, m_baseURL); } -void Document::setInPageCache(bool flag) +void Document::setPageCacheState(PageCacheState state) { - if (m_inPageCache == flag) + if (m_pageCacheState == state) return; - m_inPageCache = flag; + m_pageCacheState = state; FrameView* v = view(); Page* page = this->page(); - if (page) - page->lockAllOverlayScrollbarsToHidden(flag); - - if (flag) { + switch (state) { + case InPageCache: if (v) { // FIXME: There is some scrolling related work that needs to happen whenever a page goes into the // page cache and similar work that needs to occur when it comes out. This is where we do the work @@ -4073,74 +4559,110 @@ void Document::setInPageCache(bool flag) v->resetScrollbarsAndClearContentsSize(); if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) scrollingCoordinator->clearStateTree(); - } else - v->resetScrollbars(); + } } + +#if ENABLE(POINTER_LOCK) + exitPointerLock(); +#endif + + styleScope().clearResolver(); + clearSelectorQueryCache(); m_styleRecalcTimer.stop(); - } else { + + clearSharedObjectPool(); + break; + case NotInPageCache: if (childNeedsStyleRecalc()) scheduleStyleRecalc(); + break; + case AboutToEnterPageCache: + break; } } void Document::documentWillBecomeInactive() { -#if USE(ACCELERATED_COMPOSITING) if (renderView()) renderView()->setIsInWindow(false); -#endif } -void Document::documentWillSuspendForPageCache() +void Document::suspend(ActiveDOMObject::ReasonForSuspension reason) { + if (m_isSuspended) + return; + documentWillBecomeInactive(); - HashSet::iterator end = m_documentSuspensionCallbackElements.end(); - for (HashSet::iterator i = m_documentSuspensionCallbackElements.begin(); i != end; ++i) - (*i)->documentWillSuspendForPageCache(); + for (auto* element : m_documentSuspensionCallbackElements) + element->prepareForDocumentSuspension(); #ifndef NDEBUG // Clear the update flag to be able to check if the viewport arguments update // is dispatched, after the document is restored from the page cache. m_didDispatchViewportPropertiesChanged = false; #endif + + ASSERT(page()); + page()->lockAllOverlayScrollbarsToHidden(true); + + if (RenderView* view = renderView()) { + if (view->usesCompositing()) + view->compositor().cancelCompositingLayerUpdate(); + } + + suspendScheduledTasks(reason); + + ASSERT(m_frame); + m_frame->clearTimers(); + + m_visualUpdatesAllowed = false; + m_visualUpdatesSuppressionTimer.stop(); + + m_isSuspended = true; } -void Document::documentDidResumeFromPageCache() +void Document::resume(ActiveDOMObject::ReasonForSuspension reason) { + if (!m_isSuspended) + return; + Vector elements; copyToVector(m_documentSuspensionCallbackElements, elements); - Vector::iterator end = elements.end(); - for (Vector::iterator i = elements.begin(); i != end; ++i) - (*i)->documentDidResumeFromPageCache(); + for (auto* element : elements) + element->resumeFromDocumentSuspension(); -#if USE(ACCELERATED_COMPOSITING) if (renderView()) renderView()->setIsInWindow(true); -#endif ASSERT(page()); page()->lockAllOverlayScrollbarsToHidden(false); ASSERT(m_frame); m_frame->loader().client().dispatchDidBecomeFrameset(isFrameSet()); + m_frame->animation().resumeAnimationsForDocument(this); + + resumeScheduledTasks(reason); + + m_visualUpdatesAllowed = true; + + m_isSuspended = false; } -void Document::registerForPageCacheSuspensionCallbacks(Element* e) +void Document::registerForDocumentSuspensionCallbacks(Element* e) { m_documentSuspensionCallbackElements.add(e); } -void Document::unregisterForPageCacheSuspensionCallbacks(Element* e) +void Document::unregisterForDocumentSuspensionCallbacks(Element* e) { m_documentSuspensionCallbackElements.remove(e); } void Document::mediaVolumeDidChange() { - HashSet::iterator end = m_mediaVolumeCallbackElements.end(); - for (HashSet::iterator i = m_mediaVolumeCallbackElements.begin(); i != end; ++i) - (*i)->mediaVolumeDidChange(); + for (auto* element : m_mediaVolumeCallbackElements) + element->mediaVolumeDidChange(); } void Document::registerForMediaVolumeCallbacks(Element* e) @@ -4153,17 +4675,39 @@ void Document::unregisterForMediaVolumeCallbacks(Element* e) m_mediaVolumeCallbackElements.remove(e); } +bool Document::audioPlaybackRequiresUserGesture() const +{ + if (DocumentLoader* loader = this->loader()) { + // If an audio playback policy was set during navigation, use it. If not, use the global settings. + AutoplayPolicy policy = loader->autoplayPolicy(); + if (policy != AutoplayPolicy::Default) + return policy == AutoplayPolicy::AllowWithoutSound || policy == AutoplayPolicy::Deny; + } + + return settings().audioPlaybackRequiresUserGesture(); +} + +bool Document::videoPlaybackRequiresUserGesture() const +{ + if (DocumentLoader* loader = this->loader()) { + // If a video playback policy was set during navigation, use it. If not, use the global settings. + AutoplayPolicy policy = loader->autoplayPolicy(); + if (policy != AutoplayPolicy::Default) + return policy == AutoplayPolicy::Deny; + } + + return settings().videoPlaybackRequiresUserGesture(); +} + void Document::storageBlockingStateDidChange() { - if (Settings* settings = this->settings()) - securityOrigin()->setStorageBlockingPolicy(settings->storageBlockingPolicy()); + securityOrigin().setStorageBlockingPolicy(settings().storageBlockingPolicy()); } void Document::privateBrowsingStateDidChange() { - HashSet::iterator end = m_privateBrowsingStateChangedElements.end(); - for (HashSet::iterator it = m_privateBrowsingStateChangedElements.begin(); it != end; ++it) - (*it)->privateBrowsingStateDidChange(); + for (auto* element : m_privateBrowsingStateChangedElements) + element->privateBrowsingStateDidChange(); } void Document::registerForPrivateBrowsingStateChangedCallbacks(Element* e) @@ -4177,10 +4721,11 @@ void Document::unregisterForPrivateBrowsingStateChangedCallbacks(Element* e) } #if ENABLE(VIDEO_TRACK) + void Document::registerForCaptionPreferencesChangedCallbacks(Element* e) { if (page()) - page()->group().captionPreferences()->setInterestedInCaptionPreferenceChanges(); + page()->group().captionPreferences().setInterestedInCaptionPreferenceChanges(); m_captionPreferencesChangedElements.add(e); } @@ -4192,10 +4737,46 @@ void Document::unregisterForCaptionPreferencesChangedCallbacks(Element* e) void Document::captionPreferencesChanged() { - HashSet::iterator end = m_captionPreferencesChangedElements.end(); - for (HashSet::iterator it = m_captionPreferencesChangedElements.begin(); it != end; ++it) - (*it)->captionPreferencesChanged(); + for (auto* element : m_captionPreferencesChangedElements) + element->captionPreferencesChanged(); +} + +#endif + +#if ENABLE(MEDIA_CONTROLS_SCRIPT) + +void Document::registerForPageScaleFactorChangedCallbacks(HTMLMediaElement* element) +{ + m_pageScaleFactorChangedElements.add(element); +} + +void Document::unregisterForPageScaleFactorChangedCallbacks(HTMLMediaElement* element) +{ + m_pageScaleFactorChangedElements.remove(element); +} + +void Document::pageScaleFactorChangedAndStable() +{ + for (HTMLMediaElement* mediaElement : m_pageScaleFactorChangedElements) + mediaElement->pageScaleFactorChanged(); +} + +void Document::registerForUserInterfaceLayoutDirectionChangedCallbacks(HTMLMediaElement& element) +{ + m_userInterfaceLayoutDirectionChangedElements.add(&element); +} + +void Document::unregisterForUserInterfaceLayoutDirectionChangedCallbacks(HTMLMediaElement& element) +{ + m_userInterfaceLayoutDirectionChangedElements.remove(&element); } + +void Document::userInterfaceLayoutDirectionChanged() +{ + for (auto* mediaElement : m_userInterfaceLayoutDirectionChangedElements) + mediaElement->userInterfaceLayoutDirectionChanged(); +} + #endif void Document::setShouldCreateRenderers(bool f) @@ -4224,6 +4805,7 @@ static Editor::Command command(Document* document, const String& commandName, bo bool Document::execCommand(const String& commandName, bool userInterface, const String& value) { + EventQueueScope eventQueueScope; return command(this, commandName, userInterface).execute(value); } @@ -4252,9 +4834,8 @@ String Document::queryCommandValue(const String& commandName) return command(this, commandName).value(); } -void Document::pushCurrentScript(PassRefPtr newCurrentScript) +void Document::pushCurrentScript(HTMLScriptElement* newCurrentScript) { - ASSERT(newCurrentScript); m_currentScriptStack.append(newCurrentScript); } @@ -4269,7 +4850,7 @@ void Document::popCurrentScript() void Document::applyXSLTransform(ProcessingInstruction* pi) { RefPtr processor = XSLTProcessor::create(); - processor->setXSLStyleSheet(static_cast(pi->sheet())); + processor->setXSLStyleSheet(downcast(pi->sheet())); String resultMIMEType; String newSource; String resultEncoding; @@ -4278,12 +4859,11 @@ void Document::applyXSLTransform(ProcessingInstruction* pi) // FIXME: If the transform failed we should probably report an error (like Mozilla does). Frame* ownerFrame = frame(); processor->createDocumentFromSource(newSource, resultEncoding, resultMIMEType, this, ownerFrame); - InspectorInstrumentation::frameDocumentUpdated(ownerFrame); } -void Document::setTransformSource(PassOwnPtr source) +void Document::setTransformSource(std::unique_ptr source) { - m_transformSource = source; + m_transformSource = WTFMove(source); } #endif @@ -4295,7 +4875,24 @@ void Document::setDesignMode(InheritedBool value) frame->document()->scheduleForcedStyleRecalc(); } -Document::InheritedBool Document::getDesignMode() const +String Document::designMode() const +{ + return inDesignMode() ? ASCIILiteral("on") : ASCIILiteral("off"); +} + +void Document::setDesignMode(const String& value) +{ + InheritedBool mode; + if (equalLettersIgnoringASCIICase(value, "on")) + mode = on; + else if (equalLettersIgnoringASCIICase(value, "off")) + mode = off; + else + mode = inherit; + setDesignMode(mode); +} + +auto Document::getDesignMode() const -> InheritedBool { return m_designMode; } @@ -4321,109 +4918,113 @@ Document* Document::parentDocument() const Document& Document::topDocument() const { + // FIXME: This special-casing avoids incorrectly determined top documents during the process + // of AXObjectCache teardown or notification posting for cached or being-destroyed documents. + if (pageCacheState() == NotInPageCache && !m_renderTreeBeingDestroyed) { + if (!m_frame) + return const_cast(*this); + // This should always be non-null. + Document* mainFrameDocument = m_frame->mainFrame().document(); + return mainFrameDocument ? *mainFrameDocument : const_cast(*this); + } + Document* document = const_cast(this); - while (Element* element = document->ownerElement()) + while (HTMLFrameOwnerElement* element = document->ownerElement()) document = &element->document(); return *document; } -PassRefPtr Document::createAttribute(const String& name, ExceptionCode& ec) +ExceptionOr> Document::createAttribute(const String& name) { - return createAttributeNS(String(), name, ec, true); + return createAttributeNS({ }, isHTMLDocument() ? name.convertToASCIILowercase() : name, true); } -PassRefPtr Document::createAttributeNS(const String& namespaceURI, const String& qualifiedName, ExceptionCode& ec, bool shouldIgnoreNamespaceChecks) +ExceptionOr> Document::createAttributeNS(const AtomicString& namespaceURI, const String& qualifiedName, bool shouldIgnoreNamespaceChecks) { - String prefix, localName; - if (!parseQualifiedName(qualifiedName, prefix, localName, ec)) - return nullptr; - - QualifiedName qName(prefix, localName, namespaceURI); - - if (!shouldIgnoreNamespaceChecks && !hasValidNamespaceForAttributes(qName)) { - ec = NAMESPACE_ERR; - return nullptr; - } - - return Attr::create(*this, qName, emptyString()); + auto parseResult = parseQualifiedName(namespaceURI, qualifiedName); + if (parseResult.hasException()) + return parseResult.releaseException(); + QualifiedName parsedName { parseResult.releaseReturnValue() }; + if (!shouldIgnoreNamespaceChecks && !hasValidNamespaceForAttributes(parsedName)) + return Exception { NAMESPACE_ERR }; + return Attr::create(*this, parsedName, emptyString()); } -#if ENABLE(SVG) const SVGDocumentExtensions* Document::svgExtensions() { return m_svgExtensions.get(); } -SVGDocumentExtensions* Document::accessSVGExtensions() +SVGDocumentExtensions& Document::accessSVGExtensions() { if (!m_svgExtensions) - m_svgExtensions = adoptPtr(new SVGDocumentExtensions(this)); - return m_svgExtensions.get(); + m_svgExtensions = std::make_unique(this); + return *m_svgExtensions; } bool Document::hasSVGRootNode() const { return documentElement() && documentElement()->hasTagName(SVGNames::svgTag); } -#endif -PassRefPtr Document::ensureCachedCollection(CollectionType type) +template +Ref Document::ensureCachedCollection() { - return ensureRareData().ensureNodeLists().addCachedCollection(*this, type); + return ensureRareData().ensureNodeLists().addCachedCollection::traversalType>>(*this, collectionType); } -PassRefPtr Document::images() +Ref Document::images() { - return ensureCachedCollection(DocImages); + return ensureCachedCollection(); } -PassRefPtr Document::applets() +Ref Document::applets() { - return ensureCachedCollection(DocApplets); + return ensureCachedCollection(); } -PassRefPtr Document::embeds() +Ref Document::embeds() { - return ensureCachedCollection(DocEmbeds); + return ensureCachedCollection(); } -PassRefPtr Document::plugins() +Ref Document::plugins() { // This is an alias for embeds() required for the JS DOM bindings. - return ensureCachedCollection(DocEmbeds); + return ensureCachedCollection(); } -PassRefPtr Document::scripts() +Ref Document::scripts() { - return ensureCachedCollection(DocScripts); + return ensureCachedCollection(); } -PassRefPtr Document::links() +Ref Document::links() { - return ensureCachedCollection(DocLinks); + return ensureCachedCollection(); } -PassRefPtr Document::forms() +Ref Document::forms() { - return ensureCachedCollection(DocForms); + return ensureCachedCollection(); } -PassRefPtr Document::anchors() +Ref Document::anchors() { - return ensureCachedCollection(DocAnchors); + return ensureCachedCollection(); } -PassRefPtr Document::all() +Ref Document::all() { return ensureRareData().ensureNodeLists().addCachedCollection(*this, DocAll); } -PassRefPtr Document::windowNamedItems(const AtomicString& name) +Ref Document::windowNamedItems(const AtomicString& name) { return ensureRareData().ensureNodeLists().addCachedCollection(*this, WindowNamedItems, name); } -PassRefPtr Document::documentNamedItems(const AtomicString& name) +Ref Document::documentNamedItems(const AtomicString& name) { return ensureRareData().ensureNodeLists().addCachedCollection(*this, DocumentNamedItems, name); } @@ -4436,14 +5037,14 @@ void Document::finishedParsing() #if ENABLE(WEB_TIMING) if (!m_documentTiming.domContentLoadedEventStart) - m_documentTiming.domContentLoadedEventStart = monotonicallyIncreasingTime(); + m_documentTiming.domContentLoadedEventStart = MonotonicTime::now(); #endif dispatchEvent(Event::create(eventNames().DOMContentLoadedEvent, true, false)); #if ENABLE(WEB_TIMING) if (!m_documentTiming.domContentLoadedEventEnd) - m_documentTiming.domContentLoadedEventEnd = monotonicallyIncreasingTime(); + m_documentTiming.domContentLoadedEventEnd = MonotonicTime::now(); #endif if (RefPtr f = frame()) { @@ -4458,7 +5059,7 @@ void Document::finishedParsing() f->loader().finishedParsing(); - InspectorInstrumentation::domContentLoadedEventFired(f.get()); + InspectorInstrumentation::domContentLoadedEventFired(*f); } // Schedule dropping of the DocumentSharedObjectPool. We keep it alive for a while after parsing finishes @@ -4468,32 +5069,23 @@ void Document::finishedParsing() static const int timeToKeepSharedObjectPoolAliveAfterParsingFinishedInSeconds = 10; m_sharedObjectPoolClearTimer.startOneShot(timeToKeepSharedObjectPoolAliveAfterParsingFinishedInSeconds); - // Parser should have picked up all preloads by now - m_cachedResourceLoader->clearPreloads(); + // Parser should have picked up all speculative preloads by now + m_cachedResourceLoader->clearPreloads(CachedResourceLoader::ClearPreloadsMode::ClearSpeculativePreloads); } -void Document::sharedObjectPoolClearTimerFired(Timer&) +void Document::clearSharedObjectPool() { - m_sharedObjectPool.clear(); + m_sharedObjectPool = nullptr; + m_sharedObjectPoolClearTimer.stop(); } -void Document::didAccessStyleResolver() -{ - m_styleResolverThrowawayTimer.restart(); -} +#if ENABLE(TELEPHONE_NUMBER_DETECTION) -void Document::styleResolverThrowawayTimerFired(DeferrableOneShotTimer&) -{ - ASSERT(!m_inStyleRecalc); - clearStyleResolver(); -} +// FIXME: Find a better place for this code. -#if PLATFORM(IOS) -// FIXME: Find a better place for this functionality. bool Document::isTelephoneNumberParsingEnabled() const { - Settings* settings = this->settings(); - return settings && settings->telephoneNumberParsingEnabled() && m_isTelephoneNumberParsingAllowed; + return settings().telephoneNumberParsingEnabled() && m_isTelephoneNumberParsingAllowed; } void Document::setIsTelephoneNumberParsingAllowed(bool isTelephoneNumberParsingAllowed) @@ -4505,196 +5097,185 @@ bool Document::isTelephoneNumberParsingAllowed() const { return m_isTelephoneNumberParsingAllowed; } + #endif -PassRefPtr Document::createExpression(const String& expression, - XPathNSResolver* resolver, - ExceptionCode& ec) +ExceptionOr> Document::createExpression(const String& expression, RefPtr&& resolver) { if (!m_xpathEvaluator) m_xpathEvaluator = XPathEvaluator::create(); - return m_xpathEvaluator->createExpression(expression, resolver, ec); + return m_xpathEvaluator->createExpression(expression, WTFMove(resolver)); } -PassRefPtr Document::createNSResolver(Node* nodeResolver) +Ref Document::createNSResolver(Node* nodeResolver) { if (!m_xpathEvaluator) m_xpathEvaluator = XPathEvaluator::create(); return m_xpathEvaluator->createNSResolver(nodeResolver); } -PassRefPtr Document::evaluate(const String& expression, - Node* contextNode, - XPathNSResolver* resolver, - unsigned short type, - XPathResult* result, - ExceptionCode& ec) +ExceptionOr> Document::evaluate(const String& expression, Node* contextNode, RefPtr&& resolver, unsigned short type, XPathResult* result) { if (!m_xpathEvaluator) m_xpathEvaluator = XPathEvaluator::create(); - return m_xpathEvaluator->evaluate(expression, contextNode, resolver, type, result, ec); + return m_xpathEvaluator->evaluate(expression, contextNode, WTFMove(resolver), type, result); } -const Vector& Document::shortcutIconURLs() -{ - // Include any icons where type = link, rel = "shortcut icon". - return iconURLs(Favicon); -} - -const Vector& Document::iconURLs(int iconTypesMask) -{ - m_iconURLs.clear(); - - if (!head() || !(head()->children())) - return m_iconURLs; - - RefPtr children = head()->children(); - unsigned int length = children->length(); - for (unsigned int i = 0; i < length; ++i) { - Node* child = children->item(i); - if (!child->hasTagName(linkTag)) - continue; - HTMLLinkElement* linkElement = toHTMLLinkElement(child); - if (!(linkElement->iconType() & iconTypesMask)) - continue; - if (linkElement->href().isEmpty()) - continue; - - // Put it at the front to ensure that icons seen later take precedence as required by the spec. - IconURL newURL(linkElement->href(), linkElement->iconSizes(), linkElement->type(), linkElement->iconType()); - m_iconURLs.append(newURL); - } - - m_iconURLs.reverse(); - return m_iconURLs; -} - -void Document::addIconURL(const String& url, const String&, const String&, IconType iconType) -{ - if (url.isEmpty()) - return; - - Frame* f = frame(); - if (!f) - return; - - f->loader().didChangeIcons(iconType); -} - -static bool isEligibleForSeamless(Document* parent, Document* child) +static bool shouldInheritSecurityOriginFromOwner(const URL& url) { - // It should not matter what we return for the top-most document. - if (!parent) - return false; - if (parent->isSandboxed(SandboxSeamlessIframes)) - return false; - if (child->isSrcdocDocument()) - return true; - if (parent->securityOrigin()->canAccess(child->securityOrigin())) - return true; - return parent->securityOrigin()->canRequest(child->url()); + // Paraphrased from (8 July 2016) + // + // If a Document has the address "about:blank" + // The origin of the document is the origin it was assigned when its browsing context was created. + // If a Document has the address "about:srcdoc" + // The origin of the document is the origin of its parent document. + // + // Note: We generalize this to invalid URLs because we treat such URLs as about:blank. + // + return url.isEmpty() || equalIgnoringASCIICase(url.string(), blankURL()) || equalLettersIgnoringASCIICase(url.string(), "about:srcdoc"); } void Document::initSecurityContext() { if (haveInitializedSecurityOrigin()) { - ASSERT(securityOrigin()); + ASSERT(SecurityContext::securityOrigin()); return; } if (!m_frame) { // No source for a security context. // This can occur via document.implementation.createDocument(). - m_cookieURL = URL(ParsedURLString, emptyString()); - setSecurityOrigin(SecurityOrigin::createUnique()); - setContentSecurityPolicy(ContentSecurityPolicy::create(this)); + setCookieURL(URL(ParsedURLString, emptyString())); + setSecurityOriginPolicy(SecurityOriginPolicy::create(SecurityOrigin::createUnique())); + setContentSecurityPolicy(std::make_unique(*this)); return; } // In the common case, create the security context from the currently // loading URL with a fresh content security policy. - m_cookieURL = m_url; + setCookieURL(m_url); enforceSandboxFlags(m_frame->loader().effectiveSandboxFlags()); -#if PLATFORM(IOS) - // On iOS we display attachments inline regardless of whether the response includes - // the HTTP header "Content-Disposition: attachment". So, we enforce a unique - // security origin for such documents. As an optimization, we don't need to parse - // the responde header (i.e. call ResourceResponse::isAttachment()) for a synthesized - // document because such documents cannot be an attachment. - if (!m_isSynthesized && m_frame->loader().activeDocumentLoader()->response().isAttachment()) - enforceSandboxFlags(SandboxOrigin); + if (shouldEnforceContentDispositionAttachmentSandbox()) + applyContentDispositionAttachmentSandbox(); + + setSecurityOriginPolicy(SecurityOriginPolicy::create(isSandboxed(SandboxOrigin) ? SecurityOrigin::createUnique() : SecurityOrigin::create(m_url))); + setContentSecurityPolicy(std::make_unique(*this)); + + String overrideContentSecurityPolicy = m_frame->loader().client().overrideContentSecurityPolicy(); + if (!overrideContentSecurityPolicy.isNull()) + contentSecurityPolicy()->didReceiveHeader(overrideContentSecurityPolicy, ContentSecurityPolicyHeaderType::Enforce, ContentSecurityPolicy::PolicyFrom::API); + +#if USE(QUICK_LOOK) + if (shouldEnforceQuickLookSandbox()) + applyQuickLookSandbox(); #endif - setSecurityOrigin(isSandboxed(SandboxOrigin) ? SecurityOrigin::createUnique() : SecurityOrigin::create(m_url)); - setContentSecurityPolicy(ContentSecurityPolicy::create(this)); - - if (Settings* settings = this->settings()) { - if (!settings->webSecurityEnabled()) { - // Web security is turned off. We should let this document access every other document. This is used primary by testing - // harnesses for web sites. - securityOrigin()->grantUniversalAccess(); - } else if (securityOrigin()->isLocal()) { - if (settings->allowUniversalAccessFromFileURLs() || m_frame->loader().client().shouldForceUniversalAccessFromLocalURL(m_url)) { - // Some clients want local URLs to have universal access, but that setting is dangerous for other clients. - securityOrigin()->grantUniversalAccess(); - } else if (!settings->allowFileAccessFromFileURLs()) { - // Some clients want local URLs to have even tighter restrictions by default, and not be able to access other local files. - // FIXME 81578: The naming of this is confusing. Files with restricted access to other local files - // still can have other privileges that can be remembered, thereby not making them unique origins. - securityOrigin()->enforceFilePathSeparation(); - } + if (shouldEnforceHTTP09Sandbox()) { + String message = makeString("Sandboxing '", m_url.stringCenterEllipsizedToLength(), "' because it is using HTTP/0.9."); + addConsoleMessage(MessageSource::Security, MessageLevel::Error, message); + enforceSandboxFlags(SandboxScripts | SandboxPlugins); + } + + if (settings().needsStorageAccessFromFileURLsQuirk()) + securityOrigin().grantStorageAccessFromFileURLsQuirk(); + if (!settings().webSecurityEnabled()) { + // Web security is turned off. We should let this document access every other document. This is used primary by testing + // harnesses for web sites. + securityOrigin().grantUniversalAccess(); + } else if (securityOrigin().isLocal()) { + if (settings().allowUniversalAccessFromFileURLs() || m_frame->loader().client().shouldForceUniversalAccessFromLocalURL(m_url)) { + // Some clients want local URLs to have universal access, but that setting is dangerous for other clients. + securityOrigin().grantUniversalAccess(); + } else if (!settings().allowFileAccessFromFileURLs()) { + // Some clients want local URLs to have even tighter restrictions by default, and not be able to access other local files. + // FIXME 81578: The naming of this is confusing. Files with restricted access to other local files + // still can have other privileges that can be remembered, thereby not making them unique origins. + securityOrigin().enforceFilePathSeparation(); } - securityOrigin()->setStorageBlockingPolicy(settings->storageBlockingPolicy()); } + securityOrigin().setStorageBlockingPolicy(settings().storageBlockingPolicy()); Document* parentDocument = ownerElement() ? &ownerElement()->document() : nullptr; if (parentDocument && m_frame->loader().shouldTreatURLAsSrcdocDocument(url())) { m_isSrcdocDocument = true; setBaseURLOverride(parentDocument->baseURL()); } - - // FIXME: What happens if we inherit the security origin? This check may need to be later. - //