| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| 4 * (C) 2001 Dirk Mueller (mueller@kde.org) | 4 * (C) 2001 Dirk Mueller (mueller@kde.org) |
| 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights
reserved. | 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights |
| 6 * reserved. |
| 6 * | 7 * |
| 7 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
| 8 * modify it under the terms of the GNU Library General Public | 9 * modify it under the terms of the GNU Library General Public |
| 9 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
| 10 * version 2 of the License, or (at your option) any later version. | 11 * version 2 of the License, or (at your option) any later version. |
| 11 * | 12 * |
| 12 * This library is distributed in the hope that it will be useful, | 13 * This library is distributed in the hope that it will be useful, |
| 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 15 * Library General Public License for more details. | 16 * Library General Public License for more details. |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 75 fragment.removeChildren(); | 76 fragment.removeChildren(); |
| 76 return; | 77 return; |
| 77 } | 78 } |
| 78 nodes.append(&node); | 79 nodes.append(&node); |
| 79 if (ContainerNode* oldParent = node.parentNode()) | 80 if (ContainerNode* oldParent = node.parentNode()) |
| 80 oldParent->removeChild(&node, exceptionState); | 81 oldParent->removeChild(&node, exceptionState); |
| 81 } | 82 } |
| 82 | 83 |
| 83 void ContainerNode::parserTakeAllChildrenFrom(ContainerNode& oldParent) { | 84 void ContainerNode::parserTakeAllChildrenFrom(ContainerNode& oldParent) { |
| 84 while (Node* child = oldParent.firstChild()) { | 85 while (Node* child = oldParent.firstChild()) { |
| 85 // Explicitly remove since appending can fail, but this loop shouldn't be in
finite. | 86 // Explicitly remove since appending can fail, but this loop shouldn't be |
| 87 // infinite. |
| 86 oldParent.parserRemoveChild(*child); | 88 oldParent.parserRemoveChild(*child); |
| 87 parserAppendChild(child); | 89 parserAppendChild(child); |
| 88 } | 90 } |
| 89 } | 91 } |
| 90 | 92 |
| 91 ContainerNode::~ContainerNode() { | 93 ContainerNode::~ContainerNode() { |
| 92 DCHECK(needsAttach()); | 94 DCHECK(needsAttach()); |
| 93 } | 95 } |
| 94 | 96 |
| 95 DISABLE_CFI_PERF | 97 DISABLE_CFI_PERF |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 128 isElementNode()) { | 130 isElementNode()) { |
| 129 DCHECK(isChildTypeAllowed(*newChild)); | 131 DCHECK(isChildTypeAllowed(*newChild)); |
| 130 if (containsConsideringHostElements(*newChild)) { | 132 if (containsConsideringHostElements(*newChild)) { |
| 131 exceptionState.throwDOMException( | 133 exceptionState.throwDOMException( |
| 132 HierarchyRequestError, "The new child element contains the parent."); | 134 HierarchyRequestError, "The new child element contains the parent."); |
| 133 return false; | 135 return false; |
| 134 } | 136 } |
| 135 return true; | 137 return true; |
| 136 } | 138 } |
| 137 | 139 |
| 138 // This should never happen, but also protect release builds from tree corrupt
ion. | 140 // This should never happen, but also protect release builds from tree |
| 141 // corruption. |
| 139 DCHECK(!newChild->isPseudoElement()); | 142 DCHECK(!newChild->isPseudoElement()); |
| 140 if (newChild->isPseudoElement()) { | 143 if (newChild->isPseudoElement()) { |
| 141 exceptionState.throwDOMException( | 144 exceptionState.throwDOMException( |
| 142 HierarchyRequestError, "The new child element is a pseudo-element."); | 145 HierarchyRequestError, "The new child element is a pseudo-element."); |
| 143 return false; | 146 return false; |
| 144 } | 147 } |
| 145 | 148 |
| 146 return checkAcceptChildGuaranteedNodeTypes(*newChild, oldChild, | 149 return checkAcceptChildGuaranteedNodeTypes(*newChild, oldChild, |
| 147 exceptionState); | 150 exceptionState); |
| 148 } | 151 } |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 293 ChildListMutationScope mutation(*this); | 296 ChildListMutationScope mutation(*this); |
| 294 insertNodeVector(targets, refChild, AdoptAndInsertBefore()); | 297 insertNodeVector(targets, refChild, AdoptAndInsertBefore()); |
| 295 return newChild; | 298 return newChild; |
| 296 } | 299 } |
| 297 | 300 |
| 298 void ContainerNode::insertBeforeCommon(Node& nextChild, Node& newChild) { | 301 void ContainerNode::insertBeforeCommon(Node& nextChild, Node& newChild) { |
| 299 #if DCHECK_IS_ON() | 302 #if DCHECK_IS_ON() |
| 300 DCHECK(EventDispatchForbiddenScope::isEventDispatchForbidden()); | 303 DCHECK(EventDispatchForbiddenScope::isEventDispatchForbidden()); |
| 301 #endif | 304 #endif |
| 302 DCHECK(ScriptForbiddenScope::isScriptForbidden()); | 305 DCHECK(ScriptForbiddenScope::isScriptForbidden()); |
| 303 DCHECK( | 306 // Use insertBefore if you need to handle reparenting (and want DOM mutation |
| 304 !newChild | 307 // events). |
| 305 .parentNode()); // Use insertBefore if you need to handle reparentin
g (and want DOM mutation events). | 308 DCHECK(!newChild.parentNode()); |
| 306 DCHECK(!newChild.nextSibling()); | 309 DCHECK(!newChild.nextSibling()); |
| 307 DCHECK(!newChild.previousSibling()); | 310 DCHECK(!newChild.previousSibling()); |
| 308 DCHECK(!newChild.isShadowRoot()); | 311 DCHECK(!newChild.isShadowRoot()); |
| 309 | 312 |
| 310 Node* prev = nextChild.previousSibling(); | 313 Node* prev = nextChild.previousSibling(); |
| 311 DCHECK_NE(m_lastChild, prev); | 314 DCHECK_NE(m_lastChild, prev); |
| 312 nextChild.setPreviousSibling(&newChild); | 315 nextChild.setPreviousSibling(&newChild); |
| 313 if (prev) { | 316 if (prev) { |
| 314 DCHECK_NE(firstChild(), nextChild); | 317 DCHECK_NE(firstChild(), nextChild); |
| 315 DCHECK_EQ(prev->nextSibling(), nextChild); | 318 DCHECK_EQ(prev->nextSibling(), nextChild); |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 480 | 483 |
| 481 DEFINE_TRACE_WRAPPERS(ContainerNode) { | 484 DEFINE_TRACE_WRAPPERS(ContainerNode) { |
| 482 visitor->traceWrappers(m_firstChild); | 485 visitor->traceWrappers(m_firstChild); |
| 483 visitor->traceWrappers(m_lastChild); | 486 visitor->traceWrappers(m_lastChild); |
| 484 Node::traceWrappers(visitor); | 487 Node::traceWrappers(visitor); |
| 485 } | 488 } |
| 486 | 489 |
| 487 Node* ContainerNode::removeChild(Node* oldChild, | 490 Node* ContainerNode::removeChild(Node* oldChild, |
| 488 ExceptionState& exceptionState) { | 491 ExceptionState& exceptionState) { |
| 489 // NotFoundError: Raised if oldChild is not a child of this node. | 492 // NotFoundError: Raised if oldChild is not a child of this node. |
| 490 // FIXME: We should never really get PseudoElements in here, but editing will
sometimes | 493 // FIXME: We should never really get PseudoElements in here, but editing will |
| 491 // attempt to remove them still. We should fix that and enable this ASSERT. | 494 // sometimes attempt to remove them still. We should fix that and enable this |
| 492 // DCHECK(!oldChild->isPseudoElement()) | 495 // DCHECK. DCHECK(!oldChild->isPseudoElement()) |
| 493 if (!oldChild || oldChild->parentNode() != this || | 496 if (!oldChild || oldChild->parentNode() != this || |
| 494 oldChild->isPseudoElement()) { | 497 oldChild->isPseudoElement()) { |
| 495 exceptionState.throwDOMException( | 498 exceptionState.throwDOMException( |
| 496 NotFoundError, "The node to be removed is not a child of this node."); | 499 NotFoundError, "The node to be removed is not a child of this node."); |
| 497 return nullptr; | 500 return nullptr; |
| 498 } | 501 } |
| 499 | 502 |
| 500 Node* child = oldChild; | 503 Node* child = oldChild; |
| 501 | 504 |
| 502 document().removeFocusedElementOfSubtree(child); | 505 document().removeFocusedElementOfSubtree(child); |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 584 | 587 |
| 585 Node* prev = oldChild.previousSibling(); | 588 Node* prev = oldChild.previousSibling(); |
| 586 Node* next = oldChild.nextSibling(); | 589 Node* next = oldChild.nextSibling(); |
| 587 removeBetween(prev, next, oldChild); | 590 removeBetween(prev, next, oldChild); |
| 588 | 591 |
| 589 notifyNodeRemoved(oldChild); | 592 notifyNodeRemoved(oldChild); |
| 590 childrenChanged(ChildrenChange::forRemoval(oldChild, prev, next, | 593 childrenChanged(ChildrenChange::forRemoval(oldChild, prev, next, |
| 591 ChildrenChangeSourceParser)); | 594 ChildrenChangeSourceParser)); |
| 592 } | 595 } |
| 593 | 596 |
| 594 // This differs from other remove functions because it forcibly removes all the
children, | 597 // This differs from other remove functions because it forcibly removes all the |
| 595 // regardless of read-only status or event exceptions, e.g. | 598 // children, regardless of read-only status or event exceptions, e.g. |
| 596 void ContainerNode::removeChildren(SubtreeModificationAction action) { | 599 void ContainerNode::removeChildren(SubtreeModificationAction action) { |
| 597 if (!m_firstChild) | 600 if (!m_firstChild) |
| 598 return; | 601 return; |
| 599 | 602 |
| 600 // Do any prep work needed before actually starting to detach | 603 // Do any prep work needed before actually starting to detach |
| 601 // and remove... e.g. stop loading frames, fire unload events. | 604 // and remove... e.g. stop loading frames, fire unload events. |
| 602 willRemoveChildren(); | 605 willRemoveChildren(); |
| 603 | 606 |
| 604 { | 607 { |
| 605 // Removing focus can cause frames to load, either via events (focusout, blu
r) | 608 // Removing focus can cause frames to load, either via events (focusout, |
| 606 // or widget updates (e.g., for <embed>). | 609 // blur) or widget updates (e.g., for <embed>). |
| 607 SubframeLoadingDisabler disabler(*this); | 610 SubframeLoadingDisabler disabler(*this); |
| 608 | 611 |
| 609 // Exclude this node when looking for removed focusedElement since only | 612 // Exclude this node when looking for removed focusedElement since only |
| 610 // children will be removed. | 613 // children will be removed. |
| 611 // This must be later than willRemoveChildren, which might change focus | 614 // This must be later than willRemoveChildren, which might change focus |
| 612 // state of a child. | 615 // state of a child. |
| 613 document().removeFocusedElementOfSubtree(this, true); | 616 document().removeFocusedElementOfSubtree(this, true); |
| 614 | 617 |
| 615 // Removing a node from a selection can cause widget updates. | 618 // Removing a node from a selection can cause widget updates. |
| 616 document().nodeChildrenWillBeRemoved(*this); | 619 document().nodeChildrenWillBeRemoved(*this); |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 731 notifyNodeInsertedInternal(*shadowRoot, postInsertionNotificationTargets); | 734 notifyNodeInsertedInternal(*shadowRoot, postInsertionNotificationTargets); |
| 732 } | 735 } |
| 733 } | 736 } |
| 734 | 737 |
| 735 void ContainerNode::notifyNodeRemoved(Node& root) { | 738 void ContainerNode::notifyNodeRemoved(Node& root) { |
| 736 ScriptForbiddenScope forbidScript; | 739 ScriptForbiddenScope forbidScript; |
| 737 EventDispatchForbiddenScope assertNoEventDispatch; | 740 EventDispatchForbiddenScope assertNoEventDispatch; |
| 738 | 741 |
| 739 for (Node& node : NodeTraversal::inclusiveDescendantsOf(root)) { | 742 for (Node& node : NodeTraversal::inclusiveDescendantsOf(root)) { |
| 740 // As an optimization we skip notifying Text nodes and other leaf nodes | 743 // As an optimization we skip notifying Text nodes and other leaf nodes |
| 741 // of removal when they're not in the Document tree and not in a shadow root
since the virtual | 744 // of removal when they're not in the Document tree and not in a shadow root |
| 742 // call to removedFrom is not needed. | 745 // since the virtual call to removedFrom is not needed. |
| 743 if (!node.isContainerNode() && !node.isInTreeScope()) | 746 if (!node.isContainerNode() && !node.isInTreeScope()) |
| 744 continue; | 747 continue; |
| 745 node.removedFrom(this); | 748 node.removedFrom(this); |
| 746 for (ShadowRoot* shadowRoot = node.youngestShadowRoot(); shadowRoot; | 749 for (ShadowRoot* shadowRoot = node.youngestShadowRoot(); shadowRoot; |
| 747 shadowRoot = shadowRoot->olderShadowRoot()) | 750 shadowRoot = shadowRoot->olderShadowRoot()) |
| 748 notifyNodeRemoved(*shadowRoot); | 751 notifyNodeRemoved(*shadowRoot); |
| 749 } | 752 } |
| 750 } | 753 } |
| 751 | 754 |
| 752 DISABLE_CFI_PERF | 755 DISABLE_CFI_PERF |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 826 } | 829 } |
| 827 DCHECK(o); | 830 DCHECK(o); |
| 828 | 831 |
| 829 if (!o->isInline() || o->isAtomicInlineLevel()) { | 832 if (!o->isInline() || o->isAtomicInlineLevel()) { |
| 830 point = o->localToAbsolute(FloatPoint(), UseTransforms); | 833 point = o->localToAbsolute(FloatPoint(), UseTransforms); |
| 831 return true; | 834 return true; |
| 832 } | 835 } |
| 833 | 836 |
| 834 if (p->node() && p->node() == this && o->isText() && !o->isBR() && | 837 if (p->node() && p->node() == this && o->isText() && !o->isBR() && |
| 835 !toLayoutText(o)->hasTextBoxes()) { | 838 !toLayoutText(o)->hasTextBoxes()) { |
| 836 // Do nothing - skip unrendered whitespace that is a child or next sibling
of the anchor. | 839 // Do nothing - skip unrendered whitespace that is a child or next sibling |
| 837 // FIXME: This fails to skip a whitespace sibling when there was also a wh
itespace child (because p has moved). | 840 // of the anchor. |
| 841 // FIXME: This fails to skip a whitespace sibling when there was also a |
| 842 // whitespace child (because p has moved). |
| 838 } else if ((o->isText() && !o->isBR()) || o->isAtomicInlineLevel()) { | 843 } else if ((o->isText() && !o->isBR()) || o->isAtomicInlineLevel()) { |
| 839 point = FloatPoint(); | 844 point = FloatPoint(); |
| 840 if (o->isText()) { | 845 if (o->isText()) { |
| 841 if (toLayoutText(o)->firstTextBox()) | 846 if (toLayoutText(o)->firstTextBox()) |
| 842 point.move( | 847 point.move( |
| 843 toLayoutText(o)->linesBoundingBox().x(), | 848 toLayoutText(o)->linesBoundingBox().x(), |
| 844 toLayoutText(o)->firstTextBox()->root().lineTop().toFloat()); | 849 toLayoutText(o)->firstTextBox()->root().lineTop().toFloat()); |
| 845 point = o->localToAbsolute(point, UseTransforms); | 850 point = o->localToAbsolute(point, UseTransforms); |
| 846 } else { | 851 } else { |
| 847 DCHECK(o->isBox()); | 852 DCHECK(o->isBox()); |
| 848 LayoutBox* box = toLayoutBox(o); | 853 LayoutBox* box = toLayoutBox(o); |
| 849 point.moveBy(box->location()); | 854 point.moveBy(box->location()); |
| 850 point = o->container()->localToAbsolute(point, UseTransforms); | 855 point = o->container()->localToAbsolute(point, UseTransforms); |
| 851 } | 856 } |
| 852 return true; | 857 return true; |
| 853 } | 858 } |
| 854 } | 859 } |
| 855 | 860 |
| 856 // If the target doesn't have any children or siblings that could be used to c
alculate the scroll position, we must be | 861 // If the target doesn't have any children or siblings that could be used to |
| 857 // at the end of the document. Scroll to the bottom. FIXME: who said anything
about scrolling? | 862 // calculate the scroll position, we must be at the end of the |
| 863 // document. Scroll to the bottom. |
| 864 // FIXME: who said anything about scrolling? |
| 858 if (!o && document().view()) { | 865 if (!o && document().view()) { |
| 859 point = FloatPoint(0, document().view()->contentsHeight()); | 866 point = FloatPoint(0, document().view()->contentsHeight()); |
| 860 return true; | 867 return true; |
| 861 } | 868 } |
| 862 return false; | 869 return false; |
| 863 } | 870 } |
| 864 | 871 |
| 865 static inline LayoutObject* endOfContinuations(LayoutObject* layoutObject) { | 872 static inline LayoutObject* endOfContinuations(LayoutObject* layoutObject) { |
| 866 LayoutObject* prev = nullptr; | 873 LayoutObject* prev = nullptr; |
| 867 LayoutObject* cur = layoutObject; | 874 LayoutObject* cur = layoutObject; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 894 LayoutObject* startContinuation = nullptr; | 901 LayoutObject* startContinuation = nullptr; |
| 895 // Find the last text/image child, to get a position. | 902 // Find the last text/image child, to get a position. |
| 896 while (o) { | 903 while (o) { |
| 897 if (LayoutObject* oLastChild = o->slowLastChild()) { | 904 if (LayoutObject* oLastChild = o->slowLastChild()) { |
| 898 o = oLastChild; | 905 o = oLastChild; |
| 899 } else if (o != layoutObject() && o->previousSibling()) { | 906 } else if (o != layoutObject() && o->previousSibling()) { |
| 900 o = o->previousSibling(); | 907 o = o->previousSibling(); |
| 901 } else { | 908 } else { |
| 902 LayoutObject* prev = nullptr; | 909 LayoutObject* prev = nullptr; |
| 903 while (!prev) { | 910 while (!prev) { |
| 904 // Check if the current layoutObject has contiunation and move the locat
ion for | 911 // Check if the current layoutObject has contiunation and move the |
| 905 // finding the layoutObject to the end of continuations if there is the
continuation. | 912 // location for finding the layoutObject to the end of continuations if |
| 906 // Skip to check the contiunation on contiunations section | 913 // there is the continuation. Skip to check the contiunation on |
| 914 // contiunations section |
| 907 if (startContinuation == o) { | 915 if (startContinuation == o) { |
| 908 startContinuation = nullptr; | 916 startContinuation = nullptr; |
| 909 } else if (!startContinuation) { | 917 } else if (!startContinuation) { |
| 910 if (LayoutObject* continuation = endOfContinuations(o)) { | 918 if (LayoutObject* continuation = endOfContinuations(o)) { |
| 911 startContinuation = o; | 919 startContinuation = o; |
| 912 prev = continuation; | 920 prev = continuation; |
| 913 break; | 921 break; |
| 914 } | 922 } |
| 915 } | 923 } |
| 916 // Prevent to overrun out of own layout tree | 924 // Prevent to overrun out of own layout tree |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 963 upperLeft = lowerRight; | 971 upperLeft = lowerRight; |
| 964 } | 972 } |
| 965 | 973 |
| 966 FloatSize size = lowerRight.expandedTo(upperLeft) - upperLeft; | 974 FloatSize size = lowerRight.expandedTo(upperLeft) - upperLeft; |
| 967 if (std::isnan(size.width()) || std::isnan(size.height())) | 975 if (std::isnan(size.width()) || std::isnan(size.height())) |
| 968 return LayoutRect(); | 976 return LayoutRect(); |
| 969 | 977 |
| 970 return enclosingLayoutRect(FloatRect(upperLeft, size)); | 978 return enclosingLayoutRect(FloatRect(upperLeft, size)); |
| 971 } | 979 } |
| 972 | 980 |
| 973 // This is used by FrameSelection to denote when the active-state of the page ha
s changed | 981 // This is used by FrameSelection to denote when the active-state of the page |
| 974 // independent of the focused element changing. | 982 // has changed independent of the focused element changing. |
| 975 void ContainerNode::focusStateChanged() { | 983 void ContainerNode::focusStateChanged() { |
| 976 // If we're just changing the window's active state and the focused node has n
o | 984 // If we're just changing the window's active state and the focused node has |
| 977 // layoutObject we can just ignore the state change. | 985 // no layoutObject we can just ignore the state change. |
| 978 if (!layoutObject()) | 986 if (!layoutObject()) |
| 979 return; | 987 return; |
| 980 | 988 |
| 981 if (computedStyle()->affectedByFocus()) { | 989 if (computedStyle()->affectedByFocus()) { |
| 982 StyleChangeType changeType = | 990 StyleChangeType changeType = |
| 983 computedStyle()->hasPseudoStyle(PseudoIdFirstLetter) | 991 computedStyle()->hasPseudoStyle(PseudoIdFirstLetter) |
| 984 ? SubtreeStyleChange | 992 ? SubtreeStyleChange |
| 985 : LocalStyleChange; | 993 : LocalStyleChange; |
| 986 setNeedsStyleRecalc( | 994 setNeedsStyleRecalc( |
| 987 changeType, | 995 changeType, |
| 988 StyleChangeReasonForTracing::createWithExtraData( | 996 StyleChangeReasonForTracing::createWithExtraData( |
| 989 StyleChangeReason::PseudoClass, StyleChangeExtraData::Focus)); | 997 StyleChangeReason::PseudoClass, StyleChangeExtraData::Focus)); |
| 990 } | 998 } |
| 991 if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByFocus()) | 999 if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByFocus()) |
| 992 toElement(this)->pseudoStateChanged(CSSSelector::PseudoFocus); | 1000 toElement(this)->pseudoStateChanged(CSSSelector::PseudoFocus); |
| 993 | 1001 |
| 994 LayoutTheme::theme().controlStateChanged(*layoutObject(), FocusControlState); | 1002 LayoutTheme::theme().controlStateChanged(*layoutObject(), FocusControlState); |
| 995 } | 1003 } |
| 996 | 1004 |
| 997 void ContainerNode::setFocus(bool received) { | 1005 void ContainerNode::setFocus(bool received) { |
| 998 // Recurse up author shadow trees to mark shadow hosts if it matches :focus. | 1006 // Recurse up author shadow trees to mark shadow hosts if it matches :focus. |
| 999 // TODO(kochi): Handle UA shadows which marks multiple nodes as focused such a
s | 1007 // TODO(kochi): Handle UA shadows which marks multiple nodes as focused such |
| 1000 // <input type="date"> the same way as author shadow. | 1008 // as <input type="date"> the same way as author shadow. |
| 1001 if (ShadowRoot* root = containingShadowRoot()) { | 1009 if (ShadowRoot* root = containingShadowRoot()) { |
| 1002 if (root->type() != ShadowRootType::UserAgent) | 1010 if (root->type() != ShadowRootType::UserAgent) |
| 1003 ownerShadowHost()->setFocus(received); | 1011 ownerShadowHost()->setFocus(received); |
| 1004 } | 1012 } |
| 1005 | 1013 |
| 1006 // If this is an author shadow host and indirectly focused (has focused elemen
t within | 1014 // If this is an author shadow host and indirectly focused (has focused |
| 1007 // its shadow root), update focus. | 1015 // element within its shadow root), update focus. |
| 1008 if (isElementNode() && document().focusedElement() && | 1016 if (isElementNode() && document().focusedElement() && |
| 1009 document().focusedElement() != this) { | 1017 document().focusedElement() != this) { |
| 1010 if (toElement(this)->authorShadowRoot()) | 1018 if (toElement(this)->authorShadowRoot()) |
| 1011 received = | 1019 received = |
| 1012 received && toElement(this)->authorShadowRoot()->delegatesFocus(); | 1020 received && toElement(this)->authorShadowRoot()->delegatesFocus(); |
| 1013 } | 1021 } |
| 1014 | 1022 |
| 1015 if (focused() == received) | 1023 if (focused() == received) |
| 1016 return; | 1024 return; |
| 1017 | 1025 |
| 1018 Node::setFocus(received); | 1026 Node::setFocus(received); |
| 1019 | 1027 |
| 1020 focusStateChanged(); | 1028 focusStateChanged(); |
| 1021 | 1029 |
| 1022 if (layoutObject() || received) | 1030 if (layoutObject() || received) |
| 1023 return; | 1031 return; |
| 1024 | 1032 |
| 1025 // If :focus sets display: none, we lose focus but still need to recalc our st
yle. | 1033 // If :focus sets display: none, we lose focus but still need to recalc our |
| 1034 // style. |
| 1026 if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByFocus()) | 1035 if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByFocus()) |
| 1027 toElement(this)->pseudoStateChanged(CSSSelector::PseudoFocus); | 1036 toElement(this)->pseudoStateChanged(CSSSelector::PseudoFocus); |
| 1028 else | 1037 else |
| 1029 setNeedsStyleRecalc( | 1038 setNeedsStyleRecalc( |
| 1030 LocalStyleChange, | 1039 LocalStyleChange, |
| 1031 StyleChangeReasonForTracing::createWithExtraData( | 1040 StyleChangeReasonForTracing::createWithExtraData( |
| 1032 StyleChangeReason::PseudoClass, StyleChangeExtraData::Focus)); | 1041 StyleChangeReason::PseudoClass, StyleChangeExtraData::Focus)); |
| 1033 } | 1042 } |
| 1034 | 1043 |
| 1035 void ContainerNode::setActive(bool down) { | 1044 void ContainerNode::setActive(bool down) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1101 if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByDrag()) | 1110 if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByDrag()) |
| 1102 toElement(this)->pseudoStateChanged(CSSSelector::PseudoDrag); | 1111 toElement(this)->pseudoStateChanged(CSSSelector::PseudoDrag); |
| 1103 } | 1112 } |
| 1104 | 1113 |
| 1105 void ContainerNode::setHovered(bool over) { | 1114 void ContainerNode::setHovered(bool over) { |
| 1106 if (over == hovered()) | 1115 if (over == hovered()) |
| 1107 return; | 1116 return; |
| 1108 | 1117 |
| 1109 Node::setHovered(over); | 1118 Node::setHovered(over); |
| 1110 | 1119 |
| 1111 // If :hover sets display: none we lose our hover but still need to recalc our
style. | 1120 // If :hover sets display: none we lose our hover but still need to recalc our |
| 1121 // style. |
| 1112 if (!layoutObject()) { | 1122 if (!layoutObject()) { |
| 1113 if (over) | 1123 if (over) |
| 1114 return; | 1124 return; |
| 1115 if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByHover()) | 1125 if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByHover()) |
| 1116 toElement(this)->pseudoStateChanged(CSSSelector::PseudoHover); | 1126 toElement(this)->pseudoStateChanged(CSSSelector::PseudoHover); |
| 1117 else | 1127 else |
| 1118 setNeedsStyleRecalc( | 1128 setNeedsStyleRecalc( |
| 1119 LocalStyleChange, | 1129 LocalStyleChange, |
| 1120 StyleChangeReasonForTracing::createWithExtraData( | 1130 StyleChangeReasonForTracing::createWithExtraData( |
| 1121 StyleChangeReason::PseudoClass, StyleChangeExtraData::Hover)); | 1131 StyleChangeReason::PseudoClass, StyleChangeExtraData::Hover)); |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1255 void ContainerNode::setRestyleFlag(DynamicRestyleFlags mask) { | 1265 void ContainerNode::setRestyleFlag(DynamicRestyleFlags mask) { |
| 1256 DCHECK(isElementNode() || isShadowRoot()); | 1266 DCHECK(isElementNode() || isShadowRoot()); |
| 1257 ensureRareData().setRestyleFlag(mask); | 1267 ensureRareData().setRestyleFlag(mask); |
| 1258 } | 1268 } |
| 1259 | 1269 |
| 1260 void ContainerNode::recalcDescendantStyles(StyleRecalcChange change) { | 1270 void ContainerNode::recalcDescendantStyles(StyleRecalcChange change) { |
| 1261 DCHECK(document().inStyleRecalc()); | 1271 DCHECK(document().inStyleRecalc()); |
| 1262 DCHECK(change >= UpdatePseudoElements || childNeedsStyleRecalc()); | 1272 DCHECK(change >= UpdatePseudoElements || childNeedsStyleRecalc()); |
| 1263 DCHECK(!needsStyleRecalc()); | 1273 DCHECK(!needsStyleRecalc()); |
| 1264 | 1274 |
| 1265 // This loop is deliberately backwards because we use insertBefore in the layo
ut tree, and want to avoid | 1275 // This loop is deliberately backwards because we use insertBefore in the |
| 1266 // a potentially n^2 loop to find the insertion point while resolving style. H
aving us start from the last | 1276 // layout tree, and want to avoid a potentially n^2 loop to find the insertion |
| 1267 // child and work our way back means in the common case, we'll find the insert
ion point in O(1) time. | 1277 // point while resolving style. Having us start from the last child and work |
| 1268 // See crbug.com/288225 | 1278 // our way back means in the common case, we'll find the insertion point in |
| 1279 // O(1) time. See crbug.com/288225 |
| 1269 StyleResolver& styleResolver = document().ensureStyleResolver(); | 1280 StyleResolver& styleResolver = document().ensureStyleResolver(); |
| 1270 Text* lastTextNode = nullptr; | 1281 Text* lastTextNode = nullptr; |
| 1271 for (Node* child = lastChild(); child; child = child->previousSibling()) { | 1282 for (Node* child = lastChild(); child; child = child->previousSibling()) { |
| 1272 if (child->isTextNode()) { | 1283 if (child->isTextNode()) { |
| 1273 toText(child)->recalcTextStyle(change, lastTextNode); | 1284 toText(child)->recalcTextStyle(change, lastTextNode); |
| 1274 lastTextNode = toText(child); | 1285 lastTextNode = toText(child); |
| 1275 } else if (child->isElementNode()) { | 1286 } else if (child->isElementNode()) { |
| 1276 Element* element = toElement(child); | 1287 Element* element = toElement(child); |
| 1277 if (element->shouldCallRecalcStyle(change)) | 1288 if (element->shouldCallRecalcStyle(change)) |
| 1278 element->recalcStyle(change, lastTextNode); | 1289 element->recalcStyle(change, lastTextNode); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1353 void ContainerNode::invalidateNodeListCachesInAncestors( | 1364 void ContainerNode::invalidateNodeListCachesInAncestors( |
| 1354 const QualifiedName* attrName, | 1365 const QualifiedName* attrName, |
| 1355 Element* attributeOwnerElement) { | 1366 Element* attributeOwnerElement) { |
| 1356 if (hasRareData() && (!attrName || isAttributeNode())) { | 1367 if (hasRareData() && (!attrName || isAttributeNode())) { |
| 1357 if (NodeListsNodeData* lists = rareData()->nodeLists()) { | 1368 if (NodeListsNodeData* lists = rareData()->nodeLists()) { |
| 1358 if (ChildNodeList* childNodeList = lists->childNodeList(*this)) | 1369 if (ChildNodeList* childNodeList = lists->childNodeList(*this)) |
| 1359 childNodeList->invalidateCache(); | 1370 childNodeList->invalidateCache(); |
| 1360 } | 1371 } |
| 1361 } | 1372 } |
| 1362 | 1373 |
| 1363 // Modifications to attributes that are not associated with an Element can't i
nvalidate NodeList caches. | 1374 // Modifications to attributes that are not associated with an Element can't |
| 1375 // invalidate NodeList caches. |
| 1364 if (attrName && !attributeOwnerElement) | 1376 if (attrName && !attributeOwnerElement) |
| 1365 return; | 1377 return; |
| 1366 | 1378 |
| 1367 if (!document().shouldInvalidateNodeListCaches(attrName)) | 1379 if (!document().shouldInvalidateNodeListCaches(attrName)) |
| 1368 return; | 1380 return; |
| 1369 | 1381 |
| 1370 document().invalidateNodeListCaches(attrName); | 1382 document().invalidateNodeListCaches(attrName); |
| 1371 | 1383 |
| 1372 for (ContainerNode* node = this; node; node = node->parentNode()) { | 1384 for (ContainerNode* node = this; node; node = node->parentNode()) { |
| 1373 if (NodeListsNodeData* lists = node->nodeLists()) | 1385 if (NodeListsNodeData* lists = node->nodeLists()) |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1387 const AtomicString& namespaceURI, | 1399 const AtomicString& namespaceURI, |
| 1388 const AtomicString& localName) { | 1400 const AtomicString& localName) { |
| 1389 if (namespaceURI == starAtom) | 1401 if (namespaceURI == starAtom) |
| 1390 return getElementsByTagName(localName); | 1402 return getElementsByTagName(localName); |
| 1391 | 1403 |
| 1392 return ensureCachedCollection<TagCollection>( | 1404 return ensureCachedCollection<TagCollection>( |
| 1393 TagCollectionType, namespaceURI.isEmpty() ? nullAtom : namespaceURI, | 1405 TagCollectionType, namespaceURI.isEmpty() ? nullAtom : namespaceURI, |
| 1394 localName); | 1406 localName); |
| 1395 } | 1407 } |
| 1396 | 1408 |
| 1397 // Takes an AtomicString in argument because it is common for elements to share
the same name attribute. | 1409 // Takes an AtomicString in argument because it is common for elements to share |
| 1398 // Therefore, the NameNodeList factory function expects an AtomicString type. | 1410 // the same name attribute. Therefore, the NameNodeList factory function |
| 1411 // expects an AtomicString type. |
| 1399 NameNodeList* ContainerNode::getElementsByName( | 1412 NameNodeList* ContainerNode::getElementsByName( |
| 1400 const AtomicString& elementName) { | 1413 const AtomicString& elementName) { |
| 1401 return ensureCachedCollection<NameNodeList>(NameNodeListType, elementName); | 1414 return ensureCachedCollection<NameNodeList>(NameNodeListType, elementName); |
| 1402 } | 1415 } |
| 1403 | 1416 |
| 1404 // Takes an AtomicString in argument because it is common for elements to share
the same set of class names. | 1417 // Takes an AtomicString in argument because it is common for elements to share |
| 1405 // Therefore, the ClassNodeList factory function expects an AtomicString type. | 1418 // the same set of class names. Therefore, the ClassNodeList factory function |
| 1419 // expects an AtomicString type. |
| 1406 ClassCollection* ContainerNode::getElementsByClassName( | 1420 ClassCollection* ContainerNode::getElementsByClassName( |
| 1407 const AtomicString& classNames) { | 1421 const AtomicString& classNames) { |
| 1408 return ensureCachedCollection<ClassCollection>(ClassCollectionType, | 1422 return ensureCachedCollection<ClassCollection>(ClassCollectionType, |
| 1409 classNames); | 1423 classNames); |
| 1410 } | 1424 } |
| 1411 | 1425 |
| 1412 RadioNodeList* ContainerNode::radioNodeList(const AtomicString& name, | 1426 RadioNodeList* ContainerNode::radioNodeList(const AtomicString& name, |
| 1413 bool onlyMatchImgElements) { | 1427 bool onlyMatchImgElements) { |
| 1414 DCHECK(isHTMLFormElement(this) || isHTMLFieldSetElement(this)); | 1428 DCHECK(isHTMLFormElement(this) || isHTMLFieldSetElement(this)); |
| 1415 CollectionType type = | 1429 CollectionType type = |
| 1416 onlyMatchImgElements ? RadioImgNodeListType : RadioNodeListType; | 1430 onlyMatchImgElements ? RadioImgNodeListType : RadioNodeListType; |
| 1417 return ensureCachedCollection<RadioNodeList>(type, name); | 1431 return ensureCachedCollection<RadioNodeList>(type, name); |
| 1418 } | 1432 } |
| 1419 | 1433 |
| 1420 Element* ContainerNode::getElementById(const AtomicString& id) const { | 1434 Element* ContainerNode::getElementById(const AtomicString& id) const { |
| 1421 if (isInTreeScope()) { | 1435 if (isInTreeScope()) { |
| 1422 // Fast path if we are in a tree scope: call getElementById() on tree scope | 1436 // Fast path if we are in a tree scope: call getElementById() on tree scope |
| 1423 // and check if the matching element is in our subtree. | 1437 // and check if the matching element is in our subtree. |
| 1424 Element* element = containingTreeScope().getElementById(id); | 1438 Element* element = containingTreeScope().getElementById(id); |
| 1425 if (!element) | 1439 if (!element) |
| 1426 return nullptr; | 1440 return nullptr; |
| 1427 if (element->isDescendantOf(this)) | 1441 if (element->isDescendantOf(this)) |
| 1428 return element; | 1442 return element; |
| 1429 } | 1443 } |
| 1430 | 1444 |
| 1431 // Fall back to traversing our subtree. In case of duplicate ids, the first el
ement found will be returned. | 1445 // Fall back to traversing our subtree. In case of duplicate ids, the first |
| 1446 // element found will be returned. |
| 1432 for (Element& element : ElementTraversal::descendantsOf(*this)) { | 1447 for (Element& element : ElementTraversal::descendantsOf(*this)) { |
| 1433 if (element.getIdAttribute() == id) | 1448 if (element.getIdAttribute() == id) |
| 1434 return &element; | 1449 return &element; |
| 1435 } | 1450 } |
| 1436 return nullptr; | 1451 return nullptr; |
| 1437 } | 1452 } |
| 1438 | 1453 |
| 1439 NodeListsNodeData& ContainerNode::ensureNodeLists() { | 1454 NodeListsNodeData& ContainerNode::ensureNodeLists() { |
| 1440 return ensureRareData().ensureNodeLists(); | 1455 return ensureRareData().ensureNodeLists(); |
| 1441 } | 1456 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1452 return true; | 1467 return true; |
| 1453 | 1468 |
| 1454 if (node->isElementNode() && toElement(node)->shadow()) | 1469 if (node->isElementNode() && toElement(node)->shadow()) |
| 1455 return true; | 1470 return true; |
| 1456 | 1471 |
| 1457 return false; | 1472 return false; |
| 1458 } | 1473 } |
| 1459 #endif | 1474 #endif |
| 1460 | 1475 |
| 1461 } // namespace blink | 1476 } // namespace blink |
| OLD | NEW |