Cache the "raw" standard font data in the worker-thread (PR 12726 follow-up)
*This implementation is basically a copy of the pre-existing `builtInCMapCache` implementation.* For some, badly generated, PDF documents it's possible that we'll end up having to fetch the *same* standard font data over and over (which is obviously inefficient). While not common, it's certainly possible that a PDF document uses *custom* font names where the actual font then references one of the standard fonts; see e.g. issue 11399 for one such example. Note that I did suggest adding worker-thread caching of standard font data in PR 12726, however it wasn't deemed necessary at the time. Now that we have a real-world example that benefit from caching, I think that we should simply implement this now.
This commit is contained in:
		
							parent
							
								
									6d88d8cdaa
								
							
						
					
					
						commit
						a01c599247
					
				| @ -71,6 +71,7 @@ class Catalog { | ||||
| 
 | ||||
|     this.fontCache = new RefSetCache(); | ||||
|     this.builtInCMapCache = new Map(); | ||||
|     this.standardFontDataCache = new Map(); | ||||
|     this.globalImageCache = new GlobalImageCache(); | ||||
|     this.pageKidsCountCache = new RefSetCache(); | ||||
|     this.pageIndexCache = new RefSetCache(); | ||||
| @ -1020,6 +1021,7 @@ class Catalog { | ||||
|       } | ||||
|       this.fontCache.clear(); | ||||
|       this.builtInCMapCache.clear(); | ||||
|       this.standardFontDataCache.clear(); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -79,6 +79,7 @@ class Page { | ||||
|     globalIdFactory, | ||||
|     fontCache, | ||||
|     builtInCMapCache, | ||||
|     standardFontDataCache, | ||||
|     globalImageCache, | ||||
|     nonBlendModesSet, | ||||
|     xfaFactory, | ||||
| @ -90,6 +91,7 @@ class Page { | ||||
|     this.ref = ref; | ||||
|     this.fontCache = fontCache; | ||||
|     this.builtInCMapCache = builtInCMapCache; | ||||
|     this.standardFontDataCache = standardFontDataCache; | ||||
|     this.globalImageCache = globalImageCache; | ||||
|     this.nonBlendModesSet = nonBlendModesSet; | ||||
|     this.evaluatorOptions = pdfManager.evaluatorOptions; | ||||
| @ -255,6 +257,7 @@ class Page { | ||||
|       idFactory: this._localIdFactory, | ||||
|       fontCache: this.fontCache, | ||||
|       builtInCMapCache: this.builtInCMapCache, | ||||
|       standardFontDataCache: this.standardFontDataCache, | ||||
|       globalImageCache: this.globalImageCache, | ||||
|       options: this.evaluatorOptions, | ||||
|     }); | ||||
| @ -321,6 +324,7 @@ class Page { | ||||
|       idFactory: this._localIdFactory, | ||||
|       fontCache: this.fontCache, | ||||
|       builtInCMapCache: this.builtInCMapCache, | ||||
|       standardFontDataCache: this.standardFontDataCache, | ||||
|       globalImageCache: this.globalImageCache, | ||||
|       options: this.evaluatorOptions, | ||||
|     }); | ||||
| @ -425,6 +429,7 @@ class Page { | ||||
|         idFactory: this._localIdFactory, | ||||
|         fontCache: this.fontCache, | ||||
|         builtInCMapCache: this.builtInCMapCache, | ||||
|         standardFontDataCache: this.standardFontDataCache, | ||||
|         globalImageCache: this.globalImageCache, | ||||
|         options: this.evaluatorOptions, | ||||
|       }); | ||||
| @ -889,6 +894,7 @@ class PDFDocument { | ||||
|       idFactory: this._globalIdFactory, | ||||
|       fontCache: this.catalog.fontCache, | ||||
|       builtInCMapCache: this.catalog.builtInCMapCache, | ||||
|       standardFontDataCache: this.catalog.standardFontDataCache, | ||||
|       options, | ||||
|     }); | ||||
|     const operatorList = new OperatorList(); | ||||
| @ -1148,6 +1154,7 @@ class PDFDocument { | ||||
|           globalIdFactory: this._globalIdFactory, | ||||
|           fontCache: catalog.fontCache, | ||||
|           builtInCMapCache: catalog.builtInCMapCache, | ||||
|           standardFontDataCache: catalog.standardFontDataCache, | ||||
|           globalImageCache: catalog.globalImageCache, | ||||
|           nonBlendModesSet: catalog.nonBlendModesSet, | ||||
|           xfaFactory: this.xfaFactory, | ||||
| @ -1170,6 +1177,7 @@ class PDFDocument { | ||||
|         globalIdFactory: this._globalIdFactory, | ||||
|         fontCache: catalog.fontCache, | ||||
|         builtInCMapCache: catalog.builtInCMapCache, | ||||
|         standardFontDataCache: catalog.standardFontDataCache, | ||||
|         globalImageCache: catalog.globalImageCache, | ||||
|         nonBlendModesSet: catalog.nonBlendModesSet, | ||||
|         xfaFactory: null, | ||||
|  | ||||
| @ -207,6 +207,7 @@ class PartialEvaluator { | ||||
|     idFactory, | ||||
|     fontCache, | ||||
|     builtInCMapCache, | ||||
|     standardFontDataCache, | ||||
|     globalImageCache, | ||||
|     options = null, | ||||
|   }) { | ||||
| @ -216,6 +217,7 @@ class PartialEvaluator { | ||||
|     this.idFactory = idFactory; | ||||
|     this.fontCache = fontCache; | ||||
|     this.builtInCMapCache = builtInCMapCache; | ||||
|     this.standardFontDataCache = standardFontDataCache; | ||||
|     this.globalImageCache = globalImageCache; | ||||
|     this.options = options || DefaultPartialEvaluatorOptions; | ||||
|     this.parsingType3Font = false; | ||||
| @ -390,8 +392,13 @@ class PartialEvaluator { | ||||
|   } | ||||
| 
 | ||||
|   async fetchStandardFontData(name) { | ||||
|     const cachedData = this.standardFontDataCache.get(name); | ||||
|     if (cachedData) { | ||||
|       return new Stream(cachedData); | ||||
|     } | ||||
| 
 | ||||
|     // The symbol fonts are not consistent across platforms, always load the
 | ||||
|     // font data for them.
 | ||||
|     // standard font data for them.
 | ||||
|     if ( | ||||
|       this.options.useSystemFonts && | ||||
|       name !== "Symbol" && | ||||
| @ -399,31 +406,42 @@ class PartialEvaluator { | ||||
|     ) { | ||||
|       return null; | ||||
|     } | ||||
|     const standardFontNameToFileName = getFontNameToFileMap(); | ||||
|     const filename = standardFontNameToFileName[name]; | ||||
| 
 | ||||
|     const standardFontNameToFileName = getFontNameToFileMap(), | ||||
|       filename = standardFontNameToFileName[name]; | ||||
|     let data; | ||||
| 
 | ||||
|     if (this.options.standardFontDataUrl !== null) { | ||||
|       const url = `${this.options.standardFontDataUrl}${filename}`; | ||||
|       const response = await fetch(url); | ||||
|       if (!response.ok) { | ||||
|         warn( | ||||
|           `fetchStandardFontData failed to fetch file "${url}" with "${response.statusText}".` | ||||
|           `fetchStandardFontData: failed to fetch file "${url}" with "${response.statusText}".` | ||||
|         ); | ||||
|       } else { | ||||
|         data = await response.arrayBuffer(); | ||||
|       } | ||||
|     } else { | ||||
|       // Get the data on the main-thread instead.
 | ||||
|       try { | ||||
|         data = await this.handler.sendWithPromise("FetchStandardFontData", { | ||||
|           filename, | ||||
|         }); | ||||
|       } catch (e) { | ||||
|         warn( | ||||
|           `fetchStandardFontData: failed to fetch file "${filename}" with "${e}".` | ||||
|         ); | ||||
|         return null; | ||||
|       } | ||||
|       return new Stream(await response.arrayBuffer()); | ||||
|     } | ||||
|     // Get the data on the main thread instead.
 | ||||
|     try { | ||||
|       const data = await this.handler.sendWithPromise("FetchStandardFontData", { | ||||
|         filename, | ||||
|       }); | ||||
|       return new Stream(data); | ||||
|     } catch (e) { | ||||
|       warn( | ||||
|         `fetchStandardFontData failed to fetch file "${filename}" with "${e}".` | ||||
|       ); | ||||
| 
 | ||||
|     if (!data) { | ||||
|       return null; | ||||
|     } | ||||
|     return null; | ||||
|     // Cache the "raw" standard font data, to avoid fetching it repeateadly
 | ||||
|     // (see e.g. issue 11399).
 | ||||
|     this.standardFontDataCache.set(name, data); | ||||
| 
 | ||||
|     return new Stream(data); | ||||
|   } | ||||
| 
 | ||||
|   async buildFormXObject( | ||||
|  | ||||
| @ -125,6 +125,7 @@ describe("annotation", function () { | ||||
|       idFactory: createIdFactory(/* pageIndex = */ 0), | ||||
|       fontCache: new RefSetCache(), | ||||
|       builtInCMapCache, | ||||
|       standardFontDataCache: new Map(), | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user