Skip to content

Commit 33b4eca

Browse files
authored
[201_104] Fix inner product symbol not rendering on Tab cycling popup window (#3104)
1 parent b44d977 commit 33b4eca

2 files changed

Lines changed: 125 additions & 19 deletions

File tree

devel/201_104.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# [201_104] Fix inner product symbol not rendering in Tab cycling popup
2+
3+
### What
4+
Fixed `⟨⟩` (angle bracket pair) showing as a red broken symbol in the Tab cycling completion popup when typing `<` in math mode.
5+
6+
### Why
7+
The Tab cycling popup renders symbol labels using `math_font_rep`. Its `get_extents`, `get_xpositions`, and `draw_fixed` methods all passed the full string to `search_font`, which only handles single math symbols. For a bracket pair like `"<langle><rangle>"` (two concatenated TeXmacs symbols), `search_font` fails — it is not a single dictionary entry and the character fallback rejects `<` — so it returns `error_font`, which draws in red.
8+
9+
### How
10+
Modified `src/Graphics/Fonts/math_font.cpp`.
11+
12+
Added a single-char fast path (via `tm_char_forwards`) to `get_extents`, `get_xpositions`, and both `draw_fixed` overloads. Single characters use the original `search_font` lookup unchanged. Multi-character strings iterate character by character:
13+
14+
- `get_extents`: accumulates per-symbol metrics, combining advance widths and taking the union of ink bounds.
15+
- `get_xpositions`: fills the position array by accumulating advance widths per symbol.
16+
- `draw_fixed(x, y)`: draws each symbol at its accumulated x-offset.
17+
- `draw_fixed(x, y, xk)`: delegates to `font_rep::draw_fixed` (base class already iterates char-by-char).
18+
19+
No Scheme-level changes needed — `lambda-to-symbol` in `math-edit.scm` already returns `(string-append lb rb)`.
20+
21+
### How to test
22+
1. Open Mogan Editor and create a new document.
23+
2. Enter math mode (`$` or via Insert → Math).
24+
3. Type `<` and press `Tab` to open the cycling popup.
25+
4. **Verify**: The `⟨⟩` entry displays correctly (not in red).
26+
5. Press `Tab` to cycle through variants and select `⟨⟩`.
27+
6. **Verify**: The correct angle bracket pair is inserted in the document.

src/Graphics/Fonts/math_font.cpp

Lines changed: 98 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -175,39 +175,118 @@ math_font_rep::supports (string c) {
175175

176176
void
177177
math_font_rep::get_extents (string s, metric& ex) {
178-
font fn;
179-
search_font (s, fn);
180-
fn->get_extents (s, ex);
178+
// Fast path: single TeXmacs character
179+
int i= 0;
180+
tm_char_forwards (s, i);
181+
if (i >= N (s)) {
182+
font fn;
183+
search_font (s, fn);
184+
fn->get_extents (s, ex);
185+
return;
186+
}
187+
// Multi-character string (e.g. "<langle><rangle>"): accumulate extents
188+
// character by character so each symbol is looked up individually.
189+
metric ey;
190+
SI advance= 0;
191+
bool first = true;
192+
i = 0;
193+
while (i < N (s)) {
194+
int j= i;
195+
tm_char_forwards (s, j);
196+
get_extents (s (i, j), ey);
197+
if (first) {
198+
ex[0]= ey[0];
199+
first= false;
200+
}
201+
else {
202+
ex->x2= advance + ey->x2;
203+
ex->y1= min (ex->y1, ey->y1);
204+
ex->y2= max (ex->y2, ey->y2);
205+
ex->x3= min (ex->x3, advance + ey->x3);
206+
ex->y3= min (ex->y3, ey->y3);
207+
ex->x4= max (ex->x4, advance + ey->x4);
208+
ex->y4= max (ex->y4, ey->y4);
209+
}
210+
advance+= ey->x2;
211+
i= j;
212+
}
181213
}
182214

183215
void
184216
math_font_rep::get_xpositions (string s, SI* xpos) {
185217
if (s == "") return;
186-
font fn;
187-
string r= s;
188-
search_font (r, fn);
189-
if (r == s) fn->get_xpositions (s, xpos);
190-
else if (N (r) != 1) font_rep::get_xpositions (s, xpos);
191-
else {
192-
int i, n= N (s);
193-
for (i= 1; i < n; i++)
194-
xpos[i]= 0;
195-
fn->get_xpositions (r, xpos + n - 1);
218+
// Fast path: single TeXmacs character
219+
int i= 0;
220+
tm_char_forwards (s, i);
221+
if (i >= N (s)) {
222+
font fn;
223+
string r= s;
224+
search_font (r, fn);
225+
if (r == s) fn->get_xpositions (s, xpos);
226+
else if (N (r) != 1) font_rep::get_xpositions (s, xpos);
227+
else {
228+
int k, n= N (s);
229+
for (k= 1; k < n; k++)
230+
xpos[k]= 0;
231+
fn->get_xpositions (r, xpos + n - 1);
232+
}
233+
return;
234+
}
235+
// Multi-character string: compute positions character by character.
236+
xpos[0] = 0;
237+
SI advance= 0;
238+
i = 0;
239+
while (i < N (s)) {
240+
int j= i;
241+
tm_char_forwards (s, j);
242+
metric ex;
243+
get_extents (s (i, j), ex);
244+
advance+= ex->x2;
245+
xpos[j]= advance;
246+
i = j;
196247
}
197248
}
198249

199250
void
200251
math_font_rep::draw_fixed (renderer ren, string s, SI x, SI y) {
201-
font fn;
202-
search_font (s, fn);
203-
fn->draw_fixed (ren, s, x, y);
252+
// Fast path: single TeXmacs character
253+
int i= 0;
254+
tm_char_forwards (s, i);
255+
if (i >= N (s)) {
256+
font fn;
257+
search_font (s, fn);
258+
fn->draw_fixed (ren, s, x, y);
259+
return;
260+
}
261+
// Multi-character string: draw each symbol at its own x-advance offset.
262+
SI advance= 0;
263+
i = 0;
264+
while (i < N (s)) {
265+
int j= i;
266+
tm_char_forwards (s, j);
267+
string c= s (i, j);
268+
draw_fixed (ren, c, x + advance, y);
269+
metric ex;
270+
get_extents (c, ex);
271+
advance+= ex->x2;
272+
i= j;
273+
}
204274
}
205275

206276
void
207277
math_font_rep::draw_fixed (renderer ren, string s, SI x, SI y, SI xk) {
208-
font fn;
209-
search_font (s, fn);
210-
fn->draw_fixed (ren, s, x, y, xk);
278+
// Fast path: single TeXmacs character
279+
int i= 0;
280+
tm_char_forwards (s, i);
281+
if (i >= N (s)) {
282+
font fn;
283+
search_font (s, fn);
284+
fn->draw_fixed (ren, s, x, y, xk);
285+
return;
286+
}
287+
// Multi-character string: delegate to base class which iterates char-by-char
288+
// using get_xpositions (now consistent) and calls single-char draw_fixed.
289+
font_rep::draw_fixed (ren, s, x, y, xk);
211290
}
212291

213292
font

0 commit comments

Comments
 (0)