Merge pull request #1683 from gavin-ts/fontencoding-syncmap
fix d2fonts race condition in TestCLI_E2E
This commit is contained in:
commit
df1d49f6be
6 changed files with 153 additions and 77 deletions
|
|
@ -13,6 +13,7 @@ import (
|
||||||
|
|
||||||
"oss.terrastruct.com/d2/lib/font"
|
"oss.terrastruct.com/d2/lib/font"
|
||||||
fontlib "oss.terrastruct.com/d2/lib/font"
|
fontlib "oss.terrastruct.com/d2/lib/font"
|
||||||
|
"oss.terrastruct.com/d2/lib/syncmap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FontFamily string
|
type FontFamily string
|
||||||
|
|
@ -44,14 +45,15 @@ func (f Font) GetEncodedSubset(corpus string) string {
|
||||||
|
|
||||||
FontFamiliesMu.Lock()
|
FontFamiliesMu.Lock()
|
||||||
defer FontFamiliesMu.Unlock()
|
defer FontFamiliesMu.Unlock()
|
||||||
fontBuf := make([]byte, len(FontFaces[f]))
|
face := FontFaces.Get(f)
|
||||||
copy(fontBuf, FontFaces[f])
|
fontBuf := make([]byte, len(face))
|
||||||
|
copy(fontBuf, face)
|
||||||
fontBuf = font.UTF8CutFont(fontBuf, uniqueChars)
|
fontBuf = font.UTF8CutFont(fontBuf, uniqueChars)
|
||||||
|
|
||||||
fontBuf, err := fontlib.Sfnt2Woff(fontBuf)
|
fontBuf, err := fontlib.Sfnt2Woff(fontBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If subset fails, return full encoding
|
// If subset fails, return full encoding
|
||||||
return FontEncodings[f]
|
return FontEncodings.Get(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("data:application/font-woff;base64,%v", base64.StdEncoding.EncodeToString(fontBuf))
|
return fmt.Sprintf("data:application/font-woff;base64,%v", base64.StdEncoding.EncodeToString(fontBuf))
|
||||||
|
|
@ -134,165 +136,197 @@ var fuzzyBubblesBoldBase64 string
|
||||||
//go:embed ttf/*
|
//go:embed ttf/*
|
||||||
var fontFacesFS embed.FS
|
var fontFacesFS embed.FS
|
||||||
|
|
||||||
var FontEncodings map[Font]string
|
var FontEncodings syncmap.SyncMap[Font, string]
|
||||||
var FontFaces map[Font][]byte
|
var FontFaces syncmap.SyncMap[Font, []byte]
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
FontEncodings = map[Font]string{
|
FontEncodings = syncmap.New[Font, string]()
|
||||||
{
|
|
||||||
|
FontEncodings.Set(
|
||||||
|
Font{
|
||||||
Family: SourceSansPro,
|
Family: SourceSansPro,
|
||||||
Style: FONT_STYLE_REGULAR,
|
Style: FONT_STYLE_REGULAR,
|
||||||
}: sourceSansProRegularBase64,
|
},
|
||||||
{
|
sourceSansProRegularBase64)
|
||||||
|
|
||||||
|
FontEncodings.Set(
|
||||||
|
Font{
|
||||||
Family: SourceSansPro,
|
Family: SourceSansPro,
|
||||||
Style: FONT_STYLE_BOLD,
|
Style: FONT_STYLE_BOLD,
|
||||||
}: sourceSansProBoldBase64,
|
},
|
||||||
{
|
sourceSansProBoldBase64)
|
||||||
|
|
||||||
|
FontEncodings.Set(
|
||||||
|
Font{
|
||||||
Family: SourceSansPro,
|
Family: SourceSansPro,
|
||||||
Style: FONT_STYLE_SEMIBOLD,
|
Style: FONT_STYLE_SEMIBOLD,
|
||||||
}: sourceSansProSemiboldBase64,
|
},
|
||||||
{
|
sourceSansProSemiboldBase64)
|
||||||
|
|
||||||
|
FontEncodings.Set(
|
||||||
|
Font{
|
||||||
Family: SourceSansPro,
|
Family: SourceSansPro,
|
||||||
Style: FONT_STYLE_ITALIC,
|
Style: FONT_STYLE_ITALIC,
|
||||||
}: sourceSansProItalicBase64,
|
},
|
||||||
{
|
sourceSansProItalicBase64)
|
||||||
|
|
||||||
|
FontEncodings.Set(
|
||||||
|
Font{
|
||||||
Family: SourceCodePro,
|
Family: SourceCodePro,
|
||||||
Style: FONT_STYLE_REGULAR,
|
Style: FONT_STYLE_REGULAR,
|
||||||
}: sourceCodeProRegularBase64,
|
},
|
||||||
{
|
sourceCodeProRegularBase64)
|
||||||
|
|
||||||
|
FontEncodings.Set(
|
||||||
|
Font{
|
||||||
Family: SourceCodePro,
|
Family: SourceCodePro,
|
||||||
Style: FONT_STYLE_BOLD,
|
Style: FONT_STYLE_BOLD,
|
||||||
}: sourceCodeProBoldBase64,
|
},
|
||||||
{
|
sourceCodeProBoldBase64)
|
||||||
|
|
||||||
|
FontEncodings.Set(
|
||||||
|
Font{
|
||||||
Family: SourceCodePro,
|
Family: SourceCodePro,
|
||||||
Style: FONT_STYLE_SEMIBOLD,
|
Style: FONT_STYLE_SEMIBOLD,
|
||||||
}: sourceCodeProSemiboldBase64,
|
},
|
||||||
{
|
sourceCodeProSemiboldBase64)
|
||||||
|
|
||||||
|
FontEncodings.Set(
|
||||||
|
Font{
|
||||||
Family: SourceCodePro,
|
Family: SourceCodePro,
|
||||||
Style: FONT_STYLE_ITALIC,
|
Style: FONT_STYLE_ITALIC,
|
||||||
}: sourceCodeProItalicBase64,
|
},
|
||||||
{
|
sourceCodeProItalicBase64)
|
||||||
|
|
||||||
|
FontEncodings.Set(
|
||||||
|
Font{
|
||||||
Family: HandDrawn,
|
Family: HandDrawn,
|
||||||
Style: FONT_STYLE_REGULAR,
|
Style: FONT_STYLE_REGULAR,
|
||||||
}: fuzzyBubblesRegularBase64,
|
},
|
||||||
{
|
fuzzyBubblesRegularBase64)
|
||||||
|
|
||||||
|
FontEncodings.Set(
|
||||||
|
Font{
|
||||||
Family: HandDrawn,
|
Family: HandDrawn,
|
||||||
Style: FONT_STYLE_ITALIC,
|
Style: FONT_STYLE_ITALIC,
|
||||||
// This font has no italic, so just reuse regular
|
// This font has no italic, so just reuse regular
|
||||||
}: fuzzyBubblesRegularBase64,
|
}, fuzzyBubblesRegularBase64)
|
||||||
{
|
FontEncodings.Set(
|
||||||
|
Font{
|
||||||
Family: HandDrawn,
|
Family: HandDrawn,
|
||||||
Style: FONT_STYLE_BOLD,
|
Style: FONT_STYLE_BOLD,
|
||||||
}: fuzzyBubblesBoldBase64,
|
}, fuzzyBubblesBoldBase64)
|
||||||
{
|
FontEncodings.Set(
|
||||||
|
Font{
|
||||||
Family: HandDrawn,
|
Family: HandDrawn,
|
||||||
Style: FONT_STYLE_SEMIBOLD,
|
Style: FONT_STYLE_SEMIBOLD,
|
||||||
// This font has no semibold, so just reuse bold
|
// This font has no semibold, so just reuse bold
|
||||||
}: fuzzyBubblesBoldBase64,
|
}, fuzzyBubblesBoldBase64)
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range FontEncodings {
|
FontEncodings.Range(func(k Font, v string) bool {
|
||||||
FontEncodings[k] = strings.TrimSuffix(v, "\n")
|
FontEncodings.Set(k, strings.TrimSuffix(v, "\n"))
|
||||||
}
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
FontFaces = syncmap.New[Font, []byte]()
|
||||||
|
|
||||||
FontFaces = map[Font][]byte{}
|
|
||||||
b, err := fontFacesFS.ReadFile("ttf/SourceSansPro-Regular.ttf")
|
b, err := fontFacesFS.ReadFile("ttf/SourceSansPro-Regular.ttf")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
FontFaces[Font{
|
FontFaces.Set(Font{
|
||||||
Family: SourceSansPro,
|
Family: SourceSansPro,
|
||||||
Style: FONT_STYLE_REGULAR,
|
Style: FONT_STYLE_REGULAR,
|
||||||
}] = b
|
}, b)
|
||||||
|
|
||||||
b, err = fontFacesFS.ReadFile("ttf/SourceCodePro-Regular.ttf")
|
b, err = fontFacesFS.ReadFile("ttf/SourceCodePro-Regular.ttf")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
FontFaces[Font{
|
FontFaces.Set(Font{
|
||||||
Family: SourceCodePro,
|
Family: SourceCodePro,
|
||||||
Style: FONT_STYLE_REGULAR,
|
Style: FONT_STYLE_REGULAR,
|
||||||
}] = b
|
}, b)
|
||||||
|
|
||||||
b, err = fontFacesFS.ReadFile("ttf/SourceCodePro-Bold.ttf")
|
b, err = fontFacesFS.ReadFile("ttf/SourceCodePro-Bold.ttf")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
FontFaces[Font{
|
FontFaces.Set(Font{
|
||||||
Family: SourceCodePro,
|
Family: SourceCodePro,
|
||||||
Style: FONT_STYLE_BOLD,
|
Style: FONT_STYLE_BOLD,
|
||||||
}] = b
|
}, b)
|
||||||
|
|
||||||
b, err = fontFacesFS.ReadFile("ttf/SourceCodePro-Semibold.ttf")
|
b, err = fontFacesFS.ReadFile("ttf/SourceCodePro-Semibold.ttf")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
FontFaces[Font{
|
FontFaces.Set(Font{
|
||||||
Family: SourceCodePro,
|
Family: SourceCodePro,
|
||||||
Style: FONT_STYLE_SEMIBOLD,
|
Style: FONT_STYLE_SEMIBOLD,
|
||||||
}] = b
|
}, b)
|
||||||
|
|
||||||
b, err = fontFacesFS.ReadFile("ttf/SourceCodePro-Italic.ttf")
|
b, err = fontFacesFS.ReadFile("ttf/SourceCodePro-Italic.ttf")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
FontFaces[Font{
|
FontFaces.Set(Font{
|
||||||
Family: SourceCodePro,
|
Family: SourceCodePro,
|
||||||
Style: FONT_STYLE_ITALIC,
|
Style: FONT_STYLE_ITALIC,
|
||||||
}] = b
|
}, b)
|
||||||
|
|
||||||
b, err = fontFacesFS.ReadFile("ttf/SourceSansPro-Bold.ttf")
|
b, err = fontFacesFS.ReadFile("ttf/SourceSansPro-Bold.ttf")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
FontFaces[Font{
|
FontFaces.Set(Font{
|
||||||
Family: SourceSansPro,
|
Family: SourceSansPro,
|
||||||
Style: FONT_STYLE_BOLD,
|
Style: FONT_STYLE_BOLD,
|
||||||
}] = b
|
}, b)
|
||||||
|
|
||||||
b, err = fontFacesFS.ReadFile("ttf/SourceSansPro-Semibold.ttf")
|
b, err = fontFacesFS.ReadFile("ttf/SourceSansPro-Semibold.ttf")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
FontFaces[Font{
|
FontFaces.Set(Font{
|
||||||
Family: SourceSansPro,
|
Family: SourceSansPro,
|
||||||
Style: FONT_STYLE_SEMIBOLD,
|
Style: FONT_STYLE_SEMIBOLD,
|
||||||
}] = b
|
}, b)
|
||||||
|
|
||||||
b, err = fontFacesFS.ReadFile("ttf/SourceSansPro-Italic.ttf")
|
b, err = fontFacesFS.ReadFile("ttf/SourceSansPro-Italic.ttf")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
FontFaces[Font{
|
FontFaces.Set(Font{
|
||||||
Family: SourceSansPro,
|
Family: SourceSansPro,
|
||||||
Style: FONT_STYLE_ITALIC,
|
Style: FONT_STYLE_ITALIC,
|
||||||
}] = b
|
}, b)
|
||||||
|
|
||||||
b, err = fontFacesFS.ReadFile("ttf/FuzzyBubbles-Regular.ttf")
|
b, err = fontFacesFS.ReadFile("ttf/FuzzyBubbles-Regular.ttf")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
FontFaces[Font{
|
FontFaces.Set(Font{
|
||||||
Family: HandDrawn,
|
Family: HandDrawn,
|
||||||
Style: FONT_STYLE_REGULAR,
|
Style: FONT_STYLE_REGULAR,
|
||||||
}] = b
|
}, b)
|
||||||
FontFaces[Font{
|
FontFaces.Set(Font{
|
||||||
Family: HandDrawn,
|
Family: HandDrawn,
|
||||||
Style: FONT_STYLE_ITALIC,
|
Style: FONT_STYLE_ITALIC,
|
||||||
}] = b
|
}, b)
|
||||||
|
|
||||||
b, err = fontFacesFS.ReadFile("ttf/FuzzyBubbles-Bold.ttf")
|
b, err = fontFacesFS.ReadFile("ttf/FuzzyBubbles-Bold.ttf")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
FontFaces[Font{
|
FontFaces.Set(Font{
|
||||||
Family: HandDrawn,
|
Family: HandDrawn,
|
||||||
Style: FONT_STYLE_BOLD,
|
Style: FONT_STYLE_BOLD,
|
||||||
}] = b
|
}, b)
|
||||||
FontFaces[Font{
|
FontFaces.Set(Font{
|
||||||
Family: HandDrawn,
|
Family: HandDrawn,
|
||||||
Style: FONT_STYLE_SEMIBOLD,
|
Style: FONT_STYLE_SEMIBOLD,
|
||||||
}] = b
|
}, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
var D2_FONT_TO_FAMILY = map[string]FontFamily{
|
var D2_FONT_TO_FAMILY = map[string]FontFamily{
|
||||||
|
|
@ -301,14 +335,14 @@ var D2_FONT_TO_FAMILY = map[string]FontFamily{
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddFontStyle(font Font, style FontStyle, ttf []byte) error {
|
func AddFontStyle(font Font, style FontStyle, ttf []byte) error {
|
||||||
FontFaces[font] = ttf
|
FontFaces.Set(font, ttf)
|
||||||
|
|
||||||
woff, err := fontlib.Sfnt2Woff(ttf)
|
woff, err := fontlib.Sfnt2Woff(ttf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to encode ttf to woff: %v", err)
|
return fmt.Errorf("failed to encode ttf to woff: %v", err)
|
||||||
}
|
}
|
||||||
encodedWoff := fmt.Sprintf("data:application/font-woff;base64,%v", base64.StdEncoding.EncodeToString(woff))
|
encodedWoff := fmt.Sprintf("data:application/font-woff;base64,%v", base64.StdEncoding.EncodeToString(woff))
|
||||||
FontEncodings[font] = encodedWoff
|
FontEncodings.Set(font, encodedWoff)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -332,8 +366,8 @@ func AddFontFamily(name string, regularTTF, italicTTF, boldTTF, semiboldTTF []by
|
||||||
Family: SourceSansPro,
|
Family: SourceSansPro,
|
||||||
Style: FONT_STYLE_REGULAR,
|
Style: FONT_STYLE_REGULAR,
|
||||||
}
|
}
|
||||||
FontFaces[regularFont] = FontFaces[fallbackFont]
|
FontFaces.Set(regularFont, FontFaces.Get(fallbackFont))
|
||||||
FontEncodings[regularFont] = FontEncodings[fallbackFont]
|
FontEncodings.Set(regularFont, FontEncodings.Get(fallbackFont))
|
||||||
}
|
}
|
||||||
|
|
||||||
italicFont := Font{
|
italicFont := Font{
|
||||||
|
|
@ -350,8 +384,8 @@ func AddFontFamily(name string, regularTTF, italicTTF, boldTTF, semiboldTTF []by
|
||||||
Family: SourceSansPro,
|
Family: SourceSansPro,
|
||||||
Style: FONT_STYLE_ITALIC,
|
Style: FONT_STYLE_ITALIC,
|
||||||
}
|
}
|
||||||
FontFaces[italicFont] = FontFaces[fallbackFont]
|
FontFaces.Set(italicFont, FontFaces.Get(fallbackFont))
|
||||||
FontEncodings[italicFont] = FontEncodings[fallbackFont]
|
FontEncodings.Set(italicFont, FontEncodings.Get(fallbackFont))
|
||||||
}
|
}
|
||||||
|
|
||||||
boldFont := Font{
|
boldFont := Font{
|
||||||
|
|
@ -368,8 +402,8 @@ func AddFontFamily(name string, regularTTF, italicTTF, boldTTF, semiboldTTF []by
|
||||||
Family: SourceSansPro,
|
Family: SourceSansPro,
|
||||||
Style: FONT_STYLE_BOLD,
|
Style: FONT_STYLE_BOLD,
|
||||||
}
|
}
|
||||||
FontFaces[boldFont] = FontFaces[fallbackFont]
|
FontFaces.Set(boldFont, FontFaces.Get(fallbackFont))
|
||||||
FontEncodings[boldFont] = FontEncodings[fallbackFont]
|
FontEncodings.Set(boldFont, FontEncodings.Get(fallbackFont))
|
||||||
}
|
}
|
||||||
|
|
||||||
semiboldFont := Font{
|
semiboldFont := Font{
|
||||||
|
|
@ -386,8 +420,8 @@ func AddFontFamily(name string, regularTTF, italicTTF, boldTTF, semiboldTTF []by
|
||||||
Family: SourceSansPro,
|
Family: SourceSansPro,
|
||||||
Style: FONT_STYLE_SEMIBOLD,
|
Style: FONT_STYLE_SEMIBOLD,
|
||||||
}
|
}
|
||||||
FontFaces[semiboldFont] = FontFaces[fallbackFont]
|
FontFaces.Set(semiboldFont, FontFaces.Get(fallbackFont))
|
||||||
FontEncodings[semiboldFont] = FontEncodings[fallbackFont]
|
FontEncodings.Set(semiboldFont, FontEncodings.Get(fallbackFont))
|
||||||
}
|
}
|
||||||
|
|
||||||
FontFamilies = append(FontFamilies, customFontFamily)
|
FontFamilies = append(FontFamilies, customFontFamily)
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,9 @@ func TestCutFont(t *testing.T) {
|
||||||
Family: SourceCodePro,
|
Family: SourceCodePro,
|
||||||
Style: FONT_STYLE_BOLD,
|
Style: FONT_STYLE_BOLD,
|
||||||
}
|
}
|
||||||
fontBuf := make([]byte, len(FontFaces[f]))
|
face := FontFaces.Get(f)
|
||||||
copy(fontBuf, FontFaces[f])
|
fontBuf := make([]byte, len(face))
|
||||||
|
copy(fontBuf, face)
|
||||||
fontBuf = font.UTF8CutFont(fontBuf, " 1")
|
fontBuf = font.UTF8CutFont(fontBuf, " 1")
|
||||||
err := diff.Testdata(filepath.Join("testdata", "d2fonts", "cut"), ".txt", fontBuf)
|
err := diff.Testdata(filepath.Join("testdata", "d2fonts", "cut"), ".txt", fontBuf)
|
||||||
assert.Success(t, err)
|
assert.Success(t, err)
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ func Append(diagram *d2target.Diagram, ruler *textmeasure.Ruler, in []byte) []by
|
||||||
font-family: font-regular;
|
font-family: font-regular;
|
||||||
src: url("%s");
|
src: url("%s");
|
||||||
}
|
}
|
||||||
]]></style>`, d2fonts.FontEncodings[d2fonts.SourceSansPro.Font(0, d2fonts.FONT_STYLE_REGULAR)])
|
]]></style>`, d2fonts.FontEncodings.Get(d2fonts.SourceSansPro.Font(0, d2fonts.FONT_STYLE_REGULAR)))
|
||||||
}
|
}
|
||||||
if !strings.Contains(svg, `font-family: "font-bold"`) {
|
if !strings.Contains(svg, `font-family: "font-bold"`) {
|
||||||
appendix += fmt.Sprintf(`<style type="text/css"><![CDATA[
|
appendix += fmt.Sprintf(`<style type="text/css"><![CDATA[
|
||||||
|
|
@ -140,7 +140,7 @@ func Append(diagram *d2target.Diagram, ruler *textmeasure.Ruler, in []byte) []by
|
||||||
font-family: font-bold;
|
font-family: font-bold;
|
||||||
src: url("%s");
|
src: url("%s");
|
||||||
}
|
}
|
||||||
]]></style>`, d2fonts.FontEncodings[d2fonts.SourceSansPro.Font(0, d2fonts.FONT_STYLE_BOLD)])
|
]]></style>`, d2fonts.FontEncodings.Get(d2fonts.SourceSansPro.Font(0, d2fonts.FONT_STYLE_BOLD)))
|
||||||
}
|
}
|
||||||
|
|
||||||
closingIndex := strings.LastIndex(svg, "</svg></svg>")
|
closingIndex := strings.LastIndex(svg, "</svg></svg>")
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,8 @@ func Init() *GoFPDF {
|
||||||
UnitStr: "pt",
|
UnitStr: "pt",
|
||||||
})
|
})
|
||||||
|
|
||||||
newGofPDF.AddUTF8FontFromBytes("source", "", d2fonts.FontFaces[d2fonts.SourceSansPro.Font(0, d2fonts.FONT_STYLE_REGULAR)])
|
newGofPDF.AddUTF8FontFromBytes("source", "", d2fonts.FontFaces.Get(d2fonts.SourceSansPro.Font(0, d2fonts.FONT_STYLE_REGULAR)))
|
||||||
newGofPDF.AddUTF8FontFromBytes("source", "B", d2fonts.FontFaces[d2fonts.SourceSansPro.Font(0, d2fonts.FONT_STYLE_BOLD)])
|
newGofPDF.AddUTF8FontFromBytes("source", "B", d2fonts.FontFaces.Get(d2fonts.SourceSansPro.Font(0, d2fonts.FONT_STYLE_BOLD)))
|
||||||
newGofPDF.SetAutoPageBreak(false, 0)
|
newGofPDF.SetAutoPageBreak(false, 0)
|
||||||
newGofPDF.SetLineWidth(2)
|
newGofPDF.SetLineWidth(2)
|
||||||
newGofPDF.SetMargins(0, 0, 0)
|
newGofPDF.SetMargins(0, 0, 0)
|
||||||
|
|
|
||||||
40
lib/syncmap/syncmap.go
Normal file
40
lib/syncmap/syncmap.go
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
package syncmap
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
|
type SyncMap[K comparable, V any] struct {
|
||||||
|
_map *sync.Map
|
||||||
|
}
|
||||||
|
|
||||||
|
func New[K comparable, V any]() SyncMap[K, V] {
|
||||||
|
return SyncMap[K, V]{
|
||||||
|
_map: &sync.Map{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm SyncMap[K, V]) Set(key K, value V) {
|
||||||
|
sm._map.Store(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm SyncMap[K, V]) Lookup(key K) (value V, ok bool) {
|
||||||
|
v, has := sm._map.Load(key)
|
||||||
|
if !has {
|
||||||
|
return value, false
|
||||||
|
}
|
||||||
|
return v.(V), true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm SyncMap[K, V]) Get(key K) (value V) {
|
||||||
|
v, _ := sm.Lookup(key)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm SyncMap[K, V]) Delete(key K) {
|
||||||
|
sm._map.Delete(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm SyncMap[K, V]) Range(f func(key K, value V) bool) {
|
||||||
|
sm._map.Range(func(k, v any) bool {
|
||||||
|
return f(k.(K), v.(V))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -126,11 +126,12 @@ func NewRuler() (*Ruler, error) {
|
||||||
Style: fontStyle,
|
Style: fontStyle,
|
||||||
}
|
}
|
||||||
// Note: FontFaces lookup is size-agnostic
|
// Note: FontFaces lookup is size-agnostic
|
||||||
if _, ok := d2fonts.FontFaces[font]; !ok {
|
face, has := d2fonts.FontFaces.Lookup(font)
|
||||||
|
if !has {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, loaded := r.ttfs[font]; !loaded {
|
if _, loaded := r.ttfs[font]; !loaded {
|
||||||
ttf, err := truetype.Parse(d2fonts.FontFaces[font])
|
ttf, err := truetype.Parse(face)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue