Skip to content

Commit 70de7fc

Browse files
semvis123hhrutter
authored andcommitted
Fix concurrent write to map userfontmetrics
1 parent bda08dd commit 70de7fc

File tree

5 files changed

+31
-1
lines changed

5 files changed

+31
-1
lines changed

pkg/api/font.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,9 @@ func planeString(i int) string {
199199
// CreateUserFontDemoFiles creates single page PDF for each Unicode plane covered.
200200
func CreateUserFontDemoFiles(dir, fn string) error {
201201
w, h := 7800, 7800
202+
font.UserFontMetricsLock.RLock()
202203
ttf, ok := font.UserFontMetrics[fn]
204+
font.UserFontMetricsLock.RUnlock()
203205
if !ok {
204206
return errors.Errorf("pdfcpu: font %s not available\n", fn)
205207
}

pkg/font/metrics.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"path/filepath"
2626
"strconv"
2727
"strings"
28+
"sync"
2829

2930
"github.com/pdfcpu/pdfcpu/internal/corefont/metrics"
3031
"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/types"
@@ -195,6 +196,7 @@ var UserFontDir string
195196

196197
// UserFontMetrics represents font metrics for TTF or OTF font files installed into UserFontDir.
197198
var UserFontMetrics = map[string]TTFLight{}
199+
var UserFontMetricsLock = &sync.RWMutex{}
198200

199201
func load(fileName string, fd *TTFLight) error {
200202
//fmt.Printf("reading gob from: %s\n", fileName)
@@ -244,7 +246,9 @@ func LoadUserFonts() error {
244246
fn = strings.TrimSuffix(f.Name(), path.Ext(f.Name()))
245247
//fmt.Printf("loading %s.ttf...\n", fn)
246248
//fmt.Printf("Loaded %s:\n%s", fn, ttf)
249+
UserFontMetricsLock.Lock()
247250
UserFontMetrics[fn] = ttf
251+
UserFontMetricsLock.Unlock()
248252
}
249253
return nil
250254
}
@@ -254,6 +258,8 @@ func BoundingBox(fontName string) *types.Rectangle {
254258
if IsCoreFont(fontName) {
255259
return metrics.CoreFontMetrics[fontName].FBox
256260
}
261+
UserFontMetricsLock.RLock()
262+
defer UserFontMetricsLock.RUnlock()
257263
llx := UserFontMetrics[fontName].LLx
258264
lly := UserFontMetrics[fontName].LLy
259265
urx := UserFontMetrics[fontName].URx
@@ -266,6 +272,8 @@ func CharWidth(fontName string, r rune) int {
266272
if IsCoreFont(fontName) {
267273
return metrics.CoreFontCharWidth(fontName, int(r))
268274
}
275+
UserFontMetricsLock.RLock()
276+
defer UserFontMetricsLock.RUnlock()
269277
ttf, ok := UserFontMetrics[fontName]
270278
if !ok {
271279
fmt.Fprintf(os.Stderr, "pdfcpu: user font not loaded: %s\n", fontName)
@@ -366,13 +374,17 @@ func CoreFontNames() []string {
366374

367375
// IsUserFont returns true for installed TrueType fonts.
368376
func IsUserFont(fontName string) bool {
377+
UserFontMetricsLock.RLock()
378+
defer UserFontMetricsLock.RUnlock()
369379
_, ok := UserFontMetrics[fontName]
370380
return ok
371381
}
372382

373383
// UserFontNames return a list of all installed TrueType fonts.
374384
func UserFontNames() []string {
375385
ss := []string{}
386+
UserFontMetricsLock.RLock()
387+
defer UserFontMetricsLock.RUnlock()
376388
for fontName := range UserFontMetrics {
377389
ss = append(ss, fontName)
378390
}
@@ -382,6 +394,8 @@ func UserFontNames() []string {
382394
// UserFontNamesVerbose return a list of all installed TrueType fonts including glyph count.
383395
func UserFontNamesVerbose() []string {
384396
ss := []string{}
397+
UserFontMetricsLock.RLock()
398+
defer UserFontMetricsLock.RUnlock()
385399
for fName, ttf := range UserFontMetrics {
386400
s := fName + " (" + strconv.Itoa(ttf.GlyphCount) + " glyphs)"
387401
ss = append(ss, s)

pkg/pdfcpu/font/fontDict.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,10 @@ func usedGIDsFromCMap(cMap string) ([]uint16, error) {
738738
// UpdateUserfont updates the fontdict for fontName via supplied font resource.
739739
func UpdateUserfont(xRefTable *model.XRefTable, fontName string, f model.FontResource) error {
740740

741+
font.UserFontMetricsLock.RLock()
741742
ttf, ok := font.UserFontMetrics[fontName]
743+
font.UserFontMetricsLock.RUnlock()
744+
742745
if !ok {
743746
return errors.Errorf("pdfcpu: userfont %s not available", fontName)
744747
}
@@ -838,7 +841,9 @@ func CIDFontSpecialEncDict(xRefTable *model.XRefTable, ttf font.TTFLight, baseFo
838841

839842
func type0CJKFontDict(xRefTable *model.XRefTable, fontName, lang, script string, indRef *types.IndirectRef) (*types.IndirectRef, error) {
840843

844+
font.UserFontMetricsLock.RLock()
841845
ttf, ok := font.UserFontMetrics[fontName]
846+
font.UserFontMetricsLock.RUnlock()
842847
if !ok {
843848
return nil, errors.Errorf("pdfcpu: font %s not available", fontName)
844849
}
@@ -875,7 +880,9 @@ func type0FontDict(xRefTable *model.XRefTable, fontName, lang string, subFont bo
875880
// Combines a CIDFont and a CMap to produce a font whose glyphs may be accessed
876881
// by means of variable-length character codes in a string to be shown.
877882

883+
font.UserFontMetricsLock.RLock()
878884
ttf, ok := font.UserFontMetrics[fontName]
885+
font.UserFontMetricsLock.RUnlock()
879886
if !ok {
880887
return nil, errors.Errorf("pdfcpu: font %s not available", fontName)
881888
}
@@ -922,8 +929,9 @@ func type0FontDict(xRefTable *model.XRefTable, fontName, lang string, subFont bo
922929
}
923930

924931
func trueTypeFontDict(xRefTable *model.XRefTable, fontName, fontLang string) (*types.IndirectRef, error) {
925-
932+
font.UserFontMetricsLock.RLock()
926933
ttf, ok := font.UserFontMetrics[fontName]
934+
font.UserFontMetricsLock.RUnlock()
927935
if !ok {
928936
return nil, errors.Errorf("pdfcpu: font %s not available", fontName)
929937
}

pkg/pdfcpu/model/text.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,11 @@ func PrepBytes(xRefTable *XRefTable, s, fontName string, cjk, rtl bool) string {
190190
xRefTable.UsedGIDs[fontName] = map[uint16]bool{}
191191
usedGIDs = xRefTable.UsedGIDs[fontName]
192192
}
193+
194+
font.UserFontMetricsLock.RLock()
193195
ttf := font.UserFontMetrics[fontName]
196+
font.UserFontMetricsLock.RUnlock()
197+
194198
for _, r := range s {
195199
gid, ok := ttf.Chars[uint32(r)]
196200
if ok {

pkg/pdfcpu/primitives/font.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ func (f *FormFont) validateISO639() error {
5555
}
5656

5757
func (f *FormFont) validateScriptSupport() error {
58+
font.UserFontMetricsLock.RLock()
5859
fd, ok := font.UserFontMetrics[f.Name]
60+
font.UserFontMetricsLock.RUnlock()
5961
if !ok {
6062
return errors.Errorf("pdfcpu: userfont %s not available", f.Name)
6163
}

0 commit comments

Comments
 (0)