diff --git a/pdf/lib/src/widgets/multi_page.dart b/pdf/lib/src/widgets/multi_page.dart index aafee958..298b2cec 100644 --- a/pdf/lib/src/widgets/multi_page.dart +++ b/pdf/lib/src/widgets/multi_page.dart @@ -188,28 +188,18 @@ class MultiPage extends Page { final _margin = resolvedMargin!; context.canvas ..saveContext() - ..setTransform(Matrix4.identity() - ..rotateZ(-math.pi / 2) - ..translate( - x - pageHeight + _margin.top - _margin.left, - y + _margin.left - _margin.bottom, - )); - - final availableWidth = pageHeight - resolvedMargin!.vertical; - if (pageTheme.textDirection == TextDirection.rtl) { - child.box = child.box!.copyWith( - x: (availableWidth - child.box!.width) + child.box!.x, + ..setTransform( + Matrix4.identity() + ..rotateZ(-math.pi / 2) + ..translate( + x - pageHeight + _margin.top - _margin.left, + y + _margin.left - _margin.bottom, + ), ); - } child.paint(context); context.canvas.restoreContext(); } else { - var childXPos = x; - if (pageTheme.textDirection == TextDirection.rtl) { - final availableWidth = pageFormat.width - resolvedMargin!.horizontal; - childXPos = (availableWidth - child.box!.width) + x; - } - child.box = child.box!.copyWith(x: childXPos, y: y); + child.box = child.box!.copyWith(x: x, y: y); child.paint(context); } } @@ -384,7 +374,7 @@ class MultiPage extends Page { final pageHeightMargin = _mustRotate ? _margin.horizontal : _margin.vertical; final pageWidthMargin = _mustRotate ? _margin.vertical : _margin.horizontal; final availableWidth = pageWidth - pageWidthMargin; - + final isRTL = pageTheme.textDirection == TextDirection.rtl; for (final page in _pages) { var offsetStart = pageHeight - (_mustRotate ? pageHeightMargin - _margin.bottom : _margin.top); var offsetEnd = _mustRotate ? pageHeightMargin - _margin.left : _margin.bottom; @@ -394,7 +384,8 @@ class MultiPage extends Page { child.layout(page.context, page.fullConstraints, parentUsesSize: false); assert(child.box != null); - _paintChild(page.context, child, _margin.left, _margin.bottom, pageFormat.height); + final xPos = isRTL ? _margin.left + (availableWidth - child.box!.width) : _margin.left; + _paintChild(page.context, child, xPos, _margin.bottom, pageFormat.height); } var totalFlex = 0; @@ -419,21 +410,20 @@ class MultiPage extends Page { if (header != null) { final headerWidget = header!(page.context); - headerWidget.layout(page.context, page.constraints, parentUsesSize: false); assert(headerWidget.box != null); offsetStart -= headerWidget.box!.height; - _paintChild( - page.context, headerWidget, _margin.left, page.offsetStart! - headerWidget.box!.height, pageFormat.height); + final xPos = isRTL ? _margin.left + (availableWidth - headerWidget.box!.width) : _margin.left; + _paintChild(page.context, headerWidget, xPos, page.offsetStart! - headerWidget.box!.height, pageFormat.height); } if (footer != null) { final footerWidget = footer!(page.context); - footerWidget.layout(page.context, page.constraints, parentUsesSize: false); assert(footerWidget.box != null); + final xPos = isRTL ? _margin.left + (availableWidth - footerWidget.box!.width) : _margin.left; offsetEnd += footerWidget.box!.height; - _paintChild(page.context, footerWidget, _margin.left, _margin.bottom, pageFormat.height); + _paintChild(page.context, footerWidget, xPos, _margin.bottom, pageFormat.height); } final freeSpace = math.max(0.0, offsetStart - offsetEnd - allocatedSize); @@ -508,24 +498,29 @@ class MultiPage extends Page { allocatedFlexSpace += maxChildExtent; } } - var pos = offsetStart - leadingSpace; for (final widget in page.widgets) { pos -= widget.child.box!.height; late double x; switch (crossAxisAlignment) { + case CrossAxisAlignment.stretch: case CrossAxisAlignment.start: - x = 0; + if (isRTL) { + x = availableWidth - widget.child.box!.width; + } else { + x = 0; + } break; case CrossAxisAlignment.end: - x = availableWidth - widget.child.box!.width; + if (isRTL) { + x = 0; + } else { + x = availableWidth - widget.child.box!.width; + } break; case CrossAxisAlignment.center: x = availableWidth / 2 - widget.child.box!.width / 2; break; - case CrossAxisAlignment.stretch: - x = 0; - break; } final child = widget.child; if (child is SpanningWidget && child.canSpan) { @@ -540,7 +535,8 @@ class MultiPage extends Page { child.layout(page.context, page.fullConstraints, parentUsesSize: false); assert(child.box != null); - _paintChild(page.context, child, _margin.left, _margin.bottom, pageFormat.height); + final xPos = isRTL ? _margin.left + (availableWidth - child.box!.width) : _margin.left; + _paintChild(page.context, child, xPos, _margin.bottom, pageFormat.height); } } } diff --git a/pdf/lib/src/widgets/text.dart b/pdf/lib/src/widgets/text.dart index 9b3962d6..e7792d65 100644 --- a/pdf/lib/src/widgets/text.dart +++ b/pdf/lib/src/widgets/text.dart @@ -566,7 +566,7 @@ class _Line { delta = isRTL ? wordsWidth : 0; break; case TextAlign.right: - delta = totalWidth - wordsWidth; + delta = isRTL ? totalWidth: totalWidth - wordsWidth; break; case TextAlign.start: delta = isRTL ? totalWidth : 0; @@ -576,6 +576,9 @@ class _Line { break; case TextAlign.center: delta = (totalWidth - wordsWidth) / 2.0; + if(isRTL) { + delta += wordsWidth; + } break; case TextAlign.justify: delta = isRTL ? totalWidth : 0; diff --git a/pdf/test/rtl_layout_test.dart b/pdf/test/rtl_layout_test.dart index 570b4561..336547f7 100644 --- a/pdf/test/rtl_layout_test.dart +++ b/pdf/test/rtl_layout_test.dart @@ -15,7 +15,6 @@ */ import 'dart:io'; -import 'dart:typed_data'; import 'package:pdf/pdf.dart'; import 'package:pdf/widgets.dart'; @@ -42,16 +41,38 @@ final _yellowBox = Container( ); void main() { - late final arabicFont; setUpAll(() { Document.debug = true; pdf = Document(); - final fontData = File('test/fonts/cairo.ttf').readAsBytesSync(); - // final fontData = File('test/fonts/hacen_tunisia.ttf').readAsBytesSync(); - arabicFont = Font.ttf(fontData.buffer.asByteData()); }); - test('Should render Text aligned right', () { + test('Should render a blue box followed by a red box ordered RTL aligned right', () { + pdf.addPage( + Page( + textDirection: TextDirection.rtl, + pageFormat: const PdfPageFormat(150, 50), + build: (Context context) => TestAnnotation( + anno: 'RTL Row', + child: Row( + children: [_blueBox, _redBox], + ), + ), + ), + ); + }); + + test('RTL Text', () { + pdf.addPage( + Page( + textDirection: TextDirection.rtl, + pageFormat: const PdfPageFormat(150, 50), + build: (Context context) => Text( + 'RTL Text', + ), + ), + ); + }); + test('RTL Text TextAlign.end', () { pdf.addPage( Page( textDirection: TextDirection.rtl, @@ -59,23 +80,67 @@ void main() { build: (Context context) => SizedBox( width: 150, child: Text( - 'مرحبا بالعالم', - style: TextStyle(font: arabicFont), + 'RTL Text : TextAlign.end', + textAlign: TextAlign.end, ), ), ), ); }); - test('Should render a blue box followed by a red box ordered RTL aligned right', () { + test('RTL Text TextAlign.left', () { pdf.addPage( Page( textDirection: TextDirection.rtl, pageFormat: const PdfPageFormat(150, 50), - build: (Context context) => TestAnnotation( - anno: 'RTL Row', - child: Row( - children: [_blueBox, _redBox], + build: (Context context) => SizedBox( + width: 150, + child: Text( + 'RTL Text : TextAlign.left', + textAlign: TextAlign.left, + ), + ), + ), + ); + }); + + test('LTR Text', () { + pdf.addPage( + Page( + textDirection: TextDirection.ltr, + pageFormat: const PdfPageFormat(150, 50), + build: (Context context) => Text( + 'LTR Text', + ), + ), + ); + }); + test('LTR Text TextAlign.end', () { + pdf.addPage( + Page( + textDirection: TextDirection.ltr, + pageFormat: const PdfPageFormat(150, 50), + build: (Context context) => SizedBox( + width: 150, + child: Text( + 'RTL Text : TextAlign.end', + textAlign: TextAlign.end, + ), + ), + ), + ); + }); + + test('LTR Text TextAlign.right', () { + pdf.addPage( + Page( + textDirection: TextDirection.ltr, + pageFormat: const PdfPageFormat(150, 50), + build: (Context context) => SizedBox( + width: 150, + child: Text( + 'LTR Text : TextAlign.right', + textAlign: TextAlign.right, ), ), ), @@ -286,10 +351,12 @@ void main() { pageFormat: const PdfPageFormat(150, 150), build: (Context context) { return [ - ListView(children: [ - Text('RTL MultiPage'), - for (int i = 0; i < 15; i++) Text('List item'), - ]), + Text('RTL MultiPage', style: const TextStyle(fontSize: 9)), + ListView( + children: [ + for (int i = 0; i < 15; i++) Text('List item'), + ], + ), ]; }, ), @@ -303,7 +370,7 @@ void main() { pageFormat: const PdfPageFormat(150, 150), build: (Context context) { return [ - Text('LTR MultiPage'), + Text('LTR MultiPage', style: const TextStyle(fontSize: 9)), ListView(children: [ for (int i = 0; i < 15; i++) Text('List item'), ]), @@ -444,7 +511,7 @@ void main() { return TestAnnotation( anno: 'LTR RadiusDirectional.horizontal end', child: Container( - margin: const EdgeInsets.only(top: 22), + margin: const EdgeInsets.only(top: 11), decoration: const BoxDecoration( color: PdfColors.blue, borderRadius: BorderRadiusDirectional.horizontal( @@ -609,6 +676,7 @@ class TestAnnotation extends StatelessWidget { child: Text( anno, style: const TextStyle(color: PdfColors.black, fontSize: 9), + textDirection: TextDirection.ltr, textAlign: TextAlign.center, ), ),