Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions devel/201_104.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# [201_104] Fix inner product symbol not rendering in Tab cycling popup

### What
Fixed `⟨⟩` (angle bracket pair) showing as a red broken symbol in the Tab cycling completion popup when typing `<` in math mode.

### Why
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.

### How
Modified `src/Graphics/Fonts/math_font.cpp`.

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:

- `get_extents`: accumulates per-symbol metrics, combining advance widths and taking the union of ink bounds.
- `get_xpositions`: fills the position array by accumulating advance widths per symbol.
- `draw_fixed(x, y)`: draws each symbol at its accumulated x-offset.
- `draw_fixed(x, y, xk)`: delegates to `font_rep::draw_fixed` (base class already iterates char-by-char).

No Scheme-level changes needed — `lambda-to-symbol` in `math-edit.scm` already returns `(string-append lb rb)`.

### How to test
1. Open Mogan Editor and create a new document.
2. Enter math mode (`$` or via Insert → Math).
3. Type `<` and press `Tab` to open the cycling popup.
4. **Verify**: The `⟨⟩` entry displays correctly (not in red).
5. Press `Tab` to cycle through variants and select `⟨⟩`.
6. **Verify**: The correct angle bracket pair is inserted in the document.
117 changes: 98 additions & 19 deletions src/Graphics/Fonts/math_font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,39 +175,118 @@ math_font_rep::supports (string c) {

void
math_font_rep::get_extents (string s, metric& ex) {
font fn;
search_font (s, fn);
fn->get_extents (s, ex);
// Fast path: single TeXmacs character
int i= 0;
tm_char_forwards (s, i);
if (i >= N (s)) {
font fn;
search_font (s, fn);
fn->get_extents (s, ex);
return;
}
// Multi-character string (e.g. "<langle><rangle>"): accumulate extents
// character by character so each symbol is looked up individually.
metric ey;
SI advance= 0;
bool first = true;
i = 0;
while (i < N (s)) {
int j= i;
tm_char_forwards (s, j);
get_extents (s (i, j), ey);
if (first) {
ex[0]= ey[0];
first= false;
}
else {
ex->x2= advance + ey->x2;
ex->y1= min (ex->y1, ey->y1);
ex->y2= max (ex->y2, ey->y2);
ex->x3= min (ex->x3, advance + ey->x3);
ex->y3= min (ex->y3, ey->y3);
ex->x4= max (ex->x4, advance + ey->x4);
ex->y4= max (ex->y4, ey->y4);
}
advance+= ey->x2;
i= j;
}
}

void
math_font_rep::get_xpositions (string s, SI* xpos) {
if (s == "") return;
font fn;
string r= s;
search_font (r, fn);
if (r == s) fn->get_xpositions (s, xpos);
else if (N (r) != 1) font_rep::get_xpositions (s, xpos);
else {
int i, n= N (s);
for (i= 1; i < n; i++)
xpos[i]= 0;
fn->get_xpositions (r, xpos + n - 1);
// Fast path: single TeXmacs character
int i= 0;
tm_char_forwards (s, i);
if (i >= N (s)) {
font fn;
string r= s;
search_font (r, fn);
if (r == s) fn->get_xpositions (s, xpos);
else if (N (r) != 1) font_rep::get_xpositions (s, xpos);
else {
int k, n= N (s);
for (k= 1; k < n; k++)
xpos[k]= 0;
fn->get_xpositions (r, xpos + n - 1);
}
return;
}
// Multi-character string: compute positions character by character.
xpos[0] = 0;
SI advance= 0;
i = 0;
while (i < N (s)) {
int j= i;
tm_char_forwards (s, j);
metric ex;
get_extents (s (i, j), ex);
advance+= ex->x2;
xpos[j]= advance;
i = j;
}
Comment on lines +235 to 247
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 get_xpositions 多字符路径未填充 TeXmacs 符号的中间字节位置

对于形如 <langle><rangle> 的字符串,xpos[0] 和字符端点(如 xpos[8]xpos[16])被正确设置,但 <langle> 内部的字节位置 xpos[1]..xpos[7] 始终未赋值。当前调用方(font_rep::draw_fixed)仅读取字符起始边界处的 xpos[old],因此对渲染不产生影响;但若未来有调用方(如光标定位)按字节读取中间位置,会得到未初始化的值。可参考基类 font_rep::get_xpositions 的做法,对 <...> 区间内的所有中间字节赋予当前累积偏移值以保持一致性。

}

void
math_font_rep::draw_fixed (renderer ren, string s, SI x, SI y) {
font fn;
search_font (s, fn);
fn->draw_fixed (ren, s, x, y);
// Fast path: single TeXmacs character
int i= 0;
tm_char_forwards (s, i);
if (i >= N (s)) {
font fn;
search_font (s, fn);
fn->draw_fixed (ren, s, x, y);
return;
}
// Multi-character string: draw each symbol at its own x-advance offset.
SI advance= 0;
i = 0;
while (i < N (s)) {
int j= i;
tm_char_forwards (s, j);
string c= s (i, j);
draw_fixed (ren, c, x + advance, y);
metric ex;
get_extents (c, ex);
advance+= ex->x2;
i= j;
}
Comment on lines +261 to +273
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 draw_fixed 中每个字符触发两次 search_font 查找

递归调用 draw_fixed(ren, c, ...) 内部会通过快速路径执行一次 search_font,之后紧跟的 get_extents(c, ex) 又会再次执行一次 search_font,导致同一个字符的字体查找被执行两次。可以先调用 get_extents 获取 advance,再绘制,以减少重复查找。

Suggested change
// Multi-character string: draw each symbol at its own x-advance offset.
SI advance= 0;
i = 0;
while (i < N (s)) {
int j= i;
tm_char_forwards (s, j);
string c= s (i, j);
draw_fixed (ren, c, x + advance, y);
metric ex;
get_extents (c, ex);
advance+= ex->x2;
i= j;
}
// Multi-character string: draw each symbol at its own x-advance offset.
SI advance= 0;
i = 0;
while (i < N (s)) {
int j= i;
tm_char_forwards (s, j);
string c= s (i, j);
metric ex;
get_extents (c, ex);
draw_fixed (ren, c, x + advance, y);
advance+= ex->x2;
i= j;
}

}

void
math_font_rep::draw_fixed (renderer ren, string s, SI x, SI y, SI xk) {
font fn;
search_font (s, fn);
fn->draw_fixed (ren, s, x, y, xk);
// Fast path: single TeXmacs character
int i= 0;
tm_char_forwards (s, i);
if (i >= N (s)) {
font fn;
search_font (s, fn);
fn->draw_fixed (ren, s, x, y, xk);
return;
}
// Multi-character string: delegate to base class which iterates char-by-char
// using get_xpositions (now consistent) and calls single-char draw_fixed.
font_rep::draw_fixed (ren, s, x, y, xk);
}

font
Expand Down
Loading