LEFT | RIGHT |
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 Peter Kelly (pmk@post.com) | 4 * (C) 2001 Peter Kelly (pmk@post.com) |
5 * (C) 2001 Dirk Mueller (mueller@kde.org) | 5 * (C) 2001 Dirk Mueller (mueller@kde.org) |
6 * (C) 2007 David Smith (catfish.man@gmail.com) | 6 * (C) 2007 David Smith (catfish.man@gmail.com) |
7 * Copyright (C) 2004-2017 Apple Inc. All rights reserved. | 7 * Copyright (C) 2004-2017 Apple Inc. All rights reserved. |
8 * (C) 2007 Eric Seidel (eric@webkit.org) | 8 * (C) 2007 Eric Seidel (eric@webkit.org) |
9 * | 9 * |
10 * This library is free software; you can redistribute it and/or | 10 * This library is free software; you can redistribute it and/or |
(...skipping 678 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
689 bool insideFixed; | 689 bool insideFixed; |
690 LayoutRect absoluteBounds = renderer()->absoluteAnchorRect(&insideFixed); | 690 LayoutRect absoluteBounds = renderer()->absoluteAnchorRect(&insideFixed); |
691 if (centerIfNotVisible) | 691 if (centerIfNotVisible) |
692 renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBou
nds, insideFixed, ScrollAlignment::alignCenterIfNotVisible, ScrollAlignment::ali
gnCenterIfNotVisible, ShouldAllowCrossOriginScrolling::No); | 692 renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBou
nds, insideFixed, ScrollAlignment::alignCenterIfNotVisible, ScrollAlignment::ali
gnCenterIfNotVisible, ShouldAllowCrossOriginScrolling::No); |
693 else | 693 else |
694 renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBou
nds, insideFixed, ScrollAlignment::alignToEdgeIfNotVisible, ScrollAlignment::ali
gnToEdgeIfNotVisible, ShouldAllowCrossOriginScrolling::No); | 694 renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBou
nds, insideFixed, ScrollAlignment::alignToEdgeIfNotVisible, ScrollAlignment::ali
gnToEdgeIfNotVisible, ShouldAllowCrossOriginScrolling::No); |
695 } | 695 } |
696 | 696 |
697 void Element::scrollBy(const ScrollToOptions& options) | 697 void Element::scrollBy(const ScrollToOptions& options) |
698 { | 698 { |
699 return scrollBy(options.left.value_or(0), options.top.value_or(0)); | 699 ScrollToOptions scrollToOptions = normalizeNonFiniteCoordinatesOrFallBackTo(
options, 0, 0); |
700 } | 700 scrollToOptions.left.value() += scrollLeft(); |
701 | 701 scrollToOptions.top.value() += scrollTop(); |
702 static inline double normalizeNonFiniteValue(double f) | 702 scrollTo(scrollToOptions); |
703 { | |
704 return std::isfinite(f) ? f : 0; | |
705 } | 703 } |
706 | 704 |
707 void Element::scrollBy(double x, double y) | 705 void Element::scrollBy(double x, double y) |
708 { | 706 { |
709 scrollTo(scrollLeft() + normalizeNonFiniteValue(x), scrollTop() + normalizeN
onFiniteValue(y)); | 707 scrollBy({ x, y }); |
710 } | 708 } |
711 | 709 |
712 void Element::scrollTo(const ScrollToOptions& options, ScrollClamping clamping) | 710 void Element::scrollTo(const ScrollToOptions& options, ScrollClamping clamping) |
713 { | 711 { |
714 // If the element is the root element and document is in quirks mode, termin
ate these steps. | 712 // If the element is the root element and document is in quirks mode, termin
ate these steps. |
715 // Note that WebKit always uses quirks mode document scrolling behavior. See
Document::scrollingElement(). | 713 // Note that WebKit always uses quirks mode document scrolling behavior. See
Document::scrollingElement(). |
716 if (this == document().documentElement()) | 714 if (this == document().documentElement()) |
717 return; | 715 return; |
718 | 716 |
719 document().updateLayoutIgnorePendingStylesheets(); | 717 document().updateLayoutIgnorePendingStylesheets(); |
720 | 718 |
721 // If the element does not have any associated CSS layout box, the element h
as no associated scrolling box, | 719 // If the element does not have any associated CSS layout box, the element h
as no associated scrolling box, |
722 // or the element has no overflow, terminate these steps. | 720 // or the element has no overflow, terminate these steps. |
723 RenderBox* renderer = renderBox(); | 721 RenderBox* renderer = renderBox(); |
724 if (!renderer || !renderer->hasOverflowClip()) | 722 if (!renderer || !renderer->hasOverflowClip()) |
725 return; | 723 return; |
726 | 724 |
727 // Normalize non-finite values for left and top dictionary members of option
s, if present. | 725 ScrollToOptions scrollToOptions = normalizeNonFiniteCoordinatesOrFallBackTo(
options, |
728 double x = options.left ? normalizeNonFiniteValue(options.left.value()) : ad
justForAbsoluteZoom(renderer->scrollLeft(), *renderer); | 726 adjustForAbsoluteZoom(renderer->scrollLeft(), *renderer), |
729 double y = options.top ? normalizeNonFiniteValue(options.top.value()) : adju
stForAbsoluteZoom(renderer->scrollTop(), *renderer); | 727 adjustForAbsoluteZoom(renderer->scrollTop(), *renderer) |
730 | 728 ); |
731 renderer->setScrollLeft(clampToInteger(x * renderer->style().effectiveZoom()
), clamping); | 729 renderer->setScrollLeft(clampToInteger(scrollToOptions.left.value() * render
er->style().effectiveZoom()), clamping); |
732 renderer->setScrollTop(clampToInteger(y * renderer->style().effectiveZoom())
, clamping); | 730 renderer->setScrollTop(clampToInteger(scrollToOptions.top.value() * renderer
->style().effectiveZoom()), clamping); |
733 } | 731 } |
734 | 732 |
735 void Element::scrollTo(double x, double y) | 733 void Element::scrollTo(double x, double y) |
736 { | 734 { |
737 scrollTo({ x, y }); | 735 scrollTo({ x, y }); |
738 } | 736 } |
739 | 737 |
740 void Element::scrollByUnits(int units, ScrollGranularity granularity) | 738 void Element::scrollByUnits(int units, ScrollGranularity granularity) |
741 { | 739 { |
742 document().updateLayoutIgnorePendingStylesheets(); | 740 document().updateLayoutIgnorePendingStylesheets(); |
(...skipping 733 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1476 } | 1474 } |
1477 } | 1475 } |
1478 | 1476 |
1479 URL Element::absoluteLinkURL() const | 1477 URL Element::absoluteLinkURL() const |
1480 { | 1478 { |
1481 if (!isLink()) | 1479 if (!isLink()) |
1482 return URL(); | 1480 return URL(); |
1483 | 1481 |
1484 AtomicString linkAttribute; | 1482 AtomicString linkAttribute; |
1485 if (hasTagName(SVGNames::aTag)) | 1483 if (hasTagName(SVGNames::aTag)) |
1486 linkAttribute = getAttribute(XLinkNames::hrefAttr); | 1484 linkAttribute = getAttribute(SVGNames::hrefAttr, XLinkNames::hrefAttr); |
1487 else | 1485 else |
1488 linkAttribute = getAttribute(HTMLNames::hrefAttr); | 1486 linkAttribute = getAttribute(HTMLNames::hrefAttr); |
1489 | 1487 |
1490 if (linkAttribute.isEmpty()) | 1488 if (linkAttribute.isEmpty()) |
1491 return URL(); | 1489 return URL(); |
1492 | 1490 |
1493 return document().completeURL(stripLeadingAndTrailingHTMLSpaces(linkAttribut
e)); | 1491 return document().completeURL(stripLeadingAndTrailingHTMLSpaces(linkAttribut
e)); |
1494 } | 1492 } |
1495 | 1493 |
1496 #if ENABLE(TOUCH_EVENTS) | 1494 #if ENABLE(TOUCH_EVENTS) |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1650 if (hasID()) | 1648 if (hasID()) |
1651 attributeChanged(idAttr, nullAtom(), getIdAttribute()); | 1649 attributeChanged(idAttr, nullAtom(), getIdAttribute()); |
1652 if (hasClass()) | 1650 if (hasClass()) |
1653 attributeChanged(classAttr, nullAtom(), getAttribute(classAttr)); | 1651 attributeChanged(classAttr, nullAtom(), getAttribute(classAttr)); |
1654 } | 1652 } |
1655 | 1653 |
1656 // FIXME: Do we need to update newDocument's intersection observer targets? | 1654 // FIXME: Do we need to update newDocument's intersection observer targets? |
1657 | 1655 |
1658 if (UNLIKELY(isDefinedCustomElement())) | 1656 if (UNLIKELY(isDefinedCustomElement())) |
1659 CustomElementReactionQueue::enqueueAdoptedCallbackIfNeeded(*this, oldDoc
ument, newDocument); | 1657 CustomElementReactionQueue::enqueueAdoptedCallbackIfNeeded(*this, oldDoc
ument, newDocument); |
| 1658 |
| 1659 #if ENABLE(INTERSECTION_OBSERVER) |
| 1660 if (auto* observerData = intersectionObserverData()) { |
| 1661 for (auto* observer : observerData->observers) { |
| 1662 if (oldDocument.deactivateIntersectionObserver(*observer)) |
| 1663 newDocument.activateIntersectionObserver(*observer); |
| 1664 } |
| 1665 } |
| 1666 #endif |
1660 } | 1667 } |
1661 | 1668 |
1662 bool Element::hasAttributes() const | 1669 bool Element::hasAttributes() const |
1663 { | 1670 { |
1664 synchronizeAllAttributes(); | 1671 synchronizeAllAttributes(); |
1665 return elementData() && elementData()->length(); | 1672 return elementData() && elementData()->length(); |
1666 } | 1673 } |
1667 | 1674 |
1668 bool Element::hasEquivalentAttributes(const Element* other) const | 1675 bool Element::hasEquivalentAttributes(const Element* other) const |
1669 { | 1676 { |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1751 if (newDocument) | 1758 if (newDocument) |
1752 updateNameForDocument(*newDocument, nullAtom(), nameValue); | 1759 updateNameForDocument(*newDocument, nullAtom(), nameValue); |
1753 } | 1760 } |
1754 | 1761 |
1755 if (newScope && hasTagName(labelTag)) { | 1762 if (newScope && hasTagName(labelTag)) { |
1756 if (newScope->shouldCacheLabelsByForAttribute()) | 1763 if (newScope->shouldCacheLabelsByForAttribute()) |
1757 updateLabel(*newScope, nullAtom(), attributeWithoutSynchronization(f
orAttr)); | 1764 updateLabel(*newScope, nullAtom(), attributeWithoutSynchronization(f
orAttr)); |
1758 } | 1765 } |
1759 | 1766 |
1760 if (becomeConnected) { | 1767 if (becomeConnected) { |
1761 if (UNLIKELY(isCustomElementUpgradeCandidate())) | 1768 if (UNLIKELY(isCustomElementUpgradeCandidate())) { |
| 1769 ASSERT(isConnected()); |
1762 CustomElementReactionQueue::enqueueElementUpgradeIfDefined(*this); | 1770 CustomElementReactionQueue::enqueueElementUpgradeIfDefined(*this); |
| 1771 } |
1763 if (UNLIKELY(isDefinedCustomElement())) | 1772 if (UNLIKELY(isDefinedCustomElement())) |
1764 CustomElementReactionQueue::enqueueConnectedCallbackIfNeeded(*this); | 1773 CustomElementReactionQueue::enqueueConnectedCallbackIfNeeded(*this); |
1765 } | 1774 } |
1766 | 1775 |
1767 if (UNLIKELY(hasTagName(articleTag) && newDocument)) | 1776 if (UNLIKELY(hasTagName(articleTag) && newDocument)) |
1768 newDocument->registerArticleElement(*this); | 1777 newDocument->registerArticleElement(*this); |
1769 | 1778 |
1770 return InsertedIntoAncestorResult::Done; | 1779 return InsertedIntoAncestorResult::Done; |
1771 } | 1780 } |
1772 | 1781 |
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2011 } | 2020 } |
2012 | 2021 |
2013 void Element::enqueueToUpgrade(JSCustomElementInterface& elementInterface) | 2022 void Element::enqueueToUpgrade(JSCustomElementInterface& elementInterface) |
2014 { | 2023 { |
2015 ASSERT(!isDefinedCustomElement() && !isFailedCustomElement()); | 2024 ASSERT(!isDefinedCustomElement() && !isFailedCustomElement()); |
2016 setFlag(IsCustomElement); | 2025 setFlag(IsCustomElement); |
2017 setFlag(IsEditingTextOrUndefinedCustomElementFlag); | 2026 setFlag(IsEditingTextOrUndefinedCustomElementFlag); |
2018 InspectorInstrumentation::didChangeCustomElementState(*this); | 2027 InspectorInstrumentation::didChangeCustomElementState(*this); |
2019 | 2028 |
2020 auto& data = ensureElementRareData(); | 2029 auto& data = ensureElementRareData(); |
2021 ASSERT(!data.customElementReactionQueue()); | 2030 bool alreadyScheduledToUpgrade = data.customElementReactionQueue(); |
2022 | 2031 if (!alreadyScheduledToUpgrade) |
2023 data.setCustomElementReactionQueue(std::make_unique<CustomElementReactionQue
ue>(elementInterface)); | 2032 data.setCustomElementReactionQueue(std::make_unique<CustomElementReactio
nQueue>(elementInterface)); |
2024 data.customElementReactionQueue()->enqueueElementUpgrade(*this); | 2033 data.customElementReactionQueue()->enqueueElementUpgrade(*this, alreadySched
uledToUpgrade); |
2025 } | 2034 } |
2026 | 2035 |
2027 CustomElementReactionQueue* Element::reactionQueue() const | 2036 CustomElementReactionQueue* Element::reactionQueue() const |
2028 { | 2037 { |
2029 ASSERT(isDefinedCustomElement() || isCustomElementUpgradeCandidate()); | 2038 ASSERT(isDefinedCustomElement() || isCustomElementUpgradeCandidate()); |
2030 if (!hasRareData()) | 2039 if (!hasRareData()) |
2031 return nullptr; | 2040 return nullptr; |
2032 return elementRareData()->customElementReactionQueue(); | 2041 return elementRareData()->customElementReactionQueue(); |
2033 } | 2042 } |
2034 | 2043 |
(...skipping 1205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3240 void Element::requestPointerLock() | 3249 void Element::requestPointerLock() |
3241 { | 3250 { |
3242 if (document().page()) | 3251 if (document().page()) |
3243 document().page()->pointerLockController().requestPointerLock(this); | 3252 document().page()->pointerLockController().requestPointerLock(this); |
3244 } | 3253 } |
3245 #endif | 3254 #endif |
3246 | 3255 |
3247 #if ENABLE(INTERSECTION_OBSERVER) | 3256 #if ENABLE(INTERSECTION_OBSERVER) |
3248 void Element::startObservingIntersections(IntersectionObserver& observer) | 3257 void Element::startObservingIntersections(IntersectionObserver& observer) |
3249 { | 3258 { |
3250 auto& data = ensureElementRareData(); | 3259 auto* trackingDocument = observer.trackingDocument(); |
3251 | 3260 if (!trackingDocument) |
3252 auto* registrations = data.intersectionObserverRegistrations(); | 3261 return; |
3253 if (!registrations) { | 3262 auto& observerData = ensureIntersectionObserverData(); |
3254 data.setIntersectionObserverRegistrations(std::make_unique<Vector<Inters
ectionObserverRegistration>>()); | 3263 auto& registrations = observerData.registrations; |
3255 registrations = data.intersectionObserverRegistrations(); | |
3256 } | |
3257 | 3264 |
3258 // If target is in this's internal [[ObservationTargets]] slot, return. | 3265 // If target is in this's internal [[ObservationTargets]] slot, return. |
3259 for (auto& registration : *registrations) { | 3266 for (auto& registration : registrations) { |
3260 if (registration.observer == &observer) | 3267 if (registration.observer == &observer) |
3261 return; | 3268 return; |
3262 } | 3269 } |
3263 | 3270 |
3264 // Let intersectionObserverRegistration be an IntersectionObserverRegistrati
on record with an observer | 3271 // Let intersectionObserverRegistration be an IntersectionObserverRegistrati
on record with an observer |
3265 // property set to this and a previousThreshold property set so that it's im
mediately differently from | 3272 // property set to this and a previousThreshold property set so that it's im
mediately differently from |
3266 // the current threshold, triggering an initial notification. | 3273 // the current threshold, triggering an initial notification. |
3267 // Append intersectionObserverRegistration to targets internal [[RegisteredI
ntersectionObservers]] slot. | 3274 // Append intersectionObserverRegistration to targets internal [[RegisteredI
ntersectionObservers]] slot. |
3268 registrations->append({ &observer, std::numeric_limits<size_t>::max(), false
}); | 3275 registrations.append({ &observer, std::numeric_limits<size_t>::max(), false
}); |
3269 | 3276 |
3270 // Add target to this's internal [[ObservationTargets]] slot. | 3277 // Add target to this's internal [[ObservationTargets]] slot. |
3271 observer.addObservationTarget(*this); | 3278 observer.addObservationTarget(*this); |
3272 | |
3273 document().addToIntersectionObserverTargets(*this); | |
3274 document().postTask([&document = document()] (ScriptExecutionContext&) mutab
le { | |
3275 document.updateIntersectionObservations(); | |
3276 }); | |
3277 | |
3278 } | 3279 } |
3279 | 3280 |
3280 void Element::endObservingIntersections(IntersectionObserver& observer) | 3281 void Element::endObservingIntersections(IntersectionObserver& observer) |
3281 { | 3282 { |
3282 // Remove the IntersectionObserverRegistration record whose observer propert
y is equal to this from | 3283 // Remove the IntersectionObserverRegistration record whose observer propert
y is equal to this from |
3283 // targets internal [[RegisteredIntersectionObservers]] slot. | 3284 // targets internal [[RegisteredIntersectionObservers]] slot. |
3284 auto* registrations = hasRareData() ? elementRareData()->intersectionObserve
rRegistrations() : nullptr; | 3285 auto* observerData = hasRareData() ? elementRareData()->intersectionObserver
Data() : nullptr; |
3285 if (!registrations) { | 3286 if (!observerData) { |
3286 ASSERT(!observer.hasObservationTarget(*this)); | 3287 ASSERT(!observer.hasObservationTarget(*this)); |
3287 return; | 3288 return; |
3288 } | 3289 } |
3289 | 3290 |
3290 for (size_t i = 0; i < registrations->size(); ++i) { | 3291 auto& registrations = observerData->registrations; |
3291 auto& observerRegistration = registrations->at(i); | 3292 |
| 3293 for (size_t i = 0; i < registrations.size(); ++i) { |
| 3294 auto& observerRegistration = registrations.at(i); |
3292 if (observerRegistration.observer == &observer) { | 3295 if (observerRegistration.observer == &observer) { |
3293 registrations->remove(i); | 3296 registrations.remove(i); |
3294 break; | 3297 break; |
3295 } | 3298 } |
3296 } | 3299 } |
3297 | 3300 |
3298 // Remove target from this's internal [[ObservationTargets]] slot. | 3301 // Remove target from this's internal [[ObservationTargets]] slot. |
3299 observer.removeObservationTarget(*this); | 3302 observer.removeObservationTarget(*this); |
3300 | |
3301 if (registrations->isEmpty()) | |
3302 document().removeFromIntersectionObserverTargets(*this); | |
3303 } | 3303 } |
3304 | 3304 |
3305 void Element::disconnectFromIntersectionObservers() | 3305 void Element::disconnectFromIntersectionObservers() |
3306 { | 3306 { |
3307 auto* registrations = hasRareData() ? elementRareData()->intersectionObserve
rRegistrations() : nullptr; | 3307 auto* observerData = intersectionObserverData(); |
3308 if (registrations) { | 3308 if (!observerData) |
3309 for (auto& registration : *registrations) | 3309 return; |
3310 registration.observer->removeObservationTarget(*this); | 3310 |
3311 } | 3311 for (auto& registration : observerData->registrations) |
3312 | 3312 registration.observer->removeObservationTarget(*this); |
3313 document().removeFromIntersectionObserverTargets(*this); | 3313 observerData->registrations.clear(); |
3314 } | 3314 |
3315 | 3315 for (auto* observer : observerData->observers) |
3316 Vector<IntersectionObserverRegistration>* Element::intersectionObserverRegistrat
ions() | 3316 observer->rootDestroyed(); |
3317 { | 3317 observerData->observers.clear(); |
3318 return hasRareData() ? elementRareData()->intersectionObserverRegistrations(
) : nullptr; | 3318 } |
| 3319 |
| 3320 IntersectionObserverData& Element::ensureIntersectionObserverData() |
| 3321 { |
| 3322 auto& data = ensureElementRareData(); |
| 3323 if (!data.intersectionObserverData()) |
| 3324 data.setIntersectionObserverData(std::make_unique<IntersectionObserverDa
ta>()); |
| 3325 return *data.intersectionObserverData(); |
| 3326 } |
| 3327 |
| 3328 IntersectionObserverData* Element::intersectionObserverData() |
| 3329 { |
| 3330 return hasRareData() ? elementRareData()->intersectionObserverData() : nullp
tr; |
3319 } | 3331 } |
3320 #endif | 3332 #endif |
3321 | 3333 |
3322 SpellcheckAttributeState Element::spellcheckAttributeState() const | 3334 SpellcheckAttributeState Element::spellcheckAttributeState() const |
3323 { | 3335 { |
3324 const AtomicString& value = attributeWithoutSynchronization(HTMLNames::spell
checkAttr); | 3336 const AtomicString& value = attributeWithoutSynchronization(HTMLNames::spell
checkAttr); |
3325 if (value.isNull()) | 3337 if (value.isNull()) |
3326 return SpellcheckAttributeDefault; | 3338 return SpellcheckAttributeDefault; |
3327 if (value.isEmpty() || equalLettersIgnoringASCIICase(value, "true")) | 3339 if (value.isEmpty() || equalLettersIgnoringASCIICase(value, "true")) |
3328 return SpellcheckAttributeTrue; | 3340 return SpellcheckAttributeTrue; |
(...skipping 622 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3951 if (auto timeline = document().existingTimeline()) { | 3963 if (auto timeline = document().existingTimeline()) { |
3952 for (auto& animation : timeline->animationsForElement(*this, AnimationTi
meline::Ordering::Sorted)) { | 3964 for (auto& animation : timeline->animationsForElement(*this, AnimationTi
meline::Ordering::Sorted)) { |
3953 if (animation->canBeListed()) | 3965 if (animation->canBeListed()) |
3954 animations.append(animation); | 3966 animations.append(animation); |
3955 } | 3967 } |
3956 } | 3968 } |
3957 return animations; | 3969 return animations; |
3958 } | 3970 } |
3959 | 3971 |
3960 } // namespace WebCore | 3972 } // namespace WebCore |
LEFT | RIGHT |