Skip to content

Commit ffb4cea

Browse files
committed
Enhance DOCX to PDF conversion by suppressing borders for vertically merged cells and adjusting post-table gap calculation; exclude CJK fullwidth glyphs and thin spaces from Latin fraction.
1 parent 181002d commit ffb4cea

1 file changed

Lines changed: 34 additions & 6 deletions

File tree

src/MiniPdf/DocxToPdfConverter.cs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2993,19 +2993,40 @@ private static void RenderTable(RenderState state, DocxTable table)
29932993
var isLastCell = cellGridEnd >= colCount;
29942994
var borders = cell.Borders;
29952995

2996+
// Suppress horizontal borders inside vertically-merged cell groups:
2997+
// - vMerge continue cells: suppress top border (internal to merge)
2998+
// - Any cell whose next row continues the merge at the same column: suppress bottom border
2999+
var suppressTop = cell.IsVMergeContinue;
3000+
var suppressBottom = false;
3001+
if (cell.IsVMergeRestart || cell.IsVMergeContinue)
3002+
{
3003+
// Check if the next row has a vMerge continue at the same column
3004+
var nextRowIdx = rowIndex + 1;
3005+
if (nextRowIdx < table.Rows.Count)
3006+
{
3007+
var nci = 0;
3008+
foreach (var nc in table.Rows[nextRowIdx].Cells)
3009+
{
3010+
if (nci == bci) { suppressBottom = nc.IsVMergeContinue; break; }
3011+
nci += nc.GridSpan;
3012+
if (nci > bci) break;
3013+
}
3014+
}
3015+
}
3016+
29963017
// Resolve each border: prefer cell-level, fall back to table-level
29973018
DocxBorderEdge? topBorder, bottomBorder, leftBorder, rightBorder;
29983019
if (borders != null)
29993020
{
3000-
topBorder = borders.Top ?? (table.HasBorders ? (isFirstRow ? table.BorderTop : table.BorderInsideH) : null);
3001-
bottomBorder = borders.Bottom ?? (table.HasBorders ? (isLastRow ? table.BorderBottom : table.BorderInsideH) : null);
3021+
topBorder = suppressTop ? null : (borders.Top ?? (table.HasBorders ? (isFirstRow ? table.BorderTop : table.BorderInsideH) : null));
3022+
bottomBorder = suppressBottom ? null : (borders.Bottom ?? (table.HasBorders ? (isLastRow ? table.BorderBottom : table.BorderInsideH) : null));
30023023
leftBorder = borders.Left ?? (table.HasBorders ? (isFirstCell ? table.BorderLeft : table.BorderInsideV) : null);
30033024
rightBorder = borders.Right ?? (table.HasBorders ? (isLastCell ? table.BorderRight : table.BorderInsideV) : null);
30043025
}
30053026
else if (table.HasBorders)
30063027
{
3007-
topBorder = isFirstRow ? table.BorderTop : table.BorderInsideH;
3008-
bottomBorder = isLastRow ? table.BorderBottom : table.BorderInsideH;
3028+
topBorder = suppressTop ? null : (isFirstRow ? table.BorderTop : table.BorderInsideH);
3029+
bottomBorder = suppressBottom ? null : (isLastRow ? table.BorderBottom : table.BorderInsideH);
30093030
leftBorder = isFirstCell ? table.BorderLeft : table.BorderInsideV;
30103031
rightBorder = isLastCell ? table.BorderRight : table.BorderInsideV;
30113032
}
@@ -3074,7 +3095,11 @@ private static void RenderTable(RenderState state, DocxTable table)
30743095
// to the row bottom (rowHeight - textContentHeight + cellPaddingV).
30753096
// Image-only cells are excluded so they don't mask a tight text fit.
30763097
var naturalGap = lastRowHeight - maxTextContentH + cellPaddingV;
3077-
var postTableGap = Math.Max(2f, options.FontSize - naturalGap);
3098+
// The next paragraph draws text at the baseline (state.CurrentY) and
3099+
// the visual top extends upward by ~fontSize*0.6 (font ascent). Use
3100+
// fontSize*0.8 as the floor so the text visual top clears the table
3101+
// bottom border with a small gap (~2 pt), matching Word behaviour.
3102+
var postTableGap = Math.Max(options.FontSize * 0.8f, options.FontSize - naturalGap);
30783103
state.AdvanceY(postTableGap);
30793104
}
30803105
else
@@ -3585,7 +3610,10 @@ private static float EstimateWrapTextWidth(string text, float fontSize, bool bol
35853610
var w = GetHelveticaCharWidth(ch);
35863611
var actual = (hasCjk && ch == ' ') ? 500 : w;
35873612
totalUnits += actual;
3588-
if (!(w == 1000 && ch >= '\u2E80'))
3613+
// Exclude CJK fullwidth glyphs and auto-inserted thin spaces (\u2009)
3614+
// from the Latin fraction. Thin spaces are inter-script spacing that
3615+
// doesn't shrink under CJK font Latin-glyph reduction.
3616+
if (!(w == 1000 && ch >= '\u2E80') && ch != '\u2009')
35893617
latinUnits += actual;
35903618
}
35913619
if (latinUnits > 0 && totalUnits > 0)

0 commit comments

Comments
 (0)