| Differences between
and this patch
- a/Source/JavaScriptCore/ChangeLog +27 lines
Lines 1-3 a/Source/JavaScriptCore/ChangeLog_sec1
1
2021-03-13  Alexey Shvayka  <shvaikalesh@gmail.com>
2
3
        Cache cross-origin methods / accessors of Window and Location per lexical global object
4
        https://bugs.webkit.org/show_bug.cgi?id=222739
5
6
        Reviewed by Darin Adler.
7
8
        1. Add WeakGCMap::ensure() to avoid double hashing and clean up JSObject::getOwnPropertyDescriptor().
9
        2. Assert early that JSCustom{Getter,Setter}Function is created with non-null function pointer.
10
        3. Rename getCustom{Getter,Setter}Function() to align with newly-added JSDOMGlobalObject methods.
11
12
        * runtime/JSCustomGetterFunction.cpp:
13
        (JSC::JSC_DEFINE_HOST_FUNCTION):
14
        (JSC::JSCustomGetterFunction::create):
15
        * runtime/JSCustomSetterFunction.cpp:
16
        (JSC::JSC_DEFINE_HOST_FUNCTION):
17
        (JSC::JSCustomSetterFunction::create):
18
        * runtime/JSObject.cpp:
19
        (JSC::createCustomGetterFunction):
20
        (JSC::createCustomSetterFunction):
21
        (JSC::JSObject::getOwnPropertyDescriptor):
22
        (JSC::getCustomGetterFunction): Deleted.
23
        (JSC::getCustomSetterFunction): Deleted.
24
        * runtime/Lookup.h:
25
        (JSC::nonCachingStaticFunctionGetterImpl): Deleted.
26
        * runtime/WeakGCMap.h:
27
1
2021-03-12  Carlos Garcia Campos  <cgarcia@igalia.com>
28
2021-03-12  Carlos Garcia Campos  <cgarcia@igalia.com>
2
29
3
        [GTK] Bump API version when building with libsoup3
30
        [GTK] Bump API version when building with libsoup3
- a/Source/WTF/ChangeLog +10 lines
Lines 1-3 a/Source/WTF/ChangeLog_sec1
1
2021-03-13  Tim Horton  <timothy_horton@apple.com>
2
3
        Adopt DDMacAction instead of DDAction on macOS
4
        https://bugs.webkit.org/show_bug.cgi?id=223145
5
        <rdar://problem/70127512>
6
7
        Reviewed by Megan Gardner.
8
9
        * wtf/PlatformHave.h:
10
1
2021-03-12  Lauro Moura  <lmoura@igalia.com>
11
2021-03-12  Lauro Moura  <lmoura@igalia.com>
2
12
3
        REGRESSION(r274327) [GLIB] 2D Canvas tests timing out after enabling GPUProces in testing
13
        REGRESSION(r274327) [GLIB] 2D Canvas tests timing out after enabling GPUProces in testing
- a/Source/WebCore/ChangeLog +153 lines
Lines 1-3 a/Source/WebCore/ChangeLog_sec1
1
2021-03-15  Martin Robinson  <mrobinson@webkit.org>
2
3
        [css-scroll-snap] Properly handle overflowing snap areas
4
        https://bugs.webkit.org/show_bug.cgi?id=223175
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        Properly handle overflowing snap areas. This requires rewriting the snapping
9
        algorithm. ScrollSnapOffsetsInfo now store snap area rectangles, which are
10
        used to handle overflowing snap areas. In addition, snap offset ranges are no
11
        longer kept to handle proximity. Instead this is done when choosing candidate
12
        snap offsets.
13
14
        Because ScrollSnapOffsetsInfo now contains a rectangle type, its template needs
15
        this type as well. In order to make it simpler to use ScrollSnapOffsetsInfo this
16
        change exposes two type aliases, FloatScrollSnapOffsetsInfo and LayoutScrollSnapOffsetsInfo
17
        which are used everywhere.
18
19
        No new tests. This change fixes the WPT test:
20
        imported/w3c/web-platform-tests/css/css-scroll-snap/overflowing-snap-areas.html
21
22
        * page/scrolling/AsyncScrollingCoordinator.cpp: Use the new type aliases.
23
        * page/scrolling/ScrollSnapOffsetsInfo.cpp:
24
        (WebCore::findFirstSnapStopOffsetBetweenOriginAndDestination): Updated to return an offset/index
25
        pair so the return type of this function is compatible with that of calculateClosestSnapOffset.
26
        (WebCore::updateSnapOffsetsForScrollableArea): No longer store offset ranges for proximity snapping
27
        and also store snap areas converted to "offset" coordinates.
28
        (WebCore::convertOffsetInfo): No longer need to convert offset ranges, but this does now
29
        require converting offset areas.
30
        (WebCore::FloatScrollSnapOffsetsInfo::convertUnits const): Use the new type aliases.
31
        (WebCore::LayoutScrollSnapOffsetsInfo::convertUnits const): Ditto.
32
        (WebCore::maxForAxis): Added this helper which gets the maximum in a particular axis given the axis.
33
        (WebCore::minForAxis): Ditto.
34
        (WebCore::isNearEnoughToOffsetForProximity): Added this helper which replaces computeAxisProximitySnapOffsetRanges.
35
        (WebCore::calculateClosestSnapOffset): This replaces closestSnapOffsetWithOffsetsAndRanges, but also
36
        and indicesOfNearestSnapOffsets. Now written using snap areas from the data structure as well as
37
        with proper handling for overflowing snap areas.
38
        (WebCore::LayoutScrollSnapOffsetsInfo::closestSnapOffset const): Update for new method names and type aliases.
39
        (WebCore::FloatScrollSnapOffsetsInfo::closestSnapOffset const): Ditto.
40
        * page/scrolling/ScrollSnapOffsetsInfo.h:
41
        (WebCore::ScrollSnapOffsetsInfo::isEqual const): No longer look at snap offset ranges, but do take into
42
        consideration the snap areas.
43
        (WebCore::ScrollSnapOffsetsInfo::offsetsForAxis const): Renamed the template argument.
44
        (WebCore::operator<<): Removed.
45
        * page/scrolling/ScrollingStateScrollingNode.cpp: Use the new type alias.
46
        * page/scrolling/ScrollingStateScrollingNode.h: Ditto.
47
        * page/scrolling/ScrollingTreeScrollingNode.cpp: Ditto.
48
        * page/scrolling/ScrollingTreeScrollingNode.h: Ditto.
49
        * page/scrolling/mac/ScrollingTreeScrollingNodeDelegateMac.mm:
50
        (WebCore::ScrollingTreeScrollingNodeDelegateMac::updateFromStateNode): convertUnits now takes two template arguments.
51
        * platform/ScrollController.cpp:
52
        (WebCore::ScrollController::updateScrollSnapPoints): Pass in the viewport size when selecting snap points.
53
        (WebCore::ScrollController::adjustScrollDestination): Ditto.
54
        * platform/ScrollController.h: Use the new type alias.
55
        * platform/ScrollSnapAnimatorState.cpp:
56
        (WebCore::ScrollSnapAnimatorState::setupAnimationForState): Pass viewport size to targetOffsetForStartOffset.
57
        (WebCore::ScrollSnapAnimatorState::targetOffsetForStartOffset const): Ditto.
58
        (WebCore::operator<<): No longer print snap offset ranges.
59
        * platform/ScrollSnapAnimatorState.h: Removed method dealing with ranges. Now pass viewport size to targetOffsetForStartOffset.
60
        * platform/ScrollableArea.cpp: Use the new type aliases.
61
        * platform/ScrollableArea.h: Ditto.
62
        * platform/mac/ScrollAnimatorMac.mm: Ditto.
63
64
2021-03-13  Fujii Hironori  <Hironori.Fujii@sony.com>
65
66
        Non-unified builds can't compile JSWebGLRenderingContext.cpp: error: member access into incomplete type 'WebCore::WebGLSampler'
67
        https://bugs.webkit.org/show_bug.cgi?id=223142
68
69
        Reviewed by Youenn Fablet.
70
71
        * html/canvas/WebGLRenderingContextBase.h: Added some missing header inclusions.
72
        * html/canvas/WebGLTransformFeedback.cpp:
73
        * html/canvas/WebGLTransformFeedback.h: Fixed a recursive header inclusion with WebGL2RenderingContext.h.
74
75
2021-03-13  Martin Robinson  <mrobinson@webkit.org>
76
77
        Add basic (non-momentum) wheel event handling for scroll snap
78
        https://bugs.webkit.org/show_bug.cgi?id=222594
79
80
        Reviewed by Simon Fraser.
81
82
        Test: css3/scroll-snap/scroll-snap-wheel-event.html
83
84
        Enable scroll snapping for basic wheel events on GTK+ and WPE. The Mac port
85
        has special wheel handling due to momentum scrolling. Other scroll-snap-enabled
86
        ports can just use a basic version.
87
88
        * platform/ScrollAnimator.cpp:
89
        (WebCore::ScrollAnimator::scroll): Accept a bitmask of options now. This
90
        will allow using this method when handling wheel events that do not animate.
91
        (WebCore::ScrollAnimator::handleWheelEvent): Trigger ::scroll with
92
        scroll snapping enabled and pass the appropriate option to disable animations.
93
        (WebCore::ScrollAnimator::processWheelEventForScrollSnap): Deleted.
94
        * platform/ScrollAnimator.h:
95
        (WebCore::ScrollAnimator::ScrollAnimator::processWheelEventForScrollSnap): Made
96
        this a method that can be overridden by subclasses.
97
        * platform/mac/ScrollAnimatorMac.h: Added processWheelEventForScrollSnap.
98
        * platform/mac/ScrollAnimatorMac.mm:
99
        (WebCore::ScrollAnimatorMac::scroll): Pay attention to the NeverAnimate bitmask now.
100
        (WebCore::ScrollAnimatorMac::processWheelEventForScrollSnap): Added.
101
102
2021-03-13  Alexey Shvayka  <shvaikalesh@gmail.com>
103
104
        Cache cross-origin methods / accessors of Window and Location per lexical global object
105
        https://bugs.webkit.org/show_bug.cgi?id=222739
106
107
        Reviewed by Darin Adler.
108
109
        For cross-origin methods / accessors, Window and Location objects return different JSFunction
110
        instances on every [[Get]]. The intent was to ensure isolation by supplying different Realms with
111
        different function objects. However, within the same callee Realm, this makes subsequent lookups
112
        of a cross-origin method / accessor fail reference equality test, which is rather confusing:
113
114
            `crossOriginWindow.focus === crossOriginWindow.focus // => false`
115
116
        This patch implements [[CrossOriginPropertyDescriptorMap]], bringing consistent function identity
117
        and aligning WebKit with the spec [1], Blink, and Gecko. For convenience, cache maps are added to
118
        JSDOMGlobalObject (to accommodate RemoteDOMWindow) and cover both Window and Location objects.
119
120
        As a cache map key, a pair of lexical global object and raw function pointer is used, which guarantees
121
        correctness even if Window and Location would expose cross-origin property of the same name.
122
123
        This patch removes 9 custom getters, adds runtime lookup for "showModalDialog" (which is rare),
124
        and removes [ForwardDeclareInHeader] extended attribute as it's now unused and non-trivial to generate.
125
126
        Also, fixes cross-realm `postMessage.length` to equal 1 as per WebIDL.
127
128
        [1] https://html.spec.whatwg.org/multipage/browsers.html#crossorigingetownpropertyhelper-(-o,-p-)
129
130
        Tests: imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-caching.html
131
               imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-length.html
132
               imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-name.html
133
134
        * bindings/js/JSDOMGlobalObject.cpp:
135
        (WebCore::JSDOMGlobalObject::JSDOMGlobalObject):
136
        (WebCore::JSDOMGlobalObject::createCrossOriginFunction):
137
        (WebCore::JSDOMGlobalObject::createCrossOriginGetterSetter):
138
        * bindings/js/JSDOMGlobalObject.h:
139
        * bindings/js/JSDOMWindowCustom.cpp:
140
        (WebCore::jsDOMWindowGetOwnPropertySlotRestrictedAccess):
141
        (WebCore::JSDOMWindow::getOwnPropertySlot):
142
        * bindings/js/JSLocationCustom.cpp:
143
        (WebCore::getOwnPropertySlotCommon):
144
        (WebCore::JSC_DEFINE_CUSTOM_GETTER): Deleted.
145
        * bindings/scripts/CodeGeneratorJS.pm:
146
        (GenerateHeader):
147
        (GenerateImplementation):
148
        * bindings/scripts/IDLAttributes.json:
149
        * page/DOMWindow.idl:
150
        * page/History.idl:
151
        * page/Location.idl:
152
        * page/RemoteDOMWindow.idl:
153
1
2021-03-12  Eric Carlson  <eric.carlson@apple.com>
154
2021-03-12  Eric Carlson  <eric.carlson@apple.com>
2
155
3
        Add more MediaStream logging
156
        Add more MediaStream logging
- a/Source/WebCore/PAL/ChangeLog +10 lines
Lines 1-3 a/Source/WebCore/PAL/ChangeLog_sec1
1
2021-03-13  Tim Horton  <timothy_horton@apple.com>
2
3
        Adopt DDMacAction instead of DDAction on macOS
4
        https://bugs.webkit.org/show_bug.cgi?id=223145
5
        <rdar://problem/70127512>
6
7
        Reviewed by Megan Gardner.
8
9
        * pal/spi/mac/DataDetectorsSPI.h:
10
1
2021-03-12  Myles C. Maxfield  <mmaxfield@apple.com>
11
2021-03-12  Myles C. Maxfield  <mmaxfield@apple.com>
2
12
3
        [macOS] MobileAsset fonts are broken in Reader mode in Safari
13
        [macOS] MobileAsset fonts are broken in Reader mode in Safari
- a/Source/WebKit/ChangeLog +37 lines
Lines 1-3 a/Source/WebKit/ChangeLog_sec1
1
2021-03-15  Martin Robinson  <mrobinson@webkit.org>
2
3
        [css-scroll-snap] Properly handle overflowing snap areas
4
        https://bugs.webkit.org/show_bug.cgi?id=223175
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        ScrollSnapOffsetsInfo no longer holds snap offset ranges, but is also templated off
9
        of a rect type. In WebKit we switch to using the FloatScrollSnapOffsetsInfo alias.
10
        Additionally, we need to pass in the viewport size when requesting a snap offset
11
        position.
12
13
        * Shared/RemoteLayerTree/RemoteScrollingCoordinatorTransaction.cpp:
14
        (ArgumentCoder<ScrollingStateScrollingNode>::decode): Switch to using the FloatScrollSnapOffsetsInfo alias.
15
        (ArgumentCoder<FloatScrollSnapOffsetsInfo>::encode): Ditto. Also we no longer need to encode the ranges.
16
        (ArgumentCoder<FloatScrollSnapOffsetsInfo>::decode): Ditto.
17
        * Shared/WebCoreArgumentCoders.cpp: Ditto.
18
        * Shared/WebCoreArgumentCoders.h: Ditto.
19
        * UIProcess/RemoteLayerTree/ios/RemoteScrollingCoordinatorProxyIOS.mm:
20
        (WebKit::RemoteScrollingCoordinatorProxy::closestSnapOffsetForMainFrameScrolling const): Pass in the viewport size now.
21
        * UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm:
22
        (-[WKScrollingNodeScrollViewDelegate scrollViewWillEndDragging:withVelocity:targetContentOffset:]): Ditto.
23
24
2021-03-13  Tim Horton  <timothy_horton@apple.com>
25
26
        Adopt DDMacAction instead of DDAction on macOS
27
        https://bugs.webkit.org/show_bug.cgi?id=223145
28
        <rdar://problem/70127512>
29
30
        Reviewed by Megan Gardner.
31
32
        * Platform/mac/MenuUtilities.mm:
33
        (WebKit::actionForMenuItem):
34
        (WebKit::menuItemForTelephoneNumber):
35
        (WebKit::menuForTelephoneNumber):
36
        Adopt the new class name, when available.
37
1
2021-03-12  Jer Noble  <jer.noble@apple.com>
38
2021-03-12  Jer Noble  <jer.noble@apple.com>
2
39
3
        [Cocoa][WebM] Hang when reloading page before WebM content is loaded
40
        [Cocoa][WebM] Hang when reloading page before WebM content is loaded
- a/Source/JavaScriptCore/runtime/JSCustomGetterFunction.cpp -2 / +1 lines
Lines 40-48 JSC_DEFINE_HOST_FUNCTION(customGetterFunctionCall, (JSGlobalObject* globalObject a/Source/JavaScriptCore/runtime/JSCustomGetterFunction.cpp_sec1
40
40
41
    JSCustomGetterFunction* customGetterFunction = jsCast<JSCustomGetterFunction*>(callFrame->jsCallee());
41
    JSCustomGetterFunction* customGetterFunction = jsCast<JSCustomGetterFunction*>(callFrame->jsCallee());
42
    JSValue thisValue = callFrame->thisValue();
42
    JSValue thisValue = callFrame->thisValue();
43
44
    GetValueFunc getter = customGetterFunction->getter();
43
    GetValueFunc getter = customGetterFunction->getter();
45
    ASSERT(getter);
46
44
47
    if (auto domAttribute = customGetterFunction->domAttribute()) {
45
    if (auto domAttribute = customGetterFunction->domAttribute()) {
48
        if (!thisValue.inherits(vm, domAttribute->classInfo))
46
        if (!thisValue.inherits(vm, domAttribute->classInfo))
Lines 62-67 JSCustomGetterFunction::JSCustomGetterFunction(VM& vm, NativeExecutable* executa a/Source/JavaScriptCore/runtime/JSCustomGetterFunction.cpp_sec2
62
60
63
JSCustomGetterFunction* JSCustomGetterFunction::create(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, GetValueFunc getter, Optional<DOMAttributeAnnotation> domAttribute)
61
JSCustomGetterFunction* JSCustomGetterFunction::create(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, GetValueFunc getter, Optional<DOMAttributeAnnotation> domAttribute)
64
{
62
{
63
    ASSERT(getter);
65
    NativeExecutable* executable = vm.getHostFunction(customGetterFunctionCall, callHostFunctionAsConstructor, String(propertyName.publicName()));
64
    NativeExecutable* executable = vm.getHostFunction(customGetterFunctionCall, callHostFunctionAsConstructor, String(propertyName.publicName()));
66
    Structure* structure = globalObject->customGetterFunctionStructure();
65
    Structure* structure = globalObject->customGetterFunctionStructure();
67
    JSCustomGetterFunction* function = new (NotNull, allocateCell<JSCustomGetterFunction>(vm.heap)) JSCustomGetterFunction(vm, executable, globalObject, structure, propertyName, getter, domAttribute);
66
    JSCustomGetterFunction* function = new (NotNull, allocateCell<JSCustomGetterFunction>(vm.heap)) JSCustomGetterFunction(vm, executable, globalObject, structure, propertyName, getter, domAttribute);
- a/Source/JavaScriptCore/runtime/JSCustomSetterFunction.cpp -1 / +1 lines
Lines 36-42 static JSC_DECLARE_HOST_FUNCTION(customSetterFunctionCall); a/Source/JavaScriptCore/runtime/JSCustomSetterFunction.cpp_sec1
36
JSC_DEFINE_HOST_FUNCTION(customSetterFunctionCall, (JSGlobalObject* globalObject, CallFrame* callFrame))
36
JSC_DEFINE_HOST_FUNCTION(customSetterFunctionCall, (JSGlobalObject* globalObject, CallFrame* callFrame))
37
{
37
{
38
    PutValueFunc setter = jsCast<JSCustomSetterFunction*>(callFrame->jsCallee())->setter();
38
    PutValueFunc setter = jsCast<JSCustomSetterFunction*>(callFrame->jsCallee())->setter();
39
    ASSERT(setter);
40
    setter(globalObject, JSValue::encode(callFrame->thisValue()), JSValue::encode(callFrame->argument(0)));
39
    setter(globalObject, JSValue::encode(callFrame->thisValue()), JSValue::encode(callFrame->argument(0)));
41
    return JSValue::encode(jsUndefined());
40
    return JSValue::encode(jsUndefined());
42
}
41
}
Lines 49-54 JSCustomSetterFunction::JSCustomSetterFunction(VM& vm, NativeExecutable* executa a/Source/JavaScriptCore/runtime/JSCustomSetterFunction.cpp_sec2
49
48
50
JSCustomSetterFunction* JSCustomSetterFunction::create(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, PutValueFunc setter)
49
JSCustomSetterFunction* JSCustomSetterFunction::create(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, PutValueFunc setter)
51
{
50
{
51
    ASSERT(setter);
52
    NativeExecutable* executable = vm.getHostFunction(customSetterFunctionCall, callHostFunctionAsConstructor, String(propertyName.publicName()));
52
    NativeExecutable* executable = vm.getHostFunction(customSetterFunctionCall, callHostFunctionAsConstructor, String(propertyName.publicName()));
53
    Structure* structure = globalObject->customSetterFunctionStructure();
53
    Structure* structure = globalObject->customSetterFunctionStructure();
54
    JSCustomSetterFunction* function = new (NotNull, allocateCell<JSCustomSetterFunction>(vm.heap)) JSCustomSetterFunction(vm, executable, globalObject, structure, setter);
54
    JSCustomSetterFunction* function = new (NotNull, allocateCell<JSCustomSetterFunction>(vm.heap)) JSCustomSetterFunction(vm, executable, globalObject, structure, setter);
- a/Source/JavaScriptCore/runtime/JSObject.cpp -16 / +10 lines
Lines 3521-3544 Butterfly* JSObject::allocateMoreOutOfLineStorage(VM& vm, size_t oldSize, size_t a/Source/JavaScriptCore/runtime/JSObject.cpp_sec1
3521
    return Butterfly::createOrGrowPropertyStorage(butterfly(), vm, this, structure(vm), oldSize, newSize);
3521
    return Butterfly::createOrGrowPropertyStorage(butterfly(), vm, this, structure(vm), oldSize, newSize);
3522
}
3522
}
3523
3523
3524
static JSCustomGetterFunction* getCustomGetterFunction(JSGlobalObject* globalObject, PropertyName propertyName, GetValueFunc getValueFunc, Optional<DOMAttributeAnnotation> domAttribute)
3524
static JSCustomGetterFunction* createCustomGetterFunction(JSGlobalObject* globalObject, PropertyName propertyName, GetValueFunc getValueFunc, Optional<DOMAttributeAnnotation> domAttribute)
3525
{
3525
{
3526
    JSCustomGetterFunction* customGetterFunction = globalObject->customGetterFunctionMap().get(getValueFunc);
3526
    return globalObject->customGetterFunctionMap().ensure(getValueFunc, [&] {
3527
    if (!customGetterFunction) {
3527
        return JSCustomGetterFunction::create(globalObject->vm(), globalObject, propertyName, getValueFunc, domAttribute);
3528
        customGetterFunction = JSCustomGetterFunction::create(globalObject->vm(), globalObject, propertyName, getValueFunc, domAttribute);
3528
    }).iterator->value.get();
3529
        globalObject->customGetterFunctionMap().set(getValueFunc, customGetterFunction);
3530
    }
3531
    return customGetterFunction;
3532
}
3529
}
3533
3530
3534
static JSCustomSetterFunction* getCustomSetterFunction(JSGlobalObject* globalObject, PropertyName propertyName, PutValueFunc putValueFunc)
3531
static JSCustomSetterFunction* createCustomSetterFunction(JSGlobalObject* globalObject, PropertyName propertyName, PutValueFunc putValueFunc)
3535
{
3532
{
3536
    JSCustomSetterFunction* customSetterFunction = globalObject->customSetterFunctionMap().get(putValueFunc);
3533
    return globalObject->customSetterFunctionMap().ensure(putValueFunc, [&] {
3537
    if (!customSetterFunction) {
3534
        return JSCustomSetterFunction::create(globalObject->vm(), globalObject, propertyName, putValueFunc);
3538
        customSetterFunction = JSCustomSetterFunction::create(globalObject->vm(), globalObject, propertyName, putValueFunc);
3535
    }).iterator->value.get();
3539
        globalObject->customSetterFunctionMap().set(putValueFunc, customSetterFunction);
3540
    }
3541
    return customSetterFunction;
3542
}
3536
}
3543
3537
3544
bool JSObject::getOwnPropertyDescriptor(JSGlobalObject* globalObject, PropertyName propertyName, PropertyDescriptor& descriptor)
3538
bool JSObject::getOwnPropertyDescriptor(JSGlobalObject* globalObject, PropertyName propertyName, PropertyDescriptor& descriptor)
Lines 3559-3567 bool JSObject::getOwnPropertyDescriptor(JSGlobalObject* globalObject, PropertyNa a/Source/JavaScriptCore/runtime/JSObject.cpp_sec2
3559
        descriptor.setAccessorDescriptor((slot.attributes() | PropertyAttribute::Accessor) & ~PropertyAttribute::CustomAccessor);
3553
        descriptor.setAccessorDescriptor((slot.attributes() | PropertyAttribute::Accessor) & ~PropertyAttribute::CustomAccessor);
3560
        JSGlobalObject* slotBaseGlobalObject = slot.slotBase()->globalObject(vm);
3554
        JSGlobalObject* slotBaseGlobalObject = slot.slotBase()->globalObject(vm);
3561
        if (slot.customGetter())
3555
        if (slot.customGetter())
3562
            descriptor.setGetter(getCustomGetterFunction(slotBaseGlobalObject, propertyName, slot.customGetter(), slot.domAttribute()));
3556
            descriptor.setGetter(createCustomGetterFunction(slotBaseGlobalObject, propertyName, slot.customGetter(), slot.domAttribute()));
3563
        if (slot.customSetter())
3557
        if (slot.customSetter())
3564
            descriptor.setSetter(getCustomSetterFunction(slotBaseGlobalObject, propertyName, slot.customSetter()));
3558
            descriptor.setSetter(createCustomSetterFunction(slotBaseGlobalObject, propertyName, slot.customSetter()));
3565
    } else {
3559
    } else {
3566
        JSValue value = slot.getValue(globalObject, propertyName);
3560
        JSValue value = slot.getValue(globalObject, propertyName);
3567
        RETURN_IF_EXCEPTION(scope, false);
3561
        RETURN_IF_EXCEPTION(scope, false);
- a/Source/JavaScriptCore/runtime/Lookup.h -5 lines
Lines 414-422 inline void reifyStaticProperties(VM& vm, const ClassInfo* classInfo, const Hash a/Source/JavaScriptCore/runtime/Lookup.h_sec1
414
    }
414
    }
415
}
415
}
416
416
417
template<RawNativeFunction nativeFunction, int length> EncodedJSValue nonCachingStaticFunctionGetterImpl(JSGlobalObject* globalObject, PropertyName propertyName)
418
{
419
    return JSValue::encode(JSFunction::create(globalObject->vm(), globalObject, length, propertyName.publicName(), nativeFunction));
420
}
421
422
} // namespace JSC
417
} // namespace JSC
- a/Source/JavaScriptCore/runtime/WeakGCMap.h +6 lines
Lines 64-69 public: a/Source/JavaScriptCore/runtime/WeakGCMap.h_sec1
64
        return m_map.set(key, WTFMove(value));
64
        return m_map.set(key, WTFMove(value));
65
    }
65
    }
66
66
67
    template<typename Functor>
68
    AddResult ensure(const KeyType& key, Functor&& functor)
69
    {
70
        return m_map.ensure(key, std::forward<Functor>(functor));
71
    }
72
67
    bool remove(const KeyType& key)
73
    bool remove(const KeyType& key)
68
    {
74
    {
69
        return m_map.remove(key);
75
        return m_map.remove(key);
- a/Source/WTF/wtf/PlatformHave.h +1 lines
Lines 916-921 a/Source/WTF/wtf/PlatformHave.h_sec1
916
916
917
#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 120000
917
#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 120000
918
#define HAVE_STATIC_FONT_REGISTRY 1
918
#define HAVE_STATIC_FONT_REGISTRY 1
919
#define HAVE_DATA_DETECTORS_MAC_ACTION 1
919
#endif
920
#endif
920
921
921
#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 120000) \
922
#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 120000) \
- a/Source/WebCore/PAL/pal/spi/mac/DataDetectorsSPI.h -1 / +12 lines
Lines 39-44 a/Source/WebCore/PAL/pal/spi/mac/DataDetectorsSPI.h_sec1
39
#import <DataDetectors/DDActionsManager.h>
39
#import <DataDetectors/DDActionsManager.h>
40
#import <DataDetectors/DDHighlightDrawing.h>
40
#import <DataDetectors/DDHighlightDrawing.h>
41
41
42
#if HAVE(DATA_DETECTORS_MAC_ACTION)
43
#import <DataDetectors/DDMacAction.h>
44
#endif
45
42
#else // !USE(APPLE_INTERNAL_SDK)
46
#else // !USE(APPLE_INTERNAL_SDK)
43
47
44
@interface DDActionContext : NSObject <NSCopying, NSSecureCoding>
48
@interface DDActionContext : NSObject <NSCopying, NSSecureCoding>
Lines 98-116 WTF_EXTERN_C_END a/Source/WebCore/PAL/pal/spi/mac/DataDetectorsSPI.h_sec2
98
typedef struct __DDHighlight *DDHighlightRef;
102
typedef struct __DDHighlight *DDHighlightRef;
99
typedef NSUInteger DDHighlightStyle;
103
typedef NSUInteger DDHighlightStyle;
100
104
105
#if !HAVE(DATA_DETECTORS_MAC_ACTION)
101
@interface DDAction : NSObject
106
@interface DDAction : NSObject
102
107
103
@property (readonly) NSString *actionUTI;
108
@property (readonly) NSString *actionUTI;
104
109
105
@end
110
@end
111
#endif
106
112
107
SOFT_LINK_PRIVATE_FRAMEWORK_OPTIONAL(DataDetectors)
113
SOFT_LINK_PRIVATE_FRAMEWORK_OPTIONAL(DataDetectors)
108
SOFT_LINK_PRIVATE_FRAMEWORK_OPTIONAL(DataDetectorsCore)
114
SOFT_LINK_PRIVATE_FRAMEWORK_OPTIONAL(DataDetectorsCore)
109
115
110
SOFT_LINK_CLASS_OPTIONAL(DataDetectors, DDAction)
111
SOFT_LINK_CLASS_OPTIONAL(DataDetectors, DDActionContext)
116
SOFT_LINK_CLASS_OPTIONAL(DataDetectors, DDActionContext)
112
SOFT_LINK_CLASS_OPTIONAL(DataDetectors, DDActionsManager)
117
SOFT_LINK_CLASS_OPTIONAL(DataDetectors, DDActionsManager)
113
118
119
#if HAVE(DATA_DETECTORS_MAC_ACTION)
120
SOFT_LINK_CLASS_OPTIONAL(DataDetectors, DDMacAction)
121
#else
122
SOFT_LINK_CLASS_OPTIONAL(DataDetectors, DDAction)
123
#endif
124
114
SOFT_LINK_CONSTANT(DataDetectorsCore, DDBinderPhoneNumberKey, CFStringRef)
125
SOFT_LINK_CONSTANT(DataDetectorsCore, DDBinderPhoneNumberKey, CFStringRef)
115
#if HAVE(DD_HIGHLIGHT_CREATE_WITH_SCALE)
126
#if HAVE(DD_HIGHLIGHT_CREATE_WITH_SCALE)
116
SOFT_LINK(DataDetectors, DDHighlightCreateWithRectsInVisibleRectWithStyleScaleAndDirection, DDHighlightRef, (CFAllocatorRef allocator, CGRect* rects, CFIndex count, CGRect globalVisibleRect, DDHighlightStyle style, Boolean withButton, NSWritingDirection writingDirection, Boolean endsWithEOL, Boolean flipped, CGFloat scale), (allocator, rects, count, globalVisibleRect, style, withButton, writingDirection, endsWithEOL, flipped, scale))
127
SOFT_LINK(DataDetectors, DDHighlightCreateWithRectsInVisibleRectWithStyleScaleAndDirection, DDHighlightRef, (CFAllocatorRef allocator, CGRect* rects, CFIndex count, CGRect globalVisibleRect, DDHighlightStyle style, Boolean withButton, NSWritingDirection writingDirection, Boolean endsWithEOL, Boolean flipped, CGFloat scale), (allocator, rects, count, globalVisibleRect, style, withButton, writingDirection, endsWithEOL, flipped, scale))
- a/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp +26 lines
Lines 54-62 a/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp_sec1
54
#include "WorkletGlobalScope.h"
54
#include "WorkletGlobalScope.h"
55
#include <JavaScriptCore/BuiltinNames.h>
55
#include <JavaScriptCore/BuiltinNames.h>
56
#include <JavaScriptCore/CodeBlock.h>
56
#include <JavaScriptCore/CodeBlock.h>
57
#include <JavaScriptCore/GetterSetter.h>
58
#include <JavaScriptCore/JSCustomGetterFunction.h>
59
#include <JavaScriptCore/JSCustomSetterFunction.h>
57
#include <JavaScriptCore/JSInternalPromise.h>
60
#include <JavaScriptCore/JSInternalPromise.h>
58
#include <JavaScriptCore/StructureInlines.h>
61
#include <JavaScriptCore/StructureInlines.h>
59
#include <JavaScriptCore/WasmStreamingCompiler.h>
62
#include <JavaScriptCore/WasmStreamingCompiler.h>
63
#include <JavaScriptCore/WeakGCMapInlines.h>
60
64
61
namespace WebCore {
65
namespace WebCore {
62
using namespace JSC;
66
using namespace JSC;
Lines 75-80 JSDOMGlobalObject::JSDOMGlobalObject(VM& vm, Structure* structure, Ref<DOMWrappe a/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp_sec2
75
    , m_world(WTFMove(world))
79
    , m_world(WTFMove(world))
76
    , m_worldIsNormal(m_world->isNormal())
80
    , m_worldIsNormal(m_world->isNormal())
77
    , m_builtinInternalFunctions(vm)
81
    , m_builtinInternalFunctions(vm)
82
    , m_crossOriginFunctionMap(vm)
83
    , m_crossOriginGetterSetterMap(vm)
78
{
84
{
79
}
85
}
80
86
Lines 298-303 void JSDOMGlobalObject::clearDOMGuardedObjects() a/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp_sec3
298
        guarded->clear();
304
        guarded->clear();
299
}
305
}
300
306
307
JSFunction* JSDOMGlobalObject::createCrossOriginFunction(JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, NativeFunction nativeFunction, unsigned length)
308
{
309
    CrossOriginMapKey key = std::make_pair(lexicalGlobalObject, nativeFunction.rawPointer());
310
    return m_crossOriginFunctionMap.ensure(key, [&] {
311
        return JSFunction::create(lexicalGlobalObject->vm(), lexicalGlobalObject, length, propertyName.publicName(), nativeFunction);
312
    }).iterator->value.get();
313
}
314
315
GetterSetter* JSDOMGlobalObject::createCrossOriginGetterSetter(JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, GetValueFunc getter, PutValueFunc setter)
316
{
317
    ASSERT(getter || setter);
318
    CrossOriginMapKey key = std::make_pair(lexicalGlobalObject, getter ? reinterpret_cast<void*>(getter) : reinterpret_cast<void*>(setter));
319
    return m_crossOriginGetterSetterMap.ensure(key, [&] {
320
        auto& vm = lexicalGlobalObject->vm();
321
        return GetterSetter::create(vm, lexicalGlobalObject,
322
            getter ? JSCustomGetterFunction::create(vm, lexicalGlobalObject, propertyName, getter) : nullptr,
323
            setter ? JSCustomSetterFunction::create(vm, lexicalGlobalObject, propertyName, setter) : nullptr);
324
    }).iterator->value.get();
325
}
326
301
#if ENABLE(WEBASSEMBLY)
327
#if ENABLE(WEBASSEMBLY)
302
// https://webassembly.github.io/spec/web-api/index.html#compile-a-potential-webassembly-response
328
// https://webassembly.github.io/spec/web-api/index.html#compile-a-potential-webassembly-response
303
static JSC::JSPromise* handleResponseOnStreamingAction(JSC::JSGlobalObject* globalObject, JSC::JSValue source, JSC::Wasm::CompilerMode compilerMode, JSC::JSObject* importObject)
329
static JSC::JSPromise* handleResponseOnStreamingAction(JSC::JSGlobalObject* globalObject, JSC::JSValue source, JSC::Wasm::CompilerMode compilerMode, JSC::JSObject* importObject)
- a/Source/WebCore/bindings/js/JSDOMGlobalObject.h +8 lines
Lines 31-36 a/Source/WebCore/bindings/js/JSDOMGlobalObject.h_sec1
31
#include <JavaScriptCore/JSGlobalObject.h>
31
#include <JavaScriptCore/JSGlobalObject.h>
32
#include <JavaScriptCore/JSObjectInlines.h>
32
#include <JavaScriptCore/JSObjectInlines.h>
33
#include <JavaScriptCore/LockDuringMarking.h>
33
#include <JavaScriptCore/LockDuringMarking.h>
34
#include <JavaScriptCore/WeakGCMap.h>
34
35
35
namespace WebCore {
36
namespace WebCore {
36
37
Lines 83-88 public: a/Source/WebCore/bindings/js/JSDOMGlobalObject.h_sec2
83
84
84
    JSC::JSProxy& proxy() const { ASSERT(m_proxy); return *m_proxy.get(); }
85
    JSC::JSProxy& proxy() const { ASSERT(m_proxy); return *m_proxy.get(); }
85
86
87
    JSC::JSFunction* createCrossOriginFunction(JSC::JSGlobalObject*, JSC::PropertyName, JSC::NativeFunction, unsigned length);
88
    JSC::GetterSetter* createCrossOriginGetterSetter(JSC::JSGlobalObject*, JSC::PropertyName, JSC::GetValueFunc, JSC::PutValueFunc);
89
86
public:
90
public:
87
    ~JSDOMGlobalObject();
91
    ~JSDOMGlobalObject();
88
92
Lines 124-130 private: a/Source/WebCore/bindings/js/JSDOMGlobalObject.h_sec3
124
    void addBuiltinGlobals(JSC::VM&);
128
    void addBuiltinGlobals(JSC::VM&);
125
    friend void JSBuiltinInternalFunctions::initialize(JSDOMGlobalObject&);
129
    friend void JSBuiltinInternalFunctions::initialize(JSDOMGlobalObject&);
126
130
131
    using CrossOriginMapKey = std::pair<JSC::JSGlobalObject*, void*>;
132
127
    JSBuiltinInternalFunctions m_builtinInternalFunctions;
133
    JSBuiltinInternalFunctions m_builtinInternalFunctions;
134
    JSC::WeakGCMap<CrossOriginMapKey, JSC::JSFunction> m_crossOriginFunctionMap;
135
    JSC::WeakGCMap<CrossOriginMapKey, JSC::GetterSetter> m_crossOriginGetterSetterMap;
128
};
136
};
129
137
130
template<class ConstructorClass>
138
template<class ConstructorClass>
- a/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp -85 / +23 lines
Lines 48-59 a/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp_sec1
48
#include "Settings.h"
48
#include "Settings.h"
49
#include "WebCoreJSClientData.h"
49
#include "WebCoreJSClientData.h"
50
#include <JavaScriptCore/BuiltinNames.h>
50
#include <JavaScriptCore/BuiltinNames.h>
51
#include <JavaScriptCore/GetterSetter.h>
52
#include <JavaScriptCore/HeapAnalyzer.h>
51
#include <JavaScriptCore/HeapAnalyzer.h>
53
#include <JavaScriptCore/InternalFunction.h>
52
#include <JavaScriptCore/InternalFunction.h>
54
#include <JavaScriptCore/JSCInlines.h>
53
#include <JavaScriptCore/JSCInlines.h>
55
#include <JavaScriptCore/JSCustomGetterFunction.h>
56
#include <JavaScriptCore/JSCustomSetterFunction.h>
57
#include <JavaScriptCore/JSFunction.h>
54
#include <JavaScriptCore/JSFunction.h>
58
#include <JavaScriptCore/JSMicrotask.h>
55
#include <JavaScriptCore/JSMicrotask.h>
59
#include <JavaScriptCore/Lookup.h>
56
#include <JavaScriptCore/Lookup.h>
Lines 67-124 namespace WebCore { a/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp_sec2
67
using namespace JSC;
64
using namespace JSC;
68
65
69
static JSC_DECLARE_HOST_FUNCTION(jsDOMWindowInstanceFunction_openDatabase);
66
static JSC_DECLARE_HOST_FUNCTION(jsDOMWindowInstanceFunction_openDatabase);
70
static JSC_DECLARE_CUSTOM_GETTER(jsRemoteDOMWindowInstanceFunction_blurNonCaching);
71
static JSC_DECLARE_CUSTOM_GETTER(jsDOMWindowInstanceFunction_blurNonCaching);
72
static JSC_DECLARE_CUSTOM_GETTER(jsRemoteDOMWindowInstanceFunction_closeNonCaching);
73
static JSC_DECLARE_CUSTOM_GETTER(jsDOMWindowInstanceFunction_closeNonCaching);
74
static JSC_DECLARE_CUSTOM_GETTER(jsRemoteDOMWindowInstanceFunction_focusNonCaching);
75
static JSC_DECLARE_CUSTOM_GETTER(jsDOMWindowInstanceFunction_focusNonCaching);
76
static JSC_DECLARE_CUSTOM_GETTER(jsRemoteDOMWindowInstanceFunction_postMessageNonCaching);
77
static JSC_DECLARE_CUSTOM_GETTER(jsDOMWindowInstanceFunction_postMessageNonCaching);
78
#if ENABLE(USER_MESSAGE_HANDLERS)
67
#if ENABLE(USER_MESSAGE_HANDLERS)
79
static JSC_DECLARE_CUSTOM_GETTER(jsDOMWindow_webkit);
68
static JSC_DECLARE_CUSTOM_GETTER(jsDOMWindow_webkit);
80
#endif
69
#endif
81
70
82
JSC_DEFINE_CUSTOM_GETTER(jsRemoteDOMWindowInstanceFunction_blurNonCaching, (JSGlobalObject* globalObject, EncodedJSValue, PropertyName propertyName))
83
{
84
    return nonCachingStaticFunctionGetterImpl<jsRemoteDOMWindowInstanceFunction_blur, 0>(globalObject, propertyName);
85
}
86
87
JSC_DEFINE_CUSTOM_GETTER(jsDOMWindowInstanceFunction_blurNonCaching, (JSGlobalObject* globalObject, EncodedJSValue, PropertyName propertyName))
88
{
89
    return nonCachingStaticFunctionGetterImpl<jsDOMWindowInstanceFunction_blur, 0>(globalObject, propertyName);
90
}
91
92
JSC_DEFINE_CUSTOM_GETTER(jsRemoteDOMWindowInstanceFunction_closeNonCaching, (JSGlobalObject* globalObject, EncodedJSValue, PropertyName propertyName))
93
{
94
    return nonCachingStaticFunctionGetterImpl<jsRemoteDOMWindowInstanceFunction_close, 0>(globalObject, propertyName);
95
}
96
97
JSC_DEFINE_CUSTOM_GETTER(jsDOMWindowInstanceFunction_closeNonCaching, (JSGlobalObject* globalObject, EncodedJSValue, PropertyName propertyName))
98
{
99
    return nonCachingStaticFunctionGetterImpl<jsDOMWindowInstanceFunction_close, 0>(globalObject, propertyName);
100
}
101
102
JSC_DEFINE_CUSTOM_GETTER(jsRemoteDOMWindowInstanceFunction_focusNonCaching, (JSGlobalObject* globalObject, EncodedJSValue, PropertyName propertyName))
103
{
104
    return nonCachingStaticFunctionGetterImpl<jsRemoteDOMWindowInstanceFunction_focus, 0>(globalObject, propertyName);
105
}
106
107
JSC_DEFINE_CUSTOM_GETTER(jsDOMWindowInstanceFunction_focusNonCaching, (JSGlobalObject* globalObject, EncodedJSValue, PropertyName propertyName))
108
{
109
    return nonCachingStaticFunctionGetterImpl<jsDOMWindowInstanceFunction_focus, 0>(globalObject, propertyName);
110
}
111
112
JSC_DEFINE_CUSTOM_GETTER(jsRemoteDOMWindowInstanceFunction_postMessageNonCaching, (JSGlobalObject* globalObject, EncodedJSValue, PropertyName propertyName))
113
{
114
    return nonCachingStaticFunctionGetterImpl<jsRemoteDOMWindowInstanceFunction_postMessage, 0>(globalObject, propertyName);
115
}
116
117
JSC_DEFINE_CUSTOM_GETTER(jsDOMWindowInstanceFunction_postMessageNonCaching, (JSGlobalObject* globalObject, EncodedJSValue, PropertyName propertyName))
118
{
119
    return nonCachingStaticFunctionGetterImpl<jsDOMWindowInstanceFunction_postMessage, 2>(globalObject, propertyName);
120
}
121
122
template<typename Visitor>
71
template<typename Visitor>
123
void JSDOMWindow::visitAdditionalChildren(Visitor& visitor)
72
void JSDOMWindow::visitAdditionalChildren(Visitor& visitor)
124
{
73
{
Lines 157-201 bool jsDOMWindowGetOwnPropertySlotRestrictedAccess(JSDOMGlobalObject* thisObject a/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp_sec3
157
    // https://html.spec.whatwg.org/#crossorigingetownpropertyhelper-(-o,-p-)
106
    // https://html.spec.whatwg.org/#crossorigingetownpropertyhelper-(-o,-p-)
158
107
159
    // These are the functions we allow access to cross-origin (DoNotCheckSecurity in IDL).
108
    // These are the functions we allow access to cross-origin (DoNotCheckSecurity in IDL).
160
    // Always provide the original function, on a fresh uncached function object.
109
    auto* classInfo = windowType == DOMWindowType::Remote ? JSRemoteDOMWindow::info() : JSDOMWindow::info();
161
    if (propertyName == builtinNames.blurPublicName()) {
110
    if (propertyName == builtinNames.closePublicName()
162
        slot.setCustom(thisObject, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum), windowType == DOMWindowType::Remote ? jsRemoteDOMWindowInstanceFunction_blurNonCaching : jsDOMWindowInstanceFunction_blurNonCaching);
111
        || propertyName == builtinNames.focusPublicName()
163
        return true;
112
        || propertyName == builtinNames.blurPublicName()
164
    }
113
        || propertyName == builtinNames.postMessagePublicName()) {
165
    if (propertyName == builtinNames.closePublicName()) {
114
        auto* entry = classInfo->staticPropHashTable->entry(propertyName);
166
        slot.setCustom(thisObject, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum), windowType == DOMWindowType::Remote ? jsRemoteDOMWindowInstanceFunction_closeNonCaching : jsDOMWindowInstanceFunction_closeNonCaching);
115
        auto* jsFunction = thisObject->createCrossOriginFunction(&lexicalGlobalObject, propertyName, entry->function(), entry->functionLength());
167
        return true;
116
        slot.setValue(thisObject, PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum, jsFunction);
168
    }
169
    if (propertyName == builtinNames.focusPublicName()) {
170
        slot.setCustom(thisObject, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum), windowType == DOMWindowType::Remote ? jsRemoteDOMWindowInstanceFunction_focusNonCaching : jsDOMWindowInstanceFunction_focusNonCaching);
171
        return true;
172
    }
173
    if (propertyName == builtinNames.postMessagePublicName()) {
174
        slot.setCustom(thisObject, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum), windowType == DOMWindowType::Remote ? jsRemoteDOMWindowInstanceFunction_postMessageNonCaching : jsDOMWindowInstanceFunction_postMessageNonCaching);
175
        return true;
117
        return true;
176
    }
118
    }
177
119
178
    // When accessing cross-origin known Window properties, we always use the original property getter,
120
    // When accessing cross-origin known Window properties, we always use the original property getter,
179
    // even if the property was removed / redefined. As of early 2016, this matches Firefox and Chrome's
121
    // even if the property was removed / redefined. As of early 2016, this matches Firefox and Chrome's
180
    // behavior.
122
    // behavior.
181
    auto* classInfo = windowType == DOMWindowType::Remote ? JSRemoteDOMWindow::info() : JSDOMWindow::info();
123
    if (propertyName == builtinNames.windowPublicName()
182
    if (auto* entry = classInfo->staticPropHashTable->entry(propertyName)) {
124
        || propertyName == builtinNames.selfPublicName()
183
        // Only allow access to these specific properties.
125
        || propertyName == builtinNames.locationPublicName()
184
        if (propertyName == builtinNames.locationPublicName()
126
        || propertyName == builtinNames.closedPublicName()
185
            || propertyName == builtinNames.closedPublicName()
127
        || propertyName == builtinNames.framesPublicName()
186
            || propertyName == vm.propertyNames->length
128
        || propertyName == vm.propertyNames->length
187
            || propertyName == builtinNames.selfPublicName()
129
        || propertyName == builtinNames.topPublicName()
188
            || propertyName == builtinNames.windowPublicName()
130
        || propertyName == builtinNames.openerPublicName()
189
            || propertyName == builtinNames.framesPublicName()
131
        || propertyName == builtinNames.parentPublicName()) {
190
            || propertyName == builtinNames.openerPublicName()
132
        auto* entry = classInfo->staticPropHashTable->entry(propertyName);
191
            || propertyName == builtinNames.parentPublicName()
133
        auto* setter = propertyName == builtinNames.locationPublicName() ? entry->propertyPutter() : nullptr;
192
            || propertyName == builtinNames.topPublicName()) {
134
        auto* getterSetter = thisObject->createCrossOriginGetterSetter(&lexicalGlobalObject, propertyName, entry->propertyGetter(), setter);
193
            auto* getter = JSCustomGetterFunction::create(vm, &lexicalGlobalObject, propertyName, entry->propertyGetter());
135
        slot.setGetterSlot(thisObject, PropertyAttribute::Accessor | PropertyAttribute::DontEnum, getterSetter);
194
            auto* setter = propertyName == builtinNames.locationPublicName() ? JSCustomSetterFunction::create(vm, &lexicalGlobalObject, propertyName, entry->propertyPutter()) : nullptr;
136
        return true;
195
            auto* getterSetter = GetterSetter::create(vm, &lexicalGlobalObject, getter, setter);
196
            slot.setGetterSlot(thisObject, PropertyAttribute::Accessor | PropertyAttribute::DontEnum, getterSetter);
197
            return true;
198
        }
199
    }
137
    }
200
138
201
    // Check for child frames by name before built-in properties to match Mozilla. This does
139
    // Check for child frames by name before built-in properties to match Mozilla. This does
Lines 265-271 bool JSDOMWindow::getOwnPropertySlot(JSObject* object, JSGlobalObject* lexicalGl a/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp_sec4
265
        // Detect when we're getting the property 'showModalDialog', this is disabled, and has its original value.
203
        // Detect when we're getting the property 'showModalDialog', this is disabled, and has its original value.
266
        bool isShowModalDialogAndShouldHide = propertyName == static_cast<JSVMClientData*>(lexicalGlobalObject->vm().clientData)->builtinNames().showModalDialogPublicName()
204
        bool isShowModalDialogAndShouldHide = propertyName == static_cast<JSVMClientData*>(lexicalGlobalObject->vm().clientData)->builtinNames().showModalDialogPublicName()
267
            && (!frame || !DOMWindow::canShowModalDialog(*frame))
205
            && (!frame || !DOMWindow::canShowModalDialog(*frame))
268
            && slot.isValue() && isHostFunction(slot.getValue(lexicalGlobalObject, propertyName), jsDOMWindowInstanceFunction_showModalDialog);
206
            && slot.isValue() && isHostFunction(slot.getValue(lexicalGlobalObject, propertyName), s_info.staticPropHashTable->entry(propertyName)->function());
269
        // Unless we're in the showModalDialog special case, we're done.
207
        // Unless we're in the showModalDialog special case, we're done.
270
        if (!isShowModalDialogAndShouldHide)
208
        if (!isShowModalDialogAndShouldHide)
271
            return true;
209
            return true;
- a/Source/WebCore/bindings/js/JSLocationCustom.cpp -12 / +4 lines
Lines 29-49 a/Source/WebCore/bindings/js/JSLocationCustom.cpp_sec1
29
#include "JSDOMWindowCustom.h"
29
#include "JSDOMWindowCustom.h"
30
#include "RuntimeApplicationChecks.h"
30
#include "RuntimeApplicationChecks.h"
31
#include "WebCoreJSClientData.h"
31
#include "WebCoreJSClientData.h"
32
#include <JavaScriptCore/GetterSetter.h>
33
#include <JavaScriptCore/JSCustomSetterFunction.h>
34
#include <JavaScriptCore/JSFunction.h>
32
#include <JavaScriptCore/JSFunction.h>
35
#include <JavaScriptCore/Lookup.h>
33
#include <JavaScriptCore/Lookup.h>
36
34
37
namespace WebCore {
35
namespace WebCore {
38
using namespace JSC;
36
using namespace JSC;
39
37
40
static JSC_DECLARE_CUSTOM_GETTER(jsLocationInstanceFunction_replaceNonCaching);
41
42
JSC_DEFINE_CUSTOM_GETTER(jsLocationInstanceFunction_replaceNonCaching, (JSGlobalObject* globalObject, EncodedJSValue, PropertyName propertyName))
43
{
44
    return nonCachingStaticFunctionGetterImpl<jsLocationInstanceFunction_replace, 1>(globalObject, propertyName);
45
}
46
47
static bool getOwnPropertySlotCommon(JSLocation& thisObject, JSGlobalObject& lexicalGlobalObject, PropertyName propertyName, PropertySlot& slot)
38
static bool getOwnPropertySlotCommon(JSLocation& thisObject, JSGlobalObject& lexicalGlobalObject, PropertyName propertyName, PropertySlot& slot)
48
{
39
{
49
    VM& vm = lexicalGlobalObject.vm();
40
    VM& vm = lexicalGlobalObject.vm();
Lines 64-70 static bool getOwnPropertySlotCommon(JSLocation& thisObject, JSGlobalObject& lex a/Source/WebCore/bindings/js/JSLocationCustom.cpp_sec2
64
55
65
    // We only allow access to Location.replace() cross origin.
56
    // We only allow access to Location.replace() cross origin.
66
    if (propertyName == vm.propertyNames->replace) {
57
    if (propertyName == vm.propertyNames->replace) {
67
        slot.setCustom(&thisObject, static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum), jsLocationInstanceFunction_replaceNonCaching);
58
        auto* entry = JSLocation::info()->staticPropHashTable->entry(propertyName);
59
        auto* jsFunction = thisObject.globalObject()->createCrossOriginFunction(&lexicalGlobalObject, propertyName, entry->function(), entry->functionLength());
60
        slot.setValue(&thisObject, PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum, jsFunction);
68
        return true;
61
        return true;
69
    }
62
    }
70
63
Lines 72-79 static bool getOwnPropertySlotCommon(JSLocation& thisObject, JSGlobalObject& lex a/Source/WebCore/bindings/js/JSLocationCustom.cpp_sec3
72
    // a descriptor that has a setter but no getter.
65
    // a descriptor that has a setter but no getter.
73
    if (slot.internalMethodType() == PropertySlot::InternalMethodType::GetOwnProperty && propertyName == static_cast<JSVMClientData*>(vm.clientData)->builtinNames().hrefPublicName()) {
66
    if (slot.internalMethodType() == PropertySlot::InternalMethodType::GetOwnProperty && propertyName == static_cast<JSVMClientData*>(vm.clientData)->builtinNames().hrefPublicName()) {
74
        auto* entry = JSLocation::info()->staticPropHashTable->entry(propertyName);
67
        auto* entry = JSLocation::info()->staticPropHashTable->entry(propertyName);
75
        auto* setter = JSCustomSetterFunction::create(vm, &lexicalGlobalObject, propertyName, entry->propertyPutter());
68
        auto* getterSetter = thisObject.globalObject()->createCrossOriginGetterSetter(&lexicalGlobalObject, propertyName, nullptr, entry->propertyPutter());
76
        auto* getterSetter = GetterSetter::create(vm, &lexicalGlobalObject, nullptr, setter);
77
        slot.setGetterSlot(&thisObject, PropertyAttribute::Accessor | PropertyAttribute::DontEnum, getterSetter);
69
        slot.setGetterSlot(&thisObject, PropertyAttribute::Accessor | PropertyAttribute::DontEnum, getterSetter);
78
        return true;
70
        return true;
79
    }
71
    }
- a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm -54 lines
Lines 3066-3074 sub GenerateHeader a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm_sec1
3066
    my $numCustomOperations = 0;
3066
    my $numCustomOperations = 0;
3067
    my $numCustomAttributes = 0;
3067
    my $numCustomAttributes = 0;
3068
3068
3069
    my $hasForwardDeclaringOperations = 0;
3070
    my $hasForwardDeclaringAttributes = 0;
3071
3072
    my $hasDOMJITAttributes = 0;
3069
    my $hasDOMJITAttributes = 0;
3073
3070
3074
    # Attribute and function enums
3071
    # Attribute and function enums
Lines 3084-3091 sub GenerateHeader a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm_sec2
3084
                push(@headerContent, "#endif\n") if $conditionalString;
3081
                push(@headerContent, "#endif\n") if $conditionalString;
3085
            }
3082
            }
3086
            $hasDOMJITAttributes = 1 if $attribute->extendedAttributes->{DOMJIT};
3083
            $hasDOMJITAttributes = 1 if $attribute->extendedAttributes->{DOMJIT};
3087
3088
            $hasForwardDeclaringAttributes = 1 if $attribute->extendedAttributes->{ForwardDeclareInHeader};
3089
        }
3084
        }
3090
    }
3085
    }
3091
3086
Lines 3144-3150 sub GenerateHeader a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm_sec3
3144
3139
3145
    foreach my $operation (@{$interface->operations}) {
3140
    foreach my $operation (@{$interface->operations}) {
3146
        $numCustomOperations++ if HasCustomMethod($operation);
3141
        $numCustomOperations++ if HasCustomMethod($operation);
3147
        $hasForwardDeclaringOperations = 1 if $operation->extendedAttributes->{ForwardDeclareInHeader};
3148
    }
3142
    }
3149
3143
3150
    if ($numCustomOperations > 0) {
3144
    if ($numCustomOperations > 0) {
Lines 3270-3321 sub GenerateHeader a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm_sec4
3270
3264
3271
    GeneratePrototypeDeclaration(\@headerContent, $className, $interface) if HeaderNeedsPrototypeDeclaration($interface);
3265
    GeneratePrototypeDeclaration(\@headerContent, $className, $interface) if HeaderNeedsPrototypeDeclaration($interface);
3272
3266
3273
    if ($hasForwardDeclaringOperations) {
3274
        my $inAppleCopyright = 0;
3275
        push(@headerContent,"// Functions\n\n");
3276
        foreach my $operation (@{$interface->operations}) {
3277
            next if $operation->{overloadIndex} && $operation->{overloadIndex} > 1;
3278
            next unless $operation->extendedAttributes->{ForwardDeclareInHeader};
3279
3280
            if ($operation->extendedAttributes->{AppleCopyright}) {
3281
                if (!$inAppleCopyright) {
3282
                    push(@headerContent, $beginAppleCopyrightForHeaderFiles);
3283
                    $inAppleCopyright = 1;
3284
                }
3285
            } elsif ($inAppleCopyright) {
3286
                push(@headerContent, $endAppleCopyright);
3287
                $inAppleCopyright = 0;
3288
            }
3289
3290
            my $conditionalAttribute = GetConditionalForOperationConsideringOverloads($operation);
3291
            my $conditionalString = $conditionalAttribute ? $codeGenerator->GenerateConditionalStringFromAttributeValue($conditionalAttribute) : undef;
3292
            push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
3293
            my $functionName = GetFunctionName($interface, $className, $operation);
3294
            push(@headerContent, "JSC_DECLARE_HOST_FUNCTION(${functionName});\n");
3295
            push(@headerContent, "#endif\n") if $conditionalString;
3296
        }
3297
3298
        push(@headerContent, $endAppleCopyright) if $inAppleCopyright;
3299
        push(@headerContent,"\n");
3300
    }
3301
3302
    if ($hasForwardDeclaringAttributes) {
3303
        push(@headerContent,"// Attributes\n\n");
3304
        foreach my $attribute (@{$interface->attributes}) {
3305
            next unless $attribute->extendedAttributes->{ForwardDeclareInHeader};
3306
3307
            my $conditionalString = $codeGenerator->GenerateConditionalString($attribute);
3308
            push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
3309
            my $getter = GetAttributeGetterName($interface, $className, $attribute);
3310
            push(@headerContent, "JSC_DECLARE_CUSTOM_GETTER(${getter});\n");
3311
            if (!IsReadonly($attribute)) {
3312
                my $setter = GetAttributeSetterName($interface, $className, $attribute);
3313
                push(@headerContent, "JSC_DECLARE_CUSTOM_SETTER(${setter});\n");
3314
            }
3315
            push(@headerContent, "#endif\n") if $conditionalString;
3316
        }
3317
    }
3318
3319
    # CheckJSCast Snippet function.
3267
    # CheckJSCast Snippet function.
3320
    if ($interface->extendedAttributes->{DOMJIT}) {
3268
    if ($interface->extendedAttributes->{DOMJIT}) {
3321
        $headerIncludes{"<JavaScriptCore/Snippet.h>"} = 1;
3269
        $headerIncludes{"<JavaScriptCore/Snippet.h>"} = 1;
Lines 4307-4313 sub GenerateImplementation a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm_sec5
4307
        push(@implContent,"// Functions\n\n");
4255
        push(@implContent,"// Functions\n\n");
4308
        foreach my $operation (@{$interface->operations}) {
4256
        foreach my $operation (@{$interface->operations}) {
4309
            next if $operation->{overloadIndex} && $operation->{overloadIndex} > 1;
4257
            next if $operation->{overloadIndex} && $operation->{overloadIndex} > 1;
4310
            next if $operation->extendedAttributes->{ForwardDeclareInHeader};
4311
            next if IsJSBuiltin($interface, $operation);
4258
            next if IsJSBuiltin($interface, $operation);
4312
            next if $operation->name eq "[Symbol.Iterator]";
4259
            next if $operation->name eq "[Symbol.Iterator]";
4313
4260
Lines 4353-4359 sub GenerateImplementation a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm_sec6
4353
        }
4300
        }
4354
4301
4355
        foreach my $attribute (@{$interface->attributes}) {
4302
        foreach my $attribute (@{$interface->attributes}) {
4356
            next if $attribute->extendedAttributes->{ForwardDeclareInHeader};
4357
            next if IsJSBuiltin($interface, $attribute);
4303
            next if IsJSBuiltin($interface, $attribute);
4358
4304
4359
            my $conditionalString = $codeGenerator->GenerateConditionalString($attribute);
4305
            my $conditionalString = $codeGenerator->GenerateConditionalString($attribute);
- a/Source/WebCore/bindings/scripts/IDLAttributes.json -3 lines
Lines 223-231 a/Source/WebCore/bindings/scripts/IDLAttributes.json_sec1
223
                "url": "https://heycam.github.io/webidl/#Exposed"
223
                "url": "https://heycam.github.io/webidl/#Exposed"
224
            }
224
            }
225
        },
225
        },
226
        "ForwardDeclareInHeader": {
227
            "contextsAllowed": ["attribute", "operation"]
228
        },
229
        "GenerateIsReachable": {
226
        "GenerateIsReachable": {
230
            "contextsAllowed": ["interface"],
227
            "contextsAllowed": ["interface"],
231
            "values": ["", "Impl", "ImplWebGLRenderingContext", "ImplCanvasBase", "ImplDocument", "ImplElementRoot", "ImplOwnerNodeRoot", "ImplScriptExecutionContext", "ReachableFromDOMWindow", "ReachableFromNavigator"]
228
            "values": ["", "Impl", "ImplWebGLRenderingContext", "ImplCanvasBase", "ImplDocument", "ImplElementRoot", "ImplOwnerNodeRoot", "ImplScriptExecutionContext", "ReachableFromDOMWindow", "ReachableFromNavigator"]
- a/Source/WebCore/html/canvas/WebGLRenderingContextBase.h +2 lines
Lines 50-55 a/Source/WebCore/html/canvas/WebGLRenderingContextBase.h_sec1
50
#include <wtf/Lock.h>
50
#include <wtf/Lock.h>
51
51
52
#if ENABLE(WEBGL2)
52
#if ENABLE(WEBGL2)
53
#include "WebGLSampler.h"
54
#include "WebGLTransformFeedback.h"
53
#include "WebGLVertexArrayObject.h"
55
#include "WebGLVertexArrayObject.h"
54
#endif
56
#endif
55
57
- a/Source/WebCore/html/canvas/WebGLTransformFeedback.cpp -1 / +1 lines
Lines 28-35 a/Source/WebCore/html/canvas/WebGLTransformFeedback.cpp_sec1
28
#if ENABLE(WEBGL2)
28
#if ENABLE(WEBGL2)
29
#include "WebGLTransformFeedback.h"
29
#include "WebGLTransformFeedback.h"
30
30
31
#include "WebGL2RenderingContext.h"
31
#include "WebGLContextGroup.h"
32
#include "WebGLContextGroup.h"
32
#include "WebGLRenderingContextBase.h"
33
#include <JavaScriptCore/AbstractSlotVisitorInlines.h>
33
#include <JavaScriptCore/AbstractSlotVisitorInlines.h>
34
#include <wtf/Lock.h>
34
#include <wtf/Lock.h>
35
#include <wtf/Locker.h>
35
#include <wtf/Locker.h>
- a/Source/WebCore/html/canvas/WebGLTransformFeedback.h -1 / +4 lines
Lines 27-33 a/Source/WebCore/html/canvas/WebGLTransformFeedback.h_sec1
27
27
28
#if ENABLE(WEBGL2)
28
#if ENABLE(WEBGL2)
29
29
30
#include "WebGL2RenderingContext.h"
31
#include "WebGLSharedObject.h"
30
#include "WebGLSharedObject.h"
32
31
33
namespace JSC {
32
namespace JSC {
Lines 40-45 class AbstractLocker; a/Source/WebCore/html/canvas/WebGLTransformFeedback.h_sec2
40
39
41
namespace WebCore {
40
namespace WebCore {
42
41
42
class WebGL2RenderingContext;
43
class WebGLBuffer;
44
class WebGLProgram;
45
43
class WebGLTransformFeedback final : public WebGLSharedObject {
46
class WebGLTransformFeedback final : public WebGLSharedObject {
44
public:
47
public:
45
    virtual ~WebGLTransformFeedback();
48
    virtual ~WebGLTransformFeedback();
- a/Source/WebCore/page/DOMWindow.idl -7 / +7 lines
Lines 62-72 a/Source/WebCore/page/DOMWindow.idl_sec1
62
    [Replaceable] readonly attribute BarProp statusbar;
62
    [Replaceable] readonly attribute BarProp statusbar;
63
    [Replaceable] readonly attribute BarProp toolbar;
63
    [Replaceable] readonly attribute BarProp toolbar;
64
    attribute DOMString status;
64
    attribute DOMString status;
65
    [DoNotCheckSecurity, CallWith=IncumbentDocument, ForwardDeclareInHeader] undefined close();
65
    [DoNotCheckSecurity, CallWith=IncumbentDocument] undefined close();
66
    [DoNotCheckSecurity, ForwardDeclareInHeader] readonly attribute boolean closed;
66
    [DoNotCheckSecurity] readonly attribute boolean closed;
67
    undefined stop();
67
    undefined stop();
68
    [DoNotCheckSecurity, CallWith=IncumbentWindow, ForwardDeclareInHeader] undefined focus();
68
    [DoNotCheckSecurity, CallWith=IncumbentWindow] undefined focus();
69
    [DoNotCheckSecurity, ForwardDeclareInHeader] undefined blur();
69
    [DoNotCheckSecurity] undefined blur();
70
70
71
    // other browsing contexts
71
    // other browsing contexts
72
    [Replaceable, DoNotCheckSecurityOnGetter, CustomGetter] readonly attribute WindowProxy frames;
72
    [Replaceable, DoNotCheckSecurityOnGetter, CustomGetter] readonly attribute WindowProxy frames;
Lines 91-98 a/Source/WebCore/page/DOMWindow.idl_sec2
91
    DOMString? prompt(optional DOMString message = "", optional DOMString defaultValue = "");
91
    DOMString? prompt(optional DOMString message = "", optional DOMString defaultValue = "");
92
    undefined print();
92
    undefined print();
93
93
94
    [CallWith=GlobalObject&IncumbentWindow, DoNotCheckSecurity, ForwardDeclareInHeader, MayThrowException] undefined postMessage(any message, USVString targetOrigin, optional sequence<object> transfer = []);
94
    [CallWith=GlobalObject&IncumbentWindow, DoNotCheckSecurity, MayThrowException] undefined postMessage(any message, USVString targetOrigin, optional sequence<object> transfer = []);
95
    [CallWith=GlobalObject&IncumbentWindow, DoNotCheckSecurity, ForwardDeclareInHeader, MayThrowException] undefined postMessage(any message, optional WindowPostMessageOptions options);
95
    [CallWith=GlobalObject&IncumbentWindow, DoNotCheckSecurity, MayThrowException] undefined postMessage(any message, optional WindowPostMessageOptions options);
96
96
97
97
98
    // Obsolete: Still part of the HTML specification (https://html.spec.whatwg.org/#Window-partial).
98
    // Obsolete: Still part of the HTML specification (https://html.spec.whatwg.org/#Window-partial).
Lines 119-125 a/Source/WebCore/page/DOMWindow.idl_sec3
119
    [NotEnumerable, Conditional=IOS_GESTURE_EVENTS] attribute EventHandler ongesturestart;
119
    [NotEnumerable, Conditional=IOS_GESTURE_EVENTS] attribute EventHandler ongesturestart;
120
120
121
    // Non-standard: This has been dropped from the HTML specification and by other browsers.
121
    // Non-standard: This has been dropped from the HTML specification and by other browsers.
122
    [Custom, ForwardDeclareInHeader] any showModalDialog(DOMString url, optional any dialogArgs, optional DOMString featureArgs);
122
    [Custom] any showModalDialog(DOMString url, optional any dialogArgs, optional DOMString featureArgs);
123
123
124
    // Non-standard: should probably deprecate this (https://bugs.webkit.org/show_bug.cgi?id=79653).
124
    // Non-standard: should probably deprecate this (https://bugs.webkit.org/show_bug.cgi?id=79653).
125
    // Blink already deprecated it (https://bugs.chromium.org/p/chromium/issues/detail?id=437569).
125
    // Blink already deprecated it (https://bugs.chromium.org/p/chromium/issues/detail?id=437569).
- a/Source/WebCore/page/History.idl -3 / +3 lines
Lines 33-41 a/Source/WebCore/page/History.idl_sec1
33
    attribute ScrollRestoration scrollRestoration;
33
    attribute ScrollRestoration scrollRestoration;
34
    [Custom] readonly attribute any state;
34
    [Custom] readonly attribute any state;
35
35
36
    [CallWith=Document, ForwardDeclareInHeader] undefined back();
36
    [CallWith=Document] undefined back();
37
    [CallWith=Document, ForwardDeclareInHeader] undefined forward();
37
    [CallWith=Document] undefined forward();
38
    [CallWith=Document, ForwardDeclareInHeader] undefined go(optional long delta = 0);
38
    [CallWith=Document] undefined go(optional long delta = 0);
39
39
40
    // FIXME: title should not be nullable as per the HTML specification.
40
    // FIXME: title should not be nullable as per the HTML specification.
41
    [MayThrowException] undefined pushState(SerializedScriptValue data, DOMString? title, optional USVString? url = null);
41
    [MayThrowException] undefined pushState(SerializedScriptValue data, DOMString? title, optional USVString? url = null);
- a/Source/WebCore/page/Location.idl -3 / +3 lines
Lines 45-53 a/Source/WebCore/page/Location.idl_sec1
45
] interface Location {
45
] interface Location {
46
    [SetterCallWith=ActiveWindow&FirstWindow, DoNotCheckSecurityOnSetter] stringifier attribute USVString href;
46
    [SetterCallWith=ActiveWindow&FirstWindow, DoNotCheckSecurityOnSetter] stringifier attribute USVString href;
47
47
48
    [CallWith=ActiveWindow&FirstWindow, MayThrowException, ForwardDeclareInHeader] undefined assign(USVString url);
48
    [CallWith=ActiveWindow&FirstWindow, MayThrowException] undefined assign(USVString url);
49
    [DoNotCheckSecurity, CallWith=ActiveWindow&FirstWindow, MayThrowException, ForwardDeclareInHeader] undefined replace(USVString url);
49
    [DoNotCheckSecurity, CallWith=ActiveWindow&FirstWindow, MayThrowException] undefined replace(USVString url);
50
    [CallWith=ActiveWindow, ForwardDeclareInHeader] undefined reload();
50
    [CallWith=ActiveWindow] undefined reload();
51
51
52
    // URI decomposition attributes
52
    // URI decomposition attributes
53
    [SetterCallWith=ActiveWindow&FirstWindow] attribute USVString protocol;
53
    [SetterCallWith=ActiveWindow&FirstWindow] attribute USVString protocol;
- a/Source/WebCore/page/RemoteDOMWindow.idl -5 / +5 lines
Lines 46-59 a/Source/WebCore/page/RemoteDOMWindow.idl_sec1
46
    [LegacyUnforgeable, ImplementedAs=self] readonly attribute WindowProxy window;
46
    [LegacyUnforgeable, ImplementedAs=self] readonly attribute WindowProxy window;
47
    [Replaceable] readonly attribute WindowProxy self;
47
    [Replaceable] readonly attribute WindowProxy self;
48
    [PutForwards=href, LegacyUnforgeable] readonly attribute Location? location; // FIXME: Should not be nullable.
48
    [PutForwards=href, LegacyUnforgeable] readonly attribute Location? location; // FIXME: Should not be nullable.
49
    [CallWith=IncumbentDocument, ForwardDeclareInHeader] undefined close();
49
    [CallWith=IncumbentDocument] undefined close();
50
    [ForwardDeclareInHeader] readonly attribute boolean closed;
50
    readonly attribute boolean closed;
51
    [CallWith=IncumbentWindow, ForwardDeclareInHeader] undefined focus();
51
    [CallWith=IncumbentWindow] undefined focus();
52
    [ForwardDeclareInHeader] undefined blur();
52
    undefined blur();
53
    [Replaceable, ImplementedAs=self] readonly attribute WindowProxy frames;
53
    [Replaceable, ImplementedAs=self] readonly attribute WindowProxy frames;
54
    [Replaceable] readonly attribute unsigned long length;
54
    [Replaceable] readonly attribute unsigned long length;
55
    [LegacyUnforgeable] readonly attribute WindowProxy? top;
55
    [LegacyUnforgeable] readonly attribute WindowProxy? top;
56
    readonly attribute WindowProxy? opener;
56
    readonly attribute WindowProxy? opener;
57
    [Replaceable] readonly attribute WindowProxy? parent;
57
    [Replaceable] readonly attribute WindowProxy? parent;
58
    [CallWith=GlobalObject&IncumbentWindow, ForwardDeclareInHeader] undefined postMessage(any message, USVString targetOrigin, optional sequence<object> transfer = []);
58
    [CallWith=GlobalObject&IncumbentWindow] undefined postMessage(any message, USVString targetOrigin, optional sequence<object> transfer = []);
59
};
59
};
- a/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp -3 / +3 lines
Lines 92-106 void AsyncScrollingCoordinator::handleWheelEventPhase(ScrollingNodeID nodeID, Pl a/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp_sec1
92
#endif
92
#endif
93
93
94
#if ENABLE(CSS_SCROLL_SNAP)
94
#if ENABLE(CSS_SCROLL_SNAP)
95
static inline void setStateScrollingNodeSnapOffsetsAsFloat(ScrollingStateScrollingNode& node, const ScrollSnapOffsetsInfo<LayoutUnit>* offsetInfo, float deviceScaleFactor)
95
static inline void setStateScrollingNodeSnapOffsetsAsFloat(ScrollingStateScrollingNode& node, const LayoutScrollSnapOffsetsInfo* offsetInfo, float deviceScaleFactor)
96
{
96
{
97
    if (!offsetInfo) {
97
    if (!offsetInfo) {
98
        node.setSnapOffsetsInfo(ScrollSnapOffsetsInfo<float>());
98
        node.setSnapOffsetsInfo(FloatScrollSnapOffsetsInfo());
99
        return;
99
        return;
100
    }
100
    }
101
101
102
    // FIXME: Incorporate current page scale factor in snapping to device pixel. Perhaps we should just convert to float here and let UI process do the pixel snapping?
102
    // FIXME: Incorporate current page scale factor in snapping to device pixel. Perhaps we should just convert to float here and let UI process do the pixel snapping?
103
    node.setSnapOffsetsInfo(offsetInfo->convertUnits<float>(deviceScaleFactor));
103
    node.setSnapOffsetsInfo(offsetInfo->convertUnits<float, FloatRect>(deviceScaleFactor));
104
}
104
}
105
#endif
105
#endif
106
106
- a/Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.cpp -175 / +168 lines
Lines 41-108 a/Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.cpp_sec1
41
41
42
namespace WebCore {
42
namespace WebCore {
43
43
44
template <typename LayoutType>
44
template <typename UnitType>
45
static void indicesOfNearestSnapOffsetRanges(LayoutType offset, const Vector<ScrollOffsetRange<LayoutType>>& snapOffsetRanges, unsigned& lowerIndex, unsigned& upperIndex)
45
static Optional<std::pair<UnitType, unsigned>> findFirstSnapStopOffsetBetweenOriginAndDestination(const Vector<SnapOffset<UnitType>>& snapOffsets, UnitType scrollOriginOffset, UnitType scrollDestinationOffset)
46
{
46
{
47
    if (snapOffsetRanges.isEmpty()) {
47
    UnitType difference = scrollDestinationOffset - scrollOriginOffset;
48
        lowerIndex = invalidSnapOffsetIndex;
49
        upperIndex = invalidSnapOffsetIndex;
50
        return;
51
    }
52
53
    int lowerIndexAsInt = -1;
54
    int upperIndexAsInt = snapOffsetRanges.size();
55
    do {
56
        int middleIndex = (lowerIndexAsInt + upperIndexAsInt) / 2;
57
        auto& range = snapOffsetRanges[middleIndex];
58
        if (range.start < offset && offset < range.end) {
59
            lowerIndexAsInt = middleIndex;
60
            upperIndexAsInt = middleIndex;
61
            break;
62
        }
63
64
        if (offset > range.end)
65
            lowerIndexAsInt = middleIndex;
66
        else
67
            upperIndexAsInt = middleIndex;
68
    } while (lowerIndexAsInt < upperIndexAsInt - 1);
69
70
    if (offset <= snapOffsetRanges.first().start)
71
        lowerIndex = invalidSnapOffsetIndex;
72
    else
73
        lowerIndex = lowerIndexAsInt;
74
75
    if (offset >= snapOffsetRanges.last().end)
76
        upperIndex = invalidSnapOffsetIndex;
77
    else
78
        upperIndex = upperIndexAsInt;
79
}
80
81
template <typename LayoutType>
82
static void indicesOfNearestSnapOffsets(LayoutType offset, const Vector<SnapOffset<LayoutType>>& snapOffsets, unsigned& lowerIndex, unsigned& upperIndex)
83
{
84
    lowerIndex = 0;
85
    upperIndex = snapOffsets.size() - 1;
86
    while (lowerIndex < upperIndex - 1) {
87
        int middleIndex = (lowerIndex + upperIndex) / 2;
88
        auto middleOffset = snapOffsets[middleIndex].offset;
89
        if (offset == middleOffset) {
90
            upperIndex = middleIndex;
91
            lowerIndex = middleIndex;
92
            break;
93
        }
94
95
        if (offset > middleOffset)
96
            lowerIndex = middleIndex;
97
        else
98
            upperIndex = middleIndex;
99
    }
100
}
101
102
template <typename LayoutType>
103
static Optional<unsigned> findFirstSnapStopOffsetBetweenOriginAndDestination(const Vector<SnapOffset<LayoutType>>& snapOffsets, LayoutType scrollOriginOffset, LayoutType scrollDestinationOffset)
104
{
105
    LayoutType difference = scrollDestinationOffset - scrollOriginOffset;
106
    if (!difference)
48
    if (!difference)
107
        return WTF::nullopt;
49
        return WTF::nullopt;
108
50
Lines 113-119 static Optional<unsigned> findFirstSnapStopOffsetBetweenOriginAndDestination(con a/Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.cpp_sec2
113
        iteration = -1;
55
        iteration = -1;
114
    }
56
    }
115
57
116
    auto isPast = [difference](LayoutType mark, LayoutType candidate) {
58
    auto isPast = [difference](UnitType mark, UnitType candidate) {
117
        return (difference > 0 && candidate > mark) || (difference < 0 && candidate < mark);
59
        return (difference > 0 && candidate > mark) || (difference < 0 && candidate < mark);
118
    };
60
    };
119
61
Lines 124-188 static Optional<unsigned> findFirstSnapStopOffsetBetweenOriginAndDestination(con a/Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.cpp_sec3
124
        if (snapOffsets[i].stop != ScrollSnapStop::Always)
66
        if (snapOffsets[i].stop != ScrollSnapStop::Always)
125
            continue;
67
            continue;
126
        if (isPast(scrollOriginOffset, offset))
68
        if (isPast(scrollOriginOffset, offset))
127
            return i;
69
            return std::make_pair(offset, static_cast<unsigned>(i));
128
    }
70
    }
129
71
130
    return WTF::nullopt;
72
    return WTF::nullopt;
131
}
73
}
132
74
133
template <typename LayoutType>
134
static std::pair<LayoutType, unsigned> closestSnapOffsetWithOffsetsAndRanges(const Vector<SnapOffset<LayoutType>>& snapOffsets, const Vector<ScrollOffsetRange<LayoutType>>& snapOffsetRanges, LayoutType scrollDestinationOffset, float velocity, Optional<LayoutType> originalOffsetForDirectionalSnapping)
135
{
136
    if (snapOffsets.isEmpty())
137
        return std::make_pair(scrollDestinationOffset, invalidSnapOffsetIndex);
138
139
    if (originalOffsetForDirectionalSnapping.hasValue()) {
140
        auto firstSnapStopOffsetIndex = findFirstSnapStopOffsetBetweenOriginAndDestination(snapOffsets, *originalOffsetForDirectionalSnapping, scrollDestinationOffset);
141
        if (firstSnapStopOffsetIndex.hasValue())
142
            return std::make_pair(snapOffsets[*firstSnapStopOffsetIndex].offset, *firstSnapStopOffsetIndex);
143
    }
144
145
    unsigned lowerSnapOffsetRangeIndex;
146
    unsigned upperSnapOffsetRangeIndex;
147
    indicesOfNearestSnapOffsetRanges<LayoutType>(scrollDestinationOffset, snapOffsetRanges, lowerSnapOffsetRangeIndex, upperSnapOffsetRangeIndex);
148
    if (lowerSnapOffsetRangeIndex == upperSnapOffsetRangeIndex && upperSnapOffsetRangeIndex != invalidSnapOffsetIndex)
149
        return std::make_pair(scrollDestinationOffset, invalidSnapOffsetIndex);
150
151
    if (scrollDestinationOffset <= snapOffsets.first().offset)
152
        return std::make_pair(snapOffsets.first().offset, 0u);
153
154
    if (scrollDestinationOffset >= snapOffsets.last().offset)
155
        return std::make_pair(snapOffsets.last().offset, snapOffsets.size() - 1);
156
157
    unsigned lowerIndex;
158
    unsigned upperIndex;
159
    indicesOfNearestSnapOffsets<LayoutType>(scrollDestinationOffset, snapOffsets, lowerIndex, upperIndex);
160
    LayoutType lowerSnapPosition = snapOffsets[lowerIndex].offset;
161
    LayoutType upperSnapPosition = snapOffsets[upperIndex].offset;
162
    if (!std::abs(velocity)) {
163
        bool isCloserToLowerSnapPosition = scrollDestinationOffset - lowerSnapPosition <= upperSnapPosition - scrollDestinationOffset;
164
        return isCloserToLowerSnapPosition ? std::make_pair(lowerSnapPosition, lowerIndex) : std::make_pair(upperSnapPosition, upperIndex);
165
    }
166
167
    // Non-zero velocity indicates a flick gesture. Even if another snap point is closer, we should choose the one in the direction of the flick gesture
168
    // as long as a scroll snap offset range does not lie between the scroll destination and the targeted snap offset. If we are doing directional
169
    // snapping, we should never snap to a point that was on the other side of the original position in the opposite direction of this scroll.
170
    // This allows directional scrolling to escape snap points.
171
    if (velocity < 0) {
172
        if (lowerSnapOffsetRangeIndex == invalidSnapOffsetIndex || lowerSnapPosition >= snapOffsetRanges[lowerSnapOffsetRangeIndex].end)
173
            return std::make_pair(lowerSnapPosition, lowerIndex);
174
        if (!originalOffsetForDirectionalSnapping.hasValue() || *originalOffsetForDirectionalSnapping > upperSnapPosition)
175
            return std::make_pair(upperSnapPosition, upperIndex);
176
    } else {
177
        if (upperSnapOffsetRangeIndex == invalidSnapOffsetIndex || snapOffsetRanges[upperSnapOffsetRangeIndex].start >= upperSnapPosition)
178
            return std::make_pair(upperSnapPosition, upperIndex);
179
        if (!originalOffsetForDirectionalSnapping.hasValue() || *originalOffsetForDirectionalSnapping < lowerSnapPosition)
180
            return std::make_pair(lowerSnapPosition, lowerIndex);
181
    }
182
183
    return std::make_pair(scrollDestinationOffset, invalidSnapOffsetIndex);
184
}
185
186
enum class InsetOrOutset {
75
enum class InsetOrOutset {
187
    Inset,
76
    Inset,
188
    Outset
77
    Outset
Lines 219-248 static LayoutUnit computeScrollSnapAlignOffset(LayoutUnit minLocation, LayoutUni a/Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.cpp_sec4
219
    }
108
    }
220
}
109
}
221
110
222
static void computeAxisProximitySnapOffsetRanges(const Vector<SnapOffset<LayoutUnit>>& snapOffsets, Vector<ScrollOffsetRange<LayoutUnit>>& offsetRanges, LayoutUnit scrollPortAxisLength)
223
{
224
    // This is an arbitrary choice for what it means to be "in proximity" of a snap offset. We should play around with
225
    // this and see what feels best.
226
    static const float ratioOfScrollPortAxisLengthToBeConsideredForProximity = 0.3;
227
    if (snapOffsets.size() < 2)
228
        return;
229
230
    // The extra rule accounting for scroll offset ranges in between the scroll destination and a potential snap offset
231
    // handles the corner case where the user scrolls with momentum very lightly away from a snap offset, such that the
232
    // predicted scroll destination is still within proximity of the snap offset. In this case, the regular (mandatory
233
    // scroll snapping) behavior would be to snap to the next offset in the direction of momentum scrolling, but
234
    // instead, it is more intuitive to either return to the original snap position (which we arbitrarily choose here)
235
    // or scroll just outside of the snap offset range. This is another minor behavior tweak that we should play around
236
    // with to see what feels best.
237
    LayoutUnit proximityDistance { ratioOfScrollPortAxisLengthToBeConsideredForProximity * scrollPortAxisLength };
238
    for (size_t index = 1; index < snapOffsets.size(); ++index) {
239
        auto startOffset = snapOffsets[index - 1].offset + proximityDistance;
240
        auto endOffset = snapOffsets[index].offset - proximityDistance;
241
        if (startOffset < endOffset)
242
            offsetRanges.append({ startOffset, endOffset });
243
    }
244
}
245
246
void updateSnapOffsetsForScrollableArea(ScrollableArea& scrollableArea, const RenderBox& scrollingElementBox, const RenderStyle& scrollingElementStyle, LayoutRect viewportRectInBorderBoxCoordinates)
111
void updateSnapOffsetsForScrollableArea(ScrollableArea& scrollableArea, const RenderBox& scrollingElementBox, const RenderStyle& scrollingElementStyle, LayoutRect viewportRectInBorderBoxCoordinates)
247
{
112
{
248
    auto scrollSnapType = scrollingElementStyle.scrollSnapType();
113
    auto scrollSnapType = scrollingElementStyle.scrollSnapType();
Lines 262-267 void updateSnapOffsetsForScrollableArea(ScrollableArea& scrollableArea, const Re a/Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.cpp_sec5
262
127
263
    HashMap<float, SnapOffset<LayoutUnit>> verticalSnapOffsetsMap;
128
    HashMap<float, SnapOffset<LayoutUnit>> verticalSnapOffsetsMap;
264
    HashMap<float, SnapOffset<LayoutUnit>> horizontalSnapOffsetsMap;
129
    HashMap<float, SnapOffset<LayoutUnit>> horizontalSnapOffsetsMap;
130
    Vector<LayoutRect> snapAreas;
265
    bool hasHorizontalSnapOffsets = scrollSnapType.axis == ScrollSnapAxis::Both || scrollSnapType.axis == ScrollSnapAxis::XAxis || scrollSnapType.axis == ScrollSnapAxis::Inline;
131
    bool hasHorizontalSnapOffsets = scrollSnapType.axis == ScrollSnapAxis::Both || scrollSnapType.axis == ScrollSnapAxis::XAxis || scrollSnapType.axis == ScrollSnapAxis::Inline;
266
    bool hasVerticalSnapOffsets = scrollSnapType.axis == ScrollSnapAxis::Both || scrollSnapType.axis == ScrollSnapAxis::YAxis || scrollSnapType.axis == ScrollSnapAxis::Block;
132
    bool hasVerticalSnapOffsets = scrollSnapType.axis == ScrollSnapAxis::Both || scrollSnapType.axis == ScrollSnapAxis::YAxis || scrollSnapType.axis == ScrollSnapAxis::Block;
267
133
Lines 288-304 void updateSnapOffsetsForScrollableArea(ScrollableArea& scrollableArea, const Re a/Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.cpp_sec6
288
154
289
        scrollSnapArea = computeScrollSnapPortOrAreaRect(scrollSnapArea, child->style().scrollMargin(), InsetOrOutset::Outset);
155
        scrollSnapArea = computeScrollSnapPortOrAreaRect(scrollSnapArea, child->style().scrollMargin(), InsetOrOutset::Outset);
290
        LOG_WITH_STREAM(ScrollSnap, stream << "    Considering scroll snap target area " << scrollSnapArea);
156
        LOG_WITH_STREAM(ScrollSnap, stream << "    Considering scroll snap target area " << scrollSnapArea);
157
291
        auto alignment = child->style().scrollSnapAlign();
158
        auto alignment = child->style().scrollSnapAlign();
159
        bool snapsHorizontally = hasHorizontalSnapOffsets && alignment.x != ScrollSnapAxisAlignType::None;
160
        bool snapsVertically = hasVerticalSnapOffsets && alignment.y != ScrollSnapAxisAlignType::None;
161
        if (!snapsHorizontally && !snapsVertically)
162
            continue;
163
164
        // The scroll snap area is defined via its scroll position, so convert everything to scroll offetss here.
165
        auto snapAreaOriginRelativeToBorderEdge = scrollSnapArea.location() - scrollSnapPort.location();
166
        LayoutRect scrollSnapAreaAsOffsets(scrollableArea.scrollOffsetFromPosition(roundedIntPoint(snapAreaOriginRelativeToBorderEdge)), scrollSnapArea.size());
167
        snapAreas.append(scrollSnapAreaAsOffsets);
168
        unsigned snapAreaIndex = snapAreas.size() - 1;
169
292
        auto stop = child->style().scrollSnapStop();
170
        auto stop = child->style().scrollSnapStop();
293
        if (hasHorizontalSnapOffsets && alignment.x != ScrollSnapAxisAlignType::None) {
171
        if (snapsHorizontally) {
294
            auto absoluteScrollXPosition = computeScrollSnapAlignOffset(scrollSnapArea.x(), scrollSnapArea.maxX(), alignment.x, scrollerIsRTL) - computeScrollSnapAlignOffset(scrollSnapPort.x(), scrollSnapPort.maxX(), alignment.x, scrollerIsRTL);
172
            auto absoluteScrollXPosition = computeScrollSnapAlignOffset(scrollSnapArea.x(), scrollSnapArea.maxX(), alignment.x, scrollerIsRTL) - computeScrollSnapAlignOffset(scrollSnapPort.x(), scrollSnapPort.maxX(), alignment.x, scrollerIsRTL);
295
            auto absoluteScrollOffset = clampTo<int>(scrollableArea.scrollOffsetFromPosition({ roundToInt(absoluteScrollXPosition), 0 }).x(), 0, maxScrollOffset.x());
173
            auto absoluteScrollOffset = clampTo<int>(scrollableArea.scrollOffsetFromPosition({ roundToInt(absoluteScrollXPosition), 0 }).x(), 0, maxScrollOffset.x());
296
            addOrUpdateStopForSnapOffset(horizontalSnapOffsetsMap, { absoluteScrollOffset, stop });
174
            addOrUpdateStopForSnapOffset(horizontalSnapOffsetsMap, { absoluteScrollOffset, stop, snapAreaIndex });
297
        }
175
        }
298
        if (hasVerticalSnapOffsets && alignment.y != ScrollSnapAxisAlignType::None) {
176
        if (snapsVertically) {
299
            auto absoluteScrollYPosition = computeScrollSnapAlignOffset(scrollSnapArea.y(), scrollSnapArea.maxY(), alignment.y, false) - computeScrollSnapAlignOffset(scrollSnapPort.y(), scrollSnapPort.maxY(), alignment.y, false);
177
            auto absoluteScrollYPosition = computeScrollSnapAlignOffset(scrollSnapArea.y(), scrollSnapArea.maxY(), alignment.y, false) - computeScrollSnapAlignOffset(scrollSnapPort.y(), scrollSnapPort.maxY(), alignment.y, false);
300
            auto absoluteScrollOffset = clampTo<int>(scrollableArea.scrollOffsetFromPosition({ 0, roundToInt(absoluteScrollYPosition) }).y(), 0, maxScrollOffset.y());
178
            auto absoluteScrollOffset = clampTo<int>(scrollableArea.scrollOffsetFromPosition({ 0, roundToInt(absoluteScrollYPosition) }).y(), 0, maxScrollOffset.y());
301
            addOrUpdateStopForSnapOffset(verticalSnapOffsetsMap, { absoluteScrollOffset, stop });
179
            addOrUpdateStopForSnapOffset(verticalSnapOffsetsMap, { absoluteScrollOffset, stop, snapAreaIndex });
302
        }
180
        }
303
    }
181
    }
304
182
Lines 308-339 void updateSnapOffsetsForScrollableArea(ScrollableArea& scrollableArea, const Re a/Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.cpp_sec7
308
    };
186
    };
309
187
310
    Vector<SnapOffset<LayoutUnit>> horizontalSnapOffsets = copyToVector(horizontalSnapOffsetsMap.values());
188
    Vector<SnapOffset<LayoutUnit>> horizontalSnapOffsets = copyToVector(horizontalSnapOffsetsMap.values());
311
    Vector<ScrollOffsetRange<LayoutUnit>> horizontalSnapOffsetRanges;
312
    if (!horizontalSnapOffsets.isEmpty()) {
189
    if (!horizontalSnapOffsets.isEmpty()) {
313
        std::sort(horizontalSnapOffsets.begin(), horizontalSnapOffsets.end(), compareSnapOffsets);
190
        std::sort(horizontalSnapOffsets.begin(), horizontalSnapOffsets.end(), compareSnapOffsets);
314
        if (scrollSnapType.strictness == ScrollSnapStrictness::Proximity)
315
            computeAxisProximitySnapOffsetRanges(horizontalSnapOffsets, horizontalSnapOffsetRanges, scrollSnapPort.width());
316
317
        LOG_WITH_STREAM(ScrollSnap, stream << " => Computed horizontal scroll snap offsets: " << horizontalSnapOffsets);
191
        LOG_WITH_STREAM(ScrollSnap, stream << " => Computed horizontal scroll snap offsets: " << horizontalSnapOffsets);
318
        LOG_WITH_STREAM(ScrollSnap, stream << " => Computed horizontal scroll snap offset ranges: " << horizontalSnapOffsetRanges);
319
    }
192
    }
320
193
321
    Vector<SnapOffset<LayoutUnit>> verticalSnapOffsets = copyToVector(verticalSnapOffsetsMap.values());
194
    Vector<SnapOffset<LayoutUnit>> verticalSnapOffsets = copyToVector(verticalSnapOffsetsMap.values());
322
    Vector<ScrollOffsetRange<LayoutUnit>> verticalSnapOffsetRanges;
323
    if (!verticalSnapOffsets.isEmpty()) {
195
    if (!verticalSnapOffsets.isEmpty()) {
324
        std::sort(verticalSnapOffsets.begin(), verticalSnapOffsets.end(), compareSnapOffsets);
196
        std::sort(verticalSnapOffsets.begin(), verticalSnapOffsets.end(), compareSnapOffsets);
325
        if (scrollSnapType.strictness == ScrollSnapStrictness::Proximity)
326
            computeAxisProximitySnapOffsetRanges(verticalSnapOffsets, verticalSnapOffsetRanges, scrollSnapPort.height());
327
328
        LOG_WITH_STREAM(ScrollSnap, stream << " => Computed vertical scroll snap offsets: " << verticalSnapOffsets);
197
        LOG_WITH_STREAM(ScrollSnap, stream << " => Computed vertical scroll snap offsets: " << verticalSnapOffsets);
329
        LOG_WITH_STREAM(ScrollSnap, stream << " => Computed vertical scroll snap offset ranges: " << verticalSnapOffsetRanges);
330
    }
198
    }
331
199
200
    if (!snapAreas.isEmpty())
201
        LOG_WITH_STREAM(ScrollSnap, stream << " => Computed snap areas: " << snapAreas);
202
332
    scrollableArea.setScrollSnapOffsetInfo({
203
    scrollableArea.setScrollSnapOffsetInfo({
204
        scrollSnapType.strictness,
333
        horizontalSnapOffsets,
205
        horizontalSnapOffsets,
334
        verticalSnapOffsets,
206
        verticalSnapOffsets,
335
        horizontalSnapOffsetRanges,
207
        snapAreas,
336
        verticalSnapOffsetRanges
337
    });
208
    });
338
}
209
}
339
210
Lines 347-403 static LayoutUnit convertOffsetUnit(float input, float /* scaleFactor */) a/Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.cpp_sec8
347
    return LayoutUnit(input);
218
    return LayoutUnit(input);
348
}
219
}
349
220
350
template <typename InputType, typename OutputType>
221
template <typename InputType, typename InputRectType, typename OutputType, typename OutputRectType>
351
static ScrollSnapOffsetsInfo<OutputType> convertOffsetInfo(const ScrollSnapOffsetsInfo<InputType>& input, float scaleFactor = 0.0)
222
static ScrollSnapOffsetsInfo<OutputType, OutputRectType> convertOffsetInfo(const ScrollSnapOffsetsInfo<InputType, InputRectType>& input, float scaleFactor = 0.0)
352
{
223
{
353
    auto convertOffsets = [scaleFactor](const Vector<SnapOffset<InputType>>& input)
224
    auto convertOffsets = [scaleFactor](const Vector<SnapOffset<InputType>>& input)
354
    {
225
    {
355
        Vector<SnapOffset<OutputType>> output;
226
        Vector<SnapOffset<OutputType>> output;
356
        output.reserveInitialCapacity(input.size());
227
        output.reserveInitialCapacity(input.size());
357
        for (auto& offset : input)
228
        for (auto& offset : input)
358
            output.uncheckedAppend({ convertOffsetUnit(offset.offset, scaleFactor), offset.stop });
229
            output.uncheckedAppend({ convertOffsetUnit(offset.offset, scaleFactor), offset.stop, offset.snapAreaIndex });
359
        return output;
230
        return output;
360
    };
231
    };
361
232
362
    auto convertOffsetRanges = [scaleFactor](const Vector<ScrollOffsetRange<InputType>>& input)
233
    auto convertRects = [scaleFactor](const Vector<InputRectType>& input)
363
    {
234
    {
364
        Vector<ScrollOffsetRange<OutputType>> output;
235
        Vector<OutputRectType> output;
365
        output.reserveInitialCapacity(input.size());
236
        output.reserveInitialCapacity(input.size());
366
        for (auto& range : input)
237
        for (auto& rect : input) {
367
            output.uncheckedAppend({ convertOffsetUnit(range.start, scaleFactor), convertOffsetUnit(range.end, scaleFactor) });
238
            OutputRectType outputRect(
239
                convertOffsetUnit(rect.x(), scaleFactor), convertOffsetUnit(rect.y(), scaleFactor),
240
                convertOffsetUnit(rect.width(), scaleFactor), convertOffsetUnit(rect.height(), scaleFactor));
241
            output.uncheckedAppend(outputRect);
242
        }
368
        return output;
243
        return output;
369
    };
244
    };
370
245
371
    return {
246
    return {
247
        input.strictness,
372
        convertOffsets(input.horizontalSnapOffsets),
248
        convertOffsets(input.horizontalSnapOffsets),
373
        convertOffsets(input.verticalSnapOffsets),
249
        convertOffsets(input.verticalSnapOffsets),
374
        convertOffsetRanges(input.horizontalSnapOffsetRanges),
250
        convertRects(input.snapAreas),
375
        convertOffsetRanges(input.verticalSnapOffsetRanges)
376
    };
251
    };
377
}
252
}
378
253
379
template <> template <>
254
template <> template <>
380
ScrollSnapOffsetsInfo<LayoutUnit> ScrollSnapOffsetsInfo<float>::convertUnits(float /* unusedScaleFactor */) const
255
LayoutScrollSnapOffsetsInfo FloatScrollSnapOffsetsInfo::convertUnits(float /* unusedScaleFactor */) const
381
{
256
{
382
    return convertOffsetInfo<float, LayoutUnit>(*this);
257
    return convertOffsetInfo<float, FloatRect, LayoutUnit, LayoutRect>(*this);
383
}
258
}
384
259
385
template <> template <>
260
template <> template <>
386
ScrollSnapOffsetsInfo<float> ScrollSnapOffsetsInfo<LayoutUnit>::convertUnits(float deviceScaleFactor) const
261
FloatScrollSnapOffsetsInfo LayoutScrollSnapOffsetsInfo::convertUnits(float deviceScaleFactor) const
387
{
262
{
388
    return convertOffsetInfo<LayoutUnit, float>(*this, deviceScaleFactor);
263
    return convertOffsetInfo<LayoutUnit, LayoutRect, float, FloatRect>(*this, deviceScaleFactor);
389
}
264
}
390
265
391
template <>
266
template <typename UnitType, typename RectType>
392
std::pair<LayoutUnit, unsigned> ScrollSnapOffsetsInfo<LayoutUnit>::closestSnapOffset(ScrollEventAxis axis, LayoutUnit scrollDestinationOffset, float velocity, Optional<LayoutUnit> originalPositionForDirectionalSnapping) const
267
static UnitType maxForAxis(RectType rect, ScrollEventAxis axis)
393
{
268
{
394
    return closestSnapOffsetWithOffsetsAndRanges(offsetsForAxis(axis), offsetRangesForAxis(axis), scrollDestinationOffset, velocity, originalPositionForDirectionalSnapping);
269
    return axis == ScrollEventAxis::Horizontal ? rect.maxX() : rect.maxY();
395
}
270
}
396
271
397
template <>
272
template <typename UnitType, typename RectType>
398
std::pair<float, unsigned> ScrollSnapOffsetsInfo<float>::closestSnapOffset(ScrollEventAxis axis, float scrollDestinationOffset, float velocity, Optional<float> originalPositionForDirectionalSnapping) const
273
static UnitType minForAxis(RectType rect, ScrollEventAxis axis)
274
{
275
    return axis == ScrollEventAxis::Horizontal ? rect.x() : rect.y();
276
}
277
278
template <typename UnitType>
279
static bool isNearEnoughToOffsetForProximity(ScrollSnapStrictness strictness, UnitType scrollDestination, UnitType candidateSnapOffset, UnitType viewportLength)
280
{
281
    if (strictness != ScrollSnapStrictness::Proximity)
282
        return true;
283
284
    // This is an arbitrary choice for what it means to be "in proximity" of a snap offset. We should play around with
285
    // this and see what feels best.
286
    static const float ratioOfScrollPortAxisLengthToBeConsideredForProximity = 0.3;
287
    return std::abs(float {candidateSnapOffset - scrollDestination}) <= (viewportLength * ratioOfScrollPortAxisLengthToBeConsideredForProximity);
288
}
289
290
template <typename UnitType, typename RectType, typename SizeType>
291
static std::pair<UnitType, unsigned> calculateClosestSnapOffset(const ScrollSnapOffsetsInfo<UnitType, RectType>& info, ScrollEventAxis axis, const SizeType& viewportSize, UnitType scrollDestinationOffset, float velocity, Optional<UnitType> originalOffset)
292
{
293
    const auto& snapOffsets = info.offsetsForAxis(axis);
294
    auto pairForNoSnapping = std::make_pair(scrollDestinationOffset, invalidSnapOffsetIndex);
295
    if (snapOffsets.isEmpty())
296
        return pairForNoSnapping;
297
298
    // The first snap point with `scroll-snap-stop: always` between the original position and destination takes precedence.
299
    if (originalOffset) {
300
        if (auto firstSnapStopOffset = findFirstSnapStopOffsetBetweenOriginAndDestination(snapOffsets, *originalOffset, scrollDestinationOffset))
301
            return *firstSnapStopOffset;
302
    }
303
304
    auto viewportLength = axis == ScrollEventAxis::Horizontal ? viewportSize.width() : viewportSize.height();
305
    bool landedInsideSnapAreaThatConsumesViewport = false;
306
    Optional<std::pair<UnitType, unsigned>> previous, next;
307
    Optional<RectType> previousSnapArea, nextSnapArea;
308
    for (unsigned i = 0; i < snapOffsets.size(); i++) {
309
        const auto& snapArea = info.snapAreas[snapOffsets[i].snapAreaIndex];
310
        landedInsideSnapAreaThatConsumesViewport |= (minForAxis<UnitType>(snapArea, axis) <= scrollDestinationOffset && maxForAxis<UnitType>(snapArea, axis) >= (scrollDestinationOffset + viewportLength));
311
        // If the scroll landed exactly on a snap offset, choose that one.
312
        UnitType potentialSnapOffset = snapOffsets[i].offset;
313
        if (potentialSnapOffset == scrollDestinationOffset)
314
            return std::make_pair(potentialSnapOffset, i);
315
316
        if (potentialSnapOffset < scrollDestinationOffset) {
317
            previous = std::make_pair(potentialSnapOffset, i);
318
            previousSnapArea = snapArea;
319
        } else if (!next && potentialSnapOffset > scrollDestinationOffset) {
320
            next = std::make_pair(potentialSnapOffset, i);
321
            nextSnapArea = snapArea;
322
        }
323
    }
324
325
    // From https://www.w3.org/TR/css-scroll-snap-1/#snap-overflow
326
    // "If the snap area is larger than the snapport in a particular axis, then any scroll position
327
    // in which the snap area covers the snapport, and the distance between the geometrically
328
    // previous and subsequent snap positions in that axis is larger than size of the snapport in
329
    // that axis, is a valid snap position in that axis. The UA may use the specified alignment as a
330
    // more precise target for certain scroll operations (e.g. explicit paging)."
331
    if (landedInsideSnapAreaThatConsumesViewport && (!previous || !next || ((*next).first - (*previous).first) >= viewportLength))
332
        return pairForNoSnapping;
333
334
    if (originalOffset) {
335
        // If this is a directional scroll and there are no scroll stops in a particular direction,
336
        // don't scroll past the edge of the scroll area.
337
        if (!next && previous)
338
            return std::make_pair(std::max((*previous).first, maxForAxis<UnitType>(*previousSnapArea, axis) - viewportLength), invalidSnapOffsetIndex);
339
        if (!previous && next)
340
            return std::make_pair(minForAxis<UnitType>(*nextSnapArea, axis), invalidSnapOffsetIndex);
341
342
        // From https://www.w3.org/TR/css-scroll-snap-1/#choosing
343
        // "User agents must ensure that a user can “escape” a snap position, regardless of the scroll
344
        // method. For example, if the snap type is mandatory and the next snap position is more than
345
        // two screen-widths away, a naïve “always snap to nearest” selection algorithm might “trap” the
346
        // user if their end position was only one screen-width away. Instead, a smarter algorithm that
347
        // only returned to the starting snap position if the end-point was a fairly small distance from
348
        // it, and otherwise ignored the starting snap position, would give better behavior."
349
        // We only do this if we are in a situation where we are choosing between two compatible
350
        // snap offsets.
351
        if (*originalOffset < scrollDestinationOffset && (*previous).first <= *originalOffset)
352
            previous.reset();
353
        if (*originalOffset > scrollDestinationOffset && (*next).first >= *originalOffset)
354
            next.reset();
355
    }
356
357
    if (next && !isNearEnoughToOffsetForProximity(info.strictness, scrollDestinationOffset, (*next).first, viewportLength))
358
        next.reset();
359
    if (previous && !isNearEnoughToOffsetForProximity(info.strictness, scrollDestinationOffset, (*previous).first, viewportLength))
360
        previous.reset();
361
362
    // If we don't have compatible offsets to choose between, just do the obvious thing
363
    // and do no snapping or only select the single compatible offset.
364
    if (!previous && !next)
365
        return pairForNoSnapping;
366
    if (!previous)
367
        return *next;
368
    if (!next)
369
        return *previous;
370
371
    // If this scroll isn't directional, then choose whatever snap point is closer.
372
    UnitType previousSnapOffset = (*previous).first;
373
    UnitType nextSnapOffset = (*next).first;
374
    if (!std::abs(velocity)) {
375
        bool isCloserToPreviousSnapIndex = scrollDestinationOffset - previousSnapOffset <= nextSnapOffset - scrollDestinationOffset;
376
        return isCloserToPreviousSnapIndex ? *previous : *next;
377
    }
378
379
    // Finally, if we have a directional scroll prefer the snap point that is in the scroll direction.
380
    return velocity < 0 ? *previous : *next;
381
}
382
383
384
template <> template <>
385
std::pair<LayoutUnit, unsigned> LayoutScrollSnapOffsetsInfo::closestSnapOffset(ScrollEventAxis axis, const LayoutSize& viewportSize, LayoutUnit scrollDestinationOffset, float velocity, Optional<LayoutUnit> originalOffsetForDirectionalSnapping) const
386
{
387
    return calculateClosestSnapOffset<LayoutUnit, LayoutRect, LayoutSize>(*this, axis, viewportSize, scrollDestinationOffset, velocity, originalOffsetForDirectionalSnapping);
388
}
389
390
template <> template <>
391
std::pair<float, unsigned> FloatScrollSnapOffsetsInfo::closestSnapOffset(ScrollEventAxis axis, const FloatSize& viewportSize, float scrollDestinationOffset, float velocity, Optional<float> originalOffsetForDirectionalSnapping) const
399
{
392
{
400
    return closestSnapOffsetWithOffsetsAndRanges(offsetsForAxis(axis), offsetRangesForAxis(axis), scrollDestinationOffset, velocity, originalPositionForDirectionalSnapping);
393
    return calculateClosestSnapOffset<float, FloatRect, FloatSize>(*this, axis, viewportSize, scrollDestinationOffset, velocity, originalOffsetForDirectionalSnapping);
401
}
394
}
402
395
403
}
396
}
- a/Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.h -42 / +27 lines
Lines 27-32 a/Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.h_sec1
27
27
28
#if ENABLE(CSS_SCROLL_SNAP)
28
#if ENABLE(CSS_SCROLL_SNAP)
29
29
30
#include "FloatRect.h"
31
#include "FloatSize.h"
32
#include "LayoutRect.h"
33
#include "LayoutSize.h"
30
#include "LayoutUnit.h"
34
#include "LayoutUnit.h"
31
#include "ScrollTypes.h"
35
#include "ScrollTypes.h"
32
#include "StyleScrollSnapPoints.h"
36
#include "StyleScrollSnapPoints.h"
Lines 35-73 a/Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.h_sec2
35
39
36
namespace WebCore {
40
namespace WebCore {
37
41
38
class LayoutRect;
39
class ScrollableArea;
42
class ScrollableArea;
40
class RenderBox;
43
class RenderBox;
41
class RenderStyle;
44
class RenderStyle;
42
45
43
template <typename T>
46
template <typename OffsetType>
44
struct SnapOffset {
47
struct SnapOffset {
45
    T offset;
48
    OffsetType offset;
46
    ScrollSnapStop stop;
49
    ScrollSnapStop stop;
50
    unsigned snapAreaIndex;
47
};
51
};
48
52
49
template <typename T>
53
template <typename OffsetType, typename RectType>
50
struct ScrollOffsetRange {
51
    T start;
52
    T end;
53
};
54
55
template <typename T>
56
struct ScrollSnapOffsetsInfo {
54
struct ScrollSnapOffsetsInfo {
57
    WTF_MAKE_STRUCT_FAST_ALLOCATED;
55
    WTF_MAKE_STRUCT_FAST_ALLOCATED;
58
    Vector<SnapOffset<T>> horizontalSnapOffsets;
56
    ScrollSnapStrictness strictness;
59
    Vector<SnapOffset<T>> verticalSnapOffsets;
60
57
61
    // Snap offset ranges represent non-empty ranges of scroll offsets in which scrolling may rest after scroll snapping.
58
    Vector<SnapOffset<OffsetType>> horizontalSnapOffsets;
62
    // These are used in two cases: (1) for proximity scroll snapping, where portions of areas between adjacent snap offsets
59
    Vector<SnapOffset<OffsetType>> verticalSnapOffsets;
63
    // may emit snap offset ranges, and (2) in the case where the snap area is larger than the snap port, in which case areas
60
    Vector<RectType> snapAreas;
64
    // where the snap port fits within the snap area are considered to be valid snap positions.
65
    Vector<ScrollOffsetRange<T>> horizontalSnapOffsetRanges;
66
    Vector<ScrollOffsetRange<T>> verticalSnapOffsetRanges;
67
61
68
    bool isEqual(const ScrollSnapOffsetsInfo<T>& other) const
62
    bool isEqual(const ScrollSnapOffsetsInfo<OffsetType, RectType>& other) const
69
    {
63
    {
70
        return horizontalSnapOffsets == other.horizontalSnapOffsets && verticalSnapOffsets == other.verticalSnapOffsets && horizontalSnapOffsetRanges == other.horizontalSnapOffsetRanges && verticalSnapOffsetRanges == other.verticalSnapOffsetRanges;
64
        return strictness == other.strictness && horizontalSnapOffsets == other.horizontalSnapOffsets && verticalSnapOffsets == other.verticalSnapOffsets && snapAreas == other.snapAreas;
71
    }
65
    }
72
66
73
    bool isEmpty() const
67
    bool isEmpty() const
Lines 75-103 struct ScrollSnapOffsetsInfo { a/Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.h_sec3
75
        return horizontalSnapOffsets.isEmpty() && verticalSnapOffsets.isEmpty();
69
        return horizontalSnapOffsets.isEmpty() && verticalSnapOffsets.isEmpty();
76
    }
70
    }
77
71
78
    Vector<SnapOffset<T>> offsetsForAxis(ScrollEventAxis axis) const
72
    Vector<SnapOffset<OffsetType>> offsetsForAxis(ScrollEventAxis axis) const
79
    {
73
    {
80
        return axis == ScrollEventAxis::Vertical ? verticalSnapOffsets : horizontalSnapOffsets;
74
        return axis == ScrollEventAxis::Vertical ? verticalSnapOffsets : horizontalSnapOffsets;
81
    }
75
    }
82
76
83
    Vector<ScrollOffsetRange<T>> offsetRangesForAxis(ScrollEventAxis axis) const
77
    template<typename OutputType, typename OutputRectType> ScrollSnapOffsetsInfo<OutputType, OutputRectType> convertUnits(float deviceScaleFactor = 0.0) const;
84
    {
78
    template<typename SizeType> WEBCORE_EXPORT std::pair<OffsetType, unsigned> closestSnapOffset(ScrollEventAxis, const SizeType& viewportSize, OffsetType scrollDestinationOffset, float velocity, Optional<OffsetType> originalPositionForDirectionalSnapping = WTF::nullopt) const;
85
        return axis == ScrollEventAxis::Vertical ? verticalSnapOffsetRanges : horizontalSnapOffsetRanges;
86
    }
87
88
    template<typename OutputType> ScrollSnapOffsetsInfo<OutputType> convertUnits(float deviceScaleFactor = 0.0) const;
89
    WEBCORE_EXPORT std::pair<T, unsigned> closestSnapOffset(ScrollEventAxis, T scrollDestinationOffset, float velocity, Optional<T> originalPositionForDirectionalSnapping = WTF::nullopt) const;
90
};
79
};
91
80
81
using LayoutScrollSnapOffsetsInfo = ScrollSnapOffsetsInfo<LayoutUnit, LayoutRect>;
82
using FloatScrollSnapOffsetsInfo = ScrollSnapOffsetsInfo<float, FloatRect>;
83
92
template <> template <>
84
template <> template <>
93
ScrollSnapOffsetsInfo<LayoutUnit> ScrollSnapOffsetsInfo<float>::convertUnits(float /* unusedScaleFactor */) const;
85
LayoutScrollSnapOffsetsInfo FloatScrollSnapOffsetsInfo::convertUnits(float /* unusedScaleFactor */) const;
94
template <>
86
template <> template <>
95
WEBCORE_EXPORT std::pair<float, unsigned> ScrollSnapOffsetsInfo<float>::closestSnapOffset(ScrollEventAxis, float scrollDestinationOffset, float velocity, Optional<float> originalPositionForDirectionalSnapping) const;
87
WEBCORE_EXPORT std::pair<float, unsigned> FloatScrollSnapOffsetsInfo::closestSnapOffset(ScrollEventAxis, const FloatSize& viewportSize, float scrollDestinationOffset, float velocity, Optional<float> originalPositionForDirectionalSnapping) const;
96
88
97
template <> template <>
89
template <> template <>
98
ScrollSnapOffsetsInfo<float> ScrollSnapOffsetsInfo<LayoutUnit>::convertUnits(float deviceScaleFactor) const;
90
FloatScrollSnapOffsetsInfo LayoutScrollSnapOffsetsInfo::convertUnits(float deviceScaleFactor) const;
99
template <>
91
template <> template <>
100
WEBCORE_EXPORT std::pair<LayoutUnit, unsigned> ScrollSnapOffsetsInfo<LayoutUnit>::closestSnapOffset(ScrollEventAxis, LayoutUnit scrollDestinationOffset, float velocity, Optional<LayoutUnit> originalPositionForDirectionalSnapping) const;
92
WEBCORE_EXPORT std::pair<LayoutUnit, unsigned> LayoutScrollSnapOffsetsInfo::closestSnapOffset(ScrollEventAxis, const LayoutSize& viewportSize, LayoutUnit scrollDestinationOffset, float velocity, Optional<LayoutUnit> originalPositionForDirectionalSnapping) const;
101
93
102
const unsigned invalidSnapOffsetIndex = UINT_MAX;
94
const unsigned invalidSnapOffsetIndex = UINT_MAX;
103
95
Lines 106-112 const unsigned invalidSnapOffsetIndex = UINT_MAX; a/Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.h_sec4
106
// the scrolling container's border box.
98
// the scrolling container's border box.
107
void updateSnapOffsetsForScrollableArea(ScrollableArea&, const RenderBox& scrollingElementBox, const RenderStyle& scrollingElementStyle, LayoutRect viewportRectInBorderBoxCoordinates);
99
void updateSnapOffsetsForScrollableArea(ScrollableArea&, const RenderBox& scrollingElementBox, const RenderStyle& scrollingElementStyle, LayoutRect viewportRectInBorderBoxCoordinates);
108
100
109
template <typename T> WTF::TextStream& operator<<(WTF::TextStream& ts, SnapOffset<T> offset)
101
template <typename OffsetType> WTF::TextStream& operator<<(WTF::TextStream& ts, SnapOffset<OffsetType> offset)
110
{
102
{
111
    ts << offset.offset;
103
    ts << offset.offset;
112
    if (offset.stop == ScrollSnapStop::Always)
104
    if (offset.stop == ScrollSnapStop::Always)
Lines 114-126 template <typename T> WTF::TextStream& operator<<(WTF::TextStream& ts, SnapOffse a/Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.h_sec5
114
    return ts;
106
    return ts;
115
}
107
}
116
108
117
template<typename T>
118
TextStream& operator<<(TextStream& ts, const ScrollOffsetRange<T>& range)
119
{
120
    ts << "start: " << range.start << " end: " << range.end;
121
    return ts;
122
}
123
124
}; // namespace WebCore
109
}; // namespace WebCore
125
110
126
#endif // ENABLE(CSS_SCROLL_SNAP)
111
#endif // ENABLE(CSS_SCROLL_SNAP)
- a/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.cpp -1 / +1 lines
Lines 157-163 void ScrollingStateScrollingNode::setScrollOrigin(const IntPoint& scrollOrigin) a/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.cpp_sec1
157
}
157
}
158
158
159
#if ENABLE(CSS_SCROLL_SNAP)
159
#if ENABLE(CSS_SCROLL_SNAP)
160
void ScrollingStateScrollingNode::setSnapOffsetsInfo(const ScrollSnapOffsetsInfo<float>& info)
160
void ScrollingStateScrollingNode::setSnapOffsetsInfo(const FloatScrollSnapOffsetsInfo& info)
161
{
161
{
162
    if (m_snapOffsetsInfo.isEqual(info))
162
    if (m_snapOffsetsInfo.isEqual(info))
163
        return;
163
        return;
- a/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h -3 / +3 lines
Lines 71-78 public: a/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h_sec1
71
    WEBCORE_EXPORT void setScrollOrigin(const IntPoint&);
71
    WEBCORE_EXPORT void setScrollOrigin(const IntPoint&);
72
72
73
#if ENABLE(CSS_SCROLL_SNAP)
73
#if ENABLE(CSS_SCROLL_SNAP)
74
    const ScrollSnapOffsetsInfo<float>& snapOffsetsInfo() const { return m_snapOffsetsInfo; }
74
    const FloatScrollSnapOffsetsInfo& snapOffsetsInfo() const { return m_snapOffsetsInfo; }
75
    WEBCORE_EXPORT void setSnapOffsetsInfo(const ScrollSnapOffsetsInfo<float>& newOffsetsInfo);
75
    WEBCORE_EXPORT void setSnapOffsetsInfo(const FloatScrollSnapOffsetsInfo& newOffsetsInfo);
76
76
77
    unsigned currentHorizontalSnapPointIndex() const { return m_currentHorizontalSnapPointIndex; }
77
    unsigned currentHorizontalSnapPointIndex() const { return m_currentHorizontalSnapPointIndex; }
78
    WEBCORE_EXPORT void setCurrentHorizontalSnapPointIndex(unsigned);
78
    WEBCORE_EXPORT void setCurrentHorizontalSnapPointIndex(unsigned);
Lines 130-136 private: a/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h_sec2
130
    IntPoint m_scrollOrigin;
130
    IntPoint m_scrollOrigin;
131
131
132
#if ENABLE(CSS_SCROLL_SNAP)
132
#if ENABLE(CSS_SCROLL_SNAP)
133
    ScrollSnapOffsetsInfo<float> m_snapOffsetsInfo;
133
    FloatScrollSnapOffsetsInfo m_snapOffsetsInfo;
134
    unsigned m_currentHorizontalSnapPointIndex { 0 };
134
    unsigned m_currentHorizontalSnapPointIndex { 0 };
135
    unsigned m_currentVerticalSnapPointIndex { 0 };
135
    unsigned m_currentVerticalSnapPointIndex { 0 };
136
#endif
136
#endif
- a/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp -1 / +1 lines
Lines 327-333 void ScrollingTreeScrollingNode::dumpProperties(TextStream& ts, ScrollingStateTr a/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp_sec1
327
}
327
}
328
328
329
#if ENABLE(CSS_SCROLL_SNAP)
329
#if ENABLE(CSS_SCROLL_SNAP)
330
const ScrollSnapOffsetsInfo<float>& ScrollingTreeScrollingNode::snapOffsetsInfo() const
330
const FloatScrollSnapOffsetsInfo& ScrollingTreeScrollingNode::snapOffsetsInfo() const
331
{
331
{
332
    return m_snapOffsetsInfo;
332
    return m_snapOffsetsInfo;
333
}
333
}
- a/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h -2 / +2 lines
Lines 95-101 public: a/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h_sec1
95
    bool canHaveScrollbars() const { return m_scrollableAreaParameters.horizontalScrollbarMode != ScrollbarAlwaysOff || m_scrollableAreaParameters.verticalScrollbarMode != ScrollbarAlwaysOff; }
95
    bool canHaveScrollbars() const { return m_scrollableAreaParameters.horizontalScrollbarMode != ScrollbarAlwaysOff || m_scrollableAreaParameters.verticalScrollbarMode != ScrollbarAlwaysOff; }
96
96
97
#if ENABLE(CSS_SCROLL_SNAP)
97
#if ENABLE(CSS_SCROLL_SNAP)
98
    const ScrollSnapOffsetsInfo<float>& snapOffsetsInfo() const;
98
    const FloatScrollSnapOffsetsInfo& snapOffsetsInfo() const;
99
    unsigned currentHorizontalSnapPointIndex() const { return m_currentHorizontalSnapPointIndex; }
99
    unsigned currentHorizontalSnapPointIndex() const { return m_currentHorizontalSnapPointIndex; }
100
    unsigned currentVerticalSnapPointIndex() const { return m_currentVerticalSnapPointIndex; }
100
    unsigned currentVerticalSnapPointIndex() const { return m_currentVerticalSnapPointIndex; }
101
    void setCurrentHorizontalSnapPointIndex(unsigned index) { m_currentHorizontalSnapPointIndex = index; }
101
    void setCurrentHorizontalSnapPointIndex(unsigned index) { m_currentHorizontalSnapPointIndex = index; }
Lines 159-165 private: a/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h_sec2
159
    FloatPoint m_currentScrollPosition;
159
    FloatPoint m_currentScrollPosition;
160
    IntPoint m_scrollOrigin;
160
    IntPoint m_scrollOrigin;
161
#if ENABLE(CSS_SCROLL_SNAP)
161
#if ENABLE(CSS_SCROLL_SNAP)
162
    ScrollSnapOffsetsInfo<float> m_snapOffsetsInfo;
162
    FloatScrollSnapOffsetsInfo m_snapOffsetsInfo;
163
    unsigned m_currentHorizontalSnapPointIndex { 0 };
163
    unsigned m_currentHorizontalSnapPointIndex { 0 };
164
    unsigned m_currentVerticalSnapPointIndex { 0 };
164
    unsigned m_currentVerticalSnapPointIndex { 0 };
165
#endif
165
#endif
- a/Source/WebCore/page/scrolling/mac/ScrollingTreeScrollingNodeDelegateMac.mm -1 / +1 lines
Lines 65-71 void ScrollingTreeScrollingNodeDelegateMac::updateFromStateNode(const ScrollingS a/Source/WebCore/page/scrolling/mac/ScrollingTreeScrollingNodeDelegateMac.mm_sec1
65
65
66
#if ENABLE(CSS_SCROLL_SNAP)
66
#if ENABLE(CSS_SCROLL_SNAP)
67
    if (scrollingStateNode.hasChangedProperty(ScrollingStateNode::Property::SnapOffsetsInfo))
67
    if (scrollingStateNode.hasChangedProperty(ScrollingStateNode::Property::SnapOffsetsInfo))
68
        m_scrollController.updateScrollSnapPoints(scrollingStateNode.snapOffsetsInfo().convertUnits<LayoutUnit>());
68
        m_scrollController.updateScrollSnapPoints(scrollingStateNode.snapOffsetsInfo().convertUnits<LayoutUnit, LayoutRect>());
69
69
70
    if (scrollingStateNode.hasChangedProperty(ScrollingStateNode::Property::CurrentHorizontalSnapOffsetIndex))
70
    if (scrollingStateNode.hasChangedProperty(ScrollingStateNode::Property::CurrentHorizontalSnapOffsetIndex))
71
        m_scrollController.setActiveScrollSnapIndexForAxis(ScrollEventAxis::Horizontal, scrollingStateNode.currentHorizontalSnapPointIndex());
71
        m_scrollController.setActiveScrollSnapIndexForAxis(ScrollEventAxis::Horizontal, scrollingStateNode.currentHorizontalSnapPointIndex());
- a/Source/WebCore/platform/ScrollAnimator.cpp -20 / +15 lines
Lines 81-98 ScrollAnimator::~ScrollAnimator() a/Source/WebCore/platform/ScrollAnimator.cpp_sec1
81
#endif
81
#endif
82
}
82
}
83
83
84
bool ScrollAnimator::scroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float multiplier, ScrollBehavior behavior)
84
bool ScrollAnimator::scroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float multiplier, OptionSet<ScrollBehavior> behavior)
85
{
85
{
86
#if ENABLE(CSS_SCROLL_SNAP)
86
#if ENABLE(CSS_SCROLL_SNAP)
87
    if (behavior == ScrollBehavior::DoDirectionalSnapping) {
87
    if (behavior.contains(ScrollBehavior::DoDirectionalSnapping)) {
88
        auto newOffset = ScrollableArea::scrollOffsetFromPosition(positionFromStep(orientation, step, multiplier), toFloatSize(m_scrollableArea.scrollOrigin()));
88
        auto newOffset = ScrollableArea::scrollOffsetFromPosition(positionFromStep(orientation, step, multiplier), toFloatSize(m_scrollableArea.scrollOrigin()));
89
        auto currentOffset = m_scrollableArea.scrollOffset();
89
        auto currentOffset = m_scrollableArea.scrollOffset();
90
        behavior.remove(ScrollBehavior::DoDirectionalSnapping);
90
        if (orientation == HorizontalScrollbar) {
91
        if (orientation == HorizontalScrollbar) {
91
            newOffset.setX(m_scrollController.adjustScrollDestination(ScrollEventAxis::Horizontal, newOffset.x(), multiplier, currentOffset.x()));
92
            newOffset.setX(m_scrollController.adjustScrollDestination(ScrollEventAxis::Horizontal, newOffset.x(), multiplier, currentOffset.x()));
92
            return scroll(HorizontalScrollbar, granularity, newOffset.x() - currentOffset.x(), 1.0);
93
            return scroll(HorizontalScrollbar, granularity, newOffset.x() - currentOffset.x(), 1.0, behavior);
93
        }
94
        }
94
        newOffset.setY(m_scrollController.adjustScrollDestination(ScrollEventAxis::Vertical, newOffset.y(), multiplier, currentOffset.y()));
95
        newOffset.setY(m_scrollController.adjustScrollDestination(ScrollEventAxis::Vertical, newOffset.y(), multiplier, currentOffset.y()));
95
        return scroll(VerticalScrollbar, granularity, newOffset.y() - currentOffset.y(), 1.0);
96
        return scroll(VerticalScrollbar, granularity, newOffset.y() - currentOffset.y(), 1.0, behavior);
96
    }
97
    }
97
#else
98
#else
98
    UNUSED_PARAM(granularity);
99
    UNUSED_PARAM(granularity);
Lines 100-106 bool ScrollAnimator::scroll(ScrollbarOrientation orientation, ScrollGranularity a/Source/WebCore/platform/ScrollAnimator.cpp_sec2
100
#endif
101
#endif
101
102
102
#if ENABLE(SMOOTH_SCROLLING) && !PLATFORM(IOS_FAMILY)
103
#if ENABLE(SMOOTH_SCROLLING) && !PLATFORM(IOS_FAMILY)
103
    if (m_scrollableArea.scrollAnimatorEnabled()) {
104
    if (m_scrollableArea.scrollAnimatorEnabled() && !behavior.contains(ScrollBehavior::NeverAnimate)) {
104
        m_scrollAnimation->setCurrentPosition(m_currentPosition);
105
        m_scrollAnimation->setCurrentPosition(m_currentPosition);
105
        return m_scrollAnimation->scroll(orientation, granularity, step, multiplier);
106
        return m_scrollAnimation->scroll(orientation, granularity, step, multiplier);
106
    }
107
    }
Lines 160-169 FloatPoint ScrollAnimator::positionFromStep(ScrollbarOrientation orientation, fl a/Source/WebCore/platform/ScrollAnimator.cpp_sec3
160
161
161
#if ENABLE(CSS_SCROLL_SNAP)
162
#if ENABLE(CSS_SCROLL_SNAP)
162
#if PLATFORM(MAC)
163
#if PLATFORM(MAC)
163
bool ScrollAnimator::processWheelEventForScrollSnap(const PlatformWheelEvent& wheelEvent)
164
{
165
    return m_scrollController.processWheelEventForScrollSnap(wheelEvent);
166
}
167
#endif
164
#endif
168
165
169
bool ScrollAnimator::activeScrollSnapIndexDidChange() const
166
bool ScrollAnimator::activeScrollSnapIndexDidChange() const
Lines 179-188 unsigned ScrollAnimator::activeScrollSnapIndexForAxis(ScrollEventAxis axis) cons a/Source/WebCore/platform/ScrollAnimator.cpp_sec4
179
176
180
bool ScrollAnimator::handleWheelEvent(const PlatformWheelEvent& e)
177
bool ScrollAnimator::handleWheelEvent(const PlatformWheelEvent& e)
181
{
178
{
182
#if ENABLE(CSS_SCROLL_SNAP) && PLATFORM(MAC)
179
#if ENABLE(CSS_SCROLL_SNAP)
183
    if (m_scrollController.processWheelEventForScrollSnap(e))
180
    if (processWheelEventForScrollSnap(e))
184
        return false;
181
        return false;
185
#endif
182
#endif
183
186
#if PLATFORM(COCOA)
184
#if PLATFORM(COCOA)
187
    // Events in the PlatformWheelEventPhase::MayBegin phase have no deltas, and therefore never passes through the scroll handling logic below.
185
    // Events in the PlatformWheelEventPhase::MayBegin phase have no deltas, and therefore never passes through the scroll handling logic below.
188
    // This causes us to return with an 'unhandled' return state, even though this event was successfully processed.
186
    // This causes us to return with an 'unhandled' return state, even though this event was successfully processed.
Lines 203-209 bool ScrollAnimator::handleWheelEvent(const PlatformWheelEvent& e) a/Source/WebCore/platform/ScrollAnimator.cpp_sec5
203
201
204
    bool handled = false;
202
    bool handled = false;
205
203
206
    ScrollGranularity granularity = ScrollByPixel;
207
    IntSize maxForwardScrollDelta = m_scrollableArea.maximumScrollPosition() - m_scrollableArea.scrollPosition();
204
    IntSize maxForwardScrollDelta = m_scrollableArea.maximumScrollPosition() - m_scrollableArea.scrollPosition();
208
    IntSize maxBackwardScrollDelta = m_scrollableArea.scrollPosition() - m_scrollableArea.minimumScrollPosition();
205
    IntSize maxBackwardScrollDelta = m_scrollableArea.scrollPosition() - m_scrollableArea.minimumScrollPosition();
209
    if ((deltaX < 0 && maxForwardScrollDelta.width() > 0)
206
    if ((deltaX < 0 && maxForwardScrollDelta.width() > 0)
Lines 212-217 bool ScrollAnimator::handleWheelEvent(const PlatformWheelEvent& e) a/Source/WebCore/platform/ScrollAnimator.cpp_sec6
212
        || (deltaY > 0 && maxBackwardScrollDelta.height() > 0)) {
209
        || (deltaY > 0 && maxBackwardScrollDelta.height() > 0)) {
213
        handled = true;
210
        handled = true;
214
211
212
        OptionSet<ScrollBehavior> behavior(ScrollBehavior::DoDirectionalSnapping);
213
        if (e.hasPreciseScrollingDeltas())
214
            behavior.add(ScrollBehavior::NeverAnimate);
215
215
        if (deltaY) {
216
        if (deltaY) {
216
            if (e.granularity() == ScrollByPageWheelEvent) {
217
            if (e.granularity() == ScrollByPageWheelEvent) {
217
                bool negative = deltaY < 0;
218
                bool negative = deltaY < 0;
Lines 219-228 bool ScrollAnimator::handleWheelEvent(const PlatformWheelEvent& e) a/Source/WebCore/platform/ScrollAnimator.cpp_sec7
219
                if (negative)
220
                if (negative)
220
                    deltaY = -deltaY;
221
                    deltaY = -deltaY;
221
            }
222
            }
222
            if (e.hasPreciseScrollingDeltas())
223
            scroll(VerticalScrollbar, ScrollByPixel, verticalScrollbar->pixelStep(), -deltaY, behavior);
223
                scrollToPositionWithoutAnimation(positionFromStep(VerticalScrollbar, verticalScrollbar->pixelStep(), -deltaY));
224
            else
225
                scroll(VerticalScrollbar, granularity, verticalScrollbar->pixelStep(), -deltaY);
226
        }
224
        }
227
225
228
        if (deltaX) {
226
        if (deltaX) {
Lines 232-241 bool ScrollAnimator::handleWheelEvent(const PlatformWheelEvent& e) a/Source/WebCore/platform/ScrollAnimator.cpp_sec8
232
                if (negative)
230
                if (negative)
233
                    deltaX = -deltaX;
231
                    deltaX = -deltaX;
234
            }
232
            }
235
            if (e.hasPreciseScrollingDeltas())
233
            scroll(HorizontalScrollbar, ScrollByPixel, horizontalScrollbar->pixelStep(), -deltaX, behavior);
236
                scrollToPositionWithoutAnimation(positionFromStep(HorizontalScrollbar, horizontalScrollbar->pixelStep(), -deltaX));
237
            else
238
                scroll(HorizontalScrollbar, granularity, horizontalScrollbar->pixelStep(), -deltaX);
239
        }
234
        }
240
    }
235
    }
241
    return handled;
236
    return handled;
- a/Source/WebCore/platform/ScrollAnimator.h -6 / +5 lines
Lines 69-83 public: a/Source/WebCore/platform/ScrollAnimator.h_sec1
69
    virtual ~ScrollAnimator();
69
    virtual ~ScrollAnimator();
70
70
71
    enum ScrollBehavior {
71
    enum ScrollBehavior {
72
        Default,
72
        Default = 0,
73
        DoDirectionalSnapping,
73
        DoDirectionalSnapping = 1 << 1,
74
        NeverAnimate = 1 << 2,
74
    };
75
    };
75
76
76
    // Computes a scroll destination for the given parameters.  Returns false if
77
    // Computes a scroll destination for the given parameters.  Returns false if
77
    // already at the destination.  Otherwise, starts scrolling towards the
78
    // already at the destination.  Otherwise, starts scrolling towards the
78
    // destination and returns true.  Scrolling may be immediate or animated.
79
    // destination and returns true.  Scrolling may be immediate or animated.
79
    // The base class implementation always scrolls immediately, never animates.
80
    // The base class implementation always scrolls immediately, never animates.
80
    virtual bool scroll(ScrollbarOrientation, ScrollGranularity, float step, float multiplier, ScrollBehavior = ScrollBehavior::Default);
81
    virtual bool scroll(ScrollbarOrientation, ScrollGranularity, float step, float multiplier, OptionSet<ScrollBehavior>);
81
82
82
    bool scrollToOffsetWithoutAnimation(const FloatPoint&, ScrollClamping = ScrollClamping::Clamped);
83
    bool scrollToOffsetWithoutAnimation(const FloatPoint&, ScrollClamping = ScrollClamping::Clamped);
83
    virtual bool scrollToPositionWithoutAnimation(const FloatPoint& position, ScrollClamping = ScrollClamping::Clamped);
84
    virtual bool scrollToPositionWithoutAnimation(const FloatPoint& position, ScrollClamping = ScrollClamping::Clamped);
Lines 149-157 public: a/Source/WebCore/platform/ScrollAnimator.h_sec2
149
#endif
150
#endif
150
151
151
#if ENABLE(CSS_SCROLL_SNAP)
152
#if ENABLE(CSS_SCROLL_SNAP)
152
#if PLATFORM(MAC)
153
    virtual bool processWheelEventForScrollSnap(const PlatformWheelEvent&) { return false; }
153
    bool processWheelEventForScrollSnap(const PlatformWheelEvent&);
154
#endif
155
    void updateScrollSnapState();
154
    void updateScrollSnapState();
156
    bool activeScrollSnapIndexDidChange() const;
155
    bool activeScrollSnapIndexDidChange() const;
157
    unsigned activeScrollSnapIndexForAxis(ScrollEventAxis) const;
156
    unsigned activeScrollSnapIndexForAxis(ScrollEventAxis) const;
- a/Source/WebCore/platform/ScrollController.cpp -4 / +6 lines
Lines 67-73 void ScrollController::updateScrollSnapState(const ScrollableArea& scrollableAre a/Source/WebCore/platform/ScrollController.cpp_sec1
67
    updateScrollSnapPoints(*snapOffsetInfo);
67
    updateScrollSnapPoints(*snapOffsetInfo);
68
}
68
}
69
69
70
void ScrollController::updateScrollSnapPoints(const ScrollSnapOffsetsInfo<LayoutUnit>& snapOffsetInfo)
70
void ScrollController::updateScrollSnapPoints(const LayoutScrollSnapOffsetsInfo& snapOffsetInfo)
71
{
71
{
72
    if (snapOffsetInfo.isEmpty()) {
72
    if (snapOffsetInfo.isEmpty()) {
73
        m_scrollSnapState = nullptr;
73
        m_scrollSnapState = nullptr;
Lines 115-122 void ScrollController::setNearestScrollSnapIndexForAxisAndOffset(ScrollEventAxis a/Source/WebCore/platform/ScrollController.cpp_sec2
115
        return;
115
        return;
116
116
117
    LayoutUnit clampedOffset = std::min(std::max(LayoutUnit(offset / scaleFactor), snapOffsets.first().offset), snapOffsets.last().offset);
117
    LayoutUnit clampedOffset = std::min(std::max(LayoutUnit(offset / scaleFactor), snapOffsets.first().offset), snapOffsets.last().offset);
118
118
    LayoutSize viewportSize(m_client.viewportSize().width(), m_client.viewportSize().height());
119
    unsigned activeIndex = snapState.snapOffsetInfo().closestSnapOffset(axis, clampedOffset, 0).second;
119
    unsigned activeIndex = snapState.snapOffsetInfo().closestSnapOffset(axis, viewportSize, clampedOffset, 0).second;
120
    if (activeIndex == activeScrollSnapIndexForAxis(axis))
120
    if (activeIndex == activeScrollSnapIndexForAxis(axis))
121
        return;
121
        return;
122
122
Lines 137-143 float ScrollController::adjustScrollDestination(ScrollEventAxis axis, float dest a/Source/WebCore/platform/ScrollController.cpp_sec3
137
    Optional<LayoutUnit> originalOffsetInLayoutUnits;
137
    Optional<LayoutUnit> originalOffsetInLayoutUnits;
138
    if (originalOffset.hasValue())
138
    if (originalOffset.hasValue())
139
        originalOffsetInLayoutUnits = LayoutUnit(*originalOffset / m_client.pageScaleFactor());
139
        originalOffsetInLayoutUnits = LayoutUnit(*originalOffset / m_client.pageScaleFactor());
140
    LayoutUnit offset = snapState.snapOffsetInfo().closestSnapOffset(axis, LayoutUnit(destinationOffset / m_client.pageScaleFactor()), velocity, originalOffsetInLayoutUnits).first;
140
141
    LayoutSize viewportSize(m_client.viewportSize().width(), m_client.viewportSize().height());
142
    LayoutUnit offset = snapState.snapOffsetInfo().closestSnapOffset(axis, viewportSize, LayoutUnit(destinationOffset / m_client.pageScaleFactor()), velocity, originalOffsetInLayoutUnits).first;
141
    return offset * m_client.pageScaleFactor();
143
    return offset * m_client.pageScaleFactor();
142
}
144
}
143
145
- a/Source/WebCore/platform/ScrollController.h -1 / +1 lines
Lines 132-138 public: a/Source/WebCore/platform/ScrollController.h_sec1
132
    void scrollPositionChanged();
132
    void scrollPositionChanged();
133
133
134
#if ENABLE(CSS_SCROLL_SNAP)
134
#if ENABLE(CSS_SCROLL_SNAP)
135
    void updateScrollSnapPoints(const ScrollSnapOffsetsInfo<LayoutUnit>&);
135
    void updateScrollSnapPoints(const LayoutScrollSnapOffsetsInfo&);
136
    void setActiveScrollSnapIndexForAxis(ScrollEventAxis, unsigned);
136
    void setActiveScrollSnapIndexForAxis(ScrollEventAxis, unsigned);
137
    void setActiveScrollSnapIndicesForOffset(ScrollOffset);
137
    void setActiveScrollSnapIndicesForOffset(ScrollOffset);
138
    bool activeScrollSnapIndexDidChange() const { return m_activeScrollSnapIndexDidChange; }
138
    bool activeScrollSnapIndexDidChange() const { return m_activeScrollSnapIndexDidChange; }
- a/Source/WebCore/platform/ScrollSnapAnimatorState.cpp -9 / +5 lines
Lines 51-58 void ScrollSnapAnimatorState::setupAnimationForState(ScrollSnapState state, cons a/Source/WebCore/platform/ScrollSnapAnimatorState.cpp_sec1
51
51
52
    m_momentumCalculator = ScrollingMomentumCalculator::create(viewportSize, contentSize, initialOffset, initialDelta, initialVelocity);
52
    m_momentumCalculator = ScrollingMomentumCalculator::create(viewportSize, contentSize, initialOffset, initialDelta, initialVelocity);
53
    auto predictedScrollTarget = m_momentumCalculator->predictedDestinationOffset();
53
    auto predictedScrollTarget = m_momentumCalculator->predictedDestinationOffset();
54
    float targetOffsetX = targetOffsetForStartOffset(ScrollEventAxis::Horizontal, contentSize.width() - viewportSize.width(), initialOffset.x(), predictedScrollTarget.width(), pageScale, initialDelta.width(), m_activeSnapIndexX);
54
    float targetOffsetX = targetOffsetForStartOffset(ScrollEventAxis::Horizontal, viewportSize, contentSize.width() - viewportSize.width(), initialOffset.x(), predictedScrollTarget.width(), pageScale, initialDelta.width(), m_activeSnapIndexX);
55
    float targetOffsetY = targetOffsetForStartOffset(ScrollEventAxis::Vertical, contentSize.height() - viewportSize.height(), initialOffset.y(), predictedScrollTarget.height(), pageScale, initialDelta.height(), m_activeSnapIndexY);
55
    float targetOffsetY = targetOffsetForStartOffset(ScrollEventAxis::Vertical, viewportSize, contentSize.height() - viewportSize.height(), initialOffset.y(), predictedScrollTarget.height(), pageScale, initialDelta.height(), m_activeSnapIndexY);
56
    m_momentumCalculator->setRetargetedScrollOffset({ targetOffsetX, targetOffsetY });
56
    m_momentumCalculator->setRetargetedScrollOffset({ targetOffsetX, targetOffsetY });
57
    m_startTime = MonotonicTime::now();
57
    m_startTime = MonotonicTime::now();
58
    m_currentState = state;
58
    m_currentState = state;
Lines 91-100 FloatPoint ScrollSnapAnimatorState::currentAnimatedScrollOffset(bool& isAnimatio a/Source/WebCore/platform/ScrollSnapAnimatorState.cpp_sec2
91
    return m_momentumCalculator->scrollOffsetAfterElapsedTime(elapsedTime);
91
    return m_momentumCalculator->scrollOffsetAfterElapsedTime(elapsedTime);
92
}
92
}
93
93
94
float ScrollSnapAnimatorState::targetOffsetForStartOffset(ScrollEventAxis axis, float maxScrollOffset, float startOffset, float predictedOffset, float pageScale, float initialDelta, unsigned& outActiveSnapIndex) const
94
float ScrollSnapAnimatorState::targetOffsetForStartOffset(ScrollEventAxis axis, const FloatSize& viewportSize, float maxScrollOffset, float startOffset, float predictedOffset, float pageScale, float initialDelta, unsigned& outActiveSnapIndex) const
95
{
95
{
96
    LayoutUnit proposedOffset;
96
    LayoutUnit proposedOffset;
97
    std::tie(proposedOffset, outActiveSnapIndex) = m_snapOffsetsInfo.closestSnapOffset(axis, LayoutUnit(predictedOffset / pageScale), initialDelta);
97
    LayoutSize viewportLayoutSize(viewportSize.width(), viewportSize.height());
98
    std::tie(proposedOffset, outActiveSnapIndex) = m_snapOffsetsInfo.closestSnapOffset(axis, viewportLayoutSize, LayoutUnit(predictedOffset / pageScale), initialDelta);
98
    if (outActiveSnapIndex != invalidSnapOffsetIndex)
99
    if (outActiveSnapIndex != invalidSnapOffsetIndex)
99
        return pageScale * proposedOffset;
100
        return pageScale * proposedOffset;
100
    return clampTo<float>(startOffset, 0, maxScrollOffset);
101
    return clampTo<float>(startOffset, 0, maxScrollOffset);
Lines 105-115 TextStream& operator<<(TextStream& ts, const ScrollSnapAnimatorState& state) a/Source/WebCore/platform/ScrollSnapAnimatorState.cpp_sec3
105
    ts << "ScrollSnapAnimatorState";
106
    ts << "ScrollSnapAnimatorState";
106
    ts.dumpProperty("snap offsets x", state.snapOffsetsForAxis(ScrollEventAxis::Horizontal));
107
    ts.dumpProperty("snap offsets x", state.snapOffsetsForAxis(ScrollEventAxis::Horizontal));
107
    ts.dumpProperty("snap offsets y", state.snapOffsetsForAxis(ScrollEventAxis::Vertical));
108
    ts.dumpProperty("snap offsets y", state.snapOffsetsForAxis(ScrollEventAxis::Vertical));
108
    if (!state.snapOffsetRangesForAxis(ScrollEventAxis::Horizontal).isEmpty())
109
        ts.dumpProperty("snap offsets ranges x", state.snapOffsetRangesForAxis(ScrollEventAxis::Horizontal));
110
    if (!state.snapOffsetRangesForAxis(ScrollEventAxis::Vertical).isEmpty())
111
        ts.dumpProperty("snap offsets ranges y", state.snapOffsetRangesForAxis(ScrollEventAxis::Vertical));
112
113
    ts.dumpProperty("active snap index x", state.activeSnapIndexForAxis(ScrollEventAxis::Horizontal));
109
    ts.dumpProperty("active snap index x", state.activeSnapIndexForAxis(ScrollEventAxis::Horizontal));
114
    ts.dumpProperty("active snap index y", state.activeSnapIndexForAxis(ScrollEventAxis::Vertical));
110
    ts.dumpProperty("active snap index y", state.activeSnapIndexForAxis(ScrollEventAxis::Vertical));
115
111
- a/Source/WebCore/platform/ScrollSnapAnimatorState.h -20 / +4 lines
Lines 57-80 public: a/Source/WebCore/platform/ScrollSnapAnimatorState.h_sec1
57
        return axis == ScrollEventAxis::Horizontal ? m_snapOffsetsInfo.horizontalSnapOffsets : m_snapOffsetsInfo.verticalSnapOffsets;
57
        return axis == ScrollEventAxis::Horizontal ? m_snapOffsetsInfo.horizontalSnapOffsets : m_snapOffsetsInfo.verticalSnapOffsets;
58
    }
58
    }
59
59
60
    const Vector<ScrollOffsetRange<LayoutUnit>>& snapOffsetRangesForAxis(ScrollEventAxis axis) const
60
    const LayoutScrollSnapOffsetsInfo& snapOffsetInfo() const { return m_snapOffsetsInfo; }
61
    {
61
    void setSnapOffsetInfo(const LayoutScrollSnapOffsetsInfo& newInfo) { m_snapOffsetsInfo = newInfo; }
62
        return axis == ScrollEventAxis::Horizontal ? m_snapOffsetsInfo.horizontalSnapOffsetRanges : m_snapOffsetsInfo.verticalSnapOffsetRanges;
63
    }
64
65
    const ScrollSnapOffsetsInfo<LayoutUnit>& snapOffsetInfo() const { return m_snapOffsetsInfo; }
66
    void setSnapOffsetInfo(const ScrollSnapOffsetsInfo<LayoutUnit>& newInfo) { m_snapOffsetsInfo = newInfo; }
67
68
    void setSnapOffsetsAndPositionRangesForAxis(ScrollEventAxis axis, const Vector<SnapOffset<LayoutUnit>>& snapOffsets, const Vector<ScrollOffsetRange<LayoutUnit>>& snapOffsetRanges)
69
    {
70
        if (axis == ScrollEventAxis::Horizontal) {
71
            m_snapOffsetsInfo.horizontalSnapOffsets = snapOffsets;
72
            m_snapOffsetsInfo.horizontalSnapOffsetRanges = snapOffsetRanges;
73
        } else {
74
            m_snapOffsetsInfo.verticalSnapOffsets = snapOffsets;
75
            m_snapOffsetsInfo.verticalSnapOffsetRanges = snapOffsetRanges;
76
        }
77
    }
78
62
79
    ScrollSnapState currentState() const { return m_currentState; }
63
    ScrollSnapState currentState() const { return m_currentState; }
80
64
Lines 100-112 public: a/Source/WebCore/platform/ScrollSnapAnimatorState.h_sec2
100
    void transitionToDestinationReachedState();
84
    void transitionToDestinationReachedState();
101
85
102
private:
86
private:
103
    float targetOffsetForStartOffset(ScrollEventAxis, float maxScrollOffset, float startOffset, float predictedOffset, float pageScale, float initialDelta, unsigned& outActiveSnapIndex) const;
87
    float targetOffsetForStartOffset(ScrollEventAxis, const FloatSize& viewportSize, float maxScrollOffset, float startOffset, float predictedOffset, float pageScale, float initialDelta, unsigned& outActiveSnapIndex) const;
104
    void teardownAnimationForState(ScrollSnapState);
88
    void teardownAnimationForState(ScrollSnapState);
105
    void setupAnimationForState(ScrollSnapState, const FloatSize& contentSize, const FloatSize& viewportSize, float pageScale, const FloatPoint& initialOffset, const FloatSize& initialVelocity, const FloatSize& initialDelta);
89
    void setupAnimationForState(ScrollSnapState, const FloatSize& contentSize, const FloatSize& viewportSize, float pageScale, const FloatPoint& initialOffset, const FloatSize& initialVelocity, const FloatSize& initialDelta);
106
90
107
    ScrollSnapState m_currentState { ScrollSnapState::UserInteraction };
91
    ScrollSnapState m_currentState { ScrollSnapState::UserInteraction };
108
92
109
    ScrollSnapOffsetsInfo<LayoutUnit> m_snapOffsetsInfo;
93
    LayoutScrollSnapOffsetsInfo m_snapOffsetsInfo;
110
94
111
    unsigned m_activeSnapIndexX { 0 };
95
    unsigned m_activeSnapIndexX { 0 };
112
    unsigned m_activeSnapIndexY { 0 };
96
    unsigned m_activeSnapIndexY { 0 };
- a/Source/WebCore/platform/ScrollableArea.cpp -4 / +4 lines
Lines 479-497 String ScrollableArea::verticalScrollbarStateForTesting() const a/Source/WebCore/platform/ScrollableArea.cpp_sec1
479
}
479
}
480
480
481
#if ENABLE(CSS_SCROLL_SNAP)
481
#if ENABLE(CSS_SCROLL_SNAP)
482
ScrollSnapOffsetsInfo<LayoutUnit>& ScrollableArea::ensureSnapOffsetsInfo()
482
LayoutScrollSnapOffsetsInfo& ScrollableArea::ensureSnapOffsetsInfo()
483
{
483
{
484
    if (!m_snapOffsetsInfo)
484
    if (!m_snapOffsetsInfo)
485
        m_snapOffsetsInfo = makeUnique<ScrollSnapOffsetsInfo<LayoutUnit>>();
485
        m_snapOffsetsInfo = makeUnique<LayoutScrollSnapOffsetsInfo>();
486
    return *m_snapOffsetsInfo;
486
    return *m_snapOffsetsInfo;
487
}
487
}
488
488
489
const ScrollSnapOffsetsInfo<LayoutUnit>* ScrollableArea::snapOffsetInfo() const
489
const LayoutScrollSnapOffsetsInfo* ScrollableArea::snapOffsetInfo() const
490
{
490
{
491
    return m_snapOffsetsInfo.get();
491
    return m_snapOffsetsInfo.get();
492
}
492
}
493
493
494
void ScrollableArea::setScrollSnapOffsetInfo(const ScrollSnapOffsetsInfo<LayoutUnit>& info)
494
void ScrollableArea::setScrollSnapOffsetInfo(const LayoutScrollSnapOffsetsInfo& info)
495
{
495
{
496
    if (info.isEmpty()) {
496
    if (info.isEmpty()) {
497
        clearSnapOffsets();
497
        clearSnapOffsets();
- a/Source/WebCore/platform/ScrollableArea.h -4 / +4 lines
Lines 91-99 public: a/Source/WebCore/platform/ScrollableArea.h_sec1
91
    bool usesScrollSnap() const;
91
    bool usesScrollSnap() const;
92
92
93
#if ENABLE(CSS_SCROLL_SNAP)
93
#if ENABLE(CSS_SCROLL_SNAP)
94
    WEBCORE_EXPORT const ScrollSnapOffsetsInfo<LayoutUnit>* snapOffsetInfo() const;
94
    WEBCORE_EXPORT const LayoutScrollSnapOffsetsInfo* snapOffsetInfo() const;
95
    virtual void updateSnapOffsets() { };
95
    virtual void updateSnapOffsets() { };
96
    void setScrollSnapOffsetInfo(const ScrollSnapOffsetsInfo<LayoutUnit>&);
96
    void setScrollSnapOffsetInfo(const LayoutScrollSnapOffsetsInfo&);
97
    void clearSnapOffsets();
97
    void clearSnapOffsets();
98
    unsigned currentHorizontalSnapPointIndex() const { return m_currentHorizontalSnapPointIndex; }
98
    unsigned currentHorizontalSnapPointIndex() const { return m_currentHorizontalSnapPointIndex; }
99
    void setCurrentHorizontalSnapPointIndex(unsigned index) { m_currentHorizontalSnapPointIndex = index; }
99
    void setCurrentHorizontalSnapPointIndex(unsigned index) { m_currentHorizontalSnapPointIndex = index; }
Lines 385-392 private: a/Source/WebCore/platform/ScrollableArea.h_sec2
385
    mutable std::unique_ptr<ScrollAnimator> m_scrollAnimator;
385
    mutable std::unique_ptr<ScrollAnimator> m_scrollAnimator;
386
386
387
#if ENABLE(CSS_SCROLL_SNAP)
387
#if ENABLE(CSS_SCROLL_SNAP)
388
    ScrollSnapOffsetsInfo<LayoutUnit>& ensureSnapOffsetsInfo();
388
    LayoutScrollSnapOffsetsInfo& ensureSnapOffsetsInfo();
389
    std::unique_ptr<ScrollSnapOffsetsInfo<LayoutUnit>> m_snapOffsetsInfo;
389
    std::unique_ptr<LayoutScrollSnapOffsetsInfo> m_snapOffsetsInfo;
390
    unsigned m_currentHorizontalSnapPointIndex { 0 };
390
    unsigned m_currentHorizontalSnapPointIndex { 0 };
391
    unsigned m_currentVerticalSnapPointIndex { 0 };
391
    unsigned m_currentVerticalSnapPointIndex { 0 };
392
#endif
392
#endif
- a/Source/WebCore/platform/mac/ScrollAnimatorMac.h -1 / +3 lines
Lines 79-85 private: a/Source/WebCore/platform/mac/ScrollAnimatorMac.h_sec1
79
    Timer m_sendContentAreaScrolledTimer;
79
    Timer m_sendContentAreaScrolledTimer;
80
    FloatSize m_contentAreaScrolledTimerScrollDelta;
80
    FloatSize m_contentAreaScrolledTimerScrollDelta;
81
81
82
    bool scroll(ScrollbarOrientation, ScrollGranularity, float step, float multiplier, ScrollBehavior) override;
82
    bool scroll(ScrollbarOrientation, ScrollGranularity, float step, float multiplier, OptionSet<ScrollBehavior>) override;
83
    bool scrollToPositionWithAnimation(const FloatPoint&) override;
83
    bool scrollToPositionWithAnimation(const FloatPoint&) override;
84
    bool scrollToPositionWithoutAnimation(const FloatPoint& position, ScrollClamping = ScrollClamping::Clamped) override;
84
    bool scrollToPositionWithoutAnimation(const FloatPoint& position, ScrollClamping = ScrollClamping::Clamped) override;
85
85
Lines 140-145 private: a/Source/WebCore/platform/mac/ScrollAnimatorMac.h_sec2
140
    String horizontalScrollbarStateForTesting() const final;
140
    String horizontalScrollbarStateForTesting() const final;
141
    String verticalScrollbarStateForTesting() const final;
141
    String verticalScrollbarStateForTesting() const final;
142
142
143
    bool processWheelEventForScrollSnap(const PlatformWheelEvent&) override;
144
143
    // ScrollControllerClient.
145
    // ScrollControllerClient.
144
#if ENABLE(RUBBER_BANDING)
146
#if ENABLE(RUBBER_BANDING)
145
    IntSize stretchAmount() const final;
147
    IntSize stretchAmount() const final;
- a/Source/WebCore/platform/mac/ScrollAnimatorMac.mm -4 / +10 lines
Lines 751-766 static bool rubberBandingEnabledForSystem() a/Source/WebCore/platform/mac/ScrollAnimatorMac.mm_sec1
751
}
751
}
752
#endif
752
#endif
753
753
754
bool ScrollAnimatorMac::scroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float multiplier, ScrollBehavior behavior)
754
bool ScrollAnimatorMac::scroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float multiplier, OptionSet<ScrollBehavior> behavior)
755
{
755
{
756
    m_haveScrolledSincePageLoad = true;
756
    m_haveScrolledSincePageLoad = true;
757
757
758
    // This method doesn't do directional snapping, but our base class does. It will call into
758
    // This method doesn't do directional snapping, but our base class does. It will call into
759
    // ScrollAnimatorMac::scroll again with the snapped positions and ScrollBehavior::Default.
759
    // ScrollAnimatorMac::scroll again with the snapped positions and ScrollBehavior::Default.
760
    if (behavior == ScrollBehavior::DoDirectionalSnapping)
760
    if (behavior.contains(ScrollBehavior::DoDirectionalSnapping))
761
        return ScrollAnimator::scroll(orientation, granularity, step, multiplier, behavior);
761
        return ScrollAnimator::scroll(orientation, granularity, step, multiplier, behavior);
762
762
763
    bool shouldAnimate = scrollAnimationEnabledForSystem() && m_scrollableArea.scrollAnimatorEnabled() && granularity != ScrollByPixel;
763
    bool shouldAnimate = scrollAnimationEnabledForSystem() && m_scrollableArea.scrollAnimatorEnabled() && granularity != ScrollByPixel
764
        && !behavior.contains(ScrollBehavior::NeverAnimate);
764
    FloatPoint newPosition = positionFromStep(orientation, step, multiplier);
765
    FloatPoint newPosition = positionFromStep(orientation, step, multiplier);
765
    newPosition = newPosition.constrainedBetween(scrollableArea().minimumScrollPosition(), scrollableArea().maximumScrollPosition());
766
    newPosition = newPosition.constrainedBetween(scrollableArea().minimumScrollPosition(), scrollableArea().maximumScrollPosition());
766
767
Lines 1277-1283 bool ScrollAnimatorMac::isPinnedForScrollDelta(const FloatSize& delta) const a/Source/WebCore/platform/mac/ScrollAnimatorMac.mm_sec2
1277
}
1278
}
1278
1279
1279
#if ENABLE(CSS_SCROLL_SNAP)
1280
#if ENABLE(CSS_SCROLL_SNAP)
1280
static bool gestureShouldBeginSnap(const PlatformWheelEvent& wheelEvent, ScrollEventAxis axis, const ScrollSnapOffsetsInfo<LayoutUnit>* offsetInfo)
1281
static bool gestureShouldBeginSnap(const PlatformWheelEvent& wheelEvent, ScrollEventAxis axis, const LayoutScrollSnapOffsetsInfo* offsetInfo)
1281
{
1282
{
1282
    if (!offsetInfo)
1283
    if (!offsetInfo)
1283
        return false;
1284
        return false;
Lines 1500-1505 void ScrollAnimatorMac::setVisibleScrollerThumbRect(const IntRect& scrollerThumb a/Source/WebCore/platform/mac/ScrollAnimatorMac.mm_sec3
1500
    m_visibleScrollerThumbRect = rectInViewCoordinates;
1501
    m_visibleScrollerThumbRect = rectInViewCoordinates;
1501
}
1502
}
1502
1503
1504
bool ScrollAnimatorMac::processWheelEventForScrollSnap(const PlatformWheelEvent& wheelEvent)
1505
{
1506
    return m_scrollController.processWheelEventForScrollSnap(wheelEvent);
1507
}
1508
1503
} // namespace WebCore
1509
} // namespace WebCore
1504
1510
1505
#endif // ENABLE(SMOOTH_SCROLLING)
1511
#endif // ENABLE(SMOOTH_SCROLLING)
- a/Source/WebKit/Platform/mac/MenuUtilities.mm -19 / +28 lines
Lines 49-54 NSString *menuItemTitleForTelephoneNumberGroup() a/Source/WebKit/Platform/mac/MenuUtilities.mm_sec1
49
    return [getTUCallClass() supplementalDialTelephonyCallString];
49
    return [getTUCallClass() supplementalDialTelephonyCallString];
50
}
50
}
51
51
52
#if HAVE(DATA_DETECTORS_MAC_ACTION)
53
static DDMacAction *actionForMenuItem(NSMenuItem *item)
54
#else
55
static DDAction *actionForMenuItem(NSMenuItem *item)
56
#endif
57
{
58
    NSDictionary *representedObject = item.representedObject;
59
    if (![representedObject isKindOfClass:[NSDictionary class]])
60
        return nil;
61
62
    id action = [representedObject objectForKey:@"DDAction"];
63
64
#if HAVE(DATA_DETECTORS_MAC_ACTION)
65
    if (![action isKindOfClass:getDDMacActionClass()])
66
        return nil;
67
#else
68
    if (![action isKindOfClass:getDDActionClass()])
69
        return nil;
70
#endif
71
72
    return action;
73
}
74
52
NSMenuItem *menuItemForTelephoneNumber(const String& telephoneNumber)
75
NSMenuItem *menuItemForTelephoneNumber(const String& telephoneNumber)
53
{
76
{
54
    if (!DataDetectorsLibrary())
77
    if (!DataDetectorsLibrary())
Lines 59-73 NSMenuItem *menuItemForTelephoneNumber(const String& telephoneNumber) a/Source/WebKit/Platform/mac/MenuUtilities.mm_sec2
59
82
60
    NSArray *proposedMenuItems = [[getDDActionsManagerClass() sharedManager] menuItemsForValue:(NSString *)telephoneNumber type:getDDBinderPhoneNumberKey() service:nil context:actionContext.get()];
83
    NSArray *proposedMenuItems = [[getDDActionsManagerClass() sharedManager] menuItemsForValue:(NSString *)telephoneNumber type:getDDBinderPhoneNumberKey() service:nil context:actionContext.get()];
61
    for (NSMenuItem *item in proposedMenuItems) {
84
    for (NSMenuItem *item in proposedMenuItems) {
62
        NSDictionary *representedObject = item.representedObject;
85
        auto action = actionForMenuItem(item);
63
        if (![representedObject isKindOfClass:[NSDictionary class]])
86
        if ([action.actionUTI hasPrefix:@"com.apple.dial"]) {
64
            continue;
65
66
        DDAction *actionObject = [representedObject objectForKey:@"DDAction"];
67
        if (![actionObject isKindOfClass:getDDActionClass()])
68
            continue;
69
70
        if ([actionObject.actionUTI hasPrefix:@"com.apple.dial"]) {
71
            item.title = formattedPhoneNumberString(telephoneNumber);
87
            item.title = formattedPhoneNumberString(telephoneNumber);
72
            return item;
88
            return item;
73
        }
89
        }
Lines 90-106 RetainPtr<NSMenu> menuForTelephoneNumber(const String& telephoneNumber) a/Source/WebKit/Platform/mac/MenuUtilities.mm_sec3
90
106
91
    NSArray *proposedMenuItems = [[getDDActionsManagerClass() sharedManager] menuItemsForValue:(NSString *)telephoneNumber type:getDDBinderPhoneNumberKey() service:nil context:actionContext.get()];
107
    NSArray *proposedMenuItems = [[getDDActionsManagerClass() sharedManager] menuItemsForValue:(NSString *)telephoneNumber type:getDDBinderPhoneNumberKey() service:nil context:actionContext.get()];
92
    for (NSMenuItem *item in proposedMenuItems) {
108
    for (NSMenuItem *item in proposedMenuItems) {
93
        NSDictionary *representedObject = item.representedObject;
109
        auto action = actionForMenuItem(item);
94
        if (![representedObject isKindOfClass:[NSDictionary class]])
110
        if ([action.actionUTI hasPrefix:@"com.apple.dial"])
95
            continue;
96
97
        DDAction *actionObject = [representedObject objectForKey:@"DDAction"];
98
        if (![actionObject isKindOfClass:getDDActionClass()])
99
            continue;
100
101
        if ([actionObject.actionUTI hasPrefix:@"com.apple.dial"])
102
            dialItem = item;
111
            dialItem = item;
103
        else if ([actionObject.actionUTI hasPrefix:@"com.apple.facetime"])
112
        else if ([action.actionUTI hasPrefix:@"com.apple.facetime"])
104
            [faceTimeItems addObject:item];
113
            [faceTimeItems addObject:item];
105
    }
114
    }
106
115
- a/Source/WebKit/Shared/RemoteLayerTree/RemoteScrollingCoordinatorTransaction.cpp -11 / +8 lines
Lines 98-106 template<> struct ArgumentCoder<RequestedScrollData> { a/Source/WebKit/Shared/RemoteLayerTree/RemoteScrollingCoordinatorTransaction.cpp_sec1
98
    static WARN_UNUSED_RETURN bool decode(Decoder&, RequestedScrollData&);
98
    static WARN_UNUSED_RETURN bool decode(Decoder&, RequestedScrollData&);
99
};
99
};
100
100
101
template<> struct ArgumentCoder<ScrollSnapOffsetsInfo<float>> {
101
template<> struct ArgumentCoder<FloatScrollSnapOffsetsInfo> {
102
    static void encode(Encoder&, const ScrollSnapOffsetsInfo<float>&);
102
    static void encode(Encoder&, const FloatScrollSnapOffsetsInfo&);
103
    static WARN_UNUSED_RETURN bool decode(Decoder&, ScrollSnapOffsetsInfo<float>&);
103
    static WARN_UNUSED_RETURN bool decode(Decoder&, FloatScrollSnapOffsetsInfo&);
104
};
104
};
105
105
106
template<> struct ArgumentCoder<SnapOffset<float>> {
106
template<> struct ArgumentCoder<SnapOffset<float>> {
Lines 311-317 bool ArgumentCoder<ScrollingStateScrollingNode>::decode(Decoder& decoder, Scroll a/Source/WebKit/Shared/RemoteLayerTree/RemoteScrollingCoordinatorTransaction.cpp_sec2
311
    SCROLLING_NODE_DECODE(ScrollingStateNode::Property::ScrollPosition, FloatPoint, setScrollPosition);
311
    SCROLLING_NODE_DECODE(ScrollingStateNode::Property::ScrollPosition, FloatPoint, setScrollPosition);
312
    SCROLLING_NODE_DECODE(ScrollingStateNode::Property::ScrollOrigin, IntPoint, setScrollOrigin);
312
    SCROLLING_NODE_DECODE(ScrollingStateNode::Property::ScrollOrigin, IntPoint, setScrollOrigin);
313
#if ENABLE(CSS_SCROLL_SNAP)
313
#if ENABLE(CSS_SCROLL_SNAP)
314
    SCROLLING_NODE_DECODE(ScrollingStateNode::Property::SnapOffsetsInfo, ScrollSnapOffsetsInfo<float>, setSnapOffsetsInfo);
314
    SCROLLING_NODE_DECODE(ScrollingStateNode::Property::SnapOffsetsInfo, FloatScrollSnapOffsetsInfo, setSnapOffsetsInfo);
315
    SCROLLING_NODE_DECODE(ScrollingStateNode::Property::CurrentHorizontalSnapOffsetIndex, unsigned, setCurrentHorizontalSnapPointIndex);
315
    SCROLLING_NODE_DECODE(ScrollingStateNode::Property::CurrentHorizontalSnapOffsetIndex, unsigned, setCurrentHorizontalSnapPointIndex);
316
    SCROLLING_NODE_DECODE(ScrollingStateNode::Property::CurrentVerticalSnapOffsetIndex, unsigned, setCurrentVerticalSnapPointIndex);
316
    SCROLLING_NODE_DECODE(ScrollingStateNode::Property::CurrentVerticalSnapOffsetIndex, unsigned, setCurrentVerticalSnapPointIndex);
317
#endif
317
#endif
Lines 544-566 bool ArgumentCoder<SnapOffset<float>>::decode(Decoder& decoder, SnapOffset<float a/Source/WebKit/Shared/RemoteLayerTree/RemoteScrollingCoordinatorTransaction.cpp_sec3
544
}
544
}
545
545
546
546
547
void ArgumentCoder<ScrollSnapOffsetsInfo<float>>::encode(Encoder& encoder, const ScrollSnapOffsetsInfo<float>& info)
547
void ArgumentCoder<FloatScrollSnapOffsetsInfo>::encode(Encoder& encoder, const FloatScrollSnapOffsetsInfo& info)
548
{
548
{
549
    encoder << info.horizontalSnapOffsets;
549
    encoder << info.horizontalSnapOffsets;
550
    encoder << info.verticalSnapOffsets;
550
    encoder << info.verticalSnapOffsets;
551
    encoder << info.horizontalSnapOffsetRanges;
551
    encoder << info.snapAreas;
552
    encoder << info.verticalSnapOffsetRanges;
553
}
552
}
554
553
555
bool ArgumentCoder<ScrollSnapOffsetsInfo<float>>::decode(Decoder& decoder, ScrollSnapOffsetsInfo<float>& info)
554
bool ArgumentCoder<FloatScrollSnapOffsetsInfo>::decode(Decoder& decoder, FloatScrollSnapOffsetsInfo& info)
556
{
555
{
557
    if (!decoder.decode(info.horizontalSnapOffsets))
556
    if (!decoder.decode(info.horizontalSnapOffsets))
558
        return false;
557
        return false;
559
    if (!decoder.decode(info.verticalSnapOffsets))
558
    if (!decoder.decode(info.verticalSnapOffsets))
560
        return false;
559
        return false;
561
    if (!decoder.decode(info.horizontalSnapOffsetRanges))
560
    if (!decoder.decode(info.snapAreas))
562
        return false;
563
    if (!decoder.decode(info.verticalSnapOffsetRanges))
564
        return false;
561
        return false;
565
    return true;
562
    return true;
566
}
563
}
- a/Source/WebKit/Shared/WebCoreArgumentCoders.cpp -26 lines
Lines 2805-2836 bool ArgumentCoder<ServiceWorkerOrClientIdentifier>::decode(Decoder& decoder, Se a/Source/WebKit/Shared/WebCoreArgumentCoders.cpp_sec1
2805
}
2805
}
2806
#endif
2806
#endif
2807
2807
2808
#if ENABLE(CSS_SCROLL_SNAP)
2809
2810
void ArgumentCoder<ScrollOffsetRange<float>>::encode(Encoder& encoder, const ScrollOffsetRange<float>& range)
2811
{
2812
    encoder << range.start;
2813
    encoder << range.end;
2814
}
2815
2816
auto ArgumentCoder<ScrollOffsetRange<float>>::decode(Decoder& decoder) -> Optional<WebCore::ScrollOffsetRange<float>>
2817
{
2818
    WebCore::ScrollOffsetRange<float> range;
2819
    float start;
2820
    if (!decoder.decode(start))
2821
        return WTF::nullopt;
2822
2823
    float end;
2824
    if (!decoder.decode(end))
2825
        return WTF::nullopt;
2826
2827
    range.start = start;
2828
    range.end = end;
2829
    return range;
2830
}
2831
2832
#endif
2833
2834
void ArgumentCoder<MediaSelectionOption>::encode(Encoder& encoder, const MediaSelectionOption& option)
2808
void ArgumentCoder<MediaSelectionOption>::encode(Encoder& encoder, const MediaSelectionOption& option)
2835
{
2809
{
2836
    encoder << option.displayName;
2810
    encoder << option.displayName;
- a/Source/WebKit/Shared/WebCoreArgumentCoders.h -9 lines
Lines 743-757 template<> struct ArgumentCoder<WebCore::ServiceWorkerOrClientIdentifier> { a/Source/WebKit/Shared/WebCoreArgumentCoders.h_sec1
743
743
744
#endif
744
#endif
745
745
746
#if ENABLE(CSS_SCROLL_SNAP)
747
748
template<> struct ArgumentCoder<WebCore::ScrollOffsetRange<float>> {
749
    static void encode(Encoder&, const WebCore::ScrollOffsetRange<float>&);
750
    static Optional<WebCore::ScrollOffsetRange<float>> decode(Decoder&);
751
};
752
753
#endif
754
755
template<> struct ArgumentCoder<WebCore::MediaSelectionOption> {
746
template<> struct ArgumentCoder<WebCore::MediaSelectionOption> {
756
    static void encode(Encoder&, const WebCore::MediaSelectionOption&);
747
    static void encode(Encoder&, const WebCore::MediaSelectionOption&);
757
    static Optional<WebCore::MediaSelectionOption> decode(Decoder&);
748
    static Optional<WebCore::MediaSelectionOption> decode(Decoder&);
- a/Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteScrollingCoordinatorProxyIOS.mm -4 / +2 lines
Lines 223-236 bool RemoteScrollingCoordinatorProxy::shouldSnapForMainFrameScrolling(ScrollEven a/Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteScrollingCoordinatorProxyIOS.mm_sec1
223
223
224
float RemoteScrollingCoordinatorProxy::closestSnapOffsetForMainFrameScrolling(ScrollEventAxis axis, float scrollDestination, float velocity, unsigned& currentIndex) const
224
float RemoteScrollingCoordinatorProxy::closestSnapOffsetForMainFrameScrolling(ScrollEventAxis axis, float scrollDestination, float velocity, unsigned& currentIndex) const
225
{
225
{
226
    ScrollingTreeNode* root = m_scrollingTree->rootNode();
226
    ScrollingTreeFrameScrollingNode* rootScrollingNode = m_scrollingTree->rootNode();
227
    ASSERT(root && root->isFrameScrollingNode());
228
    ScrollingTreeFrameScrollingNode* rootScrollingNode = static_cast<ScrollingTreeFrameScrollingNode*>(root);
229
    const auto& snapOffsetsInfo = rootScrollingNode->snapOffsetsInfo();
227
    const auto& snapOffsetsInfo = rootScrollingNode->snapOffsetsInfo();
230
228
231
    float scaledScrollDestination = scrollDestination / m_webPageProxy.displayedContentScale();
229
    float scaledScrollDestination = scrollDestination / m_webPageProxy.displayedContentScale();
232
    float rawClosestSnapOffset;
230
    float rawClosestSnapOffset;
233
    std::tie(rawClosestSnapOffset, currentIndex) = snapOffsetsInfo.closestSnapOffset(axis, scaledScrollDestination, velocity);
231
    std::tie(rawClosestSnapOffset, currentIndex) = snapOffsetsInfo.closestSnapOffset(axis, rootScrollingNode->layoutViewport().size(), scaledScrollDestination, velocity);
234
    return rawClosestSnapOffset * m_webPageProxy.displayedContentScale();
232
    return rawClosestSnapOffset * m_webPageProxy.displayedContentScale();
235
}
233
}
236
234
- a/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm -2 / +3 lines
Lines 106-121 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoi a/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm_sec1
106
    unsigned originalHorizontalSnapPosition = _scrollingTreeNodeDelegate->scrollingNode().currentHorizontalSnapPointIndex();
106
    unsigned originalHorizontalSnapPosition = _scrollingTreeNodeDelegate->scrollingNode().currentHorizontalSnapPointIndex();
107
    unsigned originalVerticalSnapPosition = _scrollingTreeNodeDelegate->scrollingNode().currentVerticalSnapPointIndex();
107
    unsigned originalVerticalSnapPosition = _scrollingTreeNodeDelegate->scrollingNode().currentVerticalSnapPointIndex();
108
108
109
    WebCore::FloatSize viewportSize(static_cast<float>(CGRectGetWidth([scrollView bounds])), static_cast<float>(CGRectGetHeight([scrollView bounds])));
109
    const auto& snapOffsetsInfo = _scrollingTreeNodeDelegate->scrollingNode().snapOffsetsInfo();
110
    const auto& snapOffsetsInfo = _scrollingTreeNodeDelegate->scrollingNode().snapOffsetsInfo();
110
    if (!snapOffsetsInfo.horizontalSnapOffsets.isEmpty()) {
111
    if (!snapOffsetsInfo.horizontalSnapOffsets.isEmpty()) {
111
        auto [potentialSnapPosition, index] = snapOffsetsInfo.closestSnapOffset(WebCore::ScrollEventAxis::Horizontal, horizontalTarget, velocity.x);
112
        auto [potentialSnapPosition, index] = snapOffsetsInfo.closestSnapOffset(WebCore::ScrollEventAxis::Horizontal, viewportSize, horizontalTarget, velocity.x);
112
        _scrollingTreeNodeDelegate->scrollingNode().setCurrentHorizontalSnapPointIndex(index);
113
        _scrollingTreeNodeDelegate->scrollingNode().setCurrentHorizontalSnapPointIndex(index);
113
        if (horizontalTarget >= 0 && horizontalTarget <= scrollView.contentSize.width)
114
        if (horizontalTarget >= 0 && horizontalTarget <= scrollView.contentSize.width)
114
            targetContentOffset->x = potentialSnapPosition;
115
            targetContentOffset->x = potentialSnapPosition;
115
    }
116
    }
116
117
117
    if (!snapOffsetsInfo.verticalSnapOffsets.isEmpty()) {
118
    if (!snapOffsetsInfo.verticalSnapOffsets.isEmpty()) {
118
        auto [potentialSnapPosition, index] = snapOffsetsInfo.closestSnapOffset(WebCore::ScrollEventAxis::Vertical, verticalTarget, velocity.x);
119
        auto [potentialSnapPosition, index] = snapOffsetsInfo.closestSnapOffset(WebCore::ScrollEventAxis::Vertical, viewportSize, verticalTarget, velocity.x);
119
        _scrollingTreeNodeDelegate->scrollingNode().setCurrentVerticalSnapPointIndex(index);
120
        _scrollingTreeNodeDelegate->scrollingNode().setCurrentVerticalSnapPointIndex(index);
120
        if (verticalTarget >= 0 && verticalTarget <= scrollView.contentSize.height)
121
        if (verticalTarget >= 0 && verticalTarget <= scrollView.contentSize.height)
121
            targetContentOffset->y = potentialSnapPosition;
122
            targetContentOffset->y = potentialSnapPosition;
- a/LayoutTests/ChangeLog +35 lines
Lines 1-3 a/LayoutTests/ChangeLog_sec1
1
2021-03-15  Martin Robinson  <mrobinson@webkit.org>
2
3
        [css-scroll-snap] Properly handle overflowing snap areas
4
        https://bugs.webkit.org/show_bug.cgi?id=223175
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        * css3/scroll-snap/scroll-snap-click-scrollbar-gutter.html: This test used snap areas that
9
        overflow the snapport, thus meant that it relied on non-spec compliant behavior. Rework it so
10
        that the snap areas do not overflow, maintaining the existing behavior.
11
        * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-then-horizontal.html: Ditto.
12
        * tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-overflow.html: Ditto.
13
14
2021-03-13  Martin Robinson  <mrobinson@webkit.org>
15
16
        Add basic (non-momentum) wheel event handling for scroll snap
17
        https://bugs.webkit.org/show_bug.cgi?id=222594
18
        Reviewed by Simon Fraser.
19
20
        * css3/scroll-snap/scroll-snap-wheel-event-expected.txt: Added.
21
        * css3/scroll-snap/scroll-snap-wheel-event.html: Added.
22
        * platform/ios-wk2/TestExpectations: Skip new test because it uses mouse event simulation.
23
        Move existing classification to better section as well.
24
        * platform/mac-wk1/fast/scrolling/latching/scroll-snap-latching-expected.txt: Rebased this previous failing test.
25
26
2021-03-13  Alexey Shvayka  <shvaikalesh@gmail.com>
27
28
        Cache cross-origin methods / accessors of Window and Location per lexical global object
29
        https://bugs.webkit.org/show_bug.cgi?id=222739
30
31
        Reviewed by Darin Adler.
32
33
        * http/tests/navigation/process-swap-window-open-expected.txt:
34
        * http/tests/navigation/process-swap-window-open.html:
35
1
2021-03-12  Said Abou-Hallawa  <said@apple.com>
36
2021-03-12  Said Abou-Hallawa  <said@apple.com>
2
37
3
        [GPU Process] inspector/canvas/memory.html fails when GPU rendering is enabled for 2D Canvas
38
        [GPU Process] inspector/canvas/memory.html fails when GPU rendering is enabled for 2D Canvas
- a/LayoutTests/imported/w3c/ChangeLog +25 lines
Lines 1-3 a/LayoutTests/imported/w3c/ChangeLog_sec1
1
2021-03-15  Martin Robinson  <mrobinson@webkit.org>
2
3
        [css-scroll-snap] Properly handle overflowing snap areas
4
        https://bugs.webkit.org/show_bug.cgi?id=223175
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        * web-platform-tests/css/css-scroll-snap/overflowing-snap-areas-expected.txt: Update expectations to
9
        show that this test is now passing.
10
11
2021-03-13  Alexey Shvayka  <shvaikalesh@gmail.com>
12
13
        Cache cross-origin methods / accessors of Window and Location per lexical global object
14
        https://bugs.webkit.org/show_bug.cgi?id=222739
15
16
        Reviewed by Darin Adler.
17
18
        * web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-caching-expected.txt: Added.
19
        * web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-caching.html: Added.
20
        * web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-common.js: Added.
21
        * web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-length-expected.txt: Added.
22
        * web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-length.html: Added.
23
        * web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-name-expected.txt: Added.
24
        * web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-name.html: Added.
25
1
2021-03-12  Manuel Rego Casasnovas  <rego@igalia.com>
26
2021-03-12  Manuel Rego Casasnovas  <rego@igalia.com>
2
27
3
        [selectors] :focus-visible matches body after keyboard event
28
        [selectors] :focus-visible matches body after keyboard event
- a/LayoutTests/css3/scroll-snap/scroll-snap-click-scrollbar-gutter.html -13 / +28 lines
Lines 34-54 a/LayoutTests/css3/scroll-snap/scroll-snap-click-scrollbar-gutter.html_sec1
34
                scroll-snap-type: both mandatory;
34
                scroll-snap-type: both mandatory;
35
            }
35
            }
36
36
37
            .block {
38
                height: 1000px;
39
                width: 250px;
40
                scroll-snap-align: start;
41
            }
42
43
            .horizontal-drawer {
37
            .horizontal-drawer {
44
                height: 100%;
38
                height: 100%;
45
                width: 2000px;
39
                width: 2000px;
46
            }
40
            }
47
41
48
            .horizontal-drawer .block {
42
            .horizontal-drawer > div {
49
                width: 1000px;
43
                float: left;
50
                height: 250px;
44
                width: 990px;
45
                height: 100%;
46
            }
47
48
            .horizontal-drawer > div.snap-point {
49
                scroll-snap-align: start;
50
                width: 10px;
51
             }
52
53
            #vertical-container > div {
54
                width: 100%;
55
                height: 990px;
56
            }
57
58
            #vertical-container > div.snap-point {
59
                scroll-snap-align: start;
60
                height: 10px;
51
            }
61
            }
62
52
        </style>
63
        </style>
53
        <script src="../../resources/js-test.js"></script>
64
        <script src="../../resources/js-test.js"></script>
54
        <script src="../../resources/ui-helper.js"></script>
65
        <script src="../../resources/ui-helper.js"></script>
Lines 87-99 a/LayoutTests/css3/scroll-snap/scroll-snap-click-scrollbar-gutter.html_sec2
87
    <body onload="onLoad();">
98
    <body onload="onLoad();">
88
        <div id="horizontal-container" class="container">
99
        <div id="horizontal-container" class="container">
89
            <div class="horizontal-drawer">
100
            <div class="horizontal-drawer">
90
                <div class="block" style="float: left; background: #80475E"></div>
101
                <div class="snap-point" style="background: #80475E"></div>
91
                <div class="block" style="width: 450px; float: left; background: #CC5A71"></div>
102
                <div></div>
103
                <div class="snap-point" style="background: #CC5A71"></div>
104
                <div></div>
92
            </div>
105
            </div>
93
        </div>
106
        </div>
94
        <div id="vertical-container" class="container">
107
        <div id="vertical-container" class="container">
95
            <div class="block" style="background: #80475E"></div>
108
            <div class="snap-point" style="background: #80475E"></div>
96
            <div class="block" style="height: 450px; background: #CC5A71"></div>
109
            <div></div>
110
            <div class="snap-point" style="background: #CC5A71"></div>
111
            <div></div>
97
        </div>
112
        </div>
98
        <p id="console"></p>
113
        <p id="console"></p>
99
        <script>
114
        <script>
- a/LayoutTests/css3/scroll-snap/scroll-snap-wheel-event-expected.txt +6 lines
Line 0 a/LayoutTests/css3/scroll-snap/scroll-snap-wheel-event-expected.txt_sec1
1
PASS horizontal mouse wheel event snapped
2
PASS vertical mouse wheel event snapped
3
PASS successfullyParsed is true
4
5
TEST COMPLETE
6
- a/LayoutTests/css3/scroll-snap/scroll-snap-wheel-event.html +80 lines
Line 0 a/LayoutTests/css3/scroll-snap/scroll-snap-wheel-event.html_sec1
1
<!DOCTYPE html>
2
<html>
3
    <head>
4
        <title>Simple wheel events should trigger scroll snapping</title>
5
        <style type="text/css">
6
            .container {
7
                height: 200px;
8
                width: 200px;
9
                overflow: auto;
10
                scroll-snap-type: both mandatory;
11
            }
12
13
            .horizontal-drawer {
14
                height: 100%;
15
                width: 500px;
16
            }
17
18
            .block {
19
                height: 100%;
20
                width: 200px;
21
                scroll-snap-align: start;
22
            }
23
        </style>
24
        <script src="../../resources/js-test.js"></script>
25
        <script src="../../resources/ui-helper.js"></script>
26
        <script>
27
        window.jsTestIsAsync = true;
28
29
        async function onLoad()
30
        {
31
            if (window.eventSender == undefined) {
32
                document.getElementById('console').innerText = "Simple wheel events should trigger scroll snapping";
33
                return;
34
            }
35
            try {
36
                eventSender.mouseMoveTo(20, 190);
37
                eventSender.mouseDown();
38
                eventSender.mouseMoveTo(80, 190);
39
                eventSender.mouseUp();
40
41
                eventSender.mouseScrollBy(-1, 0);
42
43
                let horizontalContainer = document.getElementById("horizontal-container");
44
                await UIHelper.waitForTargetScrollAnimationToSettle(horizontalContainer);
45
                expectTrue(horizontalContainer.scrollLeft == 200, "horizontal mouse wheel event snapped");
46
47
                eventSender.mouseMoveTo(190, 220);
48
                eventSender.mouseDown();
49
                eventSender.mouseMoveTo(190, 270);
50
                eventSender.mouseUp();
51
52
                eventSender.mouseScrollBy(0, -1);
53
54
                let verticalContainer = document.getElementById("vertical-container");
55
                await UIHelper.waitForTargetScrollAnimationToSettle(verticalContainer);
56
                expectTrue(verticalContainer.scrollTop == 185, "vertical mouse wheel event snapped");
57
            } catch (e) {
58
                console.log(e);
59
            } finally {
60
                finishJSTest();
61
            }
62
        }
63
        </script>
64
    </head>
65
    <body onload="onLoad();">
66
        <div id="horizontal-container" class="container">
67
            <div class="horizontal-drawer">
68
                <div class="block" style="float: left; background: #80475E"></div>
69
                <div class="block" style="float: left; background: #CC5A71"></div>
70
            </div>
71
        </div>
72
        <div id="vertical-container" class="container">
73
            <div class="block" style="background: #80475E"></div>
74
            <div class="block" style="background: #CC5A71"></div>
75
        </div>
76
        <p id="console"></p>
77
        <script>
78
        </script>
79
    </body>
80
</html>
- a/LayoutTests/http/tests/navigation/process-swap-window-open-expected.txt +5 lines
Lines 28-33 PASS w.close is an instance of Function a/LayoutTests/http/tests/navigation/process-swap-window-open-expected.txt_sec1
28
PASS w.focus is an instance of Function
28
PASS w.focus is an instance of Function
29
PASS w.blur is an instance of Function
29
PASS w.blur is an instance of Function
30
PASS w.postMessage is an instance of Function
30
PASS w.postMessage is an instance of Function
31
PASS w.close is w.close
32
PASS w.focus is w.focus
33
PASS w.blur is w.blur
34
PASS w.postMessage is w.postMessage
35
PASS w.postMessage.length is 1
31
PASS w.postMessage('test', '*') did not throw exception.
36
PASS w.postMessage('test', '*') did not throw exception.
32
PASS w.focus() did not throw exception.
37
PASS w.focus() did not throw exception.
33
PASS w.blur() did not throw exception.
38
PASS w.blur() did not throw exception.
- a/LayoutTests/http/tests/navigation/process-swap-window-open.html +5 lines
Lines 36-41 function runTest() { a/LayoutTests/http/tests/navigation/process-swap-window-open.html_sec1
36
    shouldBeType("w.focus", "Function");
36
    shouldBeType("w.focus", "Function");
37
    shouldBeType("w.blur", "Function");
37
    shouldBeType("w.blur", "Function");
38
    shouldBeType("w.postMessage", "Function");
38
    shouldBeType("w.postMessage", "Function");
39
    shouldBe("w.close", "w.close");
40
    shouldBe("w.focus", "w.focus");
41
    shouldBe("w.blur", "w.blur");
42
    shouldBe("w.postMessage", "w.postMessage");
43
    shouldBe("w.postMessage.length", "1");
39
    shouldNotThrow("w.postMessage('test', '*')");
44
    shouldNotThrow("w.postMessage('test', '*')");
40
    shouldNotThrow("w.focus()");
45
    shouldNotThrow("w.focus()");
41
    shouldNotThrow("w.blur()");
46
    shouldNotThrow("w.blur()");
- a/LayoutTests/imported/w3c/web-platform-tests/css/css-scroll-snap/overflowing-snap-areas-expected.txt -8 / +8 lines
Lines 1-13 a/LayoutTests/imported/w3c/web-platform-tests/css/css-scroll-snap/overflowing-snap-areas-expected.txt_sec1
1
1
2
PASS Snaps to the snap position if the snap area doesn't cover the snapport on x.
2
PASS Snaps to the snap position if the snap area doesn't cover the snapport on x.
3
FAIL Snaps to the snap position if the snap area covers the snapport on x on the right border. assert_equals: expected 2715 but got 200
3
PASS Snaps to the snap position if the snap area covers the snapport on x on the right border.
4
FAIL Snaps to the snap position if the snap area covers the snapport on x on the left border. assert_equals: expected 200 but got 2715
4
PASS Snaps to the snap position if the snap area covers the snapport on x on the left border.
5
PASS Snaps if the distance between the previous(400) and next(800) snap positions is smaller than snapport(500) on x.
5
PASS Snaps if the distance between the previous(400) and next(800) snap positions is smaller than snapport(500) on x.
6
PASS Snaps if the distance between the previous(400) and next(800) snap positions is smaller than snapport(500) on y.
6
PASS Snaps if the distance between the previous(400) and next(800) snap positions is smaller than snapport(500) on y.
7
FAIL Snap to current scroll position which is a valid snap position, as the snap area covers snapport on x and the distance between the previous(800) and next(1400) is larger than snapport(500). assert_equals: expected 900 but got 800
7
PASS Snap to current scroll position which is a valid snap position, as the snap area covers snapport on x and the distance between the previous(800) and next(1400) is larger than snapport(500).
8
FAIL Snap to current scroll position which is a valid snap position, as the snap area covers snapport on y and the distance between the previous(800) and next(1400) is larger than snapport(500). assert_equals: expected 900 but got 800
8
PASS Snap to current scroll position which is a valid snap position, as the snap area covers snapport on y and the distance between the previous(800) and next(1400) is larger than snapport(500).
9
FAIL Snap to current scroll position which is a valid snap position, as the snap area covers snapport on x and there is no subsequent snap positions. assert_equals: expected 1500 but got 1400
9
PASS Snap to current scroll position which is a valid snap position, as the snap area covers snapport on x and there is no subsequent snap positions.
10
FAIL Snap to current scroll position which is a valid snap position, as the snap area covers snapport on y and there is no subsequent snap positions. assert_equals: expected 1500 but got 1400
10
PASS Snap to current scroll position which is a valid snap position, as the snap area covers snapport on y and there is no subsequent snap positions.
11
FAIL Don't snap back even if scrollTo tries to scroll to positions which are outside of the scroll range and if a snap target element covers the snaport assert_equals: expected 3715 but got 2200
11
PASS Don't snap back even if scrollTo tries to scroll to positions which are outside of the scroll range and if a snap target element covers the snaport
12
FAIL Snap to current scroll position on x as the area is covering x axis.However, we snap to the specified snap position on y as the area is not covering y axis. assert_equals: expected 10 but got 0
12
PASS Snap to current scroll position on x as the area is covering x axis.However, we snap to the specified snap position on y as the area is not covering y axis.
13
13
- a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-caching-expected.txt +6 lines
Line 0 a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-caching-expected.txt_sec1
1
2
PASS Cross-origin Window methods are cached
3
PASS Cross-origin Window accessors are cached
4
PASS Cross-origin Location `replace` method is cached
5
PASS Cross-origin Location `href` setter is cached
6
- a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-caching.html +49 lines
Line 0 a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-caching.html_sec1
1
<!doctype html>
2
<meta charset=utf-8>
3
<title>Cross-origin methods and accessors are cached per Realm via[[CrossOriginPropertyDescriptorMap]]</title>
4
<link rel="help" href="https://html.spec.whatwg.org/multipage/browsers.html#crossorigingetownpropertyhelper-(-o,-p-)">
5
<script src="/resources/testharness.js"></script>
6
<script src="/resources/testharnessreport.js"></script>
7
<script src="/common/get-host-info.sub.js"></script>
8
<script src="cross-origin-objects-function-common.js"></script>
9
<div id=log></div>
10
<script>
11
"use strict";
12
13
promise_test(async t => {
14
    const w = await makeCrossOriginWindow(t);
15
    for (const {key} of crossOriginWindowMethods) {
16
        assert_equals(w[key], w[key], `w.${key} via [[Get]]`);
17
        const desc1 = Object.getOwnPropertyDescriptor(w, key);
18
        const desc2 = Object.getOwnPropertyDescriptor(w, key);
19
        assert_equals(desc1.value, desc2.value, `w.${key} via [[GetOwnProperty]]`);
20
    }
21
}, "Cross-origin Window methods are cached");
22
23
promise_test(async t => {
24
    const w = await makeCrossOriginWindow(t);
25
    for (const {key} of crossOriginWindowAccessors) {
26
        const desc1 = Object.getOwnPropertyDescriptor(w, key);
27
        const desc2 = Object.getOwnPropertyDescriptor(w, key);
28
        assert_equals(desc1.get, desc2.get, `w.${key} getter`);
29
        if (key === "location") {
30
            assert_equals(desc1.set, desc2.set, `w.${key} setter`);
31
        }
32
    }
33
}, "Cross-origin Window accessors are cached");
34
35
promise_test(async t => {
36
    const w = await makeCrossOriginWindow(t);
37
    assert_equals(w.location.replace, w.location.replace, "via [[Get]]");
38
    const desc1 = Object.getOwnPropertyDescriptor(w.location, "replace");
39
    const desc2 = Object.getOwnPropertyDescriptor(w.location, "replace");
40
    assert_equals(desc1.value, desc2.value, "via [[GetOwnProperty]]");
41
}, "Cross-origin Location `replace` method is cached");
42
43
promise_test(async t => {
44
    const w = await makeCrossOriginWindow(t);
45
    const desc1 = Object.getOwnPropertyDescriptor(w.location, "href");
46
    const desc2 = Object.getOwnPropertyDescriptor(w.location, "href");
47
    assert_equals(desc1.set, desc2.set);
48
}, "Cross-origin Location `href` setter is cached");
49
</script>
- a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-common.js +34 lines
Line 0 a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-common.js_sec1
1
"use strict";
2
3
const crossOriginWindowMethods = [
4
    {key: "close", length: 0},
5
    {key: "focus", length: 0},
6
    {key: "blur", length: 0},
7
    {key: "postMessage", length: 1},
8
];
9
10
const crossOriginWindowAccessors = [
11
    "window",
12
    "self",
13
    "location",
14
    "closed",
15
    "frames",
16
    "length",
17
    "top",
18
    "opener",
19
    "parent",
20
].map(key => ({key}));
21
22
const makeCrossOriginWindow = t => {
23
    const iframe = document.createElement("iframe");
24
    const path = location.pathname.slice(0, location.pathname.lastIndexOf("/")) + "/frame.html";
25
    iframe.src = get_host_info().HTTP_REMOTE_ORIGIN + path;
26
27
    return new Promise((resolve, reject) => {
28
        iframe.onload = () => { resolve(iframe.contentWindow); };
29
        iframe.onerror = reject;
30
31
        document.body.append(iframe);
32
        t.add_cleanup(() => { iframe.remove(); });
33
    });
34
};
- a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-length-expected.txt +6 lines
Line 0 a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-length-expected.txt_sec1
1
2
PASS Cross-origin Window methods have correct 'length'
3
PASS Cross-origin Window accessors have correct 'length'
4
PASS Cross-origin Location `replace` method has correct 'length'
5
PASS Cross-origin Location `href` setter has correct 'length'
6
- a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-length.html +45 lines
Line 0 a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-length.html_sec1
1
<!doctype html>
2
<meta charset=utf-8>
3
<title>Cross-origin methods and accessors are created with correct 'length' property</title>
4
<link rel="help" href="https://html.spec.whatwg.org/multipage/browsers.html#crossorigingetownpropertyhelper-(-o,-p-)">
5
<script src="/resources/testharness.js"></script>
6
<script src="/resources/testharnessreport.js"></script>
7
<script src="/common/get-host-info.sub.js"></script>
8
<script src="cross-origin-objects-function-common.js"></script>
9
<div id=log></div>
10
<script>
11
"use strict";
12
13
promise_test(async t => {
14
    const w = await makeCrossOriginWindow(t);
15
    for (const {key, length} of crossOriginWindowMethods) {
16
        assert_equals(w[key].length, length, `w.${key} via [[Get]]`);
17
        const desc = Object.getOwnPropertyDescriptor(w, key);
18
        assert_equals(desc.value.length, length, `w.${key} via [[GetOwnProperty]]`);
19
    }
20
}, "Cross-origin Window methods have correct 'length'");
21
22
promise_test(async t => {
23
    const w = await makeCrossOriginWindow(t);
24
    for (const {key} of crossOriginWindowAccessors) {
25
        const desc = Object.getOwnPropertyDescriptor(w, key);
26
        assert_equals(desc.get.length, 0, `w.${key}`);
27
        if (key === "location") {
28
            assert_equals(desc.set.length, 1, `w.${key}`);
29
        }
30
    }
31
}, "Cross-origin Window accessors have correct 'length'");
32
33
promise_test(async t => {
34
    const w = await makeCrossOriginWindow(t);
35
    assert_equals(w.location.replace.length, 1);
36
    const desc = Object.getOwnPropertyDescriptor(w.location, "replace");
37
    assert_equals(desc.value.length, 1);
38
}, "Cross-origin Location `replace` method has correct 'length'");
39
40
promise_test(async t => {
41
    const w = await makeCrossOriginWindow(t);
42
    const desc = Object.getOwnPropertyDescriptor(w.location, "href");
43
    assert_equals(desc.set.length, 1);
44
}, "Cross-origin Location `href` setter has correct 'length'");
45
</script>
- a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-name-expected.txt +6 lines
Line 0 a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-name-expected.txt_sec1
1
2
PASS Cross-origin Window methods have correct 'name'
3
PASS Cross-origin Window accessors have correct 'name'
4
PASS Cross-origin Location `replace` method has correct 'name'
5
PASS Cross-origin Location `href` setter has correct 'name'
6
- a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-name.html +45 lines
Line 0 a/LayoutTests/imported/w3c/web-platform-tests/html/browsers/origin/cross-origin-objects/cross-origin-objects-function-name.html_sec1
1
<!doctype html>
2
<meta charset=utf-8>
3
<title>Cross-origin methods and accessors are created with correct 'name' property</title>
4
<link rel="help" href="https://html.spec.whatwg.org/multipage/browsers.html#crossorigingetownpropertyhelper-(-o,-p-)">
5
<script src="/resources/testharness.js"></script>
6
<script src="/resources/testharnessreport.js"></script>
7
<script src="/common/get-host-info.sub.js"></script>
8
<script src="cross-origin-objects-function-common.js"></script>
9
<div id=log></div>
10
<script>
11
"use strict";
12
13
promise_test(async t => {
14
    const w = await makeCrossOriginWindow(t);
15
    for (const {key} of crossOriginWindowMethods) {
16
        assert_equals(w[key].name, key, `w.${key} via [[Get]]`);
17
        const desc = Object.getOwnPropertyDescriptor(w, key);
18
        assert_equals(desc.value.name, key, `w.${key} via [[GetOwnProperty]]`);
19
    }
20
}, "Cross-origin Window methods have correct 'name'");
21
22
promise_test(async t => {
23
    const w = await makeCrossOriginWindow(t);
24
    for (const {key} of crossOriginWindowAccessors) {
25
        const desc = Object.getOwnPropertyDescriptor(w, key);
26
        assert_equals(desc.get.name, `get ${key}`);
27
        if (key === "location") {
28
            assert_equals(desc.set.name, `set ${key}`);
29
        }
30
    }
31
}, "Cross-origin Window accessors have correct 'name'");
32
33
promise_test(async t => {
34
    const w = await makeCrossOriginWindow(t);
35
    assert_equals(w.location.replace.name, "replace");
36
    const desc = Object.getOwnPropertyDescriptor(w.location, "replace");
37
    assert_equals(desc.value.name, "replace");
38
}, "Cross-origin Location `replace` method has correct 'name'");
39
40
promise_test(async t => {
41
    const w = await makeCrossOriginWindow(t);
42
    const desc = Object.getOwnPropertyDescriptor(w.location, "href");
43
    assert_equals(desc.set.name, "set href");
44
}, "Cross-origin Location `href` setter has correct 'name'");
45
</script>
- a/LayoutTests/platform/ios-wk2/TestExpectations -1 / +2 lines
Lines 137-143 scrollbars/scrolling-by-page-on-keyboard-spacebar.html [ Failure ] a/LayoutTests/platform/ios-wk2/TestExpectations_sec1
137
scrollbars/scrollbars-on-positioned-content.html [ Failure ]
137
scrollbars/scrollbars-on-positioned-content.html [ Failure ]
138
css3/scroll-snap/scroll-padding-mainframe-paging.html [ Failure ]
138
css3/scroll-snap/scroll-padding-mainframe-paging.html [ Failure ]
139
css3/scroll-snap/scroll-padding-overflow-paging.html [ Failure ]
139
css3/scroll-snap/scroll-padding-overflow-paging.html [ Failure ]
140
css3/scroll-snap/scroll-snap-click-scrollbar-gutter.html [ Failure ]
141
140
142
# SVG tests that time out (these require EventSender)
141
# SVG tests that time out (these require EventSender)
143
svg/animations/animVal-basics.html
142
svg/animations/animVal-basics.html
Lines 933-938 editing/selection/select-out-of-floated-non-editable-09.html [ Skip ] a/LayoutTests/platform/ios-wk2/TestExpectations_sec2
933
editing/selection/select-out-of-floated-non-editable-10.html [ Skip ]
932
editing/selection/select-out-of-floated-non-editable-10.html [ Skip ]
934
editing/selection/select-out-of-floated-non-editable-11.html [ Skip ]
933
editing/selection/select-out-of-floated-non-editable-11.html [ Skip ]
935
editing/selection/select-out-of-floated-non-editable-12.html [ Skip ]
934
editing/selection/select-out-of-floated-non-editable-12.html [ Skip ]
935
css3/scroll-snap/scroll-snap-click-scrollbar-gutter.html [ Skip ]
936
css3/scroll-snap/scroll-snap-wheel-event.html [ Skip ]
936
937
937
webkit.org/b/192088 media/no-fullscreen-when-hidden.html [ Failure Pass ]
938
webkit.org/b/192088 media/no-fullscreen-when-hidden.html [ Failure Pass ]
938
939
- a/LayoutTests/platform/mac-wk1/fast/scrolling/latching/scroll-snap-latching-expected.txt -1 / +1 lines
Lines 4-10 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE a/LayoutTests/platform/mac-wk1/fast/scrolling/latching/scroll-snap-latching-expected.txt_sec1
4
4
5
5
6
PASS overflowScrollEventCount > 0 is true
6
PASS overflowScrollEventCount > 0 is true
7
FAIL windowScrollEventCount should be 0. Was 7.
7
FAIL windowScrollEventCount should be 0. Was 11.
8
PASS successfullyParsed is true
8
PASS successfullyParsed is true
9
9
10
TEST COMPLETE
10
TEST COMPLETE
- a/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-then-horizontal.html -1 / +2 lines
Lines 4-9 a/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-then-horizontal.html_sec1
4
        <style>
4
        <style>
5
            html {
5
            html {
6
                scroll-snap-type: y mandatory;
6
                scroll-snap-type: y mandatory;
7
                margin: 0;
7
            }
8
            }
8
            .verticalGallery {
9
            .verticalGallery {
9
                width: 100vw;
10
                width: 100vw;
Lines 12-18 a/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-then-horizontal.html_sec2
12
                padding: 0;
13
                padding: 0;
13
            }
14
            }
14
            .colorBox {
15
            .colorBox {
15
                height: 100vh;
16
                height: 90vh;
16
                width: 100vw;
17
                width: 100vw;
17
                float: left;
18
                float: left;
18
                scroll-snap-align: start;
19
                scroll-snap-align: start;
- a/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-overflow.html -7 / +2 lines
Lines 13-33 a/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-overflow.html_sec1
13
                position: absolute;
13
                position: absolute;
14
                top: 0;
14
                top: 0;
15
                left: 0;
15
                left: 0;
16
                overflow-x: none;
17
                overflow-y: scroll;
16
                overflow-y: scroll;
18
                scroll-snap-type: y proximity;
17
                scroll-snap-type: y proximity;
19
                -webkit-scroll-snap-type: proximity;
20
                scroll-snap-type: proximity;
21
                opacity: 0.5;
18
                opacity: 0.5;
22
            }
19
            }
23
20
24
            .area {
21
            .area {
25
                height: 600px;
22
                height: 100%;
26
                width: 600px;
23
                width: 100%;
27
                float: left;
24
                float: left;
28
                scroll-snap-align: start;
25
                scroll-snap-align: start;
29
                -webkit-scroll-snap-coordinate: 0 0;
30
                scroll-snap-coordinate: 0 0;
31
            }
26
            }
32
        </style>
27
        </style>
33
        <script>
28
        <script>

Return to Bug 223175