@@ -615,6 +615,7 @@ async function collectFacesFromSheet(sheet, baseHref, emitFace, ctx) {
615615 * @param {Array<{family:string,src:string,weight?:string|number,style?:string,stretchPct?:number}> } [options.localFonts=[]]
616616 * @param {string } [options.useProxy=""]
617617 * @param {string[] } [options.fontStylesheetDomains=[]] // extra domains to fetch cross-origin CSS from (#309)
618+ * @param {Document } [options.doc=document] // document to scan for @font-face sources (the element's ownerDocument for iframe support, #441)
618619 * @returns {Promise<string> } inlined @font-face CSS
619620 */
620621export async function embedCustomFonts ( {
@@ -624,6 +625,7 @@ export async function embedCustomFonts({
624625 localFonts = [ ] ,
625626 useProxy = '' ,
626627 fontStylesheetDomains = [ ] ,
628+ doc = document ,
627629} = { } ) {
628630 // ---------- Normalize inputs ----------
629631 if ( ! ( required instanceof Set ) ) required = new Set ( )
@@ -733,12 +735,12 @@ function faceMatchesRequired(fam, styleSpec, weightSpec, stretchSpec) {
733735 const importUrls = [ ]
734736 const IMPORT_ANY_RE_LOCAL = IMPORT_ANY_RE
735737
736- for ( const styleTag of document . querySelectorAll ( 'style' ) ) {
738+ for ( const styleTag of doc . querySelectorAll ( 'style' ) ) {
737739 const cssText = styleTag . textContent || ''
738740 for ( const m of cssText . matchAll ( IMPORT_ANY_RE_LOCAL ) ) {
739741 const u = ( m [ 2 ] || m [ 4 ] || '' ) . trim ( )
740742 if ( ! u || isIconFont ( u ) ) continue
741- const hasLink = ! ! document . querySelector ( `link[rel="stylesheet"][href="${ u } "]` )
743+ const hasLink = ! ! doc . querySelector ( `link[rel="stylesheet"][href="${ u } "]` )
742744 if ( ! hasLink ) importUrls . push ( u )
743745 }
744746 }
@@ -747,14 +749,14 @@ function faceMatchesRequired(fam, styleSpec, weightSpec, stretchSpec) {
747749 const injectedLinks = [ ]
748750 if ( importUrls . length ) {
749751 await Promise . all ( importUrls . map ( ( u ) => new Promise ( ( resolve ) => {
750- if ( document . querySelector ( `link[rel="stylesheet"][href="${ u } "]` ) ) return resolve ( null )
751- const link = document . createElement ( 'link' )
752+ if ( doc . querySelector ( `link[rel="stylesheet"][href="${ u } "]` ) ) return resolve ( null )
753+ const link = doc . createElement ( 'link' )
752754 link . rel = 'stylesheet'
753755 link . href = u
754756 link . setAttribute ( 'data-snapdom' , 'injected-import' )
755757 link . onload = ( ) => resolve ( link )
756758 link . onerror = ( ) => resolve ( null )
757- document . head . appendChild ( link )
759+ doc . head . appendChild ( link )
758760 injectedLinks . push ( link )
759761 } ) ) )
760762 }
@@ -764,7 +766,7 @@ function faceMatchesRequired(fam, styleSpec, weightSpec, stretchSpec) {
764766 // ---------- 1) External <link rel="stylesheet"> ----------
765767 // Snapshot BEFORE detaching the injected links so their @import 'd font CSS is still
766768 // collected below, then remove them from <head> to keep the capture non-destructive.
767- const linkNodes = Array . from ( document . querySelectorAll ( 'link[rel="stylesheet"]' ) ) . filter ( l => ! ! l . href )
769+ const linkNodes = Array . from ( doc . querySelectorAll ( 'link[rel="stylesheet"]' ) ) . filter ( l => ! ! l . href )
768770 for ( const l of injectedLinks ) { try { l . remove ( ) } catch { /* ok */ } }
769771
770772 for ( const link of linkNodes ) {
@@ -781,7 +783,7 @@ function faceMatchesRequired(fam, styleSpec, weightSpec, stretchSpec) {
781783 }
782784
783785 if ( sameOrigin ) {
784- const sheet = Array . from ( document . styleSheets ) . find ( s => s . href === link . href )
786+ const sheet = Array . from ( doc . styleSheets ) . find ( s => s . href === link . href )
785787 if ( sheet ) {
786788 try {
787789 const rules = sheet . cssRules || [ ]
@@ -844,7 +846,7 @@ function faceMatchesRequired(fam, styleSpec, weightSpec, stretchSpec) {
844846 depth : 0
845847 }
846848
847- for ( const sheet of document . styleSheets ) {
849+ for ( const sheet of doc . styleSheets ) {
848850 if ( sheet . href && linkNodes . some ( l => l . href === sheet . href ) ) continue
849851 try {
850852 const rootHref = sheet . href || ( location . origin + '/' )
@@ -862,7 +864,7 @@ function faceMatchesRequired(fam, styleSpec, weightSpec, stretchSpec) {
862864
863865 // ---------- 3) document.fonts with _snapdomSrc ----------
864866 try {
865- for ( const f of document . fonts || [ ] ) {
867+ for ( const f of doc . fonts || [ ] ) {
866868 if ( ! f || ! f . family || f . status !== 'loaded' || ! f . _snapdomSrc ) continue
867869 const fam = String ( f . family ) . replace ( / ^ [ ' " ] + | [ ' " ] + $ / g, '' )
868870 if ( isIconFont ( fam ) ) continue
@@ -1028,20 +1030,21 @@ export function collectUsedCodepoints(root) {
10281030 *
10291031 * @param {Set<string>|string[] } families - Plain family names (e.g., "Mansalva", "Unbounded")
10301032 * @param {number } [warmupRepetitions=2] - How many times to warm-up each family
1033+ * @param {Document } [doc=document] - Document whose fonts to await and warm up (the element's ownerDocument for iframe support)
10311034 * @returns {Promise<void> }
10321035 */
1033- export async function ensureFontsReady ( families , warmupRepetitions = 2 ) {
1034- try { await document . fonts . ready } catch { }
1036+ export async function ensureFontsReady ( families , warmupRepetitions = 2 , doc = document ) {
1037+ try { await doc . fonts . ready } catch { }
10351038
10361039 const fams = Array . from ( families || [ ] ) . filter ( Boolean )
10371040 if ( fams . length === 0 ) return
10381041
10391042 const warmupOnce = ( ) => {
1040- const container = document . createElement ( 'div' )
1043+ const container = doc . createElement ( 'div' )
10411044 container . style . cssText = 'position:absolute!important;left:-9999px!important;top:0!important;opacity:0!important;pointer-events:none!important;contain:layout size style;'
10421045
10431046 for ( const fam of fams ) {
1044- const span = document . createElement ( 'span' )
1047+ const span = doc . createElement ( 'span' )
10451048 span . textContent = 'AaBbGg1234ÁÉÍÓÚçñ—∞'
10461049 span . style . fontFamily = `"${ fam } "`
10471050 span . style . fontWeight = '700'
@@ -1054,10 +1057,10 @@ export async function ensureFontsReady(families, warmupRepetitions = 2) {
10541057 container . appendChild ( span )
10551058 }
10561059
1057- document . body . appendChild ( container )
1060+ doc . body . appendChild ( container )
10581061 // Force layout
10591062 container . offsetWidth
1060- document . body . removeChild ( container )
1063+ doc . body . removeChild ( container )
10611064 }
10621065
10631066 for ( let i = 0 ; i < Math . max ( 1 , warmupRepetitions ) ; i ++ ) {
0 commit comments