@@ -29,6 +29,7 @@ import {
2929type FlatString = string & {
3030 __flat : true ;
3131} ;
32+ type GetComputedStyle = typeof window . getComputedStyle ;
3233
3334/**
3435 * interface for an options-bag where `window.getComputedStyle` can be mocked
@@ -43,7 +44,7 @@ export interface ComputeTextAlternativeOptions {
4344 /**
4445 * mock window.getComputedStyle. Needs `content`, `display` and `visibility`
4546 */
46- getComputedStyle ?: typeof window . getComputedStyle ;
47+ getComputedStyle ?: GetComputedStyle ;
4748 /**
4849 * Set to `true` if you want to include hidden elements in the accessible name and description computation.
4950 * Skips 2A in https://w3c.github.io/accname/#computation-steps.
@@ -69,7 +70,7 @@ function asFlatString(s: string): FlatString {
6970 */
7071function isHidden (
7172 node : Node ,
72- getComputedStyleImplementation : typeof window . getComputedStyle ,
73+ getComputedStyleImplementation : GetComputedStyle ,
7374) : node is Element {
7475 if ( ! isElement ( node ) ) {
7576 return false ;
@@ -338,6 +339,10 @@ export function computeTextAlternative(
338339 options : ComputeTextAlternativeOptions = { } ,
339340) : string {
340341 const consultedNodes = new SetLike < Node > ( ) ;
342+ const computedStyles =
343+ typeof Map === "undefined"
344+ ? undefined
345+ : new Map < Element , CSSStyleDeclaration > ( ) ;
341346
342347 const window = safeWindow ( root ) ;
343348 const {
@@ -348,9 +353,36 @@ export function computeTextAlternative(
348353 // window.getComputedStyle(elementFromAnotherWindow) or if I don't bind it
349354 // the type declarations don't require a `this`
350355 // eslint-disable-next-line no-restricted-properties
351- getComputedStyle = window . getComputedStyle . bind ( window ) ,
356+ getComputedStyle : uncachedGetComputedStyle = window . getComputedStyle . bind (
357+ window ,
358+ ) ,
352359 hidden = false ,
353360 } = 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+ } ;
354386
355387 // 2F.i
356388 function computeMiscTextAlternative (
@@ -359,7 +391,7 @@ export function computeTextAlternative(
359391 ) : string {
360392 let accumulatedText = "" ;
361393 if ( isElement ( node ) && computedStyleSupportsPseudoElements ) {
362- const pseudoBefore = getComputedStyle ( node , "::before" ) ;
394+ const pseudoBefore = uncachedGetComputedStyle ( node , "::before" ) ;
363395 const beforeContent = getTextualContent ( pseudoBefore ) ;
364396 accumulatedText = `${ beforeContent } ${ accumulatedText } ` ;
365397 }
@@ -384,9 +416,8 @@ export function computeTextAlternative(
384416 // trailing separator for wpt tests
385417 accumulatedText += `${ separator } ${ result } ${ separator } ` ;
386418 } ) ;
387-
388419 if ( isElement ( node ) && computedStyleSupportsPseudoElements ) {
389- const pseudoAfter = getComputedStyle ( node , "::after" ) ;
420+ const pseudoAfter = uncachedGetComputedStyle ( node , "::after" ) ;
390421 const afterContent = getTextualContent ( pseudoAfter ) ;
391422 accumulatedText = `${ accumulatedText } ${ afterContent } ` ;
392423 }
@@ -564,7 +595,6 @@ export function computeTextAlternative(
564595 if ( consultedNodes . has ( current ) ) {
565596 return "" ;
566597 }
567-
568598 // 2A
569599 if (
570600 ! hidden &&
0 commit comments