David PHAM-VAN

Reorder MultiPage paint operations

... ... @@ -4,6 +4,7 @@
- Fix Align debug painting
- Fix GridView when empty
- Reorder MultiPage paint operations
## 1.4.1
... ... @@ -94,7 +95,7 @@
## 1.3.16
- Add better debugPaint on Align Widget
- Add better debug painting on Align Widget
- Fix Transform placement when Alignment and Origin are Null
- Add Transform.rotateBox constructor
- Add Wrap Widget
... ... @@ -126,7 +127,7 @@
## 1.3.10
- Deprecate the document argument in Printing.sharePdf()
- Add default value to alpha in PdfColor variants
- Add a default value to alpha in PdfColor variants
- Fix Table Widget
- Add Flexible and Spacer Widgets
... ... @@ -186,7 +187,7 @@
- Fix dart lint warnings
- Improve font bounds calculation
- Add RichText Widget
- Fix MultiPage max height
- Fix MultiPage max-height
- Add Stack Widget
- Update Readme
... ... @@ -196,13 +197,13 @@
## 1.3.0
- Add a Flutter like widget system
- Add a Flutter-like Widget system
## 1.2.0
- Change license to Apache 2.0
- Improve PdfRect
- Add support for CMYK, HSL anf HSV colors
- Add support for CMYK, HSL and HSV colors
- Implement rounded rect
## 1.1.1
... ... @@ -225,7 +226,7 @@
- Implement drawShape
- Add support for Jpeg images
- Fix numeric conversions in graphic operations
- Add unicode support for annotations and info block
- Add Unicode support for annotations and info block
- Add Flutter example
## 1.0.8
... ... @@ -258,7 +259,7 @@
## 1.0.2
- Update sdk support for 2.0.0
- Update SDK support for 2.0.0
## 1.0.1
... ...
... ... @@ -59,14 +59,19 @@ class Document {
final List<Page> _pages = <Page>[];
bool _paint = false;
void addPage(Page page) {
page.generate(this);
_pages.add(page);
}
List<int> save() {
for (Page page in _pages) {
page.postProcess(this);
if (!_paint) {
for (Page page in _pages) {
page.postProcess(this);
}
_paint = true;
}
return document.save();
}
... ...
... ... @@ -26,8 +26,27 @@ class _GridViewContext extends WidgetContext {
double childMainAxis;
@override
void apply(WidgetContext other) {
if (other is _GridViewContext) {
firstChild = other.firstChild;
lastChild = other.lastChild;
childCrossAxis = other.childCrossAxis;
childMainAxis = other.childMainAxis;
}
}
@override
WidgetContext clone() {
return _GridViewContext()
..firstChild = firstChild
..lastChild = lastChild
..childCrossAxis = childCrossAxis
..childMainAxis = childMainAxis;
}
@override
String toString() =>
'GridViewContext first:$firstChild last:$lastChild size:${childCrossAxis}x$childMainAxis';
'$runtimeType first:$firstChild last:$lastChild size:${childCrossAxis}x$childMainAxis';
}
class GridView extends MultiChildWidget implements SpanningWidget {
... ...
... ... @@ -18,14 +18,20 @@
part of widget;
class WidgetContext {}
abstract class WidgetContext {
WidgetContext clone();
void apply(WidgetContext other);
}
abstract class SpanningWidget extends Widget {
bool get canSpan => false;
/// Get unmodified mutable context object
@protected
WidgetContext saveContext();
/// Aplpy the context for next layout
@protected
void restoreContext(WidgetContext context);
}
... ... @@ -38,17 +44,37 @@ class NewPage extends Widget {
}
}
@immutable
class _MultiPageWidget {
const _MultiPageWidget({
@required this.child,
@required this.x,
@required this.y,
@required this.constraints,
@required this.widgetContext,
});
final Widget child;
final double x;
final double y;
final BoxConstraints constraints;
final WidgetContext widgetContext;
}
@immutable
class _MultiPageInstance {
const _MultiPageInstance(
{@required this.context,
@required this.constraints,
@required this.fullConstraints,
@required this.offsetStart});
_MultiPageInstance({
@required this.context,
@required this.constraints,
@required this.fullConstraints,
@required this.offsetStart,
});
final Context context;
final BoxConstraints constraints;
final BoxConstraints fullConstraints;
final double offsetStart;
final List<_MultiPageWidget> widgets = <_MultiPageWidget>[];
}
class MultiPage extends Page {
... ... @@ -168,16 +194,6 @@ class MultiPage extends Page {
return true;
}());
if (pageTheme.buildBackground != null) {
final Widget child = pageTheme.buildBackground(context);
if (child != null) {
child.layout(context, fullConstraints, parentUsesSize: false);
assert(child.box != null);
_paintChild(context, child, _margin.left, _margin.bottom,
pageFormat.height);
}
}
offsetStart = pageHeight -
(_mustRotate ? pageHeightMargin - margin.bottom : _margin.top);
offsetEnd =
... ... @@ -238,17 +254,23 @@ class MultiPage extends Page {
final SpanningWidget span = child;
child.layout(
context, constraints.copyWith(maxHeight: offsetStart - offsetEnd),
parentUsesSize: false);
final BoxConstraints localConstraints =
constraints.copyWith(maxHeight: offsetStart - offsetEnd);
child.layout(context, localConstraints, parentUsesSize: false);
assert(child.box != null);
_paintChild(context, child, _margin.left,
offsetStart - child.box.height, pageFormat.height);
widgetContext = span.saveContext();
_pages.last.widgets.add(
_MultiPageWidget(
child: child,
x: _margin.left,
y: offsetStart - child.box.height,
constraints: localConstraints,
widgetContext: widgetContext?.clone(),
),
);
// Has it finished spanning?
if (span.canSpan) {
widgetContext = span.saveContext();
} else {
if (!span.canSpan) {
sameCount = 0;
index++;
}
... ... @@ -258,8 +280,17 @@ class MultiPage extends Page {
continue;
}
_paintChild(context, child, _margin.left, offsetStart - child.box.height,
pageFormat.height);
_pages.last.widgets.add(
_MultiPageWidget(
child: child,
x: _margin.left,
y: offsetStart - child.box.height,
constraints: constraints,
widgetContext:
child is SpanningWidget ? child.saveContext().clone() : null,
),
);
offsetStart -= child.box.height;
sameCount = 0;
index++;
... ... @@ -271,6 +302,29 @@ class MultiPage extends Page {
final EdgeInsets _margin = margin;
for (_MultiPageInstance page in _pages) {
if (pageTheme.buildBackground != null) {
final Widget child = pageTheme.buildBackground(page.context);
if (child != null) {
child.layout(page.context, page.fullConstraints,
parentUsesSize: false);
assert(child.box != null);
_paintChild(page.context, child, _margin.left, _margin.bottom,
pageFormat.height);
}
}
for (_MultiPageWidget widget in page.widgets) {
final Widget child = widget.child;
if (child is SpanningWidget) {
final WidgetContext context = child.saveContext();
context.apply(widget.widgetContext);
}
child.layout(page.context, widget.constraints, parentUsesSize: false);
assert(child.box != null);
_paintChild(
page.context, widget.child, widget.x, widget.y, pageFormat.height);
}
if (header != null) {
final Widget headerWidget = header(page.context);
if (headerWidget != null) {
... ...
... ... @@ -84,6 +84,24 @@ class TableBorder extends BoxBorder {
class _TableContext extends WidgetContext {
int firstLine = 0;
int lastLine = 0;
@override
void apply(WidgetContext other) {
if (other is _TableContext) {
firstLine = other.firstLine;
lastLine = other.lastLine;
}
}
@override
WidgetContext clone() {
return _TableContext()
..firstLine = firstLine
..lastLine = lastLine;
}
@override
String toString() => '$runtimeType firstLine: $firstLine lastLine: $lastLine';
}
class _ColumnLayout {
... ... @@ -215,7 +233,7 @@ class Table extends Widget implements SpanningWidget {
final List<double> _widths = <double>[];
final List<double> _heights = <double>[];
_TableContext _context = _TableContext();
final _TableContext _context = _TableContext();
final TableColumnWidth defaultColumnWidth;
final Map<int, TableColumnWidth> columnWidths;
... ... @@ -227,7 +245,7 @@ class Table extends Widget implements SpanningWidget {
@override
void restoreContext(WidgetContext context) {
_context = context;
_context.apply(context);
_context.firstLine = _context.lastLine;
}
... ...
... ... @@ -44,7 +44,22 @@ class _WrapContext extends WidgetContext {
int lastChild = 0;
@override
String toString() => 'WrapContext first:$firstChild last:$lastChild';
void apply(WidgetContext other) {
if (other is _WrapContext) {
firstChild = other.firstChild;
lastChild = other.lastChild;
}
}
@override
WidgetContext clone() {
return _WrapContext()
..firstChild = firstChild
..lastChild = lastChild;
}
@override
String toString() => '$runtimeType first:$firstChild last:$lastChild';
}
/// A widget that displays its children in multiple horizontal or vertical runs.
... ...
... ... @@ -18,15 +18,19 @@
import 'dart:io';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart';
import 'package:test/test.dart';
Document pdf;
PageTheme pageTheme;
void main() {
test('Pdf Widgets Watermark', () {
setUpAll(() {
Document.debug = true;
final Document pdf = Document();
pdf = Document();
final PageTheme pageTheme = PageTheme(
pageTheme = PageTheme(
buildBackground: (Context context) => FullPage(
ignoreMargins: true,
child: Watermark.text('DRAFT'),
... ... @@ -40,7 +44,9 @@ void main() {
),
),
);
});
test('Pdf Widgets Watermark Page', () {
pdf.addPage(
Page(
pageTheme: pageTheme,
... ... @@ -51,7 +57,9 @@ void main() {
),
),
);
});
test('Pdf Widgets Watermark MultiPage', () {
pdf.addPage(
MultiPage(
pageTheme: pageTheme,
... ... @@ -63,7 +71,38 @@ void main() {
),
),
);
});
test('Pdf Widgets Watermark Page Count', () async {
final PageTheme pageTheme = PageTheme(
buildBackground: (Context context) =>
(context.pageNumber == context.pagesCount)
? Align(
alignment: Alignment.topRight,
child: SizedBox(
width: 200,
height: 200,
child: PdfLogo(color: PdfColors.blue200)),
)
: Container(),
);
pdf.addPage(
MultiPage(
pageTheme: pageTheme,
build: (Context context) => <Widget>[
Wrap(
children: List<Widget>.generate(
670,
(_) => Text('Hello World '),
),
),
],
),
);
});
tearDownAll(() {
final File file = File('widgets-watermark.pdf');
file.writeAsBytesSync(pdf.save());
});
... ...
No preview for this file type
widgets-monopage.pdf
\ No newline at end of file
... ...
No preview for this file type
widgets-multipage.pdf
\ No newline at end of file
... ...