Fixed text rendering issues
This commit is contained in:
Родитель
fdf8e3eb1a
Коммит
5402e5fedc
|
@ -23,7 +23,7 @@ namespace QuestPDF.Examples
|
|||
.PageSize(PageSizes.A4)
|
||||
.ProducePdf()
|
||||
.ShowResults()
|
||||
.Render(x => ComposeBook(x, chapters));
|
||||
.RenderDocument(x => ComposeBook(x, chapters));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -42,8 +42,8 @@ namespace QuestPDF.Examples
|
|||
RenderingTest
|
||||
.Create()
|
||||
.PageSize(PageSizes.A4)
|
||||
.ProducePdf()
|
||||
.Render(x => ComposeBook(x, chapters));
|
||||
.ProducePdf()
|
||||
.RenderDocument(x => ComposeBook(x, chapters));
|
||||
}
|
||||
|
||||
IEnumerable<float> PerformTest(int attempts)
|
||||
|
@ -102,37 +102,30 @@ namespace QuestPDF.Examples
|
|||
}
|
||||
}
|
||||
|
||||
private void ComposeBook(IContainer container, ICollection<BookChapter> chapters)
|
||||
private void ComposeBook(IDocumentContainer container, ICollection<BookChapter> chapters)
|
||||
{
|
||||
var subtitleStyle = TextStyle.Default.Size(24).SemiBold().Color(Colors.Blue.Medium);
|
||||
var normalStyle = TextStyle.Default.Size(14);
|
||||
|
||||
ComposePage(container);
|
||||
|
||||
void ComposePage(IContainer container)
|
||||
container.Page(page =>
|
||||
{
|
||||
container
|
||||
.Padding(50)
|
||||
.Decoration(decoration =>
|
||||
{
|
||||
decoration
|
||||
.Content()
|
||||
.Column(column =>
|
||||
{
|
||||
column.Item().Element(Title);
|
||||
column.Item().PageBreak();
|
||||
column.Item().Element(TableOfContents);
|
||||
column.Item().PageBreak();
|
||||
page.Margin(50);
|
||||
|
||||
page.Content().Column(column =>
|
||||
{
|
||||
column.Item().Element(Title);
|
||||
column.Item().PageBreak();
|
||||
column.Item().Element(TableOfContents);
|
||||
column.Item().PageBreak();
|
||||
|
||||
Chapters(column);
|
||||
Chapters(column);
|
||||
|
||||
column.Item().Element(Acknowledgements);
|
||||
});
|
||||
column.Item().Element(Acknowledgements);
|
||||
});
|
||||
|
||||
page.Footer().Element(Footer);
|
||||
});
|
||||
|
||||
decoration.After().Element(Footer);
|
||||
});
|
||||
}
|
||||
|
||||
void Title(IContainer container)
|
||||
{
|
||||
container
|
||||
|
|
|
@ -31,7 +31,8 @@ namespace QuestPDF.Examples
|
|||
{
|
||||
text.DefaultTextStyle(TextStyle.Default.Size(20));
|
||||
text.Span("This is a normal text, followed by an ");
|
||||
text.Span("underlined red text.", TextStyle.Default.Size(20).Color(Colors.Red.Medium).Underline());
|
||||
text.Span("underlined red text", TextStyle.Default.Color(Colors.Red.Medium).Underline());
|
||||
text.Span(".");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -189,7 +190,7 @@ namespace QuestPDF.Examples
|
|||
text.EmptyLine();
|
||||
|
||||
text.Span("The new text element also supports injecting custom content between words: ");
|
||||
text.Element().PaddingBottom(-10).Height(16).Width(32).Image(Placeholders.Image);
|
||||
text.Element().PaddingBottom(-4).Height(16).Width(32).Image(Placeholders.Image);
|
||||
text.Span(".");
|
||||
|
||||
text.EmptyLine();
|
||||
|
@ -246,7 +247,7 @@ namespace QuestPDF.Examples
|
|||
text.Span("and this is slightly bigger text.", TextStyle.Default.Size(16));
|
||||
|
||||
text.Span("The new text element also supports injecting custom content between words: ");
|
||||
text.Element().PaddingBottom(-10).Height(16).Width(32).Image(Placeholders.Image);
|
||||
text.Element().PaddingBottom(-4).Height(16).Width(32).Image(Placeholders.Image);
|
||||
text.Span(".");
|
||||
|
||||
text.EmptyLine();
|
||||
|
@ -288,7 +289,57 @@ namespace QuestPDF.Examples
|
|||
|
||||
page.Content().Text(
|
||||
"This is a specially crafted sentence with a specially chosen length for demonstration of the bug that occurs ;;;;;. ",
|
||||
TextStyle.Default.Size(11));
|
||||
TextStyle.Default.Size(11).BackgroundColor(Colors.Red.Lighten3));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EmptyText()
|
||||
{
|
||||
// issue 135
|
||||
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.RenderDocument(container =>
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Margin(50);
|
||||
page.Background(Colors.White);
|
||||
|
||||
page.Size(PageSizes.A4);
|
||||
|
||||
page.Content().Text(
|
||||
" ",
|
||||
TextStyle.Default.Size(11).BackgroundColor(Colors.Red.Lighten3));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Whitespaces()
|
||||
{
|
||||
// issue 135
|
||||
|
||||
RenderingTest
|
||||
.Create()
|
||||
.ProduceImages()
|
||||
.ShowResults()
|
||||
.RenderDocument(container =>
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Margin(50);
|
||||
page.Background(Colors.White);
|
||||
|
||||
page.Size(PageSizes.A4);
|
||||
|
||||
page.Content().Text(
|
||||
" x ",
|
||||
TextStyle.Default.Size(11).BackgroundColor(Colors.Red.Lighten3));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -9,6 +9,6 @@ namespace QuestPDF.Elements.Text.Calculation
|
|||
|
||||
public int StartIndex { get; set; }
|
||||
public float AvailableWidth { get; set; }
|
||||
public bool IsFirstLineElement { get; set; }
|
||||
public bool IsFirstElementInLine { get; set; }
|
||||
}
|
||||
}
|
|
@ -17,6 +17,6 @@ namespace QuestPDF.Elements.Text.Calculation
|
|||
public int NextIndex { get; set; }
|
||||
public int TotalIndex { get; set; }
|
||||
|
||||
public bool IsLast => EndIndex == TotalIndex;
|
||||
public bool IsLast => NextIndex == EndIndex;
|
||||
}
|
||||
}
|
|
@ -33,13 +33,15 @@ namespace QuestPDF.Elements.Text.Items
|
|||
|
||||
var startIndex = request.StartIndex;
|
||||
|
||||
if (request.IsFirstLineElement)
|
||||
// if the element is the first one within the line,
|
||||
// ignore leading spaces
|
||||
if (request.IsFirstElementInLine)
|
||||
{
|
||||
while (startIndex + 1 < Text.Length && Text[startIndex] == space)
|
||||
while (startIndex < Text.Length && Text[startIndex] == space)
|
||||
startIndex++;
|
||||
}
|
||||
|
||||
if (Text.Length == 0)
|
||||
|
||||
if (Text.Length == 0 || startIndex == Text.Length)
|
||||
{
|
||||
return new TextMeasurementResult
|
||||
{
|
||||
|
@ -58,37 +60,26 @@ namespace QuestPDF.Elements.Text.Items
|
|||
|
||||
if (textLength <= 0)
|
||||
return null;
|
||||
|
||||
if (textLength < text.Length && text[textLength] == space)
|
||||
textLength++;
|
||||
|
||||
|
||||
// break text only on spaces
|
||||
if (textLength < text.Length)
|
||||
{
|
||||
var lastSpaceIndex = text.Slice(0, textLength).LastIndexOf(space) - 1;
|
||||
var wrappedTextLength = WrapText(text, textLength, request.IsFirstElementInLine);
|
||||
|
||||
if (lastSpaceIndex <= 0)
|
||||
{
|
||||
if (!request.IsFirstLineElement)
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
textLength = lastSpaceIndex + 1;
|
||||
}
|
||||
}
|
||||
if (wrappedTextLength == null)
|
||||
return null;
|
||||
|
||||
textLength = wrappedTextLength.Value;
|
||||
|
||||
text = text.Slice(0, textLength);
|
||||
|
||||
var endIndex = startIndex + textLength;
|
||||
var nextIndex = endIndex;
|
||||
|
||||
while (nextIndex + 1 < Text.Length && Text[nextIndex] == space)
|
||||
// when breaking text, omit spaces at the end of the line
|
||||
while (nextIndex < Text.Length && Text[nextIndex] == space)
|
||||
nextIndex++;
|
||||
|
||||
// measure final text
|
||||
var finalText = text.TrimEnd();
|
||||
var width = paint.MeasureText(finalText);
|
||||
var width = paint.MeasureText(text);
|
||||
|
||||
return new TextMeasurementResult
|
||||
{
|
||||
|
@ -104,6 +95,31 @@ namespace QuestPDF.Elements.Text.Items
|
|||
NextIndex = nextIndex,
|
||||
TotalIndex = Text.Length
|
||||
};
|
||||
|
||||
static int? WrapText(ReadOnlySpan<char> text, int textLength, bool isFirstElementInLine)
|
||||
{
|
||||
// textLength - length of the part of the text that fits in available width (creating a line)
|
||||
|
||||
// entire text fits, no need to wrap
|
||||
if (textLength == text.Length)
|
||||
return textLength;
|
||||
|
||||
// current line ends at word, next character is space, perfect place to wrap
|
||||
if (text[textLength - 1] != space && text[textLength] == space)
|
||||
return textLength;
|
||||
|
||||
// find last space within the available text to wrap
|
||||
var lastSpaceIndex = text.Slice(0, textLength).LastIndexOf(space);
|
||||
|
||||
// text contains space that can be used to wrap
|
||||
if (lastSpaceIndex > 0)
|
||||
return lastSpaceIndex;
|
||||
|
||||
// there is no available space to wrap text
|
||||
// if the item is first within the line, perform safe mode and chop the word
|
||||
// otherwise, move the item into the next line
|
||||
return isFirstElementInLine ? textLength : null;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Draw(TextDrawingRequest request)
|
||||
|
|
|
@ -170,7 +170,7 @@ namespace QuestPDF.Elements.Text
|
|||
|
||||
StartIndex = currentItemIndex,
|
||||
AvailableWidth = availableWidth - currentWidth,
|
||||
IsFirstLineElement = !currentLineElements.Any()
|
||||
IsFirstElementInLine = !currentLineElements.Any()
|
||||
};
|
||||
|
||||
var measurementResponse = currentElement.Measure(measurementRequest);
|
||||
|
|
Загрузка…
Ссылка в новой задаче