Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix svg graphics element tests #227

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/gh-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ jobs:
uses: actions/configure-pages@v3
- name: Install Node.js dependencies
run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true"
- name: Build
run: "npm run build"
- name: Test build
run: "npm run build -- --mode test"
- name: Checkout WPT
run: "npm run test-setup"
- name: WPT hosts
Expand All @@ -57,6 +57,8 @@ jobs:
run: "npm run test:compare"
- name: Test results summary
run: echo "Passed $(grep -c '^PASS' ./test/report/summary.txt) of $(grep -c '^' ./test/report/summary.txt) tests" >> $GITHUB_STEP_SUMMARY
- name: Build
run: "npm run build"
- name: Clean build files
run: "rm -rf node_modules test/wpt"
- name: Upload artifact
Expand Down
64 changes: 58 additions & 6 deletions src/scroll-timeline-base.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ export function measureSource (source) {

/**
* Measure subject element relative to source
* @param {HTMLElement} source
* @param {HTMLElement|SVGElement} source
* @param {HTMLElement|undefined} subject
* @param subject
*/
Expand All @@ -201,18 +201,70 @@ export function measureSubject(source, subject) {
let node = subject;
const ancestor = source.offsetParent;
while (node && node != ancestor) {
left += node.offsetLeft;
top += node.offsetTop;
node = node.offsetParent;
if (node instanceof SVGElement) {
let rootSvgElement = node.ownerSVGElement;
while (rootSvgElement.ownerSVGElement)
rootSvgElement = rootSvgElement.ownerSVGElement;

const matrix = node.getCTM();
const bbox = node.getBBox();
let point = rootSvgElement.createSVGPoint();
point.x = bbox.x;
point.y = bbox.y;

// Position relative to svg-element
const nodePosition = point.matrixTransform(matrix);
const svgParent = rootSvgElement.parentElement;
const svgLeft = rootSvgElement.getBoundingClientRect().left - svgParent.getBoundingClientRect().left;
const svgTop = rootSvgElement.getBoundingClientRect().top - svgParent.getBoundingClientRect().top;
left += svgLeft + nodePosition.x;
top += svgTop + nodePosition.y;
node = svgParent;
} else {
left += node.offsetLeft;
top += node.offsetTop;
if (!node.offsetParent) {
// The top level element (body) does not have an offsetParent, and no offsetTop/Left
// If the body has margins, they need to be added
const style = getComputedStyle(node);
top += parseInt(style.marginTop);
left += parseInt(style.marginLeft);
}
node = node.offsetParent;
}
}
left -= source.offsetLeft + source.clientLeft;
top -= source.offsetTop + source.clientTop;

let offsetWidth, offsetHeight
if (subject instanceof SVGElement) {
let rootSvgElement = subject.ownerSVGElement;
while (rootSvgElement.ownerSVGElement)
rootSvgElement = rootSvgElement.ownerSVGElement;

const matrix = subject.getCTM();
const bbox = subject.getBBox();
let topLeftPoint = rootSvgElement.createSVGPoint();
topLeftPoint.x = bbox.x;
topLeftPoint.y = bbox.y;
let bottomRightPoint = rootSvgElement.createSVGPoint();
bottomRightPoint.x = bbox.x + bbox.width;
bottomRightPoint.y = bbox.y + bbox.height;

const tlPosition = topLeftPoint.matrixTransform(matrix);
const brPosition = bottomRightPoint.matrixTransform(matrix);
offsetWidth = Math.abs(brPosition.x - tlPosition.x);
offsetHeight = Math.abs(brPosition.y - tlPosition.y);
} else {
offsetWidth = subject.offsetWidth;
offsetHeight = subject.offsetHeight;
}
const style = getComputedStyle(subject);
return {
top,
left,
offsetWidth: subject.offsetWidth,
offsetHeight: subject.offsetHeight,
offsetWidth,
offsetHeight,
fontSize: style.fontSize,
};
}
Expand Down
14 changes: 6 additions & 8 deletions src/scroll-timeline-css-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -248,22 +248,20 @@ export class StyleParser {
// Add 1s as duration to fix this.
if(hasAnimationTimeline) {
if(!this.hasDuration(shorthand)) {

let previousShorthand = shorthand
// `auto` also is valid duration. Older browsers can’t always
// handle it properly, so we remove it from the shorthand.
if (this.hasAutoDuration(shorthand)) {
rule.block.contents = rule.block.contents.replace(
'auto',
' '
);
shorthand = previousShorthand.replace('auto', ' ')
rule.block.contents = rule.block.contents.replace(previousShorthand, shorthand);
previousShorthand = shorthand
}

// TODO: Should keep track of whether duration is artificial or not,
// so that we can later track that we need to update timing to
// properly see duration as 'auto' for the polyfill.
rule.block.contents = rule.block.contents.replace(
shorthand, " 1s " + shorthand
);
shorthand = " 1s " + previousShorthand
rule.block.contents = rule.block.contents.replace(previousShorthand, shorthand);
shouldReplacePart = true;
}
}
Expand Down
37 changes: 37 additions & 0 deletions test/entry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import '../src/index.js'
// The polyfill is dependent on the animationstart event for polyfilling animations declared in css.
// This causes timing issues when running some wpt tests that wait for animation.ready.
// The tests might run before the animations are polyfilled, making them flaky.

// The following code delays a selected list of tests until animations are polyfilled.

// List of names of tests that should wait for animationstart
const cssAnimationTests = [
'View timeline attached to SVG graphics element'
]

const animationsStarted = new Promise((resolve) => {
window.addEventListener('animationstart', () => {
setTimeout(() => resolve(), 1);
});
})

// Proxy the promise_test function
let nativePromiseTest;
Reflect.defineProperty(window, 'promise_test', {
get() {
return (func, name, properties) => {
if (cssAnimationTests.includes(name)) {
// Wait for animationstart before starting tests
return nativePromiseTest.call(null, async (...args) => {
await animationsStarted;
return func.call(null, ...args);
}, name, properties);
} else {
nativePromiseTest.call(null, func, name, properties);
}
};
}, set(v) {
nativePromiseTest = v;
}
});
20 changes: 10 additions & 10 deletions test/expected.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ FAIL /scroll-animations/css/animation-timeline-computed.html Property animation-
FAIL /scroll-animations/css/animation-timeline-computed.html Property animation-timeline value 'view(1px y)'
FAIL /scroll-animations/css/animation-timeline-computed.html Property animation-timeline value 'view(y auto)'
FAIL /scroll-animations/css/animation-timeline-computed.html Property animation-timeline value 'view(y auto auto)'
FAIL /scroll-animations/css/animation-timeline-deferred.html Animation.timeline returns attached timeline
PASS /scroll-animations/css/animation-timeline-deferred.html Animation.timeline returns attached timeline
FAIL /scroll-animations/css/animation-timeline-deferred.html Animation.timeline returns null for inactive deferred timeline
FAIL /scroll-animations/css/animation-timeline-deferred.html Animation.timeline returns null for inactive (overattached) deferred timeline
FAIL /scroll-animations/css/animation-timeline-ignored.tentative.html Changing animation-timeline changes the timeline (sanity check)
Expand Down Expand Up @@ -307,7 +307,7 @@ FAIL /scroll-animations/css/scroll-timeline-name-shadow.html Outer animation can
FAIL /scroll-animations/css/scroll-timeline-name-shadow.html Inner animation can see scroll timeline defined by ::part
FAIL /scroll-animations/css/scroll-timeline-name-shadow.html Slotted element can see scroll timeline within the shadow
PASS /scroll-animations/css/scroll-timeline-nearest-dirty.html Unrelated style mutation does not affect anonymous timeline
FAIL /scroll-animations/css/scroll-timeline-nearest-with-absolute-positioned-element.html Resolving scroll(nearest) for an absolutely positioned element
PASS /scroll-animations/css/scroll-timeline-nearest-with-absolute-positioned-element.html Resolving scroll(nearest) for an absolutely positioned element
FAIL /scroll-animations/css/scroll-timeline-paused-animations.html Test that the scroll animation is paused
FAIL /scroll-animations/css/scroll-timeline-paused-animations.html Test that the scroll animation is paused by updating animation-play-state
FAIL /scroll-animations/css/scroll-timeline-range-animation.html Animation with ranges [initial, initial]
Expand Down Expand Up @@ -405,15 +405,15 @@ PASS /scroll-animations/css/timeline-scope-parsing.tentative.html e.style['timel
PASS /scroll-animations/css/timeline-scope-parsing.tentative.html e.style['timeline-scope'] = "rgb(1, 2, 3)" should not set the property value
PASS /scroll-animations/css/timeline-scope-parsing.tentative.html e.style['timeline-scope'] = "#fefefe" should not set the property value
FAIL /scroll-animations/css/timeline-scope.html Descendant can attach to deferred timeline
PASS /scroll-animations/css/timeline-scope.html Deferred timeline with no attachments
FAIL /scroll-animations/css/timeline-scope.html Inner timeline does not interfere with outer timeline
PASS /scroll-animations/css/timeline-scope.html Deferred timeline with two attachments
FAIL /scroll-animations/css/timeline-scope.html Deferred timeline with no attachments
PASS /scroll-animations/css/timeline-scope.html Inner timeline does not interfere with outer timeline
FAIL /scroll-animations/css/timeline-scope.html Deferred timeline with two attachments
FAIL /scroll-animations/css/timeline-scope.html Dynamically re-attaching
FAIL /scroll-animations/css/timeline-scope.html Dynamically detaching
FAIL /scroll-animations/css/timeline-scope.html Removing/inserting element with attaching timeline
FAIL /scroll-animations/css/timeline-scope.html Ancestor attached element becoming display:none/block
FAIL /scroll-animations/css/timeline-scope.html A deferred timeline appearing dynamically in the ancestor chain
FAIL /scroll-animations/css/timeline-scope.html Animations prefer non-deferred timelines
PASS /scroll-animations/css/timeline-scope.html Animations prefer non-deferred timelines
FAIL /scroll-animations/css/view-timeline-animation-range-update.tentative.html Ensure that animation is updated on a style change
FAIL /scroll-animations/css/view-timeline-animation.html Default view-timeline
FAIL /scroll-animations/css/view-timeline-animation.html Horizontal view-timeline
Expand Down Expand Up @@ -1032,7 +1032,7 @@ FAIL /scroll-animations/view-timelines/get-keyframes-with-timeline-offset.html C
FAIL /scroll-animations/view-timelines/get-keyframes-with-timeline-offset.html Retain specified ordering of keyframes with timeline offsets
FAIL /scroll-animations/view-timelines/get-keyframes-with-timeline-offset.html Include unreachable keyframes
FAIL /scroll-animations/view-timelines/get-keyframes-with-timeline-offset.html Mix of computed and timeline offsets.
FAIL /scroll-animations/view-timelines/inline-subject.html View timeline attached to SVG graphics element
TIMEOUT /scroll-animations/view-timelines/inline-subject.html View timeline attached to SVG graphics element
FAIL /scroll-animations/view-timelines/inline-view-timeline-current-time.tentative.html View timeline with start and end scroll offsets that do not align with the scroll boundaries
FAIL /scroll-animations/view-timelines/inline-view-timeline-current-time.tentative.html View timeline does not clamp starting scroll offset at 0
PASS /scroll-animations/view-timelines/inline-view-timeline-current-time.tentative.html View timeline does not clamp end scroll offset at max scroll
Expand All @@ -1044,9 +1044,9 @@ FAIL /scroll-animations/view-timelines/sticky/view-timeline-sticky-offscreen-4.h
FAIL /scroll-animations/view-timelines/sticky/view-timeline-sticky-offscreen-5.html View timeline bottom-sticky before entry and top-sticky after exit.
FAIL /scroll-animations/view-timelines/sticky/view-timeline-sticky-offscreen-6.html View timeline target > viewport, bottom-sticky during entry and top-sticky during exit.
FAIL /scroll-animations/view-timelines/sticky/view-timeline-sticky-offscreen-7.html View timeline target > viewport, bottom-sticky and top-sticky during contain.
FAIL /scroll-animations/view-timelines/svg-graphics-element-001.html View timeline attached to SVG graphics element
FAIL /scroll-animations/view-timelines/svg-graphics-element-002.html View timeline attached to SVG graphics element
FAIL /scroll-animations/view-timelines/svg-graphics-element-003.html View timeline attached to SVG graphics element
PASS /scroll-animations/view-timelines/svg-graphics-element-001.html View timeline attached to SVG graphics element
PASS /scroll-animations/view-timelines/svg-graphics-element-002.html View timeline attached to SVG graphics element
PASS /scroll-animations/view-timelines/svg-graphics-element-003.html View timeline attached to SVG graphics element
FAIL /scroll-animations/view-timelines/timeline-offset-in-keyframe.html Timeline offsets in programmatic keyframes
FAIL /scroll-animations/view-timelines/timeline-offset-in-keyframe.html String offsets in programmatic keyframes
PASS /scroll-animations/view-timelines/timeline-offset-in-keyframe.html Invalid timeline offset in programmatic keyframe throws
Expand Down
47 changes: 24 additions & 23 deletions vite.config.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
import { resolve } from 'path'
import { defineConfig } from 'vite'

export default defineConfig({
build: {
sourcemap: true,
lib: {
// Could also be a dictionary or array of multiple entry points
entry: resolve(__dirname, 'src/index.js'),
name: 'ScrollTimeline',
// the proper extensions will be added
fileName: (format, entryAlias) => `scroll-timeline${format=='iife'?'':'-' + format}.js`,
formats: ['iife'],
},
minify: 'terser',
terserOptions: {
keep_classnames: /^((View|Scroll)Timeline)|CSS.*$/
},
rollupOptions: {
output: {
// Provide global variables to use in the UMD build
// for externalized deps
globals: {
},
export default defineConfig(({ mode }) => {
return {
build: {
sourcemap: true,
lib: {
// Could also be a dictionary or array of multiple entry points
entry: resolve(__dirname, mode === 'test' ? 'test/entry.js' : 'src/index.js'),
name: 'ScrollTimeline',
// the proper extensions will be added
fileName: (format, entryAlias) => `scroll-timeline${format == 'iife' ? '' : '-' + format}.js`,
formats: ['iife'],
},
}
},
minify: 'terser',
terserOptions: {
keep_classnames: /^((View|Scroll)Timeline)|CSS.*$/
},
rollupOptions: {
output: {
// Provide global variables to use in the UMD build
// for externalized deps
globals: {},
},
}
},
};
})
Loading