From 5bc5056a1f5cf84fa93edb83d47ef89938196e53 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Tue, 23 Jan 2024 10:09:23 -0800 Subject: [PATCH] chore(role): cache pseudo content calculation (#29115) --- .../src/server/injected/roleUtils.ts | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/playwright-core/src/server/injected/roleUtils.ts b/packages/playwright-core/src/server/injected/roleUtils.ts index 05ba3fda2d..6cecb1d5a5 100644 --- a/packages/playwright-core/src/server/injected/roleUtils.ts +++ b/packages/playwright-core/src/server/injected/roleUtils.ts @@ -323,7 +323,18 @@ function queryInAriaOwned(element: Element, selector: string): Element[] { return result; } -function getPseudoContent(pseudoStyle: CSSStyleDeclaration | undefined) { +function getPseudoContent(element: Element, pseudo: '::before' | '::after') { + const cache = pseudo === '::before' ? cachePseudoContentBefore : cachePseudoContentAfter; + if (cache?.has(element)) + return cache?.get(element) || ''; + const pseudoStyle = getElementComputedStyle(element, pseudo); + const content = getPseudoContentImpl(pseudoStyle); + if (cache) + cache.set(element, content); + return content; +} + +function getPseudoContentImpl(pseudoStyle: CSSStyleDeclaration | undefined) { if (!pseudoStyle) return ''; const content = pseudoStyle.content; @@ -677,7 +688,7 @@ function getElementAccessibleNameInternal(element: Element, options: AccessibleN tokens.push(node.textContent || ''); } }; - tokens.push(getPseudoContent(getElementComputedStyle(element, '::before'))); + tokens.push(getPseudoContent(element, '::before')); const assignedNodes = element.nodeName === 'SLOT' ? (element as HTMLSlotElement).assignedNodes() : []; if (assignedNodes.length) { for (const child of assignedNodes) @@ -692,7 +703,7 @@ function getElementAccessibleNameInternal(element: Element, options: AccessibleN for (const owned of getIdRefs(element, element.getAttribute('aria-owns'))) visit(owned, true); } - tokens.push(getPseudoContent(getElementComputedStyle(element, '::after'))); + tokens.push(getPseudoContent(element, '::after')); const accessibleName = tokens.join(''); if (accessibleName.trim()) return accessibleName; @@ -837,6 +848,8 @@ function getAccessibleNameFromAssociatedLabels(labels: Iterable | undefined; let cacheAccessibleNameHidden: Map | undefined; let cacheIsHidden: Map | undefined; +let cachePseudoContentBefore: Map | undefined; +let cachePseudoContentAfter: Map | undefined; let cachesCounter = 0; export function beginAriaCaches() { @@ -844,6 +857,8 @@ export function beginAriaCaches() { cacheAccessibleName ??= new Map(); cacheAccessibleNameHidden ??= new Map(); cacheIsHidden ??= new Map(); + cachePseudoContentBefore ??= new Map(); + cachePseudoContentAfter ??= new Map(); } export function endAriaCaches() { @@ -851,5 +866,7 @@ export function endAriaCaches() { cacheAccessibleName = undefined; cacheAccessibleNameHidden = undefined; cacheIsHidden = undefined; + cachePseudoContentBefore = undefined; + cachePseudoContentAfter = undefined; } }