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 |