Problems registering, no confirmation email - see http://wiki.scribus.net/canvas/Forums_Registration
============================================================
Run: 2026-04-23 12:31:34
Mode: CONTINUOUS
Reflow: enabled (no setReflow)
Trim: 152.4 x 228.6 mm (6" x 9")
Frame: 107.0 x 177.8 mm
Input: ulyssess_small.txt (269582 chars) x 1 iterations
Total pages: 107
Total time: 136.85s
Import time: 35.20s
Chain time: 101.58s
Avg per chain page: 0.9493s
Fastest chain: page 1 (0.0000s)
Slowest chain: page 105 (1.8610s)
Sampled pages (10 of 107):
Page 1: 0.0000s #
Page 13: 0.2034s ##
Page 25: 0.4450s ####
Page 36: 0.5861s #####
Page 48: 1.0333s ##########
Page 60: 1.0533s ##########
Page 72: 1.2571s ############
Page 83: 1.3777s #############
Page 95: 1.6915s ################
Page 107: 1.8068s ##################
============================================================
Run: 2026-04-23 12:32:48
Mode: CONTINUOUS
Reflow: paused during build
Trim: 152.4 x 228.6 mm (6" x 9")
Frame: 107.0 x 177.8 mm
Input: ulyssess_small.txt (269582 chars) x 1 iterations
Total pages: 107
Total time: 41.31s
Import time: 37.02s
Chain time: 4.22s
Avg per chain page: 0.0394s
Fastest chain: page 1 (0.0000s)
Slowest chain: page 2 (0.0612s)
Sampled pages (10 of 107):
Page 1: 0.0000s #
Page 13: 0.0351s #
Page 25: 0.0372s #
Page 36: 0.0570s #
Page 48: 0.0435s #
Page 60: 0.0498s #
Page 72: 0.0443s #
Page 83: 0.0452s #
Page 95: 0.0340s #
Page 107: 0.0208s #
From: DLS Project
Subject: [PATCH] Add setReflow() API to fix text frame chain performance degradation
Add a `setReflow(enabled)` Python API to let scripts pause
backward invalidation and chain walking during linked frame construction,
reducing the per-page cost.
Reflow is automatically re-enabled when a script finishes (even on crash)
via the finishScriptRun() cleanup path.
Benchmark: 107-page single-chain document (ulyssess_small.txt, 270K chars)
Before: 101.58s chain time, avg 0.95s/page, slowest page 1.86s (page 105)
After: 4.22s chain time, avg 0.04s/page, slowest page 0.06s (page 2)
Total build: 136.85s -> 41.31s (3.3x faster)
Import time: unchanged (~35s)
diff --git a/scribus/pageitem.cpp b/scribus/pageitem.cpp
index 64e91e7350..fe11cc3d33 100644
--- a/scribus/pageitem.cpp
+++ b/scribus/pageitem.cpp
@@ -1176,11 +1176,14 @@ void PageItem::link(PageItem* nxt, bool addPARSEP)
}
}
invalid = true;
- PageItem* prev = this;
- while (prev->m_backBox && !prev->m_backBox->frameOverflows())
+ if (m_Doc->m_reflowEnabled)
{
- prev->m_backBox->invalid = true;
- prev = prev->m_backBox;
+ PageItem* prev = this;
+ while (prev->m_backBox && !prev->m_backBox->frameOverflows())
+ {
+ prev->m_backBox->invalid = true;
+ prev = prev->m_backBox;
+ }
}
while (nxt)
{
diff --git a/scribus/pageitem_textframe.cpp b/scribus/pageitem_textframe.cpp
index 3b48782545..b5b9e815a0 100644
--- a/scribus/pageitem_textframe.cpp
+++ b/scribus/pageitem_textframe.cpp
@@ -1177,20 +1177,28 @@ void PageItem_TextFrame::layout()
// printBacktrace(24);
if (m_backBox != nullptr)
{
-// qDebug("textframe: len=%d, going back", itemText.length());
PageItem_TextFrame* firstInvalid = nullptr;
- PageItem_TextFrame* prevInChain = dynamic_cast<PageItem_TextFrame*>(m_backBox);
- while (prevInChain)
+ if (m_Doc->m_reflowEnabled)
{
- if (prevInChain->invalid)
- firstInvalid = prevInChain;
- prevInChain = dynamic_cast<PageItem_TextFrame*>(prevInChain->m_backBox);
+ PageItem_TextFrame* prevInChain = dynamic_cast<PageItem_TextFrame*>(m_backBox);
+ while (prevInChain)
+ {
+ if (prevInChain->invalid)
+ firstInvalid = prevInChain;
+ prevInChain = dynamic_cast<PageItem_TextFrame*>(prevInChain->m_backBox);
+ }
+ PageItem_TextFrame* nextInChain = firstInvalid;
+ while (nextInChain && (nextInChain != this))
+ {
+ nextInChain->layout();
+ nextInChain = dynamic_cast<PageItem_TextFrame*>(nextInChain->m_nextBox);
+ }
}
- PageItem_TextFrame* nextInChain = firstInvalid;
- while (nextInChain && (nextInChain != this))
+ else if (invalid)
{
- nextInChain->layout();
- nextInChain = dynamic_cast<PageItem_TextFrame*>(nextInChain->m_nextBox);
+ PageItem_TextFrame* prevFrame = dynamic_cast<PageItem_TextFrame*>(m_backBox);
+ if (prevFrame)
+ firstChar = prevFrame->m_maxChars;
}
// #9592 : warning, BackBox->layout() may not layout BackBox next box
if (!invalid)
diff --git a/scribus/plugins/scriptplugin/scriptercore.cpp b/scribus/plugins/scriptplugin/scriptercore.cpp
index 92948e67b7..f253ea6b4a 100644
--- a/scribus/plugins/scriptplugin/scriptercore.cpp
+++ b/scribus/plugins/scriptplugin/scriptercore.cpp
@@ -162,6 +162,12 @@ void ScripterCore::finishScriptRun()
if (!mainWin->HaveDoc)
return;
+ if (!mainWin->doc->m_reflowEnabled)
+ {
+ mainWin->doc->m_reflowEnabled = true;
+ mainWin->doc->invalidateAll();
+ }
+
mainWin->propertiesPalette->setDoc(mainWin->doc);
mainWin->contentPalette->setDoc(mainWin->doc);
mainWin->marksManager->setDoc(mainWin->doc);
diff --git a/scribus/plugins/scriptplugin/scriptplugin.cpp b/scribus/plugins/scriptplugin/scriptplugin.cpp
--- a/scribus/plugins/scriptplugin/scriptplugin.cpp
+++ b/scribus/plugins/scriptplugin/scriptplugin.cpp
@@ -*,* +*,* @@
+ { "setReflow", scribus_setreflow, METH_VARARGS, tr(scribus_setreflow__doc__)},
diff --git a/scribus/scribusdoc.h b/scribus/scribusdoc.h
index 1ce4404326..ac78a8b005 100644
--- a/scribus/scribusdoc.h
+++ b/scribus/scribusdoc.h
@@ -1480,6 +1480,8 @@ public:
int TotalItems {0};
PrintOptions Print_Options;
bool RePos {false};
+ bool m_reflowEnabled {true};
+
struct BookMa {
QString Title;
QString Text;
( yes, I'm only kidding )
