From eae500107c157cd3f3bbbc4a1d52359e16a59528 Mon Sep 17 00:00:00 2001 From: MoonL79 <151734889+MoonL79@users.noreply.github.com> Date: Thu, 9 Apr 2026 10:43:47 +0800 Subject: [PATCH 1/7] =?UTF-8?q?[221=5F2]=20=E4=BF=AE=E5=A4=8D=E6=9C=89?= =?UTF-8?q?=E6=A1=86=E5=AE=9A=E7=90=86=E4=B8=AD=E7=9A=84=E8=84=9A=E6=B3=A8?= =?UTF-8?q?=E4=B8=8D=E6=98=BE=E7=A4=BA=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devel/221_2.md | 52 +++++++++++++++++++++++++++++++ src/Typeset/Bridge/bridge_gui.cpp | 18 +++++++++++ src/Typeset/Line/lazy_gui.cpp | 44 ++++++++++++++++++++++++-- 3 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 devel/221_2.md diff --git a/devel/221_2.md b/devel/221_2.md new file mode 100644 index 0000000000..f551a5e4ad --- /dev/null +++ b/devel/221_2.md @@ -0,0 +1,52 @@ +[221_2] 有框定理中的脚注不显示 + +## 如何测试 + +测试项一:无框定理中的脚注正常显示 +1. 新建或打开任意 tmu 文档 +2. 插入一个定理环境,不勾选“加框” +3. 在定理正文中输入一段文字,并插入一个脚注 +4. 文档中应出现脚注上标,页面底部应正常显示脚注正文 + +测试项二:有框定理中的脚注正常显示 +1. 新建或打开任意 tmu 文档 +2. 插入一个定理环境,并勾选“加框” +3. 在定理正文中输入一段文字,并插入一个脚注 +4. 文档中应出现脚注上标,页面底部也应正常显示脚注正文 +5. 脚注正文不应因为定理有边框而丢失 + +测试项三:切换有框和无框后脚注保持正常 +1. 插入一个带脚注的定理环境,初始不勾选“加框” +2. 确认脚注正文正常显示 +3. 勾选“加框” +4. 脚注正文应继续正常显示 +5. 再取消“加框” +6. 脚注正文仍应正常显示 + +测试项四:多个有框定理脚注编号连续 +1. 在同一文档中插入两个勾选“加框”的定理环境 +2. 在每个定理中各插入一个脚注 +3. 两个脚注的上标编号应连续 +4. 页面底部应按顺序显示两个脚注正文 + +## 2026/04/09 有框定理重新包装 page item 时保留脚注 float + +### What +修复定理环境在启用“加框”后,定理内部脚注只显示上标、不显示脚注正文的问题。 + +### Why +无框定理里的脚注本来是正常的,说明 `footnote` 宏本身没有问题。 +问题出在“加框”路径上:有框定理会通过 `decorated` / `ornament` 将内部内容重新包装成外层内容。 +在这个重包装过程中,框内正文虽然已经生成了脚注对应的页面插入对象 `fl`,但原实现只取了 box 和 spacing,没有把 `fl` 一起传递到外层 page item。 +因此脚注上标仍然存在,而脚注正文在页面脚注区丢失。 + +### How +TeXmacs/packages/customize/theorem/framed-theorems.ts 中的有框定理最终走到 ornament 渲染路径 +TeXmacs/packages/environment/env-float.ts 中脚注正文通过 `` 进入页面插入通道 +src/Typeset/Bridge/bridge_gui.cpp 中: +1. 为 ornament 内部生成的 `array` 增加 `fl` 收集逻辑 +2. 在 `insert_ornament` 将外框内容重新插入段落时,把收集到的 `fl` 重新挂回外层 page item +src/Typeset/Line/lazy_gui.cpp 中同步补充 lazy ornament / art_box 路径,对内部 `fl` 进行收集并重新附着,避免不同渲染链行为不一致 + +### 备注 +本次问题的根因不是脚注没有生成,而是有框定理在 ornament 层重新包装内容时,没有保留脚注对应的页面 float。 diff --git a/src/Typeset/Bridge/bridge_gui.cpp b/src/Typeset/Bridge/bridge_gui.cpp index c65fd0e408..b9854f8ae6 100644 --- a/src/Typeset/Bridge/bridge_gui.cpp +++ b/src/Typeset/Bridge/bridge_gui.cpp @@ -25,6 +25,7 @@ class bridge_ornamented_rep : public bridge_rep { bridge body; tree with; int idx; + array ornament_fl; public: bridge_ornamented_rep (typesetter ttt, tree st, path ip, int idx); @@ -158,6 +159,14 @@ make_ornament_body (path ip, array l) { return move_box (decorate (ip), stack_box (ip, lines_bx, lines_ht), 0, dy); } +static array +collect_attached_floats (array items) { + array fl; + for (int i= 0; i < N (items); i++) + if (N (items[i]->fl) > 0) fl << items[i]->fl; + return fl; +} + box bridge_ornamented_rep::typeset_ornament (int desired_status) { int i; @@ -178,6 +187,7 @@ bridge_ornamented_rep::typeset_ornament (int desired_status) { ttt->a= a2; ttt->b= b2; ttt->local_end (l2, sb2); + ornament_fl= collect_attached_floats (l2); for (i-= 2; i >= 0; i-= 2) env->write_update (with[i]->label, old[i + 1]); return make_ornament_body (ip, l2); @@ -196,6 +206,14 @@ bridge_ornamented_rep::insert_ornament (box b) { par->a << line_item (STD_ITEM, env->mode_op, b, HYPH_INVALID); par->a << ttt->b; par->format_paragraph (); + if (N (ornament_fl) > 0) { + int i= N (par->sss->l) - 1; + while (i >= 0 && par->sss->l[i]->type == PAGE_CONTROL_ITEM) i--; + if (i >= 0) { + par->sss->l[i]= copy (par->sss->l[i]); + par->sss->l[i]->fl << ornament_fl; + } + } ttt->insert_stack (par->sss->l, par->sss->sb); } diff --git a/src/Typeset/Line/lazy_gui.cpp b/src/Typeset/Line/lazy_gui.cpp index 1961d54652..d490329bdb 100644 --- a/src/Typeset/Line/lazy_gui.cpp +++ b/src/Typeset/Line/lazy_gui.cpp @@ -22,6 +22,14 @@ using namespace moebius; box surround (edit_env env, box b, path ip, array l, array r, format fm); +static array +collect_attached_floats (array items) { + array fl; + for (int i= 0; i < N (items); i++) + if (N (items[i]->fl) > 0) fl << items[i]->fl; + return fl; +} + /****************************************************************************** * Canvases ******************************************************************************/ @@ -185,12 +193,27 @@ lazy_ornament_rep::produce (lazy_type request, format fm) { if (request == type) return this; if (request == LAZY_VSTREAM || request == LAZY_BOX) { format bfm= fm; + SI body_width= 0; + bool have_body_width= false; if (request == LAZY_VSTREAM) { format_vstream fvs= (format_vstream) fm; SI dw = ps->lpad + ps->rpad; bfm = make_format_width (fvs->width - dw); + body_width = fvs->width - dw; + have_body_width = true; + } + else if (fm->type == FORMAT_CELL) { + format_cell fc= (format_cell) fm; + SI dw= ps->lpad + ps->rpad; + body_width = fc->width - dw; + have_body_width= true; + } + box b = (box) par->produce (LAZY_BOX, bfm); + array fl; + if (have_body_width) { + lazy body= par->produce (LAZY_VSTREAM, make_format_vstream (body_width, 0, 0)); + fl = collect_attached_floats (((lazy_vstream) body)->l); } - box b = (box) par->produce (LAZY_BOX, bfm); box hb= highlight_box (ip, b, xb, ps); // FIXME: this dirty hack ensures that shoving is correct hb= move_box (decorate (ip), hb, 1, 0); @@ -203,7 +226,7 @@ lazy_ornament_rep::produce (lazy_type request, format fm) { if (request == LAZY_BOX) return make_lazy_box (hb); else { array l; - l << page_item (hb); + l << page_item (hb, fl); return lazy_vstream (ip, "", l, stack_border ()); } } @@ -259,12 +282,27 @@ lazy_art_box_rep::produce (lazy_type request, format fm) { if (request == type) return this; if (request == LAZY_VSTREAM || request == LAZY_BOX) { format bfm= fm; + SI body_width= 0; + bool have_body_width= false; if (request == LAZY_VSTREAM) { format_vstream fvs= (format_vstream) fm; SI dw = ps->lpad + ps->rpad; bfm = make_format_width (fvs->width - dw); + body_width = fvs->width - dw; + have_body_width = true; + } + else if (fm->type == FORMAT_CELL) { + format_cell fc= (format_cell) fm; + SI dw= ps->lpad + ps->rpad; + body_width = fc->width - dw; + have_body_width= true; } box b = (box) par->produce (LAZY_BOX, bfm); + array fl; + if (have_body_width) { + lazy body= par->produce (LAZY_VSTREAM, make_format_vstream (body_width, 0, 0)); + fl = collect_attached_floats (((lazy_vstream) body)->l); + } box hb= art_box (ip, b, ps); hb = move_box (decorate (ip), hb, 0, b->y1 - ps->bpad); // FIXME: this dirty hack ensures that shoving is correct @@ -278,7 +316,7 @@ lazy_art_box_rep::produce (lazy_type request, format fm) { if (request == LAZY_BOX) return make_lazy_box (hb); else { array l; - l << page_item (hb); + l << page_item (hb, fl); return lazy_vstream (ip, "", l, stack_border ()); } } From b709ba94b56ffcfcf65b00882e57c795f3619980 Mon Sep 17 00:00:00 2001 From: MoonL79 <151734889+MoonL79@users.noreply.github.com> Date: Thu, 9 Apr 2026 10:47:32 +0800 Subject: [PATCH 2/7] format --- src/Typeset/Bridge/bridge_gui.cpp | 9 +++++---- src/Typeset/Line/lazy_gui.cpp | 30 ++++++++++++++++-------------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/Typeset/Bridge/bridge_gui.cpp b/src/Typeset/Bridge/bridge_gui.cpp index b9854f8ae6..6074674362 100644 --- a/src/Typeset/Bridge/bridge_gui.cpp +++ b/src/Typeset/Bridge/bridge_gui.cpp @@ -22,9 +22,9 @@ using namespace moebius; class bridge_ornamented_rep : public bridge_rep { protected: - bridge body; - tree with; - int idx; + bridge body; + tree with; + int idx; array ornament_fl; public: @@ -208,7 +208,8 @@ bridge_ornamented_rep::insert_ornament (box b) { par->format_paragraph (); if (N (ornament_fl) > 0) { int i= N (par->sss->l) - 1; - while (i >= 0 && par->sss->l[i]->type == PAGE_CONTROL_ITEM) i--; + while (i >= 0 && par->sss->l[i]->type == PAGE_CONTROL_ITEM) + i--; if (i >= 0) { par->sss->l[i]= copy (par->sss->l[i]); par->sss->l[i]->fl << ornament_fl; diff --git a/src/Typeset/Line/lazy_gui.cpp b/src/Typeset/Line/lazy_gui.cpp index d490329bdb..cd2f454273 100644 --- a/src/Typeset/Line/lazy_gui.cpp +++ b/src/Typeset/Line/lazy_gui.cpp @@ -192,8 +192,8 @@ lazy lazy_ornament_rep::produce (lazy_type request, format fm) { if (request == type) return this; if (request == LAZY_VSTREAM || request == LAZY_BOX) { - format bfm= fm; - SI body_width= 0; + format bfm = fm; + SI body_width = 0; bool have_body_width= false; if (request == LAZY_VSTREAM) { format_vstream fvs= (format_vstream) fm; @@ -203,16 +203,17 @@ lazy_ornament_rep::produce (lazy_type request, format fm) { have_body_width = true; } else if (fm->type == FORMAT_CELL) { - format_cell fc= (format_cell) fm; - SI dw= ps->lpad + ps->rpad; + format_cell fc = (format_cell) fm; + SI dw = ps->lpad + ps->rpad; body_width = fc->width - dw; have_body_width= true; } - box b = (box) par->produce (LAZY_BOX, bfm); + box b= (box) par->produce (LAZY_BOX, bfm); array fl; if (have_body_width) { - lazy body= par->produce (LAZY_VSTREAM, make_format_vstream (body_width, 0, 0)); - fl = collect_attached_floats (((lazy_vstream) body)->l); + lazy body= + par->produce (LAZY_VSTREAM, make_format_vstream (body_width, 0, 0)); + fl= collect_attached_floats (((lazy_vstream) body)->l); } box hb= highlight_box (ip, b, xb, ps); // FIXME: this dirty hack ensures that shoving is correct @@ -281,8 +282,8 @@ lazy lazy_art_box_rep::produce (lazy_type request, format fm) { if (request == type) return this; if (request == LAZY_VSTREAM || request == LAZY_BOX) { - format bfm= fm; - SI body_width= 0; + format bfm = fm; + SI body_width = 0; bool have_body_width= false; if (request == LAZY_VSTREAM) { format_vstream fvs= (format_vstream) fm; @@ -292,16 +293,17 @@ lazy_art_box_rep::produce (lazy_type request, format fm) { have_body_width = true; } else if (fm->type == FORMAT_CELL) { - format_cell fc= (format_cell) fm; - SI dw= ps->lpad + ps->rpad; + format_cell fc = (format_cell) fm; + SI dw = ps->lpad + ps->rpad; body_width = fc->width - dw; have_body_width= true; } - box b = (box) par->produce (LAZY_BOX, bfm); + box b= (box) par->produce (LAZY_BOX, bfm); array fl; if (have_body_width) { - lazy body= par->produce (LAZY_VSTREAM, make_format_vstream (body_width, 0, 0)); - fl = collect_attached_floats (((lazy_vstream) body)->l); + lazy body= + par->produce (LAZY_VSTREAM, make_format_vstream (body_width, 0, 0)); + fl= collect_attached_floats (((lazy_vstream) body)->l); } box hb= art_box (ip, b, ps); hb = move_box (decorate (ip), hb, 0, b->y1 - ps->bpad); From 56f73dd39db7aad61199ccfce89e81db75c15380 Mon Sep 17 00:00:00 2001 From: MoonL79 <151734889+MoonL79@users.noreply.github.com> Date: Thu, 9 Apr 2026 11:09:19 +0800 Subject: [PATCH 3/7] test --- tests/Typeset/ornament_footnote_test.cpp | 94 ++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 tests/Typeset/ornament_footnote_test.cpp diff --git a/tests/Typeset/ornament_footnote_test.cpp b/tests/Typeset/ornament_footnote_test.cpp new file mode 100644 index 0000000000..8d36d39d9f --- /dev/null +++ b/tests/Typeset/ornament_footnote_test.cpp @@ -0,0 +1,94 @@ +/****************************************************************************** + * MODULE : ornament_footnote_test.cpp + * DESCRIPTION: Tests for footnote propagation through ornament wrappers + * COPYRIGHT : (C) 2026 Mingshen Chu + ******************************************************************************* + * This software falls under the GNU general public license version 3 or later. + * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE + * in the root directory or . + ******************************************************************************/ + +#include "Format/format.hpp" +#include "Metafont/load_tex.hpp" +#include "Line/lazy_vstream.hpp" +#include "base.hpp" +#include "data_cache.hpp" +#include "env.hpp" +#include "formatter.hpp" +#include "tm_sys_utils.hpp" +#include +#include + +using namespace moebius; +using moebius::drd::std_drd; + +static edit_env +create_test_env () { + drd_info drd ("none", std_drd); + hashmap h1 (UNINIT), h2 (UNINIT); + hashmap h3 (UNINIT), h4 (UNINIT); + hashmap h5 (UNINIT), h6 (UNINIT); + return edit_env (drd, "none", h1, h2, h3, h4, h5, h6); +} + +static tree +create_ornament_with_footnote () { + tree footnote_body (DOCUMENT, 1); + footnote_body[0]= tree (CONCAT, "footnote body"); + + tree paragraph (CONCAT); + paragraph << "boxed theorem body"; + paragraph << tree (FLOAT, "footnote", "", footnote_body); + paragraph << " continues"; + + tree body (DOCUMENT, 1); + body[0]= paragraph; + + return tree (ORNAMENT, body); +} + +static int +count_footnotes (array items) { + int total= 0; + for (int i= 0; i < N (items); ++i) + for (int j= 0; j < N (items[i]->fl); ++j) { + lazy_vstream ins= (lazy_vstream) items[i]->fl[j]; + if (is_tuple (ins->channel, "footnote")) total++; + } + return total; +} + +static bool +has_footnote (array items) { + return count_footnotes (items) > 0; +} + +class TestOrnamentFootnote : public QObject { + Q_OBJECT + +private slots: + void initTestCase () { + init_lolly (); + init_texmacs_home_path (); + cache_initialize (); + init_tex (); + } + + void lazy_ornament_keeps_footnote_float (); +}; + +void +TestOrnamentFootnote::lazy_ornament_keeps_footnote_float () { + edit_env env= create_test_env (); + tree ornament= create_ornament_with_footnote (); + + lazy lz= make_lazy (env, ornament, path ()); + lazy produced= + lz->produce (LAZY_VSTREAM, make_format_vstream (600 * PIXEL, 0, 0)); + lazy_vstream vs= (lazy_vstream) produced; + + QVERIFY (has_footnote (vs->l)); +} + +QTEST_MAIN (TestOrnamentFootnote) +#include "ornament_footnote_test.moc" From d7e55132ee74e344caff6fc72279a2bcc7ce0d89 Mon Sep 17 00:00:00 2001 From: MoonL79 <151734889+MoonL79@users.noreply.github.com> Date: Thu, 9 Apr 2026 11:09:45 +0800 Subject: [PATCH 4/7] format --- tests/Typeset/ornament_footnote_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Typeset/ornament_footnote_test.cpp b/tests/Typeset/ornament_footnote_test.cpp index 8d36d39d9f..8e04f070eb 100644 --- a/tests/Typeset/ornament_footnote_test.cpp +++ b/tests/Typeset/ornament_footnote_test.cpp @@ -9,8 +9,8 @@ ******************************************************************************/ #include "Format/format.hpp" -#include "Metafont/load_tex.hpp" #include "Line/lazy_vstream.hpp" +#include "Metafont/load_tex.hpp" #include "base.hpp" #include "data_cache.hpp" #include "env.hpp" @@ -79,7 +79,7 @@ private slots: void TestOrnamentFootnote::lazy_ornament_keeps_footnote_float () { - edit_env env= create_test_env (); + edit_env env = create_test_env (); tree ornament= create_ornament_with_footnote (); lazy lz= make_lazy (env, ornament, path ()); From 24050b4fede706b57049830820e52f89d2c8c5d2 Mon Sep 17 00:00:00 2001 From: MoonL79 <151734889+MoonL79@users.noreply.github.com> Date: Thu, 9 Apr 2026 11:29:14 +0800 Subject: [PATCH 5/7] fix_tests --- .../bridge_gui/bridge_ornamented_rep_test.cpp | 116 ++++++++++++++++++ .../lazy_gui/lazy_ornament_rep_test.cpp} | 14 +-- 2 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 tests/Typeset/Bridge/bridge_gui/bridge_ornamented_rep_test.cpp rename tests/Typeset/{ornament_footnote_test.cpp => Line/lazy_gui/lazy_ornament_rep_test.cpp} (87%) diff --git a/tests/Typeset/Bridge/bridge_gui/bridge_ornamented_rep_test.cpp b/tests/Typeset/Bridge/bridge_gui/bridge_ornamented_rep_test.cpp new file mode 100644 index 0000000000..f5e6c061bd --- /dev/null +++ b/tests/Typeset/Bridge/bridge_gui/bridge_ornamented_rep_test.cpp @@ -0,0 +1,116 @@ +/****************************************************************************** + * MODULE : bridge_ornamented_rep_test.cpp + * DESCRIPTION: Tests for footnote propagation in bridge_ornamented_rep + * COPYRIGHT : (C) 2026 Mingshen Chu + ******************************************************************************* + * This software falls under the GNU general public license version 3 or later. + * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE + * in the root directory or . + ******************************************************************************/ + +#include "Boxes/construct.hpp" +#include "Line/lazy_paragraph.hpp" +#include "Line/lazy_vstream.hpp" +#include "Metafont/load_tex.hpp" +#include "base.hpp" +#include "data_cache.hpp" +#include "env.hpp" +#include "tm_sys_utils.hpp" +#include +#include + +using namespace moebius; +using moebius::drd::std_drd; + +static edit_env +create_test_env () { + drd_info drd ("none", std_drd); + hashmap h1 (UNINIT), h2 (UNINIT); + hashmap h3 (UNINIT), h4 (UNINIT); + hashmap h5 (UNINIT), h6 (UNINIT); + return edit_env (drd, "none", h1, h2, h3, h4, h5, h6); +} + +static tree +create_ornament_with_footnote () { + tree footnote_body (DOCUMENT, 1); + footnote_body[0]= tree (CONCAT, "footnote body"); + + tree paragraph (CONCAT); + paragraph << "boxed theorem body"; + paragraph << tree (FLOAT, "footnote", "", footnote_body); + paragraph << " continues"; + + tree body (DOCUMENT, 1); + body[0]= paragraph; + + return tree (ORNAMENT, body); +} + +static bool +has_footnote (array items) { + for (int i= 0; i < N (items); ++i) + for (int j= 0; j < N (items[i]->fl); ++j) { + lazy_vstream ins= (lazy_vstream) items[i]->fl[j]; + if (is_tuple (ins->channel, "footnote")) return true; + } + return false; +} + +static array +collect_attached_floats_for_test (array items) { + array fl; + for (int i= 0; i < N (items); ++i) + if (N (items[i]->fl) > 0) fl << items[i]->fl; + return fl; +} + +class TestBridgeOrnamentedRep : public QObject { + Q_OBJECT + +private slots: + void initTestCase () { + init_lolly (); + init_texmacs_home_path (); + cache_initialize (); + init_tex (); + } + + void keeps_footnote_float (); +}; + +void +TestBridgeOrnamentedRep::keeps_footnote_float () { + edit_env env= create_test_env (); + env->style_init_env (); + env->update (); + + array inner_items (1); + array footnote_lines (1); + footnote_lines[0]= page_item (empty_box (path (0))); + array fl (1); + fl[0] = lazy_vstream (path (0), tuple ("footnote"), footnote_lines, + stack_border ()); + inner_items[0]= page_item (empty_box (path (1)), fl); + + array ornament_fl= collect_attached_floats_for_test (inner_items); + QVERIFY (has_footnote (inner_items)); + + lazy_paragraph par (env, path ()); + par->a << line_item (STD_ITEM, env->mode_op, empty_box (path (2)), + HYPH_INVALID); + par->format_paragraph (); + + int i= N (par->sss->l) - 1; + while (i >= 0 && par->sss->l[i]->type == PAGE_CONTROL_ITEM) + i--; + QVERIFY (i >= 0); + + par->sss->l[i]= copy (par->sss->l[i]); + par->sss->l[i]->fl << ornament_fl; + + QVERIFY (has_footnote (par->sss->l)); +} + +QTEST_MAIN (TestBridgeOrnamentedRep) +#include "bridge_ornamented_rep_test.moc" diff --git a/tests/Typeset/ornament_footnote_test.cpp b/tests/Typeset/Line/lazy_gui/lazy_ornament_rep_test.cpp similarity index 87% rename from tests/Typeset/ornament_footnote_test.cpp rename to tests/Typeset/Line/lazy_gui/lazy_ornament_rep_test.cpp index 8e04f070eb..8617e6a40d 100644 --- a/tests/Typeset/ornament_footnote_test.cpp +++ b/tests/Typeset/Line/lazy_gui/lazy_ornament_rep_test.cpp @@ -1,6 +1,6 @@ /****************************************************************************** - * MODULE : ornament_footnote_test.cpp - * DESCRIPTION: Tests for footnote propagation through ornament wrappers + * MODULE : lazy_ornament_rep_test.cpp + * DESCRIPTION: Tests for footnote propagation in lazy_ornament_rep * COPYRIGHT : (C) 2026 Mingshen Chu ******************************************************************************* * This software falls under the GNU general public license version 3 or later. @@ -63,7 +63,7 @@ has_footnote (array items) { return count_footnotes (items) > 0; } -class TestOrnamentFootnote : public QObject { +class TestLazyOrnamentRep : public QObject { Q_OBJECT private slots: @@ -74,11 +74,11 @@ private slots: init_tex (); } - void lazy_ornament_keeps_footnote_float (); + void keeps_footnote_float (); }; void -TestOrnamentFootnote::lazy_ornament_keeps_footnote_float () { +TestLazyOrnamentRep::keeps_footnote_float () { edit_env env = create_test_env (); tree ornament= create_ornament_with_footnote (); @@ -90,5 +90,5 @@ TestOrnamentFootnote::lazy_ornament_keeps_footnote_float () { QVERIFY (has_footnote (vs->l)); } -QTEST_MAIN (TestOrnamentFootnote) -#include "ornament_footnote_test.moc" +QTEST_MAIN (TestLazyOrnamentRep) +#include "lazy_ornament_rep_test.moc" From b68e18921f5a660f5ae8b5e548e651662ecbc0bf Mon Sep 17 00:00:00 2001 From: MoonL79 <151734889+MoonL79@users.noreply.github.com> Date: Thu, 9 Apr 2026 11:33:14 +0800 Subject: [PATCH 6/7] doxygen --- src/Typeset/Bridge/bridge_gui.cpp | 12 ++++++++++++ src/Typeset/Line/lazy_gui.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/Typeset/Bridge/bridge_gui.cpp b/src/Typeset/Bridge/bridge_gui.cpp index 6074674362..2a8ac19ed9 100644 --- a/src/Typeset/Bridge/bridge_gui.cpp +++ b/src/Typeset/Bridge/bridge_gui.cpp @@ -167,6 +167,18 @@ collect_attached_floats (array items) { return fl; } +/** + * @brief 对 ornament 正文做局部排版,并生成用于插入主段落的外框 box。 + * + * 该函数会在局部排版上下文中排版 ornament 内部正文,得到一组局部 + * `page_item`。随后一方面将这些 `page_item` 叠成 ornament 对应的 box, + * 另一方面收集其上附着的 `fl`,保存到成员 `ornament_fl` 中,供后续 + * `insert_ornament` 在重新插入主页面流时重新附着,从而避免脚注等页面插入 + * 对象在 bridge 层包装过程中丢失。 + * + * @param desired_status 本次排版期望达到的状态。 + * @return 由 ornament 内部局部排版结果构造出的外框 box。 + */ box bridge_ornamented_rep::typeset_ornament (int desired_status) { int i; diff --git a/src/Typeset/Line/lazy_gui.cpp b/src/Typeset/Line/lazy_gui.cpp index cd2f454273..c79bddbb4a 100644 --- a/src/Typeset/Line/lazy_gui.cpp +++ b/src/Typeset/Line/lazy_gui.cpp @@ -188,6 +188,19 @@ lazy_ornament_rep::query (lazy_type request, format fm) { return lazy_rep::query (request, fm); } +/** + * @brief 生成 ornament 的延迟排版结果。 + * + * 该函数根据请求类型返回加框内容对应的 box 或 vstream。对于 + * `LAZY_VSTREAM` 路径,除了生成外框 box 之外,还会重新请求正文的 + * vstream,并收集其内部 `page_item` 上附着的 `fl`。这样在 ornament + * 将正文重新包装成新的外层 `page_item` 时,脚注等页面插入对象不会丢失。 + * + * @param request 当前请求的延迟对象类型,支持 `LAZY_BOX` 和 `LAZY_VSTREAM`。 + * @param fm 当前排版格式;在 vstream/cell 场景下会用于推导正文可用宽度。 + * @return 生成后的延迟对象;若请求为 `LAZY_BOX` 则返回 box,否则返回携带 + * 附着 floats 的 vstream。 + */ lazy lazy_ornament_rep::produce (lazy_type request, format fm) { if (request == type) return this; @@ -278,6 +291,19 @@ lazy_art_box_rep::query (lazy_type request, format fm) { return lazy_rep::query (request, fm); } +/** + * @brief 生成 art box 的延迟排版结果。 + * + * 该函数与 `lazy_ornament_rep::produce` 类似,但外层包装使用 `art_box`。 + * 在 `LAZY_VSTREAM` 路径下,函数会先根据正文宽度重新生成内部 vstream, + * 收集其中附着的 `fl`,再在构造外层 `page_item` 时一并挂回去,确保脚注、 + * 浮动对象等页面插入语义在 art box 包装后仍然保留。 + * + * @param request 当前请求的延迟对象类型,支持 `LAZY_BOX` 和 `LAZY_VSTREAM`。 + * @param fm 当前排版格式;在 vstream/cell 场景下会用于推导正文可用宽度。 + * @return 生成后的延迟对象;若请求为 `LAZY_BOX` 则返回 box,否则返回携带 + * 附着 floats 的 vstream。 + */ lazy lazy_art_box_rep::produce (lazy_type request, format fm) { if (request == type) return this; From f414429b4159a84138e0cab0a9fc2dc7f330c434 Mon Sep 17 00:00:00 2001 From: MoonL79 <151734889+MoonL79@users.noreply.github.com> Date: Thu, 9 Apr 2026 13:37:07 +0800 Subject: [PATCH 7/7] wip --- devel/221_2.md | 4 ++++ src/Typeset/Bridge/bridge_gui.cpp | 8 -------- src/Typeset/Format/page_item.cpp | 8 ++++++++ src/Typeset/Format/page_item.hpp | 1 + src/Typeset/Line/lazy_gui.cpp | 8 -------- 5 files changed, 13 insertions(+), 16 deletions(-) diff --git a/devel/221_2.md b/devel/221_2.md index f551a5e4ad..e7a094839f 100644 --- a/devel/221_2.md +++ b/devel/221_2.md @@ -1,7 +1,11 @@ [221_2] 有框定理中的脚注不显示 ## 如何测试 +### 单元测试 +bin/test_only bridge_ornamented_rep_test +bin/test_only lazy_ornament_rep_test +### 手动测试 测试项一:无框定理中的脚注正常显示 1. 新建或打开任意 tmu 文档 2. 插入一个定理环境,不勾选“加框” diff --git a/src/Typeset/Bridge/bridge_gui.cpp b/src/Typeset/Bridge/bridge_gui.cpp index 2a8ac19ed9..c754c06eb9 100644 --- a/src/Typeset/Bridge/bridge_gui.cpp +++ b/src/Typeset/Bridge/bridge_gui.cpp @@ -159,14 +159,6 @@ make_ornament_body (path ip, array l) { return move_box (decorate (ip), stack_box (ip, lines_bx, lines_ht), 0, dy); } -static array -collect_attached_floats (array items) { - array fl; - for (int i= 0; i < N (items); i++) - if (N (items[i]->fl) > 0) fl << items[i]->fl; - return fl; -} - /** * @brief 对 ornament 正文做局部排版,并生成用于插入主段落的外框 box。 * diff --git a/src/Typeset/Format/page_item.cpp b/src/Typeset/Format/page_item.cpp index 489d5e62d4..a05b821011 100644 --- a/src/Typeset/Format/page_item.cpp +++ b/src/Typeset/Format/page_item.cpp @@ -60,3 +60,11 @@ operator<< (tm_ostream& out, page_item item) { } return out << "unknown"; } + +array +collect_attached_floats (array items) { + array fl; + for (int i= 0; i < N (items); i++) + if (N (items[i]->fl) > 0) fl << items[i]->fl; + return fl; +} diff --git a/src/Typeset/Format/page_item.hpp b/src/Typeset/Format/page_item.hpp index af3b8d3110..5574da17bd 100644 --- a/src/Typeset/Format/page_item.hpp +++ b/src/Typeset/Format/page_item.hpp @@ -52,5 +52,6 @@ class page_item { CONCRETE_NULL_CODE (page_item); tm_ostream& operator<< (tm_ostream& out, page_item item); +array collect_attached_floats (array items); #endif // defined PAGE_ITEM_H diff --git a/src/Typeset/Line/lazy_gui.cpp b/src/Typeset/Line/lazy_gui.cpp index c79bddbb4a..20347d654e 100644 --- a/src/Typeset/Line/lazy_gui.cpp +++ b/src/Typeset/Line/lazy_gui.cpp @@ -22,14 +22,6 @@ using namespace moebius; box surround (edit_env env, box b, path ip, array l, array r, format fm); -static array -collect_attached_floats (array items) { - array fl; - for (int i= 0; i < N (items); i++) - if (N (items[i]->fl) > 0) fl << items[i]->fl; - return fl; -} - /****************************************************************************** * Canvases ******************************************************************************/