22import { captureDOM } from '../core/capture'
33import { extendIconFonts } from '../modules/iconFonts.js'
44import { createContext } from '../core/context'
5- import { toImg , toSvg } from '../exporters/toImg.js'
5+ import { toImg , toSvg } from '../exporters/toImg.js'
66import { toCanvas } from '../exporters/toCanvas.js'
77import { toBlob } from '../exporters/toBlob.js'
88import { rasterize } from '../modules/rasterize.js'
@@ -39,16 +39,16 @@ export async function snapdom(element, userOptions) {
3939 const context = createContext ( userOptions )
4040
4141 if ( isSafari ( ) && ( context . embedFonts === true || hasBackgroundOrMask ( element ) ) ) {
42- for ( let i = 0 ; i < 3 ; i ++ ) {
43- try {
44- await safariWarmup ( element , userOptions )
45- console . log ( 'Iteración número:' , i )
46- _safariWarmup = false
47- } catch {
48- // swallow error
42+ for ( let i = 0 ; i < 3 ; i ++ ) {
43+ try {
44+ await safariWarmup ( element , userOptions )
45+ console . log ( 'safariWarmup:' , i )
46+ _safariWarmup = false
47+ } catch {
48+ // swallow error
49+ }
4950 }
5051 }
51- }
5252
5353 /* c8 ignore next 1 */
5454 if ( context . iconFonts && context . iconFonts . length > 0 ) extendIconFonts ( context . iconFonts )
@@ -193,6 +193,7 @@ snapdom.download = (el, options) => snapdom(el, options).then(result => result.d
193193 */
194194async function safariWarmup ( element , baseOptions ) {
195195 if ( _safariWarmup ) return
196+
196197 const preflight = {
197198 ...baseOptions ,
198199 fast : true ,
@@ -204,35 +205,46 @@ async function safariWarmup(element, baseOptions) {
204205 try {
205206 url = await captureDOM ( element , preflight )
206207 } catch {
207- // Even if captureDOM fails here, don’t block the real capture.
208- return
208+ // no bloquea la captura real
209209 }
210210
211- await new Promise ( ( resolve ) => {
212- // Build offscreen <img> to force decoding
213- const img = new Image ( )
214- img . decoding = 'sync'
215- img . loading = 'eager'
216- img . style . position = 'fixed'
217- img . style . left = 0
218- img . style . top = 0
219- img . style . width = '10px'
220- img . style . height = '10px'
221- img . style . opacity = '0.01'
222- img . style . transform = 'translateZ(10px)'
223- img . style . willChange = 'transform,opacity;'
224- img . src = url
225-
226- const cleanup = async ( ) => {
227- await new Promise ( r => setTimeout ( r , 100 ) )
228- if ( img && img . parentNode ) img . parentNode . removeChild ( img )
229- _safariWarmup = true
230- resolve ( )
231- }
211+ // 1) estabiliza layout/paint en WebKit
212+ await new Promise ( r => requestAnimationFrame ( ( ) => requestAnimationFrame ( r ) ) )
213+
214+ if ( url ) {
215+ await new Promise ( ( resolve ) => {
216+ const img = new Image ( )
217+ try { img . decoding = 'sync' ; img . loading = 'eager' } catch { }
218+ img . style . cssText =
219+ 'position:fixed;left:0px;top:0px;width:10px;height:10px;opacity:0.01;pointer-events:none;'
220+ img . src = url
221+ document . body . appendChild ( img )
222+
223+ ; ( async ( ) => {
224+ try { if ( typeof img . decode === 'function' ) await img . decode ( ) } catch { }
232225
233- document . body . appendChild ( img )
234- cleanup ( )
226+ const start = performance . now ( )
227+ while ( ! ( img . complete && img . naturalWidth > 0 ) && performance . now ( ) - start < 900 ) {
228+ await new Promise ( r => setTimeout ( r , 50 ) )
229+ }
230+
231+ await new Promise ( r => requestAnimationFrame ( r ) )
232+ try { img . remove ( ) } catch { }
233+ resolve ( )
234+ } ) ( )
235+ } )
236+
237+ }
238+
239+ // 3) “poke” a los canvas del elemento (Chart.js, etc.)
240+ element . querySelectorAll ( 'canvas' ) . forEach ( c => {
241+ try {
242+ const ctx = c . getContext ( '2d' , { willReadFrequently : true } )
243+ if ( ctx ) { ctx . getImageData ( 0 , 0 , 1 , 1 ) }
244+ } catch { }
235245 } )
246+
247+ _safariWarmup = true
236248}
237249
238250/**
@@ -248,9 +260,10 @@ function hasBackgroundOrMask(el) {
248260
249261 const bg = cs . backgroundImage && cs . backgroundImage !== 'none'
250262 const mask = ( cs . maskImage && cs . maskImage !== 'none' ) ||
251- ( cs . webkitMaskImage && cs . webkitMaskImage !== 'none' )
263+ ( cs . webkitMaskImage && cs . webkitMaskImage !== 'none' )
252264
253265 if ( bg || mask ) return true
266+ if ( node . tagName === 'CANVAS' ) return true
254267 }
255268 return false
256269}
0 commit comments