@@ -29,6 +29,7 @@ import {
29
29
type FlatString = string & {
30
30
__flat : true ;
31
31
} ;
32
+ type GetComputedStyle = typeof window . getComputedStyle ;
32
33
33
34
/**
34
35
* interface for an options-bag where `window.getComputedStyle` can be mocked
@@ -43,7 +44,7 @@ export interface ComputeTextAlternativeOptions {
43
44
/**
44
45
* mock window.getComputedStyle. Needs `content`, `display` and `visibility`
45
46
*/
46
- getComputedStyle ?: typeof window . getComputedStyle ;
47
+ getComputedStyle ?: GetComputedStyle ;
47
48
/**
48
49
* Set to `true` if you want to include hidden elements in the accessible name and description computation.
49
50
* Skips 2A in https://w3c.github.io/accname/#computation-steps.
@@ -69,7 +70,7 @@ function asFlatString(s: string): FlatString {
69
70
*/
70
71
function isHidden (
71
72
node : Node ,
72
- getComputedStyleImplementation : typeof window . getComputedStyle ,
73
+ getComputedStyleImplementation : GetComputedStyle ,
73
74
) : node is Element {
74
75
if ( ! isElement ( node ) ) {
75
76
return false ;
@@ -338,6 +339,10 @@ export function computeTextAlternative(
338
339
options : ComputeTextAlternativeOptions = { } ,
339
340
) : string {
340
341
const consultedNodes = new SetLike < Node > ( ) ;
342
+ const computedStyles =
343
+ typeof Map === "undefined"
344
+ ? undefined
345
+ : new Map < Element , CSSStyleDeclaration > ( ) ;
341
346
342
347
const window = safeWindow ( root ) ;
343
348
const {
@@ -348,9 +353,36 @@ export function computeTextAlternative(
348
353
// window.getComputedStyle(elementFromAnotherWindow) or if I don't bind it
349
354
// the type declarations don't require a `this`
350
355
// eslint-disable-next-line no-restricted-properties
351
- getComputedStyle = window . getComputedStyle . bind ( window ) ,
356
+ getComputedStyle : uncachedGetComputedStyle = window . getComputedStyle . bind (
357
+ window ,
358
+ ) ,
352
359
hidden = false ,
353
360
} = options ;
361
+ const getComputedStyle : GetComputedStyle = (
362
+ el ,
363
+ pseudoElement ,
364
+ ) : CSSStyleDeclaration => {
365
+ // We don't cache the pseudoElement styles and calls with psuedo elements
366
+ // should use the uncached version instead
367
+ if ( pseudoElement !== undefined ) {
368
+ throw new Error (
369
+ "use uncachedGetComputedStyle directly for pseudo elements" ,
370
+ ) ;
371
+ }
372
+ // If Map is not available, it is probably faster to just use the uncached
373
+ // version since a polyfill lookup would be O(n) instead of O(1) and
374
+ // the getComputedStyle function in those environments(e.g. IE11) is fast
375
+ if ( computedStyles === undefined ) {
376
+ return uncachedGetComputedStyle ( el ) ;
377
+ }
378
+ const cachedStyles = computedStyles . get ( el ) ;
379
+ if ( cachedStyles ) {
380
+ return cachedStyles ;
381
+ }
382
+ const style = uncachedGetComputedStyle ( el , pseudoElement ) ;
383
+ computedStyles . set ( el , style ) ;
384
+ return style ;
385
+ } ;
354
386
355
387
// 2F.i
356
388
function computeMiscTextAlternative (
@@ -359,7 +391,7 @@ export function computeTextAlternative(
359
391
) : string {
360
392
let accumulatedText = "" ;
361
393
if ( isElement ( node ) && computedStyleSupportsPseudoElements ) {
362
- const pseudoBefore = getComputedStyle ( node , "::before" ) ;
394
+ const pseudoBefore = uncachedGetComputedStyle ( node , "::before" ) ;
363
395
const beforeContent = getTextualContent ( pseudoBefore ) ;
364
396
accumulatedText = `${ beforeContent } ${ accumulatedText } ` ;
365
397
}
@@ -384,9 +416,8 @@ export function computeTextAlternative(
384
416
// trailing separator for wpt tests
385
417
accumulatedText += `${ separator } ${ result } ${ separator } ` ;
386
418
} ) ;
387
-
388
419
if ( isElement ( node ) && computedStyleSupportsPseudoElements ) {
389
- const pseudoAfter = getComputedStyle ( node , "::after" ) ;
420
+ const pseudoAfter = uncachedGetComputedStyle ( node , "::after" ) ;
390
421
const afterContent = getTextualContent ( pseudoAfter ) ;
391
422
accumulatedText = `${ accumulatedText } ${ afterContent } ` ;
392
423
}
@@ -564,7 +595,6 @@ export function computeTextAlternative(
564
595
if ( consultedNodes . has ( current ) ) {
565
596
return "" ;
566
597
}
567
-
568
598
// 2A
569
599
if (
570
600
! hidden &&
0 commit comments