View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0014913 | Scribus | Text Frames / Story Editor | public | 2017-07-15 10:29 | 2026-08-27 11:21 |
| Reporter | longli | Assigned To | |||
| Priority | high | Severity | minor | Reproducibility | always |
| Status | new | Resolution | open | ||
| Summary | 0014913: the bug about Automatic Linespacing | ||||
| Description | as title | ||||
| Steps To Reproduce | 1.New TextFrame, input text. 2.Set TextFrame property to Automatic Linespacing. 3.Set the font size of TextFrame to 24pt, first paragraph to 12pt, second paragraph to 18pt, third paragraph to 24pt. The line spacing of all paragraphs is displayed by the font size of the 24pt(24pt is TextFrame font size). | ||||
| Tags | #please_test | ||||
| Attached Files | |||||
| Patch | No | ||||
|
|
Automatic leading should follow the paragraph’s effective base typography, not an inherited style value that may no longer match the rendered text. This patch fixed it in my testing. About the patch: #Cause `pageitem_textframe.cpp` calculates Automatic leading from `ParagraphStyle::charStyle()` while text layout itself uses the resolved character formatting from `StoryText`. The wrap/rebreak path also had a related mismatch where font and font size could come from different character positions. #Patch behaviour - Uses the effective character style at the actual paragraph start as the basis for Automatic leading. - Keeps that basis when the paragraph continues into another linked frame. - Uses the same calculation in normal layout and wrap/rebreak paths. - Keeps mixed-size runs inside one paragraph from arbitrarily changing its base leading. - Fixed Line Spacing and Baseline Grid are unchanged. #File touched - scribus/pageitem_textframe.cpp automatic-line-spacing-effective-font-v1.0.patch (6,177 bytes)
Index: scribus/pageitem_textframe.cpp
===================================================================
--- scribus/pageitem_textframe.cpp (revision 27785)
+++ scribus/pageitem_textframe.cpp (working copy)
@@ -1071,19 +1071,31 @@
return res;
}
-//cezaryece: I remove static statement as this function is used also by PageItem_NoteFrame
-double calculateLineSpacing (const ParagraphStyle &style, PageItem *item)
+static int findParagraphStart(const StoryText& story, int pos)
+{
+ while (pos > 0 && !story.isBlockStart(pos))
+ --pos;
+ return pos;
+}
+
+static double calculateLineSpacing(const ParagraphStyle& style, const CharStyle& charStyle, PageItem* item)
{
if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing)
{
- double autoLS = static_cast<double>(item->doc()->typographicPrefs().autoLineSpacing) / 100.0;
- return (style.charStyle().font().height(style.charStyle().fontSize() / 10.0) * autoLS);
+ const double autoLS = static_cast<double>(item->doc()->typographicPrefs().autoLineSpacing) / 100.0;
+ return charStyle.font().height(charStyle.fontSize() / 10.0) * autoLS;
}
if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
return item->doc()->guidesPrefs().valueBaselineGrid;
return style.lineSpacing();
}
+//cezaryece: I remove static statement as this function is used also by PageItem_NoteFrame
+double calculateLineSpacing (const ParagraphStyle &style, PageItem *item)
+{
+ return calculateLineSpacing(style, style.charStyle(), item);
+}
+
// This assumes that layout() ran on the previous page and set the incomplete* vars
// It also clears the incomplete* vars, and changes the starting position for this frame
@@ -1346,21 +1358,23 @@
lastLineY = m_textDistanceMargins.top();
- //automatic line spacing factor (calculated once)
- double autoLS = static_cast<double>(context->typographicPrefs().autoLineSpacing) / 100.0;
+ int paragraphStart = 0;
+ CharStyle paragraphCharStyle = itemText.defaultStyle().charStyle();
// find start of first line
if (firstInFrame() < itLen)
{
const CharStyle& cstyle = itemText.charStyle(firstInFrame());
+ paragraphStart = findParagraphStart(itemText, firstInFrame());
+ paragraphCharStyle = itemText.charStyle(paragraphStart);
style = itemText.paragraphStyle(firstInFrame());
- style.setLineSpacing (calculateLineSpacing (style, this));
+ style.setLineSpacing(calculateLineSpacing(style, paragraphCharStyle, this));
// qDebug() << QString("style @0: %1 -- %2, %4/%5 char: %3").arg(style.leftMargin()).arg(style.rightMargin())
// .arg(style.charStyle().asString()).arg(style.name()).arg(style.parent()?style.parent()->name():"");
if (style.hasDropCap())
{
- chs = calculateLineSpacing (style, this) * style.dropCapLines() * 10;
+ chs = style.lineSpacing() * style.dropCapLines() * 10;
}
else
chs = cstyle.fontSize();
@@ -1432,7 +1446,8 @@
}
BulNumMode = false;
- if (itemText.isBlockStart(a))
+ const bool isParagraphStart = itemText.isBlockStart(a);
+ if (isParagraphStart)
{
if (currentIndex > 0)
{
@@ -1464,12 +1479,17 @@
}
//--<#13490
CharStyle charStyle = ((itemText.text(a) != SpecialChars::PARSEP) ? itemText.charStyle(a) : style.charStyle());
+ if (isParagraphStart)
+ {
+ paragraphStart = a;
+ paragraphCharStyle = charStyle;
+ style.setLineSpacing(calculateLineSpacing(style, paragraphCharStyle, this));
+ }
double hlcsize10 = charStyle.fontSize() / 10.0;
double scaleV = charStyle.scaleV() / 1000.0;
double scaleH = charStyle.scaleH() / 1000.0;
double offset = hlcsize10 * (charStyle.baselineOffset() / 1000.0);
- style.setLineSpacing (calculateLineSpacing (style, this));
FlopBaseline = (current.startOfCol && firstLineOffset() == FLOPBaselineGrid);
// find out about par gap and dropcap
@@ -1557,7 +1577,7 @@
// find charsize factors
if (DropCmode)
{
- DropCapDrop = calculateLineSpacing (style, this) * (DropLines - 1);
+ DropCapDrop = style.lineSpacing() * (DropLines - 1);
//text height, width, ascent and descent should be calculated for whole text provided by ScText in current position
//and that may be more than one char (variable text for example)
@@ -1636,7 +1656,7 @@
itemHeight = font.height(style.charStyle().fontSize() / 10.0);
asce = currentObjectBox.height();
wide = currentObjectBox.width();
- realAsce = calculateLineSpacing (style, this) * DropLines;
+ realAsce = style.lineSpacing() * DropLines;
glyphCluster.setScaleH(glyphCluster.scaleH() / glyphCluster.scaleV());
glyphCluster.setScaleV(realAsce / itemHeight);
glyphCluster.setScaleH(glyphCluster.scaleH() * glyphCluster.scaleV());
@@ -2511,7 +2531,7 @@
current.dropCapWidth += overhang + leftBleed; // follow-line reserve matches
}
}
- double spacing = calculateLineSpacing (style, this);
+ double spacing = style.lineSpacing();
current.yPos -= spacing * (DropLines - 1);
if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
current.yPos = adjustToBaselineGrid (current, this, OwnPage);
@@ -2615,12 +2635,14 @@
a = glyphClusters.at(i).firstChar();
currentIndex = i - current.lineData.firstCluster;
style = itemText.paragraphStyle(a);
- const_cast<ScFace&>(font) = itemText.charStyle(a).font();
- if (style.lineSpacingMode() == ParagraphStyle::AutomaticLineSpacing)
- style.setLineSpacing(font.height(hlcsize10) * autoLS);
- else if (style.lineSpacingMode() == ParagraphStyle::BaselineGridLineSpacing)
- style.setLineSpacing(m_Doc->guidesPrefs().valueBaselineGrid);
charStyle = itemText.charStyle(a);
+ const_cast<ScFace&>(font) = charStyle.font();
+ if (a < paragraphStart || itemText.isBlockStart(a))
+ {
+ paragraphStart = findParagraphStart(itemText, a);
+ paragraphCharStyle = itemText.charStyle(paragraphStart);
+ }
+ style.setLineSpacing(calculateLineSpacing(style, paragraphCharStyle, this));
}
assert( i >= 0 );
assert( i < glyphClusters.length() );
|
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2017-07-15 10:29 | longli | New Issue | |
| 2017-07-15 10:29 | longli | File Added: Automatic Linespacing.sla | |
| 2025-04-27 19:16 | cbradney | Category | Story Editor / Text Frames => Text Frames / Story Editor |
| 2026-08-27 11:21 | qirat | Note Added: 0054341 | |
| 2026-08-27 11:21 | qirat | File Added: automatic-line-spacing-effective-font-v1.0.patch | |
| 2026-08-27 11:21 | qirat | Tag Attached: #please_test |