ttf: improvement on not found glyphs (#8050)

pull/8056/head
penguindark 2021-01-12 00:49:58 +01:00 committed by GitHub
parent 5f95dd54bd
commit 55e3e50b9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 235 additions and 197 deletions

View File

@ -111,23 +111,23 @@ fn fabs(a f32) f32 {
// integer part of x
[inline]
fn ipart(x f32) f32 {
return f32(math.floor(x))
return f32(math.floor(x))
}
[inline]
fn round(x f32) f32 {
return ipart(x + 0.5)
return ipart(x + 0.5)
}
// fractional part of x
[inline]
fn fpart(x f32) f32 {
return x - f32(math.floor(x))
return x - f32(math.floor(x))
}
[inline]
fn rfpart(x f32) f32 {
return 1 - fpart(x)
return 1 - fpart(x)
}
/******************************************************************************

View File

@ -515,6 +515,13 @@ fn (mut bmp BitMap) get_chars_bbox(in_string string) []int {
}
c_index := bmp.tf.map_code(int(char))
// Glyph not found
if c_index == 0 {
w += int(space_cw * bmp.space_cw)
i += c_len
continue
}
ax , ay := bmp.tf.next_kern(c_index)
//dprintln("char_index: $c_index ax: $ax ay: $ay")
@ -548,7 +555,7 @@ fn (mut bmp BitMap) get_chars_bbox(in_string string) []int {
i+= c_len
}
return res
return res
}
pub
@ -581,6 +588,12 @@ fn (mut bmp BitMap) get_bbox(in_string string) (int, int){
}
c_index := bmp.tf.map_code(int(char))
// Glyph not found
if c_index == 0 {
w += int(space_cw * bmp.space_cw)
i += c_len
continue
}
ax , ay := bmp.tf.next_kern(c_index)
//dprintln("char_index: $c_index ax: $ax ay: $ay")
@ -612,7 +625,7 @@ fn (mut bmp BitMap) get_bbox(in_string string) (int, int){
i+= c_len
}
//dprintln("y_min: $bmp.tf.y_min y_max: $bmp.tf.y_max res: ${int((bmp.tf.y_max - bmp.tf.y_min)*buf.scale)} width: ${int( (cw) * buf.scale)}")
//buf.box(0,y_base - int((bmp.tf.y_min)*buf.scale), int( (x_max) * buf.scale), y_base-int((bmp.tf.y_max)*buf.scale), u32(0xFF00_0000) )
return w , int(abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale)
@ -623,6 +636,25 @@ fn (mut bmp BitMap) get_bbox(in_string string) (int, int){
* TTF draw glyph
*
******************************************************************************/
fn (mut bmp BitMap) draw_notdef_glyph(in_x int, in_w int) {
mut p := Point{in_x, 0, false}
x1 , y1 := bmp.trf_txt(p)
// init ch_matrix
bmp.ch_matrix[0] = bmp.tr_matrix[0] * bmp.scale * bmp.scale_x
bmp.ch_matrix[1] = bmp.tr_matrix[1] * bmp.scale * bmp.scale_x
bmp.ch_matrix[3] = bmp.tr_matrix[3] * -bmp.scale * bmp.scale_y
bmp.ch_matrix[4] = bmp.tr_matrix[4] * -bmp.scale * bmp.scale_y
bmp.ch_matrix[6] = int(x1)
bmp.ch_matrix[7] = int(y1)
x,y := bmp.trf_ch(p)
y_h := fabs(bmp.tf.y_max-bmp.tf.y_min)* bmp.scale * 0.5
bmp.box(int(x), int(y), int(x - in_w), int(y - y_h), bmp.color)
bmp.line(int(x), int(y), int(x - in_w ), int(y - y_h), bmp.color)
bmp.line(int(x - in_w ), int(y), int(x), int(y - y_h), bmp.color)
}
pub
fn (mut bmp BitMap) draw_text(in_string string) (int, int){
mut w := 0
@ -652,45 +684,52 @@ fn (mut bmp BitMap) draw_text(in_string string) (int, int){
char = u16(tmp_char)
}
c_index := bmp.tf.map_code(int(char))
ax , ay := bmp.tf.next_kern(c_index)
//dprintln("char_index: $c_index ax: $ax ay: $ay")
c_index := bmp.tf.map_code(int(char))
// Glyph not found
if c_index == 0 {
bmp.draw_notdef_glyph(w, int(space_cw * bmp.space_cw))
w += int(space_cw * bmp.space_cw)
i += c_len
continue
}
cw, _ := bmp.tf.get_horizontal_metrics(u16(char))
//cw, lsb := bmp.tf.get_horizontal_metrics(u16(char))
//dprintln("metrics: [${u16(char):c}] cw:$cw lsb:$lsb")
//----- Draw_Glyph transformations -----
mut x0 := w + int(ax * bmp.scale)
mut y0 := 0 + int(ay * bmp.scale)
p := Point{x0,y0,false}
x1 , y1 := bmp.trf_txt(p)
// init ch_matrix
bmp.ch_matrix[0] = bmp.tr_matrix[0] * bmp.scale * bmp.scale_x
bmp.ch_matrix[1] = bmp.tr_matrix[1] * bmp.scale * bmp.scale_x
bmp.ch_matrix[3] = bmp.tr_matrix[3] * -bmp.scale * bmp.scale_y
bmp.ch_matrix[4] = bmp.tr_matrix[4] * -bmp.scale * bmp.scale_y
bmp.ch_matrix[6] = int(x1)
bmp.ch_matrix[7] = int(y1)
ax , ay := bmp.tf.next_kern(c_index)
//dprintln("char_index: $c_index ax: $ax ay: $ay")
x_min, x_max := bmp.draw_glyph(c_index)
// x_min := 1
// x_max := 2
//-----------------
cw, _ := bmp.tf.get_horizontal_metrics(u16(char))
//cw, lsb := bmp.tf.get_horizontal_metrics(u16(char))
//dprintln("metrics: [${u16(char):c}] cw:$cw lsb:$lsb")
mut width := int( (abs(x_max + x_min) + ax) * bmp.scale)
if bmp.use_font_metrics {
width = int((cw+ax) * bmp.scale)
}
w += width + div_space_cw
//----- Draw_Glyph transformations -----
mut x0 := w + int(ax * bmp.scale)
mut y0 := 0 + int(ay * bmp.scale)
i+= c_len
}
//dprintln("y_min: $bmp.tf.y_min y_max: $bmp.tf.y_max res: ${int((bmp.tf.y_max - bmp.tf.y_min)*buf.scale)} width: ${int( (cw) * buf.scale)}")
//buf.box(0,y_base - int((bmp.tf.y_min)*buf.scale), int( (x_max) * buf.scale), y_base-int((bmp.tf.y_max)*buf.scale), u32(0xFF00_0000) )
return w , int(abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale)
p := Point{x0,y0,false}
x1 , y1 := bmp.trf_txt(p)
// init ch_matrix
bmp.ch_matrix[0] = bmp.tr_matrix[0] * bmp.scale * bmp.scale_x
bmp.ch_matrix[1] = bmp.tr_matrix[1] * bmp.scale * bmp.scale_x
bmp.ch_matrix[3] = bmp.tr_matrix[3] * -bmp.scale * bmp.scale_y
bmp.ch_matrix[4] = bmp.tr_matrix[4] * -bmp.scale * bmp.scale_y
bmp.ch_matrix[6] = int(x1)
bmp.ch_matrix[7] = int(y1)
x_min, x_max := bmp.draw_glyph(c_index)
// x_min := 1
// x_max := 2
//-----------------
mut width := int( (abs(x_max + x_min) + ax) * bmp.scale)
if bmp.use_font_metrics {
width = int((cw+ax) * bmp.scale)
}
w += width + div_space_cw
i+= c_len
}
//dprintln("y_min: $bmp.tf.y_min y_max: $bmp.tf.y_max res: ${int((bmp.tf.y_max - bmp.tf.y_min)*buf.scale)} width: ${int( (cw) * buf.scale)}")
//buf.box(0,y_base - int((bmp.tf.y_min)*buf.scale), int( (x_max) * buf.scale), y_base-int((bmp.tf.y_max)*buf.scale), u32(0xFF00_0000) )
return w , int(abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale)
}
pub
@ -759,13 +798,13 @@ fn (mut bmp BitMap) draw_glyph(index u16) (int, int){
} else {
//dprintln("HERE2")
// ctx.quadraticCurveTo(prev.x + x, prev.y + y,
// (prev.x + point.x) / 2 + x,
// (prev.y + point.y) / 2 + y);
//bmp.line(x0, y0, (prev.x + point.x)/2, (prev.y + point.y)/2, color2)
//bmp.quadratic(x0, y0, (prev.x + point.x)/2, (prev.y + point.y)/2, prev.x, prev.y, color2)
bmp.quadratic(x0, y0, (prev.x + point.x)/2, (prev.y + point.y)/2, prev.x, prev.y, color)
x0 = (prev.x + point.x)/2
// (prev.x + point.x) / 2 + x,
// (prev.y + point.y) / 2 + y);
//bmp.line(x0, y0, (prev.x + point.x)/2, (prev.y + point.y)/2, color2)
//bmp.quadratic(x0, y0, (prev.x + point.x)/2, (prev.y + point.y)/2, prev.x, prev.y, color2)
bmp.quadratic(x0, y0, (prev.x + point.x)/2, (prev.y + point.y)/2, prev.x, prev.y, color)
x0 = (prev.x + point.x)/2
y0 = (prev.y + point.y)/2
}
}
@ -774,29 +813,29 @@ fn (mut bmp BitMap) draw_glyph(index u16) (int, int){
//dprintln("count == glyph.contour_ends[count]")
if s == 2 { // final point was off-curve. connect to start
mut start_point := glyph.points[contour_start]
start_point.x, start_point.y = bmp.trf_ch(start_point)
if point.on_curve {
mut start_point := glyph.points[contour_start]
start_point.x, start_point.y = bmp.trf_ch(start_point)
if point.on_curve {
//ctx.quadraticCurveTo(prev.x + x, prev.y + y,
// point.x + x, point.y + y);
//bmp.line(x0, y0, start_point.x + in_x, start_point.y + in_y, u32(0x00FF0000))
bmp.quadratic(x0, y0, start_point.x, start_point.y ,
// start_point.x + in_x, start_point.y + in_y, u32(0xFF00FF00))
start_point.x, start_point.y, color)
//point.x + x, point.y + y);
//bmp.line(x0, y0, start_point.x + in_x, start_point.y + in_y, u32(0x00FF0000))
bmp.quadratic(x0, y0, start_point.x, start_point.y ,
// start_point.x + in_x, start_point.y + in_y, u32(0xFF00FF00))
start_point.x, start_point.y, color)
} else {
//ctx.quadraticCurveTo(prev.x + x, prev.y + y,
// (prev.x + point.x) / 2 + x,
// (prev.y + point.y) / 2 + y);
//bmp.line(x0, y0, start_point.x, start_point.y, u32(0x00FF0000)
bmp.quadratic(x0, y0, start_point.x, start_point.y,
(point.x + start_point.x)/2,
(point.y + start_point.y)/2,
//u32(0xFF000000))
// (prev.x + point.x) / 2 + x,
// (prev.y + point.y) / 2 + y);
//bmp.line(x0, y0, start_point.x, start_point.y, u32(0x00FF0000)
bmp.quadratic(x0, y0, start_point.x, start_point.y,
(point.x + start_point.x)/2,
(point.y + start_point.y)/2,
//u32(0xFF000000))
color)
}
}else{
} else {
// last point not in a curve
//bmp.line(point.x, point.y, sp_x, sp_y, u32(0x00FF0000))
bmp.line(point.x, point.y, sp_x, sp_y, color)

View File

@ -156,7 +156,7 @@ fn (mut tf_skl TTF_render_Sokol) create_texture(){
height: h
num_mipmaps: 0
min_filter: .linear
mag_filter: .linear
mag_filter: .linear
//usage: .dynamic
wrap_u: .clamp_to_edge
wrap_v: .clamp_to_edge

View File

@ -24,10 +24,10 @@ import strings
******************************************************************************/
struct Segment {
mut:
id_range_offset u32
start_code u16
end_code u16
id_delta u16
id_range_offset u32
start_code u16
end_code u16
id_delta u16
}
struct TrueTypeCmap {
@ -220,8 +220,8 @@ fn (mut tf TTF_File) glyph_count() u16{
old_pos := tf.pos
tf.pos = tf.tables["maxp"].offset + 4
count := tf.get_u16()
tf.pos = old_pos
return count
tf.pos = old_pos
return count
}
pub
@ -474,22 +474,21 @@ fn (mut tf TTF_File) read_compound_glyph(mut in_glyph Glyph){
simple_glyph := tf.read_glyph(component.glyph_index)
if simple_glyph.valid_glyph {
point_offset := in_glyph.points.len
for i in 0..simple_glyph.contour_ends.len {
in_glyph.contour_ends << u16(simple_glyph.contour_ends[i] + point_offset)
}
for i in 0..simple_glyph.contour_ends.len {
in_glyph.contour_ends << u16(simple_glyph.contour_ends[i] + point_offset)
}
for p in simple_glyph.points {
mut x := f32(p.x)
mut y := f32(p.y)
x = component.matrix[0] * x + component.matrix[1] * y + component.matrix[4]
y = component.matrix[2] * x + component.matrix[3] * y + component.matrix[5]
in_glyph.points << Point{
x: int(x)
y: int(y)
on_curve: p.on_curve
}
}
for p in simple_glyph.points {
mut x := f32(p.x)
mut y := f32(p.y)
x = component.matrix[0] * x + component.matrix[1] * y + component.matrix[4]
y = component.matrix[2] * x + component.matrix[3] * y + component.matrix[5]
in_glyph.points << Point{
x: int(x)
y: int(y)
on_curve: p.on_curve
}
}
}
tf.pos = old_pos
}
@ -501,7 +500,7 @@ fn (mut tf TTF_File) read_compound_glyph(mut in_glyph Glyph){
}
// ok we have a valid glyph
in_glyph.valid_glyph = true
in_glyph.valid_glyph = true
}
/******************************************************************************
@ -695,9 +694,9 @@ fn (mut tf TTF_File) read_head_table() {
tf.y_max = tf.get_i16()
tf.mac_style = tf.get_u16()
tf.lowest_rec_ppem = tf.get_u16()
tf.font_direction_hint = tf.get_i16()
tf.index_to_loc_format = tf.get_i16()
tf.glyph_data_format = tf.get_i16()
tf.font_direction_hint = tf.get_i16()
tf.index_to_loc_format = tf.get_i16()
tf.glyph_data_format = tf.get_i16()
}
/******************************************************************************
@ -721,36 +720,36 @@ fn (mut tf TTF_File) read_name_table() {
/*platform_specific_id :=*/ tf.get_u16()
/*language_id :=*/ tf.get_u16()
name_id := tf.get_u16()
length := tf.get_u16()
offset := tf.get_u16()
length := tf.get_u16()
offset := tf.get_u16()
old_pos := tf.pos
tf.pos = table_offset + string_offset + offset
old_pos := tf.pos
tf.pos = table_offset + string_offset + offset
mut name := ""
if platform_id == 0 || platform_id == 3 {
mut name := ""
if platform_id == 0 || platform_id == 3 {
name = tf.get_unicode_string(length)
} else {
name = tf.get_string(length)
}
//dprintln("Name [${platform_id} / ${platform_specific_id}] id:[$name_id] language:[$language_id] [$name]")
tf.pos = old_pos
} else {
name = tf.get_string(length)
}
//dprintln("Name [${platform_id} / ${platform_specific_id}] id:[$name_id] language:[$language_id] [$name]")
tf.pos = old_pos
match name_id {
1 {
tf.font_family = name
match name_id {
1 {
tf.font_family = name
}
2 {
tf.font_sub_family = name
}
4 {
tf.full_name = name
}
6 {
tf.postscript_name = name
}
else {}
}
2 {
tf.font_sub_family = name
}
4 {
tf.full_name = name
}
6 {
tf.postscript_name = name
}
else {}
}
}
}
@ -767,24 +766,24 @@ fn (mut tf TTF_File) read_cmap_table() {
version := tf.get_u16() // must be 0
assert version == 0
number_sub_tables := tf.get_u16()
number_sub_tables := tf.get_u16()
// tables must be sorted by platform id and then platform specific
// encoding.
for _ in 0..number_sub_tables {
// platforms are:
// 0 - Unicode -- use specific id 6 for full coverage. 0/4 common.
// 1 - Macintosh (Discouraged)
// 2 - reserved
// 3 - Microsoft
platform_id := tf.get_u16()
// encoding.
for _ in 0..number_sub_tables {
// platforms are:
// 0 - Unicode -- use specific id 6 for full coverage. 0/4 common.
// 1 - Macintosh (Discouraged)
// 2 - reserved
// 3 - Microsoft
platform_id := tf.get_u16()
platform_specific_id := tf.get_u16()
offset := tf.get_u32()
dprintln("CMap platform_id=${platform_id} specific_id=${platform_specific_id} offset=${offset}")
if platform_id == 3 && platform_specific_id <= 1 {
tf.read_cmap(table_offset + offset)
}
}
if platform_id == 3 && platform_specific_id <= 1 {
tf.read_cmap(table_offset + offset)
}
}
}
fn (mut tf TTF_File) read_cmap(offset u32) {
@ -817,17 +816,17 @@ fn (mut tf TTF_File) read_cmap(offset u32) {
******************************************************************************/
fn (mut tf TTF_File) map_code(char_code int) u16{
mut index := 0
for i in 0..tf.cmaps.len {
mut cmap := tf.cmaps[i]
if cmap.format == 0 {
//dprintln("format 0")
index = cmap.map_0(char_code)
} else if cmap.format == 4 {
//dprintln("format 4")
index = cmap.map_4(char_code, mut tf)
for i in 0..tf.cmaps.len {
mut cmap := tf.cmaps[i]
if cmap.format == 0 {
//dprintln("format 0")
index = cmap.map_0(char_code)
} else if cmap.format == 4 {
//dprintln("format 4")
index = cmap.map_4(char_code, mut tf)
}
}
}
return u16(index)
return u16(index)
}
fn (mut tm TrueTypeCmap) init_0(mut tf TTF_File) {
@ -851,45 +850,45 @@ fn (mut tm TrueTypeCmap) init_4(mut tf TTF_File) {
tm.format = 4
// 2x segcount
seg_count := tf.get_u16() >> 1
/*search_range :=*/ tf.get_u16()
/*entry_selector :=*/ tf.get_u16()
/*range_shift :=*/ tf.get_u16()
seg_count := tf.get_u16() >> 1
/*search_range :=*/ tf.get_u16()
/*entry_selector :=*/ tf.get_u16()
/*range_shift :=*/ tf.get_u16()
// Ending character code for each segment, last is 0xffff
for _ in 0..seg_count {
// Ending character code for each segment, last is 0xffff
for _ in 0..seg_count {
tm.segments << Segment{0, 0, tf.get_u16(), 0}
}
}
// reservePAD
tf.get_u16()
// reservePAD
tf.get_u16()
// starting character code for each segment
for i in 0..seg_count {
// starting character code for each segment
for i in 0..seg_count {
tm.segments[i].start_code = tf.get_u16()
}
}
// Delta for all character codes in segment
for i in 0..seg_count {
// Delta for all character codes in segment
for i in 0..seg_count {
tm.segments[i].id_delta = tf.get_u16()
}
}
// offset in bytes to glyph indexArray, or 0
for i in 0..seg_count {
// offset in bytes to glyph indexArray, or 0
for i in 0..seg_count {
ro := u32(tf.get_u16())
if ro != 0 {
tm.segments[i].id_range_offset = tf.pos - 2 + ro
} else {
tm.segments[i].id_range_offset = 0
}
}
}
/*
// DEBUG LOG
for i in 0..seg_count {
// DEBUG LOG
for i in 0..seg_count {
seg := tm.segments[i]
dprintln(" segments[$i] = $seg.start_code $seg.end_code $seg.id_delta $seg.id_range_offset")
}
}
*/
}
@ -935,21 +934,21 @@ fn (mut tf TTF_File) read_hhea_table() {
/*version :=*/ tf.get_fixed() // 0x00010000
tf.ascent = tf.get_fword()
tf.descent = tf.get_fword()
tf.line_gap = tf.get_fword()
tf.advance_width_max = tf.get_ufword()
tf.min_left_side_bearing = tf.get_fword()
tf.min_right_side_bearing = tf.get_fword()
tf.x_max_extent = tf.get_fword()
tf.caret_slope_rise = tf.get_i16()
tf.caret_slope_run = tf.get_i16()
tf.caret_offset = tf.get_fword()
tf.get_i16() // reserved
tf.get_i16() // reserved
tf.get_i16() // reserved
tf.get_i16() // reserved
tf.metric_data_format = tf.get_i16()
tf.num_of_long_hor_metrics = tf.get_u16()
tf.descent = tf.get_fword()
tf.line_gap = tf.get_fword()
tf.advance_width_max = tf.get_ufword()
tf.min_left_side_bearing = tf.get_fword()
tf.min_right_side_bearing = tf.get_fword()
tf.x_max_extent = tf.get_fword()
tf.caret_slope_rise = tf.get_i16()
tf.caret_slope_run = tf.get_i16()
tf.caret_offset = tf.get_fword()
tf.get_i16() // reserved
tf.get_i16() // reserved
tf.get_i16() // reserved
tf.get_i16() // reserved
tf.metric_data_format = tf.get_i16()
tf.num_of_long_hor_metrics = tf.get_u16()
}
/******************************************************************************
@ -959,11 +958,11 @@ fn (mut tf TTF_File) read_hhea_table() {
******************************************************************************/
struct Kern0Table {
mut:
swap bool
offset u32
n_pairs int
kmap map[u32]i16
old_index int = -1
swap bool
offset u32
n_pairs int
kmap map[u32]i16
old_index int = -1
}
fn (mut kt Kern0Table) reset() {
@ -1027,23 +1026,23 @@ fn (mut tf TTF_File) read_kern_table() {
dprintln("Kern Table version: $version Kern nTables: $n_tables")
for _ in 0..n_tables{
st_version := tf.get_u16() // sub table version
length := tf.get_u16()
coverage := tf.get_u16()
format := coverage >> 8
cross := coverage & 4
vertical := (coverage & 0x1) == 0
dprintln("Kerning subtable version [$st_version] format [$format] length [$length] coverage: [${coverage.hex()}]")
if format == 0 {
dprintln("kern format: 0")
kern := tf.create_kern_table0(vertical, cross != 0)
tf.kern << kern
} else {
dprintln("Unknown format -- skip")
tf.pos = tf.pos + length
for _ in 0..n_tables{
st_version := tf.get_u16() // sub table version
length := tf.get_u16()
coverage := tf.get_u16()
format := coverage >> 8
cross := coverage & 4
vertical := (coverage & 0x1) == 0
dprintln("Kerning subtable version [$st_version] format [$format] length [$length] coverage: [${coverage.hex()}]")
if format == 0 {
dprintln("kern format: 0")
kern := tf.create_kern_table0(vertical, cross != 0)
tf.kern << kern
} else {
dprintln("Unknown format -- skip")
tf.pos = tf.pos + length
}
}
}
}
fn (mut tf TTF_File) reset_kern() {