-
Notifications
You must be signed in to change notification settings - Fork 4
/
renderer_internals.go
144 lines (126 loc) · 4.75 KB
/
renderer_internals.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package etxt
import (
"strconv"
"github.com/tinne26/etxt/fract"
"github.com/tinne26/etxt/mask"
"golang.org/x/image/font/sfnt"
"golang.org/x/image/math/fixed"
)
// The bool indicates whether the glyph should be skipped.
func (self *Renderer) getGlyphIndex(font *sfnt.Font, codePoint rune) (index sfnt.GlyphIndex, skip bool) {
var err error
index, err = font.GlyphIndex(&self.buffer, codePoint)
if err != nil {
panic("font.GlyphIndex error: " + err.Error())
}
if index == 0 {
if self.missHandlerFn != nil {
index, skip = self.missHandlerFn(font, codePoint)
} else {
msg := "glyph index for '" + string(codePoint) + "' ["
msg += runeToUnicodeCode(codePoint) + "] missing"
panic(msg)
}
}
return index, skip
}
func (self *Renderer) withTextDirSign(value fract.Unit) fract.Unit {
if self.state.textDirection == LeftToRight {
return value
}
return -value
}
func (self *Renderer) scaleLogicalSize(logicalSize fract.Unit) fract.Unit {
return logicalSize.MulDown(self.state.scale) // *
// * I prefer MulDown to compensate having used FromFloat64Up()
// on both size and scale conversions. It's not a big deal in
// either case, but this reduces the maximum potential error.
}
// loadGlyphMask loads the mask for the given glyph at the given fractional
// pixel position. The renderer's cache handler, font, size, rasterizer and
// mask format are all taken into account.
// Precondition: !self.missingBasicProps(), rasterizer initialized,
// origin position communicated to the cache if relevant.
func (self *Renderer) loadGlyphMask(font *sfnt.Font, index sfnt.GlyphIndex, origin fract.Point) GlyphMask {
// if the mask is available in the cache, that's all
if self.cacheHandler != nil {
glyphMask, found := self.cacheHandler.GetMask(index)
if found {
return glyphMask
}
}
// glyph mask not cached, let's rasterize on our own
segments, err := font.LoadGlyph(&self.buffer, index, fixed.Int26_6(self.state.scaledSize), nil)
if err != nil {
// if you need to deal with missing glyphs, you should do so before
// reaching this point with functions like GetMissingRunes() and
// replacing the relevant runes or glyphs
panic("font.LoadGlyph(index = " + strconv.Itoa(int(index)) + ") error: " + err.Error())
}
// rasterize the glyph mask
alphaMask, err := mask.Rasterize(segments, self.state.rasterizer, origin)
if err != nil {
panic("RasterizeGlyphMask failed: " + err.Error())
}
// pass to cache and return
glyphMask := convertAlphaImageToGlyphMask(alphaMask)
if self.cacheHandler != nil {
self.cacheHandler.PassMask(index, glyphMask)
}
return glyphMask
}
// --- internal functions for draw and renderer ---
// Precondition: sizer and font have been validated to be initialized.
func (self *Renderer) getOpKernBetween(prevGlyphIndex, currGlyphIndex sfnt.GlyphIndex) fract.Unit {
return self.state.fontSizer.Kern(
self.state.activeFont, &self.buffer, self.state.scaledSize,
prevGlyphIndex, currGlyphIndex,
)
}
func (self *Renderer) getOpAdvance(currGlyphIndex sfnt.GlyphIndex) fract.Unit {
return self.state.fontSizer.GlyphAdvance(
self.state.activeFont, &self.buffer, self.state.scaledSize, currGlyphIndex,
)
}
func (self *Renderer) getOpLineAdvance(lineBreakNth int) fract.Unit {
return self.state.fontSizer.LineAdvance(
self.state.activeFont, &self.buffer, self.state.scaledSize, lineBreakNth,
)
}
func (self *Renderer) getOpLineHeight() fract.Unit {
return self.state.fontSizer.LineHeight(
self.state.activeFont, &self.buffer, self.state.scaledSize,
)
}
func (self *Renderer) getOpAscent() fract.Unit {
return self.state.fontSizer.Ascent(
self.state.activeFont, &self.buffer, self.state.scaledSize,
)
}
func (self *Renderer) getOpDescent() fract.Unit {
return self.state.fontSizer.Descent(
self.state.activeFont, &self.buffer, self.state.scaledSize,
)
}
// Notice: this is rather slow, uncached. I'm leaving it like this because
// it's rarely used anyway, and in the grand scheme of things, when this is
// actually required, most of the runtime will still go to actual font
// rendering... but *there is* room for improvement (especially if we were
// not using golang's sfnt package, which is kinda shitty).
func (self *Renderer) getSlowOpXHeight() fract.Unit {
const hintingNone = 0
metrics, err := self.state.activeFont.Metrics(&self.buffer, fixed.Int26_6(self.state.scaledSize), hintingNone)
if err != nil {
panic("font.Metrics error: " + err.Error())
}
return fract.Unit(metrics.XHeight)
}
// same concept as getSlowOpXHeight() above
func (self *Renderer) getSlowOpCapHeight() fract.Unit {
const hintingNone = 0
metrics, err := self.state.activeFont.Metrics(&self.buffer, fixed.Int26_6(self.state.scaledSize), hintingNone)
if err != nil {
panic("font.Metrics error: " + err.Error())
}
return fract.Unit(metrics.CapHeight)
}