-
Notifications
You must be signed in to change notification settings - Fork 1
/
Kerning.pbp
427 lines (364 loc) · 7.71 KB
/
Kerning.pbp
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
#ifdef _comment
Need to patch iterate_line and measure_word
Whenever we need char advance:
1. If this char is not-kernable, continue as always
2. If it is kernable, check *next* char's codepoint
3. If kerning applies, *curr* char advance shall be zero!
4. ...and next char advance should be ideally max(curr_advance, next_advance)
Possible problem: added '-' in wrapped word between kernable letters will be shifted on top of left letter
#endif
#ver 361
08 b5 03 68 13 b9 03 48 ?4 80 68 98 47 08 bd {
proc iterator_next
}
08 b5 43 68 13 b9 03 48 ?4 80 68 98 47 08 bd {
proc iterator_prev
}
70 b5 0e 46 14 46 05 46 {
proc text_layout_get_char_advance
}
2d e9 f0 4f 82 46 97 b0 0c 46 16 46 99 46 {
proc text_layout_iterate_line
}
f0 b5 8b b0 04 46 04 a8 80 e8 06 00 9d f8 40 60 {
proc graphics_fill_rect
}
; get_sys_font_do, data block - after error hashcode
75 34 80 C8 @ ?4 {
val sysfonts
}
; iterate_line before main loop
0a f1 38 02 06 92 10 46 f1 68 2a 46 @ ?4
{
; was: BL text_layout_get_char_advance(first char)
; can use R3
B.W bef_main_loop
global bef_main_loop_cont
}
; iterate_line in main loop
06 98 f1 68 cd f8 0c c0 2a 46 @ ?4
{
; was: BL text_layout_get_char_advance(curr char)
B.W in_main_loop
global in_main_loop_cont
}
; text_layout_measure_word in measuring loop
07 f1 38 00 d9 f8 0c 10 0b 9a 26 89 @ ?4 {
; was: BL text_layout_get_char_advance(curr char)
B.W for_measure_word
global for_measure_word_cont
}
; text_layout_draw_line_cb
03 4b bd e8 f0 41 ?4 bd e8 f0 81
00 bf ?4
01 4b @ ?4 {
; was:
;LDR R3, text_layout_render_char_cb
; @
;B.W text_layout_iterate_line
; R0: gctx
; R1: linedata
; R2: tli
B.W my_draw_line_with_bg
}
{
ALIGN 4
global bef_main_loop
ADD R3, SP, 0x2C ; [pciter]
BL my_get_advance
B.W bef_main_loop_cont
ALIGN 4
;--
global in_main_loop
ADD R3, SP, 0x2C ; [pciter]
BL my_get_advance
B.W in_main_loop_cont
ALIGN 4
;--
global for_measure_word
ADD R3, SP, 0x4 ; [pciter]
BL my_get_advance
B.W for_measure_word_cont
}
{
proc my_get_advance
; R0: text_ctx
; R1: font
; R2: curr codepoint
; R3: pciter
; R3+sizeof(Iterator): pciterextra
PUSH {R0-R5,LR}
; is font kernable?
MOV R0, R1
BL is_sys_font
CBZ R0, regular
; is R2 char kernable?
MOV R0, R2
BL kern_get_table
CBZ R0, regular ; no kerning
MOV R5, R0 ; kern table for this char
; load next char
MOV R4, R3 ; save iter
MOV R0, R4 ; iter
BL iterator_next
LDR R0, [R4, 0x28] ; sizeof(iterator)+pciterdata.char_iter_extra.currchardecoded
; restore pointer
PUSH {R0}
MOV R0, R4 ; iter
BL iterator_prev
POP {R0}
; can R0 char kern with prev one?
MOV R1, R5 ; kern table for prev char
BL kern_check
CBNZ R0, do_kerning
regular:
POP {R0-R5,LR}
B.W text_layout_get_char_advance
do_kerning:
POP {R0-R5,LR}
MOV R0, 0 ; zero advance
BX LR
}
{
ALIGN 4
proc kern_normalize
; R0: codepoint
; returns: uppercase version of R0, or 0 if not letter
CMP R0, 'A'
BCC zero
CMP R0, 'z'
BHI zero
CMP R0, 'Z'
BLS upper
CMP R0, 'a'
BCC zero ; in between Z..a
lower:
SUB R0, 0x20 ; convert to upper
upper:
; now R0 is A..Z
BX LR
zero:
MOV R0, 0
BX LR
}
{
ALIGN 4
proc kern_get_table
; R0: char
PUSH {R1,LR}
BL kern_normalize
CBZ R0, ret ; not a letter
SUB R0, 'A'
ADR R1, fullkern_tbl
LDRB R0, [R1,R0]
CBZ R0, ret ; non-kernable letter
ADR R1, fullkern_opts
SUB R0, 1
LDR R0, [R1,R0,2] ; LSL #2
ret:
POP {R1,PC}
;--
ALIGN 4
fullkern_tbl:
DCB 0 5 4 3 0 3 2 3
DCB 0 2 1 1 6 3 1 4
DCB 2 6 4 4 0 3 4 0 4 0
ALIGN 4
fullkern_opts:
DCD fk1 ;1
DCD fk2 ;2
DCD fk8 ;3
DCD fk14 ;4
DCD fk16 ;5
DCD fk20 ;6
fk1: DCB 1 'U'
fk2: DCB 2 'IU'
fk8: DCB 8 'AEGIOUXZ'
fk14: DCB 14 'AEGHIJKLOQUXYZ'
fk16: DCB 16 'AEFGHIJKLOQUVXYZ'
fk20: DCB 20 'ACDEFGHIJKLNOQSUVXYZ'
}
{
ALIGN 4
proc kern_check
; R0: codepoint
; R1: table
; returns nonzero if kerning should apply
PUSH {R2-R3,LR}
BL kern_normalize
MOV R2, R0 ; codepoint
LDRB R0, [R1] ; counter
cont:
LDRB R3, [R1,R0] ; tbl + counter - start with last char
CMP R3, R2
BEQ ret ; R0 (which is nonzero) will be returned
SUB R0, 1
BNE cont ; if not zero
ret:
POP {R2-R3,PC}
}
{
ALIGN 4
proc is_sys_font
; R0: font
; Returns 1 if given font is one of eight Gothic system fonts.
PUSH {R1}
LDR R1, start1
CMP R0, R1
BLT nonsys
ADD R1, 0x50 ; 2pcs
CMP R0, R1
BLT sys
LDR R1, start2
CMP R0, R1
BLT nonsys
ADD R1, 0xA0 ; 4pcs
CMP R0, R1
BLT sys
LDR R1, start3
CMP R0, R1
BLT nonsys
ADD R1, 0x50 ; 2pcs
CMP R0, R1
BLT sys
nonsys:
MOV R0, 0
sys:
; R0 (font) is not null
POP {R1}
BX LR
ALIGN 4
start1:
DCD sysfonts+0x28 ; +1 > 2pcs
start2:
DCD sysfonts+0xA0 ; +4 > 4pcs
start3:
DCD sysfonts+0x3E8 ; +25 > 2pcs
}
{
ALIGN 4
proc my_draw_line_with_bg
; R0: gctx
; R1: linedata
; R2: tli
; R3: render_char_cb
#define round_radius 4
PUSH {R0-R7,LR}
SUB SP, SP, 0xC ; reserve space for arg0 of graphics_fill_rect and var0 and var1
MOV R5, R0 ; save gctx
MOV R6, R1 ; save linedata
LDR R7, [R2, 0xC] ; save font from tli
; check font
MOV R0, R7
BL is_sys_font
CBNZ R0, goodfont
B bypass
goodfont:
BL get_rect_struct
CBNZ R0, nobypass
B bypass ; failsafe - dont draw if height doesnt match
nobypass:
MOV R7, R0 ; save it, overwriting font info which we dont need anymore
; mangle colors
LDRB R4, [R5, 0x2e] ; fill color - in order to restore it later
LDRB R1, [R5, 0x2f] ; text color
; calculate new color based on text color
EOR R1, R1, 0b101010
CMP R1, R4
BNE color_good
; calculated color is probably equivalent to existing bg color, so twist it a little
EOR R1, R1, 0b010101
color_good:
STRB R1, [R5, 0x2e] ; fill color
; prepare position for rect1
LDRH R1, [R6, 4] ; box_curr_origin.x ; FIXME: un-apply offset?
LDRH R2, [R5, 0x25] ; gctx.offset.x
SUB R1, R2
STRH R1, [SP, 4]
LDRH R1, [R6, 6] ; box_curr_origin.y
LDRH R2, [R5, 0x27] ; gctx.offset.y
LDRB R3, [R7, 2] ; stroke height - for upper offset
SUB R1, R2
ADD R1, R3
STRH R1, [SP, 6]
; and size for rect1
LDRH R2, [R6, 0xA] ; max_extent
STRH R2, [SP, 8] ; size.w
LDRB R2, [R7, 1] ; first rect height
SUB R2, R3 ; decrease by upper offset
STRH R2, [SP, 0xA] ; size.h
; prepare args...
MOV R0, R5 ; gctx
LDR R1, [SP, 4] ; origin
LDR R2, [SP, 8] ; size
; and fill remaining params (corner rounding)
MOV R3, 3 ; top-left + top-right
STR R3, [SP] ; a0
MOV R3, ${round_radius} ; radius
BL graphics_fill_rect ; R0: gctx, R1-R2: rect, R3: radius, a0: corn_mask
; prepare position for rect2
LDRH R1, [SP, 6] ; origin.y
LDRB R2, [R7, 1] ; first rect height
LDRB R3, [R7, 2] ; divider height
ADD R1, R2
ADD R1, R3
STRH R1, [SP, 6] ; update origin.y
LDRB R1, [R7, 3] ; second rect height
STRH R1, [SP, 0xA] ; size.h
; now prepare args for rect2
MOV R0, R5 ; gctx
LDR R1, [SP, 4] ; origin
LDR R2, [SP, 8] ; size
MOV R3, 12 ; bottom-left + bottom-right
STR R3, [SP] ; a0
MOV R3, ${round_radius} ; radius
BL graphics_fill_rect
; restore fill color
STRB R4, [R5, 0x2e]
bypass:
ADD SP, SP, 0xC
POP {R0-R7,LR}
B.W text_layout_iterate_line
}
{
proc get_rect_struct
; R7: font
; returns: R0: struct ptr or 0
PUSH {R1-R3}
LDRB R3, [R7, 2] ; font.lineheight
ADR R0, sizes
MOV R1, 0
loop:
LDRB R2, [R0, R1]
CMP R2, R3
BEQ ret
ADD R1, 4
CMP R1, 16
BNE loop
; else, if last struct didn't match, return 0
MOV R0, 0
MOV R1, 0
ret:
ADD R0, R1
POP {R1-R3}
BX LR
ALIGN 4
sizes:
DCB 14 ; font size
DCB 9 ; first rect height
DCB 1 ; white line height
DCB 4 ; second rect height
DCB 18 ; font size
DCB 13 ; first rect height
DCB 1 ; white line height
DCB 4 ; second rect height
DCB 24 ; font size
DCB 16 ; first rect height
DCB 1 ; white line height
DCB 7 ; second rect height
DCB 28 ; font size
DCB 18 ; first rect height
DCB 2 ; white line height
DCB 8 ; second rect height
db "v6" ; just for identification
}