Skip to content

Commit

Permalink
jk/glyph indices (#2139)
Browse files Browse the repository at this point in the history
  • Loading branch information
jkrumbiegel committed Aug 24, 2022
1 parent 75b145e commit a192fa7
Show file tree
Hide file tree
Showing 9 changed files with 58 additions and 85 deletions.
27 changes: 21 additions & 6 deletions CairoMakie/src/primitives.jl
Original file line number Diff line number Diff line change
Expand Up @@ -425,19 +425,15 @@ function draw_glyph_collection(scene, ctx, position, glyph_collection, rotation,
)

Cairo.save(ctx)
Cairo.move_to(ctx, glyphpos...)
set_font_matrix(ctx, mat)
Cairo.show_text(ctx, string(glyph))
# show_text makes an implicite move_to at the end, which starts a new one point path.
# `new_path` clears that path so it doesn't end up as an artifact in the next stroke call
Cairo.new_path(ctx)
show_glyph(ctx, glyph, glyphpos...)
Cairo.restore(ctx)

if strokewidth > 0 && strokecolor != RGBAf(0, 0, 0, 0)
Cairo.save(ctx)
Cairo.move_to(ctx, glyphpos...)
set_font_matrix(ctx, mat)
Cairo.text_path(ctx, string(glyph))
glyph_path(ctx, glyph, glyphpos...)
Cairo.set_source_rgba(ctx, rgbatuple(strokecolor)...)
Cairo.set_line_width(ctx, strokewidth)
Cairo.stroke(ctx)
Expand All @@ -453,6 +449,25 @@ function draw_glyph_collection(scene, ctx, position, glyph_collection, rotation,
return
end

struct CairoGlyph
index::Culong
x::Cdouble
y::Cdouble
end

function show_glyph(ctx, glyph, x, y)
cg = Ref(CairoGlyph(glyph, x, y))
ccall((:cairo_show_glyphs, Cairo.libcairo),
Nothing, (Ptr{Nothing}, Ptr{CairoGlyph}, Cint),
ctx.ptr, cg, 1)
end
function glyph_path(ctx, glyph::Culong, x, y)
cg = Ref(CairoGlyph(glyph, x, y))
ccall((:cairo_glyph_path, Cairo.libcairo),
Nothing, (Ptr{Nothing}, Ptr{CairoGlyph}, Cint),
ctx.ptr, cg, 1)
end

################################################################################
# Heatmap, Image #
################################################################################
Expand Down
2 changes: 1 addition & 1 deletion GLMakie/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ ColorTypes = "0.9, 0.10, 0.11"
Colors = "0.11, 0.12"
FileIO = "1.6"
FixedPointNumbers = "0.7, 0.8"
FreeTypeAbstraction = "0.8, 0.9"
FreeTypeAbstraction = "0.10"
GLFW = "3"
GeometryBasics = "0.4.1"
Makie = "=0.17.13"
Expand Down
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ FileIO = "1.6"
FixedPointNumbers = "0.6, 0.7, 0.8"
Formatting = "0.4"
FreeType = "3.0, 4.0"
FreeTypeAbstraction = "0.8, 0.9"
FreeTypeAbstraction = "0.10"
GeometryBasics = "0.4.2"
GridLayoutBase = "0.9"
ImageIO = "0.2, 0.3, 0.4, 0.5, 0.6"
Expand All @@ -74,7 +74,7 @@ KernelDensity = "0.5, 0.6"
LaTeXStrings = "1.2"
MakieCore = "=0.4.0"
Match = "1.1"
MathTeXEngine = "0.4"
MathTeXEngine = "0.5"
Observables = "0.5.1"
OffsetArrays = "1"
Packing = "0.4"
Expand Down
2 changes: 1 addition & 1 deletion WGLMakie/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
[compat]
Colors = "0.11, 0.12"
FileIO = "1.1"
FreeTypeAbstraction = "0.8, 0.9"
FreeTypeAbstraction = "0.10"
GeometryBasics = "0.4.1"
Hyperscript = "0.0.3, 0.0.4"
ImageMagick = "1.1"
Expand Down
43 changes: 7 additions & 36 deletions src/basic_recipes/text.jl
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ function texelems_and_glyph_collection(str::LaTeXString, fontscale_px, halign, v
scales_2d = [Vec2f(x[3] * Vec2f(fs)) for x in els]

texchars = [x[1] for x in els]
chars = [texchar.char for texchar in texchars]
glyphindices = [FreeTypeAbstraction.glyph_index(texchar) for texchar in texchars]
fonts = [texchar.font for texchar in texchars]
extents = GlyphExtent.(texchars)

Expand All @@ -181,23 +181,24 @@ function texelems_and_glyph_collection(str::LaTeXString, fontscale_px, halign, v
last_newline_idx = 1
newline_offset = Point3f(basepositions[1][1], 0f0, 0)

for i in eachindex(chars)
for i in eachindex(texchars)
basepositions[i] -= newline_offset
if chars[i] == ' ' || i == length(chars)
if texchars[i].represented_char == ' ' || i == length(texchars)
right_pos = basepositions[i][1] + width(bboxes[i])
if last_space_idx != 0 && right_pos > word_wrap_width
section_offset = basepositions[last_space_idx + 1][1]
lineheight = maximum((height(bb) for bb in bboxes[last_newline_idx:last_space_idx]))
last_newline_idx = last_space_idx+1
newline_offset += Point3f(section_offset, lineheight, 0)

chars[last_space_idx] = '\n'
# TODO: newlines don't really need to represented at all?
# chars[last_space_idx] = '\n'
for j in last_space_idx+1:i
basepositions[j] -= Point3f(section_offset, lineheight, 0)
end
end
last_space_idx = i
elseif chars[i] == '\n'
elseif texchars[i].represented_char == '\n'
last_space_idx = 0
end
end
Expand Down Expand Up @@ -229,38 +230,8 @@ function texelems_and_glyph_collection(str::LaTeXString, fontscale_px, halign, v
positions = basepositions .- Ref(shift)
positions .= Ref(rot) .* positions

# # we replace VLine and HLine with characters that are specifically scaled and positioned
# # such that they match line length and thickness
# for (el, position, _) in all_els
# el isa MathTeXEngine.VLine || el isa MathTeXEngine.HLine || continue
# if el isa MathTeXEngine.HLine
# w, h = el.width, el.thickness
# else
# w, h = el.thickness, el.height
# end
# font = to_font("TeX Gyre Heros Makie")
# c = el isa MathTeXEngine.HLine ? '_' : '|'
# fext = get_extent(font, c)
# inkbb = FreeTypeAbstraction.inkboundingbox(fext)
# w_ink = width(inkbb)
# h_ink = height(inkbb)
# ori = inkbb.origin

# char_scale = Vec2f(w / w_ink, h / h_ink) * fs

# pos_scaled = fs * Vec2f(position)
# pos_inkshifted = pos_scaled - char_scale * ori - Vec2f(0, h_ink / 2) # TODO fix for VLine
# pos_final = rot * Vec3f((pos_inkshifted - Vec2f(shift[Vec(1, 2)]))..., 0)

# push!(positions, pos_final)
# push!(chars, c)
# push!(fonts, font)
# push!(extents, GlyphExtent(font, c))
# push!(scales_2d, char_scale)
# end

pre_align_gl = GlyphCollection(
chars,
glyphindices,
fonts,
Point3f.(positions),
extents,
Expand Down
2 changes: 1 addition & 1 deletion src/layouting/layouting.jl
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ function glyph_collection(
# interactive features that need to know where characters begin and end
per_char(attr) = collect(attribute_per_char(str, attr)) # attribute_per_char returns generators
return GlyphCollection(
[x.char for x in charinfos],
[FreeTypeAbstraction.glyph_index(x.font, x.char) for x in charinfos],
[x.font for x in charinfos],
reduce(vcat, charorigins),
[x.extent for x in charinfos],
Expand Down
2 changes: 1 addition & 1 deletion src/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ end
Stores information about the glyphs in a string that had a layout calculated for them.
"""
struct GlyphCollection
glyphs::Vector{Char}
glyphs::Vector{UInt64}
fonts::Vector{FTFont}
origins::Vector{Point3f}
extents::Vector{GlyphExtent}
Expand Down
59 changes: 23 additions & 36 deletions src/utilities/texture_atlas.jl
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using FreeTypeAbstraction: iter_or_array

mutable struct TextureAtlas
rectangle_packer::RectanglePacker
mapping::Dict{Tuple{Char, String}, Int} # styled glyph to index in sprite_attributes
mapping::Dict{Tuple{UInt64, String}, Int} # styled glyph to index in sprite_attributes
index::Int
data::Matrix{Float16}
# rectangles we rendered our glyphs into in normalized uv coordinates
Expand Down Expand Up @@ -42,7 +40,7 @@ end
function TextureAtlas(initial_size = TEXTURE_RESOLUTION[])
return TextureAtlas(
RectanglePacker(Rect2(0, 0, initial_size...)),
Dict{Tuple{Char, String}, Int}(),
Dict{Tuple{UInt64, String}, Int}(),
1,
# We use float max here to avoid texture bleed. See #2096
fill(Float16(0.5PIXELSIZE_IN_ATLAS[] + GLYPH_PADDING[]), initial_size...),
Expand Down Expand Up @@ -150,54 +148,42 @@ end
Finds the best font for a character from a list of fallback fonts, that get chosen
if `font` can't represent char `c`
"""
function find_font_for_char(c::Char, font::NativeFont)
FT_Get_Char_Index(font, c) != 0 && return font
function find_font_for_char(glyph, font::NativeFont)
FreeTypeAbstraction.glyph_index(font, glyph) != 0 && return font
# it seems that linebreaks are not found which messes up font metrics
# if another font is selected just for those chars
c in ('\n', '\r', '\t') && return font
glyph in ('\n', '\r', '\t') && return font
for afont in alternativefonts()
if FT_Get_Char_Index(afont, c) != 0
if FreeTypeAbstraction.glyph_index(afont, glyph) != 0
return afont
end
end
error("Can't represent character $(c) with any fallback font nor $(font.family_name)!")
error("Can't represent character $(glyph) with any fallback font nor $(font.family_name)!")
end

function glyph_index!(atlas::TextureAtlas, c::Char, font::NativeFont)
if FT_Get_Char_Index(font, c) == 0
function glyph_index!(atlas::TextureAtlas, glyph, font::NativeFont)
if FreeTypeAbstraction.glyph_index(font, glyph) == 0
for afont in alternativefonts()
if FT_Get_Char_Index(afont, c) != 0
if FreeTypeAbstraction.glyph_index(afont, glyph) != 0
font = afont
end
end
end
return insert_glyph!(atlas, c, font)
return insert_glyph!(atlas, glyph, font)
end


function glyph_uv_width!(atlas::TextureAtlas, c::Char, font::NativeFont)
return atlas.uv_rectangles[glyph_index!(atlas, c, font)]
function glyph_uv_width!(atlas::TextureAtlas, glyph, font::NativeFont)
return atlas.uv_rectangles[glyph_index!(atlas, glyph, font)]
end

function glyph_uv_width!(c::Char)
return glyph_uv_width!(get_texture_atlas(), c, defaultfont())
function glyph_uv_width!(glyph)
return glyph_uv_width!(get_texture_atlas(), glyph, defaultfont())
end

# function glyph_boundingbox(c::Char, font::NativeFont, pixelsize)
# if FT_Get_Char_Index(font, c) == 0
# for afont in alternativefonts()
# if FT_Get_Char_Index(afont, c) != 0
# font = afont
# break
# end
# end
# end
# bb, ext = FreeTypeAbstraction.metrics_bb(c, font, pixelsize)
# return bb
# end

function insert_glyph!(atlas::TextureAtlas, glyph::Char, font::NativeFont)
return get!(atlas.mapping, (glyph, FreeTypeAbstraction.fontname(font))) do
function insert_glyph!(atlas::TextureAtlas, glyph, font::NativeFont)
glyphindex = FreeTypeAbstraction.glyph_index(font, glyph)
return get!(atlas.mapping, (glyphindex, FreeTypeAbstraction.fontname(font))) do
# We save glyphs as signed distance fields, i.e. we save the distance
# a pixel is away from the edge of a symbol (continuous at the edge).
# To get accurate distances we want to draw the symbol at high
Expand All @@ -210,7 +196,7 @@ function insert_glyph!(atlas::TextureAtlas, glyph::Char, font::NativeFont)
# resulting sdf.
pad = GLYPH_PADDING[]

uv_pixel = render(atlas, glyph, font, downsample, pad)
uv_pixel = render(atlas, glyphindex, font, downsample, pad)
tex_size = Vec2f(size(atlas.data) .- 1) # starts at 1

# 0 based
Expand Down Expand Up @@ -269,11 +255,12 @@ function remove_font_render_callback!(f)
end
end

function render(atlas::TextureAtlas, glyph::Char, font, downsample=5, pad=6)
#select_font_face(cc, font)
if glyph == '\n' # don't render newline
function render(atlas::TextureAtlas, glyph, font, downsample=5, pad=6)
# TODO: Is this needed or should newline be filtered before this?
if FreeTypeAbstraction.glyph_index(font, glyph) == FreeTypeAbstraction.glyph_index(font, '\n') # don't render newline
glyph = ' '
end

# the target pixel size of our distance field
pixelsize = PIXELSIZE_IN_ATLAS[]
# we render the font `downsample` sizes times bigger
Expand Down
2 changes: 1 addition & 1 deletion test/text.jl
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
])

@test glyph_collection isa Makie.GlyphCollection
@test glyph_collection.glyphs == chars
@test glyph_collection.glyphs == FreeTypeAbstraction.glyph_index.(font, chars)
@test glyph_collection.fonts == [font for _ in 1:4]
@test all(isapprox.(glyph_collection.origins, [Point3f(x, 0, 0) for x in origins], atol = 1e-10))
@test glyph_collection.scales.sv == [Vec2f(p.textsize[]) for _ in 1:4]
Expand Down

0 comments on commit a192fa7

Please sign in to comment.