skrift-x11 0.1.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/example.rb +29 -41
- data/lib/skrift/x11/boxdrawing.rb +198 -0
- data/lib/skrift/x11/glyphs.rb +168 -45
- data/lib/skrift/x11/version.rb +1 -1
- data/skrift-x11.gemspec +42 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a75688a1a4f9e322d33c58a9b0a29b2fb26c27536a137e33dd97c340a491dd98
|
|
4
|
+
data.tar.gz: 87a5c7f3f29918f0031e637acbc4d08a6d8d6f122b3112c597515086fa1d0317
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7db2e7d2a63a2afa679ca83652136e13e954b3eee2c11d55c5734c48ed10be641a8fee0eca3d1df779a1d4c19c7a4172027d9aea1659f4bb8f4728f6de3ded3e
|
|
7
|
+
data.tar.gz: 4014ba510524d9921c9eb67986b137151f98aca2cd71427e431fdcefe776c5c869e45b45de09d3a692fe77976f82da4c7df6bdb08ca687736301d43a45f5af12
|
data/example.rb
CHANGED
|
@@ -7,64 +7,52 @@ require 'pp'
|
|
|
7
7
|
|
|
8
8
|
Bundler.setup(:default, :development)
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
#$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
11
|
+
#$LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
12
12
|
|
|
13
13
|
require 'skrift/x11'
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
dpy = display = X11::Display.new
|
|
16
16
|
screen = dpy.screens.first
|
|
17
|
+
visual = dpy.find_visual(0, 32).visual_id
|
|
18
|
+
#cmap = dpy.create_colormap(0, screen.root, visual)
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
#
|
|
20
|
+
p visual
|
|
21
|
+
#p cmap
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
cmap = $dpy.create_colormap(0, screen.root, visual)
|
|
25
|
-
|
|
26
|
-
wid = display.new_id
|
|
27
|
-
$dpy.create_window(
|
|
28
|
-
32,
|
|
29
|
-
wid, screen.root,
|
|
30
|
-
0, 0, # x,y
|
|
23
|
+
wid = dpy.create_window(
|
|
24
|
+
0, 0, # x,y
|
|
31
25
|
1000, 600, # w,h
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
X11::Form::CWEventMask
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
cmap # Colormap. Necessary when depth != screen.root_depth
|
|
45
|
-
]
|
|
26
|
+
visual: visual,
|
|
27
|
+
values: {
|
|
28
|
+
X11::Form::CWBackPixel => 0, # ARGB background
|
|
29
|
+
X11::Form::CWBorderPixel => 0, # Needed in case window depth != screen.root_depth
|
|
30
|
+
X11::Form::CWEventMask =>
|
|
31
|
+
(X11::Form::SubstructureNotifyMask |
|
|
32
|
+
X11::Form::StructureNotifyMask |
|
|
33
|
+
X11::Form::ExposureMask |
|
|
34
|
+
X11::Form::KeyPressMask |
|
|
35
|
+
X11::Form::ButtonPressMask)#,
|
|
36
|
+
# X11::Form::CWColorMap => cmap # Needed for same reason as borderpixel
|
|
37
|
+
}
|
|
46
38
|
)
|
|
39
|
+
p wid
|
|
47
40
|
|
|
48
41
|
dpy.map_window(wid) # Window won't be visible until this
|
|
49
42
|
|
|
50
43
|
# A "picture" object for us to draw in the window with.
|
|
51
44
|
fmt = dpy.render_find_visual_format(visual)
|
|
45
|
+
p fmt
|
|
52
46
|
$pic = dpy.render_create_picture(wid, fmt)
|
|
53
47
|
|
|
54
|
-
|
|
55
|
-
#$fgpic = dpy.render_create_solid_fill(0xffff,0xffff,0,0)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
$gc = dpy.create_gc(wid, foreground: 0xffff0000)
|
|
59
|
-
|
|
60
|
-
puts "Main loop"
|
|
48
|
+
gc = dpy.create_gc(wid, foreground: 0xffff0000)
|
|
61
49
|
|
|
62
|
-
|
|
50
|
+
f = Font.load("resources/FiraGO-Regular_extended_with_NotoSansEgyptianHieroglyphs-Regular.ttf")
|
|
63
51
|
|
|
64
|
-
$skrift = Skrift::X11::Glyphs.new(
|
|
52
|
+
$skrift = Skrift::X11::Glyphs.new(dpy, f, x_scale: 40, y_scale: 40)
|
|
65
53
|
|
|
66
54
|
def redraw(dpy, wid, gc)
|
|
67
|
-
dpy.poly_fill_rectangle(wid, gc, [
|
|
55
|
+
dpy.poly_fill_rectangle(wid, gc, [20,45, 400, 400])
|
|
68
56
|
$skrift.render_str($pic, 0xffffff, 50,90, 'Pure Ruby w/Skrift!')
|
|
69
57
|
$skrift.render_str($pic, 0xffffff, 50,140, "And unicode:")
|
|
70
58
|
$skrift.render_str($pic, 0xff00ff, 50,200, "Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα.")
|
|
@@ -74,9 +62,9 @@ end
|
|
|
74
62
|
loop do
|
|
75
63
|
pkt = display.next_packet
|
|
76
64
|
if pkt
|
|
77
|
-
|
|
65
|
+
puts pkt.inspect[0..200]
|
|
78
66
|
#raise "Error" if pkt.is_a?(X11::Form::Error)
|
|
79
|
-
redraw(display, wid,
|
|
67
|
+
redraw(display, wid, gc) if pkt.is_a?(X11::Form::Expose)
|
|
80
68
|
|
|
81
69
|
if pkt.is_a?(X11::Form::KeyPress)
|
|
82
70
|
# lookup_keysym(dpy,pkt)
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
module Skrift
|
|
2
|
+
module X11
|
|
3
|
+
class Glyphs
|
|
4
|
+
|
|
5
|
+
def empty_box_image
|
|
6
|
+
img = Image.new(stride, boxh)
|
|
7
|
+
img.pixels = Array.new(img.width*img.height,0x00)
|
|
8
|
+
img
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def cache_box(ch)
|
|
13
|
+
@boxcache ||= {}
|
|
14
|
+
c = @boxcache[ch] if @boxcache[ch]
|
|
15
|
+
|
|
16
|
+
hx = (boxw+1)/2
|
|
17
|
+
hy = (boxh+1)/2
|
|
18
|
+
yoff = hy*stride
|
|
19
|
+
img = nil
|
|
20
|
+
h = 1 # 1/3 width of "heavy" line
|
|
21
|
+
|
|
22
|
+
lh = light_h = [-255, 0,255, 0, 255]; hh = heavy_h = [-255, -h,255, h, 255]
|
|
23
|
+
lv = light_v = [ 0,-255, 0,255, 255]; hv = heavy_v = [ -h,-255, h,255, 255]
|
|
24
|
+
|
|
25
|
+
ll = light_l = [-255, 0, 0, 0, 255]; hl = heavy_l = [-255, -h, 0, h, 255]
|
|
26
|
+
lu = light_u = [ 0,-255, 0, 0, 255]; hu = heavy_u = [ -h,-255, h, 0, 255]
|
|
27
|
+
lr = light_r = [ 0, 0,255, 0, 255]; hr = heavy_r = [ 0, -h,255, h, 255]
|
|
28
|
+
ld = light_d = [ 0, 0, 0,255, 255]; hd = heavy_d = [ -h, 0, h,255, 255]
|
|
29
|
+
|
|
30
|
+
hc = [ -h, -h, h, h, 255] # Heavy centre
|
|
31
|
+
|
|
32
|
+
d = 2
|
|
33
|
+
dblc = [-d+1, -d+1, d-1, d-1, 0] # Gap in centre of double lines.
|
|
34
|
+
light_vc = [0, -d, 0, d, 255] # Light vertical crossing centre of double line.
|
|
35
|
+
|
|
36
|
+
dh = double_h = [-255,-d,255,-d, 255] + [-255, d,255, d, 255]
|
|
37
|
+
dv = double_v = [-d,-255,-d,255, 255] + [d,-255,d,255, 255]
|
|
38
|
+
|
|
39
|
+
mask_vbar = [-d+1,-255,d-1,255,0]
|
|
40
|
+
mask_hbar = [-255,-d+1,255,d-1,0]
|
|
41
|
+
|
|
42
|
+
mt= masktop = [-255,-255, 255, -1, 0]; maskdtop = [-255,-255, 255,-d-1, 0]
|
|
43
|
+
ml=maskleft = [-255,-255, -1, 255, 0]; maskdleft = [-255,-255,-d-1, 255, 0]
|
|
44
|
+
mb=maskbottom = [-255, 1, 255, 255, 0]; maskdbottom= [-255, d+1, 255, 255, 0]
|
|
45
|
+
mr=maskright = [ 1,-255, 255, 255, 0]; maskdright = [ d+1,-255, 255, 255, 0]
|
|
46
|
+
|
|
47
|
+
mask_lbar = [-255,-d+1,d-1,d-1, 0]; dlbar=double_lbar = [-255,-d,d,d, 255]
|
|
48
|
+
mask_tbar = [-d+1,-255,d-1,d-1, 0]; dtbar=double_tbar = [-d,-255,d,d, 255]
|
|
49
|
+
mask_rbar = [-d+1,-d+1,255,d-1, 0]; drbar=double_rbar = [-d,-d,255,d, 255]
|
|
50
|
+
mask_dbar = [-d+1,-d+1,d-1,255, 0]; ddbar=double_dbar = [-d,-d,d,255, 255]
|
|
51
|
+
|
|
52
|
+
mask_c = [0,0,0,0,0]
|
|
53
|
+
|
|
54
|
+
hdl = heavy_dl = [heavy_d, heavy_l, hc]
|
|
55
|
+
hdr = heavy_dr = [heavy_d, heavy_r, hc]
|
|
56
|
+
hlu = heavy_lu = [heavy_l, heavy_u, hc]
|
|
57
|
+
hru = heavy_ru = [heavy_r, heavy_u, hc]
|
|
58
|
+
ldl = light_dl = [light_d, light_l]
|
|
59
|
+
ldr = light_dr = [light_d, light_r]
|
|
60
|
+
llu = light_lu = [light_l, light_u]
|
|
61
|
+
lru = light_ru = [light_r, light_u]
|
|
62
|
+
|
|
63
|
+
# FIXME Makes stipples wider when tx/ty etc. are big enough
|
|
64
|
+
tx = hx - boxw / 3
|
|
65
|
+
mv2 = mask_v2 = [[-tx, -255, -tx, 255, 0], [tx, -255, tx, 255,0]]
|
|
66
|
+
|
|
67
|
+
ty = hy - boxh / 3
|
|
68
|
+
mh2 = mask_h2 = [[-255,-ty, 255,-ty,0], [-255,ty,255,ty,0]]
|
|
69
|
+
|
|
70
|
+
rects = {
|
|
71
|
+
0x2500 => lh, 0x2501 => hh, 0x2502 => lv, 0x2503 => hv,
|
|
72
|
+
0x2504 => lh + mv2, 0x2505 => hh + mv2, 0x2506 => lv + mh2, 0x2507 => hv + mv2,
|
|
73
|
+
0x2508 => lh, # FIXME: Stippled
|
|
74
|
+
0x2509 => hh, # FIXME: Stippled
|
|
75
|
+
0x250A => lv, # FIXME: Stippled
|
|
76
|
+
0x250B => hv, # FIXME: Stippled
|
|
77
|
+
|
|
78
|
+
0x250C => ldr, 0x250D => hr + ld, 0x250E => hd + lr, 0x250F => hdr,
|
|
79
|
+
0x2510 => ldl, 0x2511 => hl + ld, 0x2512 => [hd, ll], 0x2513 => hdl,
|
|
80
|
+
0x2514 => lru, 0x2515 => lu + hr, 0x2516 => lr + hu, 0x2517 => hru,
|
|
81
|
+
0x2518 => llu, 0x2519 => [hl, lu], 0x251a => [ll, hu], 0x251b => hlu,
|
|
82
|
+
0x251c => lv+lr, 0x251d => [lv, hr], 0x251e => ldr + hu, 0x251f => [lru, hd],
|
|
83
|
+
|
|
84
|
+
0x2520 => hv + lr, 0x2521 => hru + ld, 0x2522 => hdr + lu, 0x2523 => hv + hr,
|
|
85
|
+
0x2524 => ll + lv, 0x2525 => hl + lv, 0x2526 => hu + ldl, 0x2527 => hd + lu,
|
|
86
|
+
0x2528 => hv + ll, 0x2529 => hlu + ld, 0x252a => hdl+lu, 0x252b => hl + hv,
|
|
87
|
+
0x252c => lh + ld, 0x252d => [hl, ldr], 0x252e => [hr, ldr], 0x252f => [hh, ld],
|
|
88
|
+
|
|
89
|
+
0x2530 => [lh, hd], 0x2531 => [hdl, lr], 0x2532 => [ll, hdr], 0x2533 => [hh, hd],
|
|
90
|
+
0x2534 => [lh, lu], 0x2535 => [lru, hl], 0x2536 => [llu, hr], 0x2537 => [hh, lu],
|
|
91
|
+
0x2538 => [lh, hu], 0x2539 => [hlu, lr], 0x253a => [hru, ll], 0x253b => [hh, hu],
|
|
92
|
+
0x253c => [lv, lh], 0x253d => lv+lr+hl, 0x253e => ll+lv+hr, 0x253f => [lv, hh],
|
|
93
|
+
|
|
94
|
+
0x2540 => [lh, ld, hu], 0x2541 => [light_h, light_u, heavy_d], 0x2542 => [heavy_v, light_h], 0x2543 => [heavy_l, heavy_u, hc, light_d, light_r],
|
|
95
|
+
0x2544 => [ll, ld, hru], 0x2545 => [heavy_dl, light_ru], 0x2546 => [light_lu, heavy_dr], 0x2547 => [heavy_h, heavy_u, light_d],
|
|
96
|
+
0x2548 => [hh, hd, light_u], 0x2549 => [heavy_v, heavy_l, light_r], 0x254a => [heavy_v, light_l, heavy_r], 0x254b => [heavy_v, heavy_h],
|
|
97
|
+
0x254c => [lh, dblc], 0x254d => [heavy_h, dblc], 0x254e => [light_v, dblc], 0x254f => [heavy_v, dblc],
|
|
98
|
+
|
|
99
|
+
0x2550 => dh, 0x2551 => dv, 0x2552 => [dh, lv, ml, maskdtop], 0x2553 => [dv, lh, mt, maskdleft],
|
|
100
|
+
0x2554 => [ddbar, drbar, mask_dbar, mask_rbar], 0x2555 => [dh, mr, lv, maskdtop],
|
|
101
|
+
0x2556 => [dv, lh,maskdright,mt], 0x2557 => [double_dbar, double_lbar, mask_dbar, mask_lbar],
|
|
102
|
+
0x2558 => [lv, dh, ml, maskdbottom], 0x2559 => [lh, dv, maskdleft, mb],
|
|
103
|
+
0x255A => [dtbar, double_rbar, mask_tbar, mask_rbar], 0x255B => [dh, lv, maskdbottom, mr],
|
|
104
|
+
0x255C => [dv, lh, mb, maskdright], 0x255D => [dtbar, dlbar, mask_tbar, mask_lbar],
|
|
105
|
+
0x255e => [lv, dh, maskleft], 0x255f => [lh, dv, dblc, maskdleft],
|
|
106
|
+
0x2560 => [dv, drbar, mask_rbar, mask_vbar], 0x2561 => [lv, dh, maskright],
|
|
107
|
+
0x2562 => [dv, ll, dblc], 0x2563 => [dlbar, dv, mask_lbar, mask_vbar],
|
|
108
|
+
0x2564 => [dh, ld, dblc], 0x2565 => [lh, dv, mt],
|
|
109
|
+
0x2566 => [dh, ddbar,mask_hbar, mask_dbar], 0x2567 => [dh, light_u,dblc],
|
|
110
|
+
0x2568 => [lh, dv, mb], 0x2569 => [dh, double_tbar, mask_hbar, mask_tbar],
|
|
111
|
+
0x256A => dh+lv, 0x256b => dv+lh, 0x256c => [dh, dv, mask_hbar, mask_vbar],
|
|
112
|
+
|
|
113
|
+
# 256d, 256e, 256f, 2570 => curves
|
|
114
|
+
# FIXME: Current is just very slightly rounded.
|
|
115
|
+
0x256d => [ldr, mask_c], 0x256e => [ldl, mask_c], 0x256f => [llu, mask_c], 0x2570 => [lru, mask_c],
|
|
116
|
+
|
|
117
|
+
# 2571, 2572. 2573 => diagonals, handled below.
|
|
118
|
+
0x2571 => nil, 0x2572 => nil, 0x2573 => nil,
|
|
119
|
+
|
|
120
|
+
0x2574 => ll, 0x2575 => lu, 0x2576 => lr, 0x2577 => ld,
|
|
121
|
+
0x2578 => hl, 0x2579 => hu, 0x257a => hr, 0x257b => hd,
|
|
122
|
+
0x257c => ll + hr, 0x257d => lu + hd, 0x257e => hl + lr, 0x257f => hu + ld
|
|
123
|
+
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
r = rects[ch.ord]
|
|
127
|
+
if r
|
|
128
|
+
img = empty_box_image
|
|
129
|
+
r.flatten.each_slice(5) do |rect|
|
|
130
|
+
p rect
|
|
131
|
+
x1,y1,x2,y2, col = *rect
|
|
132
|
+
x1 = (x1+hx).clamp(0,boxw-1)
|
|
133
|
+
x2 = (x2+hx).clamp(0,boxw-1)
|
|
134
|
+
y1 = (y1+hy).clamp(0,boxh-1)
|
|
135
|
+
y2 = (y2+hy).clamp(0,boxh-1)
|
|
136
|
+
col ||= 255
|
|
137
|
+
|
|
138
|
+
a = Array.new(x2-x1+1,col)
|
|
139
|
+
|
|
140
|
+
(y1..y2).each do |y|
|
|
141
|
+
img.pixels[y*stride + x1 .. y*stride + x2] = a
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
return img
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
if ch.ord == 0x2571
|
|
148
|
+
img = empty_box_image
|
|
149
|
+
slope = boxw.to_f / boxh
|
|
150
|
+
x = boxw.to_f-1
|
|
151
|
+
(0...boxh).each do |y|
|
|
152
|
+
err = x - x.to_i
|
|
153
|
+
img.pixels[y*stride+x.ceil] = 255 #(255*(1-err)).floor
|
|
154
|
+
img.pixels[y*stride+x.ceil-1] = (255*err).floor if x > 0
|
|
155
|
+
x-= slope
|
|
156
|
+
end
|
|
157
|
+
return img
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# FIXME: If size is *at* certain levels level, this, and the next one fails?
|
|
161
|
+
|
|
162
|
+
if ch.ord == 0x2572
|
|
163
|
+
img = empty_box_image
|
|
164
|
+
slope = boxw.to_f / boxh
|
|
165
|
+
x = boxw.to_f-1
|
|
166
|
+
(0...boxh).each do |y|
|
|
167
|
+
err = x - x.to_i
|
|
168
|
+
img.pixels[y*stride+boxw-x.ceil-1] = 255
|
|
169
|
+
img.pixels[y*stride+boxw-x.ceil] = (255*err).floor if x > 0
|
|
170
|
+
x-= slope
|
|
171
|
+
end
|
|
172
|
+
return img
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
if ch.ord == 0x2573
|
|
176
|
+
img = empty_box_image
|
|
177
|
+
slope = boxw.to_f / boxh
|
|
178
|
+
x = boxw.to_f-1
|
|
179
|
+
(0...boxh).each do |y|
|
|
180
|
+
err = x - x.to_i
|
|
181
|
+
img.pixels[y*stride+boxw-x.ceil-1] = 255
|
|
182
|
+
img.pixels[y*stride+boxw-x.ceil] = (255*err).floor if x > 0
|
|
183
|
+
img.pixels[y*stride+x.ceil-1] = (255*err).floor if x > 0
|
|
184
|
+
img.pixels[y*stride+x.ceil] = 255 #(255*(1-err)).floor
|
|
185
|
+
x-= slope
|
|
186
|
+
end
|
|
187
|
+
return img
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
if img
|
|
191
|
+
img = img.dup
|
|
192
|
+
img.pixels = img.pixels.dup
|
|
193
|
+
end
|
|
194
|
+
img || empty_box_image
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
data/lib/skrift/x11/glyphs.rb
CHANGED
|
@@ -1,25 +1,73 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
require_relative 'boxdrawing'
|
|
3
|
+
|
|
4
|
+
module X11
|
|
5
|
+
# XRender constants currently not defined in pure-x11.
|
|
6
|
+
# FIXME.
|
|
7
|
+
module Form
|
|
7
8
|
PictOpSrc=1
|
|
8
9
|
PictOpOver=3
|
|
9
10
|
CPRepeat = 1
|
|
11
|
+
end
|
|
12
|
+
end
|
|
10
13
|
|
|
14
|
+
module Skrift
|
|
15
|
+
module X11
|
|
16
|
+
|
|
11
17
|
class Glyphs
|
|
18
|
+
attr_reader :fixed_width
|
|
19
|
+
attr_accessor :maxheight
|
|
20
|
+
|
|
21
|
+
def load_font(index)
|
|
22
|
+
return @fonts[index] if @fonts[index]
|
|
23
|
+
f = @fontset[index]
|
|
24
|
+
return nil if !f
|
|
25
|
+
return @fonts[index] = Font.load(f) if File.exist?(f)
|
|
26
|
+
|
|
27
|
+
# FIXME: Do proper resolution of XDG dirs
|
|
28
|
+
fn = File.expand_path("~/.local/share/fonts/#{f}")
|
|
29
|
+
return @fonts[index] = Font.load(fn) if File.exist?(fn)
|
|
30
|
+
|
|
31
|
+
fn = `fc-match --format='%{file}\n' #{fn}`.split("\n").first
|
|
32
|
+
return @fonts[index] = Font.load(fn) if File.exist?(fn)
|
|
33
|
+
return nil
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def inspect
|
|
37
|
+
"<Glyphs #{object_id}"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def initialize dpy, font=nil, fontset: nil, x_scale:, y_scale:, pic: nil, fixed: nil, maxheight: nil, fit: false
|
|
41
|
+
@fontset = fontset
|
|
42
|
+
@fonts = @fontset ? [] : [font]
|
|
43
|
+
@font = font || load_font(0)
|
|
44
|
+
@maxheight = maxheight
|
|
12
45
|
|
|
13
|
-
def initialize dpy, font, x_scale:, y_scale:, pic: nil, fixed: nil
|
|
14
46
|
@dpy = dpy
|
|
15
|
-
@sft = SFT.new(font)
|
|
47
|
+
@sft = SFT.new(@font)
|
|
16
48
|
@sft.x_scale = x_scale
|
|
17
49
|
@sft.y_scale = y_scale
|
|
18
50
|
@pic = pic
|
|
19
51
|
@fixed = fixed
|
|
52
|
+
# When set (with a fixed cell), glyphs whose natural size exceeds the
|
|
53
|
+
# cell are scaled down to fit and centred instead of being clamped
|
|
54
|
+
# (and distorted) at the cell edge by the rasteriser.
|
|
55
|
+
@fit = fit
|
|
20
56
|
|
|
57
|
+
g = @sft.gmetrics(@sft.lookup("M".ord))
|
|
58
|
+
if !g
|
|
59
|
+
g = @sft.gmetrics(0)
|
|
60
|
+
end
|
|
61
|
+
if g
|
|
62
|
+
@fixed_width = g.advance_width.ceil
|
|
63
|
+
else
|
|
64
|
+
@fixed_width = x_scale
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
@nextgid = 1
|
|
21
68
|
@glyphcache = {}
|
|
22
69
|
@colcache = {}
|
|
70
|
+
@chcache = {}
|
|
23
71
|
|
|
24
72
|
@lm = @sft.lmetrics
|
|
25
73
|
|
|
@@ -29,11 +77,6 @@ module Skrift
|
|
|
29
77
|
end
|
|
30
78
|
|
|
31
79
|
attr_accessor :lm
|
|
32
|
-
def gm(ch)
|
|
33
|
-
gid = @sft.lookup(ch.ord)
|
|
34
|
-
@sft.gmetrics(gid)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
80
|
|
|
38
81
|
def fill_for_col(col)
|
|
39
82
|
return @colcache[col] if @colcache[col]
|
|
@@ -47,25 +90,74 @@ module Skrift
|
|
|
47
90
|
@colcache[col] ||= @dpy.render_create_solid_fill(r,g,b,0xffff)
|
|
48
91
|
end
|
|
49
92
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
else
|
|
57
|
-
nil
|
|
58
|
-
end
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
def boxw = @fixed_width
|
|
96
|
+
def stride = (@fixed_width +3)&~3
|
|
97
|
+
def boxh
|
|
98
|
+
@boxh ||= [@maxheight, @lm.ascender.ceil-@lm.descender.ceil].compact.min
|
|
59
99
|
end
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def cache_special(ch)
|
|
103
|
+
# Box drawing
|
|
104
|
+
return nil if !((0x2500 .. 0x257f) === ch.ord)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
img = cache_box(ch.ord)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
data = img.pixels.pack("C*")
|
|
111
|
+
info = ::X11::Form::GlyphInfo.new(
|
|
112
|
+
img.width, # w
|
|
113
|
+
img.height, # h
|
|
114
|
+
0, # x
|
|
115
|
+
0, # y
|
|
116
|
+
fixed_width,
|
|
117
|
+
0
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
gsgid = @nextgid
|
|
121
|
+
@nextgid += 1
|
|
122
|
+
@dpy.render_add_glyphs(@glyphset, gsgid, info, data)
|
|
123
|
+
@glyphcache[gsgid] = fixed_width
|
|
124
|
+
@chcache[ch] = {gsgid: gsgid}
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def cache_glyph(gsgid,gid, baseline)
|
|
128
|
+
return if gid.nil?
|
|
63
129
|
mtx = @sft.gmetrics(gid)
|
|
130
|
+
scaled = false
|
|
131
|
+
saved = nil
|
|
132
|
+
|
|
133
|
+
# Oversized glyph in a fixed cell: re-render it at a reduced scale so
|
|
134
|
+
# it fits the cell, then position it through the normal
|
|
135
|
+
# baseline-relative path below (no vertical shift). Otherwise the
|
|
136
|
+
# rasteriser clamps the overflow at the cell edge and distorts the
|
|
137
|
+
# shape. Only glyphs clearly wider/taller than the cell are scaled -
|
|
138
|
+
# a marginal overshoot (e.g. a 'W' a pixel past the cell) is left to
|
|
139
|
+
# the clamp, so ordinary text is untouched.
|
|
140
|
+
if @fit && @fixed && mtx
|
|
141
|
+
sx = (mtx.min_width || 0) > boxw * 1.1 ? boxw.to_f / mtx.min_width : 1.0
|
|
142
|
+
sy = (mtx.min_height || 0) > boxh * 1.1 ? boxh.to_f / mtx.min_height : 1.0
|
|
143
|
+
s = [sx, sy].min
|
|
144
|
+
if s < 1.0
|
|
145
|
+
saved = [@sft.x_scale, @sft.y_scale]
|
|
146
|
+
@sft.x_scale = @sft.x_scale * s
|
|
147
|
+
@sft.y_scale = @sft.y_scale * s
|
|
148
|
+
mtx = @sft.gmetrics(gid)
|
|
149
|
+
scaled = true
|
|
150
|
+
end
|
|
151
|
+
end
|
|
64
152
|
|
|
65
153
|
# FIXME: Not sure what to do if mtx.nil? here.
|
|
66
154
|
# Maybe use x/y scale?
|
|
67
|
-
|
|
68
|
-
|
|
155
|
+
if @fixed
|
|
156
|
+
w = fixed_width
|
|
157
|
+
else
|
|
158
|
+
w = mtx.min_width || 0
|
|
159
|
+
end
|
|
160
|
+
h = [mtx&.min_height || 1, @maxheight].compact.min
|
|
69
161
|
#p [w,h]
|
|
70
162
|
img = Image.new((w+3)&~3, h)
|
|
71
163
|
if !@sft.render(gid, img)
|
|
@@ -74,9 +166,9 @@ module Skrift
|
|
|
74
166
|
else
|
|
75
167
|
data = img.pixels.pack("C*")
|
|
76
168
|
end
|
|
77
|
-
|
|
169
|
+
|
|
78
170
|
yoff = mtx.y_offset || baseline
|
|
79
|
-
|
|
171
|
+
|
|
80
172
|
info = ::X11::Form::GlyphInfo.new(
|
|
81
173
|
img.width, # w
|
|
82
174
|
img.height, # h
|
|
@@ -86,41 +178,72 @@ module Skrift
|
|
|
86
178
|
0
|
|
87
179
|
)
|
|
88
180
|
|
|
89
|
-
@dpy.render_add_glyphs(@glyphset,
|
|
90
|
-
@glyphcache[
|
|
181
|
+
@dpy.render_add_glyphs(@glyphset, gsgid, info, data)
|
|
182
|
+
@glyphcache[gsgid] = scaled ? (fixed_width || mtx.advance_width) : mtx.advance_width
|
|
183
|
+
ensure
|
|
184
|
+
@sft.x_scale, @sft.y_scale = saved if saved
|
|
91
185
|
end
|
|
92
186
|
|
|
187
|
+
public
|
|
188
|
+
|
|
93
189
|
def text_width(str)
|
|
94
|
-
gl = map_glyphs(str)
|
|
95
190
|
# We *presume* that if you call text_width, you intend
|
|
96
191
|
# to render the string. Maybe we shouldn't?
|
|
97
|
-
cache_glyphs(
|
|
192
|
+
gl = cache_glyphs(str)
|
|
98
193
|
gl.inject(0) {|sum,gl|
|
|
99
194
|
@glyphcache[gl].to_i + sum
|
|
100
195
|
}
|
|
101
196
|
end
|
|
102
197
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
198
|
+
private
|
|
199
|
+
def each_font
|
|
200
|
+
Array(@fontset).each_index do |i|
|
|
201
|
+
yield load_font(i)
|
|
202
|
+
end
|
|
107
203
|
end
|
|
108
204
|
|
|
109
|
-
def cache_glyphs(
|
|
110
|
-
gl.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
205
|
+
def cache_glyphs(str)
|
|
206
|
+
gl = str.to_s.each_char.map do |ch|
|
|
207
|
+
|
|
208
|
+
cache = @chcache[ch]
|
|
209
|
+
|
|
210
|
+
if cache.nil?
|
|
211
|
+
cache = cache_special(ch)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
if cache.nil?
|
|
215
|
+
each_font do |font|
|
|
216
|
+
# FIXME: This is stupid and must be untangled
|
|
217
|
+
@sft.font = font
|
|
218
|
+
gid = @sft.lookup(ch.ord)
|
|
219
|
+
if gid
|
|
220
|
+
cache = @chcache[ch] = {font: font, gid: gid, gsgid: @nextgid}
|
|
221
|
+
@nextgid += 1
|
|
222
|
+
break
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
if cache
|
|
228
|
+
data = @glyphcache[cache[:gsgid]]
|
|
229
|
+
if !data
|
|
230
|
+
@sft.font = cache[:font]
|
|
231
|
+
data = cache_glyph(cache[:gsgid], cache[:gid], @lm.ascender)
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
cache[:gsgid]
|
|
235
|
+
else
|
|
236
|
+
0
|
|
114
237
|
end
|
|
115
238
|
end
|
|
116
239
|
end
|
|
117
|
-
|
|
240
|
+
|
|
241
|
+
public
|
|
118
242
|
def render_str(pic, col, x,y, str)
|
|
119
243
|
fill = fill_for_col(col)
|
|
120
|
-
gl =
|
|
121
|
-
cache_glyphs(gl)
|
|
244
|
+
gl = cache_glyphs(str)
|
|
122
245
|
@dpy.render_composite_glyphs32(
|
|
123
|
-
PictOpOver, fill, pic, @gfmt,
|
|
246
|
+
:PictOpOver, fill, pic, @gfmt,
|
|
124
247
|
@glyphset, 0,0, [x, y, gl]
|
|
125
248
|
)
|
|
126
249
|
end
|
data/lib/skrift/x11/version.rb
CHANGED
data/skrift-x11.gemspec
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/skrift/x11/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "skrift-x11"
|
|
7
|
+
spec.version = Skrift::X11::VERSION
|
|
8
|
+
spec.authors = ["Vidar Hokstad"]
|
|
9
|
+
spec.email = ["vidar@hokstad.com"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "Helpers to use the pure-Ruvy TrueType engine Skrift with pure Pure-X11 X bindings"
|
|
12
|
+
#spec.description = "TODO: Write a longer description or delete this line."
|
|
13
|
+
#spec.homepage = "TODO: Put your gem's website or public repo URL here."
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
spec.required_ruby_version = ">= 2.6.0"
|
|
16
|
+
|
|
17
|
+
#spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
|
|
18
|
+
|
|
19
|
+
#spec.metadata["homepage_uri"] = spec.homepage
|
|
20
|
+
#spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
|
|
21
|
+
#spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
|
|
22
|
+
|
|
23
|
+
# Specify which files should be added to the gem when it is released.
|
|
24
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
25
|
+
spec.files = Dir.chdir(__dir__) do
|
|
26
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
|
27
|
+
(File.expand_path(f) == __FILE__) ||
|
|
28
|
+
f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile])
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
spec.bindir = "exe"
|
|
32
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
33
|
+
spec.require_paths = ["lib"]
|
|
34
|
+
|
|
35
|
+
# Uncomment to register a new dependency of your gem
|
|
36
|
+
# spec.add_dependency "example-gem", "~> 1.0"
|
|
37
|
+
spec.add_dependency "skrift"
|
|
38
|
+
spec.add_dependency "pure-x11"
|
|
39
|
+
|
|
40
|
+
# For more information and examples about making a new gem, check out our
|
|
41
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
|
42
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: skrift-x11
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vidar Hokstad
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-06-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: skrift
|
|
@@ -51,10 +51,12 @@ files:
|
|
|
51
51
|
- example.png
|
|
52
52
|
- example.rb
|
|
53
53
|
- lib/skrift/x11.rb
|
|
54
|
+
- lib/skrift/x11/boxdrawing.rb
|
|
54
55
|
- lib/skrift/x11/glyphs.rb
|
|
55
56
|
- lib/skrift/x11/version.rb
|
|
56
57
|
- resources/FiraGO-Regular_extended_with_NotoSansEgyptianHieroglyphs-Regular.ttf
|
|
57
58
|
- sig/skrift/x11.rbs
|
|
59
|
+
- skrift-x11.gemspec
|
|
58
60
|
homepage:
|
|
59
61
|
licenses:
|
|
60
62
|
- MIT
|