diff --git a/QuestPDF.Examples/TextExamples.cs b/QuestPDF.Examples/TextExamples.cs
index 861079c..1566c3e 100644
--- a/QuestPDF.Examples/TextExamples.cs
+++ b/QuestPDF.Examples/TextExamples.cs
@@ -604,7 +604,7 @@ namespace QuestPDF.Examples
{
RenderingTest
.Create()
- .PageSize(500, 100)
+ .PageSize(250, 100)
.ProduceImages()
.ShowResults()
@@ -614,9 +614,9 @@ namespace QuestPDF.Examples
.Padding(25)
.MinimalBox()
.Background(Colors.Grey.Lighten2)
- .Text("ينا الألم. في بعض الأحيان ونظراً للالتزامات التي يفرضها علينا")
+ .Text("خوارزمية ترتيب")
.FontFamily(Fonts.Calibri)
- .FontSize(20);
+ .FontSize(30);
});
}
@@ -663,14 +663,12 @@ namespace QuestPDF.Examples
{
RenderingTest
.Create()
- .PageSize(PageSizes.A4)
+ .PageSize(new PageSize(1000, 500))
.ProducePdf()
.ShowResults()
.Render(container =>
{
- var text = "بسم الله الرحمن الرحيم" +
- "\n" +
- "الحمد لله رب العالمين (1) مالك يوم الدين";
+ var text = "في المعلوماتية أو الرياضيات، خوارزمية الترتيب هي خوارزمية تمكن من تنظيم مجموعة عناصر حسب ترتيب محدد.";
container
.Padding(25)
@@ -679,7 +677,7 @@ namespace QuestPDF.Examples
{
column.Spacing(20);
- foreach (var size in new[] { 14, 12, 11, 10, 8, 7 })
+ foreach (var size in new[] { 36, 34, 32, 30, 15 })
{
column
.Item()
@@ -690,7 +688,7 @@ namespace QuestPDF.Examples
.Background(Colors.Grey.Lighten2)
.Text(text)
.FontSize(20)
- .FontFamily("Segoe UI").DirectionFromRightToLeft();
+ .FontFamily("Segoe UI");
}
});
});
diff --git a/QuestPDF/Drawing/TextShaper.cs b/QuestPDF/Drawing/TextShaper.cs
index 46a1e91..a5e6f9e 100644
--- a/QuestPDF/Drawing/TextShaper.cs
+++ b/QuestPDF/Drawing/TextShaper.cs
@@ -62,7 +62,7 @@ namespace QuestPDF.Drawing
yOffset += glyphPositions[i].YAdvance * scaleY;
}
- return new TextShapingResult(glyphs);
+ return new TextShapingResult(buffer.Direction, glyphs);
}
void PopulateBufferWithText(Buffer buffer, string text)
@@ -98,29 +98,65 @@ namespace QuestPDF.Drawing
internal class TextShapingResult
{
- public ShapedGlyph[] Glyphs { get; }
+ private Direction Direction { get; }
+ private ShapedGlyph[] Glyphs { get; }
- public TextShapingResult(ShapedGlyph[] glyphs)
+ public int Length => Glyphs.Length;
+
+ public ShapedGlyph this[int index] =>
+ Direction == Direction.LeftToRight
+ ? Glyphs[index]
+ : Glyphs[Glyphs.Length - 1 - index];
+
+ public TextShapingResult(Direction direction, ShapedGlyph[] glyphs)
{
+ Direction = direction;
Glyphs = glyphs;
}
public int BreakText(int startIndex, float maxWidth)
{
- var index = startIndex;
- maxWidth += Glyphs[startIndex].Position.X;
-
- while (index < Glyphs.Length)
+ return Direction switch
{
- var glyph = Glyphs[index];
-
- if (glyph.Position.X + glyph.Width > maxWidth + Size.Epsilon)
- break;
-
- index++;
- }
+ Direction.LeftToRight => BreakTextLeftToRight(),
+ Direction.RightToLeft => BreakTextRightToLeft(),
+ _ => throw new ArgumentOutOfRangeException()
+ };
- return index - 1;
+ int BreakTextLeftToRight()
+ {
+ var index = startIndex;
+ maxWidth += Glyphs[startIndex].Position.X;
+
+ while (index < Glyphs.Length)
+ {
+ var glyph = Glyphs[index];
+
+ if (glyph.Position.X + glyph.Width > maxWidth + Size.Epsilon)
+ break;
+
+ index++;
+ }
+
+ return index - 1;
+ }
+
+ int BreakTextRightToLeft()
+ {
+ var index = startIndex;
+
+ var startOffset = this[startIndex].Position.X + this[startIndex].Width;
+
+ while (index < Glyphs.Length)
+ {
+ if (startOffset - this[index].Position.X > maxWidth + Size.Epsilon)
+ break;
+
+ index++;
+ }
+
+ return index - 1;
+ }
}
public float MeasureWidth(int startIndex, int endIndex)
@@ -128,10 +164,15 @@ namespace QuestPDF.Drawing
if (Glyphs.Length == 0)
return 0;
- var start = Glyphs[startIndex];
- var end = Glyphs[endIndex];
+ var start = this[startIndex];
+ var end = this[endIndex];
- return end.Position.X - start.Position.X + end.Width;
+ return Direction switch
+ {
+ Direction.LeftToRight => end.Position.X - start.Position.X + end.Width,
+ Direction.RightToLeft => start.Position.X - end.Position.X + start.Width,
+ _ => throw new NotSupportedException()
+ };
}
public DrawTextCommand? PositionText(int startIndex, int endIndex, TextStyle textStyle)
@@ -152,14 +193,18 @@ namespace QuestPDF.Drawing
{
var runIndex = sourceIndex - startIndex;
- glyphSpan[runIndex] = Glyphs[sourceIndex].Codepoint;
- positionSpan[runIndex] = Glyphs[sourceIndex].Position;
+ glyphSpan[runIndex] = this[sourceIndex].Codepoint;
+ positionSpan[runIndex] = this[sourceIndex].Position;
}
+
+ var firstVisualCharacterIndex = Direction == Direction.LeftToRight
+ ? startIndex
+ : endIndex;
return new DrawTextCommand
{
SkTextBlob = skTextBlobBuilder.Build(),
- TextOffsetX = -Glyphs[startIndex].Position.X
+ TextOffsetX = -this[firstVisualCharacterIndex].Position.X
};
}
}
diff --git a/QuestPDF/Elements/Text/Items/TextBlockSpan.cs b/QuestPDF/Elements/Text/Items/TextBlockSpan.cs
index 4dfad0f..677fcc0 100644
--- a/QuestPDF/Elements/Text/Items/TextBlockSpan.cs
+++ b/QuestPDF/Elements/Text/Items/TextBlockSpan.cs
@@ -47,11 +47,11 @@ namespace QuestPDF.Elements.Text.Items
// ignore leading spaces
if (!request.IsFirstElementInBlock && request.IsFirstElementInLine)
{
- while (startIndex < TextShapingResult.Glyphs.Length && Text[startIndex] == spaceCodepoint)
+ while (startIndex < TextShapingResult.Length && Text[startIndex] == spaceCodepoint)
startIndex++;
}
- if (TextShapingResult.Glyphs.Length == 0 || startIndex == TextShapingResult.Glyphs.Length)
+ if (TextShapingResult.Length == 0 || startIndex == TextShapingResult.Length)
{
return new TextMeasurementResult
{
@@ -90,7 +90,7 @@ namespace QuestPDF.Elements.Text.Items
StartIndex = startIndex,
EndIndex = wrappedText.Value.endIndex,
NextIndex = wrappedText.Value.nextIndex,
- TotalIndex = TextShapingResult.Glyphs.Length - 1
+ TotalIndex = TextShapingResult.Length - 1
};
}
@@ -102,7 +102,7 @@ namespace QuestPDF.Elements.Text.Items
// textLength - length of the part of the text that fits in available width (creating a line)
// entire text fits, no need to wrap
- if (endIndex == TextShapingResult.Glyphs.Length - 1)
+ if (endIndex == TextShapingResult.Length - 1)
return (endIndex, endIndex);
// breaking anywhere
@@ -110,7 +110,7 @@ namespace QuestPDF.Elements.Text.Items
return (endIndex, endIndex + 1);
// current line ends at word, next character is space, perfect place to wrap
- if (TextShapingResult.Glyphs[endIndex].Codepoint != spaceCodepoint && TextShapingResult.Glyphs[endIndex + 1].Codepoint == spaceCodepoint)
+ if (TextShapingResult[endIndex].Codepoint != spaceCodepoint && TextShapingResult[endIndex + 1].Codepoint == spaceCodepoint)
return (endIndex, endIndex + 2);
// find last space within the available text to wrap
@@ -118,7 +118,7 @@ namespace QuestPDF.Elements.Text.Items
while (lastSpaceIndex >= startIndex)
{
- if (TextShapingResult.Glyphs[lastSpaceIndex].Codepoint == spaceCodepoint)
+ if (TextShapingResult[lastSpaceIndex].Codepoint == spaceCodepoint)
break;
lastSpaceIndex--;
diff --git a/QuestPDF/QuestPDF.csproj b/QuestPDF/QuestPDF.csproj
index c581f5e..259f636 100644
--- a/QuestPDF/QuestPDF.csproj
+++ b/QuestPDF/QuestPDF.csproj
@@ -7,7 +7,7 @@
QuestPDF is an open-source, modern and battle-tested library that can help you with generating PDF documents by offering friendly, discoverable and predictable C# fluent API.
$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/Resources/ReleaseNotes.txt"))
9
- true
+ false
Logo.png
https://www.questpdf.com/images/package-logo.png
https://www.questpdf.com/