Skip to content

Commit 2341828

Browse files
committed
refactor: use CSS path() to replace svg <clipPath>
1 parent c3a5916 commit 2341828

File tree

4 files changed

+16
-39
lines changed

4 files changed

+16
-39
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@ ASS.js uses many Web APIs to render subtitles, some features will be disabled if
128128

129129
| Feature | Web API | Chrome | Firefox | Safari |
130130
| - | - | - | - | - |
131-
| `\[i]clip` | [clip-path](https://caniuse.com/css-clip-path) | 55 | 54 | 13.1 |
132131
| Auto resize | [ResizeObserver](https://caniuse.com/resizeobserver) | 64 | 69 | 13.1 |
132+
| `\[i]clip` | [clip-path](https://caniuse.com/css-clip-path) and [path()](https://caniuse.com/mdn-css_types_basic-shape_path) | 88 | 97 | 13.1 |
133133
| Animations (`\t`) | [registerProperty()](https://caniuse.com/mdn-api_css_registerproperty_static) | 78 | 128 | 16.4 |
134134
| `\q0` | [text-wrap: balance](https://caniuse.com/css-text-wrap-balance) | 114 | 121 | 17.5 |
135135
| BorderStyle=3 with `\bord0` | [@container](https://caniuse.com/mdn-css_at-rules_container_style_queries_for_custom_properties) | 111 | - | 18.0 |

src/index.js

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { compile } from 'ass-compiler';
33
import { setKeyframes } from './renderer/animation.js';
44
import { $fixFontSize } from './renderer/font-size.js';
55
import { clear, createResize, createPlay, createPause, createSeek } from './internal.js';
6-
import { createSVGEl, addGlobalStyle, uuid } from './utils.js';
6+
import { addGlobalStyle } from './utils.js';
77

88
/**
99
* @typedef {Object} ASSOption
@@ -26,10 +26,6 @@ export default class ASS {
2626
video: null,
2727
/** the box to display subtitles */
2828
box: document.createElement('div'),
29-
/** use for \clip */
30-
svg: createSVGEl('svg'),
31-
/** use for \clip */
32-
defs: createSVGEl('defs'),
3329
/**
3430
* video resize observer
3531
* @type {ResizeObserver}
@@ -117,7 +113,6 @@ export default class ASS {
117113
};
118114
this.#store.styles = styles;
119115
this.#store.dialogues = dialogues.map((dia) => Object.assign(dia, {
120-
id: `ASS-${uuid()}`,
121116
align: {
122117
// 0: left, 1: center, 2: right
123118
h: (dia.alignment + 2) % 3,
@@ -128,12 +123,7 @@ export default class ASS {
128123

129124
container.append($fixFontSize);
130125

131-
const { svg, defs, scriptRes, box } = this.#store;
132-
svg.setAttributeNS(null, 'viewBox', `0 0 ${scriptRes.width} ${scriptRes.height}`);
133-
134-
svg.append(defs);
135-
container.append(svg);
136-
126+
const { box } = this.#store;
137127
box.className = 'ASS-box';
138128
container.append(box);
139129

@@ -168,7 +158,7 @@ export default class ASS {
168158
* @returns {ASS}
169159
*/
170160
destroy() {
171-
const { video, box, svg, observer } = this.#store;
161+
const { video, box, observer } = this.#store;
172162
this.#pause();
173163
clear(this.#store);
174164
video.removeEventListener('play', this.#play);
@@ -178,7 +168,6 @@ export default class ASS {
178168
video.removeEventListener('seeking', this.#seek);
179169

180170
$fixFontSize.remove();
181-
svg.remove();
182171
box.remove();
183172
observer.unobserve(this.#store.video);
184173

src/internal.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export function createPause(store) {
7979
}
8080

8181
export function createResize(that, store) {
82-
const { video, box, svg, layoutRes } = store;
82+
const { video, box, layoutRes } = store;
8383
return function resize() {
8484
const cw = video.clientWidth;
8585
const ch = video.clientHeight;
@@ -109,11 +109,9 @@ export function createResize(that, store) {
109109
store.height = bh;
110110
store.resampledRes = { width: rw, height: rh };
111111

112-
const cssText = `width:${bw}px;height:${bh}px;top:${(ch - bh) / 2}px;left:${(cw - bw) / 2}px;`;
113-
box.style.cssText = cssText;
112+
box.style.cssText = `width:${bw}px;height:${bh}px;top:${(ch - bh) / 2}px;left:${(cw - bw) / 2}px;`;
114113
box.style.setProperty('--ass-scale', store.scale);
115114
box.style.setProperty('--ass-scale-stroke', store.sbas ? store.scale : 1);
116-
svg.style.cssText = cssText;
117115

118116
createSeek(store)();
119117
};

src/renderer/clip.js

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { createSVGEl } from '../utils.js';
2-
31
export function createRectClip(clip, sw, sh) {
2+
if (!clip.dots) return '';
43
const { x1, y1, x2, y2 } = clip.dots;
54
const polygon = [[x1, y1], [x1, y2], [x2, y2], [x2, y1], [x1, y1]]
65
.map(([x, y]) => [x / sw, y / sh])
@@ -10,38 +9,29 @@ export function createRectClip(clip, sw, sh) {
109
return `polygon(evenodd, ${polygon})`;
1110
}
1211

13-
function addClipPath($defs, clip, id, sw, sh) {
14-
if (!clip.drawing || $defs.querySelector(`#${id}`)) return;
12+
function createPathClip(clip, sw, sh, store) {
13+
if (!clip.drawing) return '';
14+
const scale = store.scale / (1 << (clip.scale - 1));
1515
let d = clip.drawing.instructions.map(({ type, points }) => (
16-
type + points.map(({ x, y }) => `${x / sw},${y / sh}`).join(',')
16+
type + points.map(({ x, y }) => `${x * scale},${y * scale}`).join(',')
1717
)).join('');
18-
const scale = 1 / (1 << (clip.scale - 1));
1918
if (clip.inverse) {
20-
d += `M0,0L0,${scale},${scale},${scale},${scale},0,0,0Z`;
19+
d += `M0,0L0,${sh},${sw},${sh},${sw},0,0,0Z`;
2120
}
22-
const $clipPath = createSVGEl('clipPath', [
23-
['id', id],
24-
['clipPathUnits', 'objectBoundingBox'],
25-
]);
26-
$clipPath.append(createSVGEl('path', [
27-
['d', d],
28-
['transform', `scale(${scale})`],
29-
['clip-rule', 'evenodd'],
30-
]));
31-
$defs.append($clipPath);
21+
return `path(evenodd, "${d}")`;
3222
}
3323

3424
export function getClipPath(dialogue, store) {
35-
const { id, clip } = dialogue;
25+
const { clip } = dialogue;
3626
if (!clip) return {};
3727
const { width, height } = store.scriptRes;
38-
addClipPath(store.defs, clip, id, width, height);
3928
const $clipArea = document.createElement('div');
4029
store.box.insertBefore($clipArea, dialogue.$div);
4130
$clipArea.append(dialogue.$div);
4231
$clipArea.className = 'ASS-clip-area';
4332
$clipArea.style.clipPath = clip.dots
4433
? createRectClip(clip, width, height)
45-
: `url(#${id})`;
34+
: createPathClip(clip, width, height, store);
35+
4636
return { $div: $clipArea };
4737
}

0 commit comments

Comments
 (0)