generate method
void
generate(
- Document document, {
- bool insert = true,
- int? index,
})
override
Implementation
@override
void generate(Document document, {bool insert = true, int? index}) {
assert(pageFormat.width > 0 && pageFormat.width < double.infinity);
assert(pageFormat.height > 0 && pageFormat.height < double.infinity);
final _margin = resolvedMargin!;
final _mustRotate = mustRotate;
final pageHeight = _mustRotate ? pageFormat.width : pageFormat.height;
final pageHeightMargin =
_mustRotate ? _margin.horizontal : _margin.vertical;
final constraints = BoxConstraints(
maxWidth: _mustRotate
? (pageFormat.height - _margin.vertical)
: (pageFormat.width - _margin.horizontal));
final fullConstraints = mustRotate
? BoxConstraints(
maxWidth: pageFormat.height - _margin.vertical,
maxHeight: pageFormat.width - _margin.horizontal)
: BoxConstraints(
maxWidth: pageFormat.width - _margin.horizontal,
maxHeight: pageFormat.height - _margin.vertical);
final calculatedTheme = theme ?? document.theme ?? ThemeData.base();
Context? context;
var offsetEnd = 0.0;
double? offsetStart;
var _index = 0;
var sameCount = 0;
final baseContext =
Context(document: document.document).inheritFromAll(<Inherited>[
calculatedTheme,
if (pageTheme.textDirection != null)
InheritedDirectionality(pageTheme.textDirection),
]);
final children = _buildList(baseContext);
WidgetContext? widgetContext;
while (_index < children.length) {
final child = children[_index];
// Detect too big widgets
if (sameCount++ > maxPages) {
throw TooManyPagesException(
'This widget created more than $maxPages pages. This may be an issue in the widget or the document. See https://pub.dev/documentation/pdf/latest/widgets/MultiPage-class.html');
}
// Calculate available space of the current page
final freeSpace = (offsetStart == null)
? fullConstraints.maxHeight
: offsetStart - offsetEnd;
// Create a new page if we don't already have one
if (context == null ||
(child is NewPage) && child.newPageNeeded(freeSpace)) {
final pdfPage = PdfPage(
document.document,
pageFormat: pageFormat,
index: index == null ? null : (index++),
);
final canvas = pdfPage.getGraphics();
canvas.reset();
context = baseContext.copyWith(page: pdfPage, canvas: canvas);
assert(() {
if (Document.debug) {
debugPaint(context!);
}
return true;
}());
offsetStart = pageHeight -
(_mustRotate ? pageHeightMargin - _margin.bottom : _margin.top);
offsetEnd =
_mustRotate ? pageHeightMargin - _margin.left : _margin.bottom;
_pages.add(_MultiPageInstance(
context: context,
constraints: constraints,
fullConstraints: fullConstraints,
offsetStart: offsetStart,
));
if (header != null) {
final headerWidget = header!(context);
headerWidget.layout(context, constraints, parentUsesSize: false);
assert(headerWidget.box != null);
offsetStart -= headerWidget.box!.height;
}
if (footer != null) {
final footerWidget = footer!(context);
footerWidget.layout(context, constraints, parentUsesSize: false);
assert(footerWidget.box != null);
offsetEnd += footerWidget.box!.height;
}
}
// If we are processing a multi-page widget, we restore its context
WidgetContext? savedContext;
if (child is SpanningWidget && child.canSpan) {
if (widgetContext != null) {
child.restoreContext(widgetContext);
widgetContext = null;
}
savedContext = child.cloneContext();
}
child.layout(context, constraints, parentUsesSize: false);
assert(child.box != null);
final canSpan = child is SpanningWidget && child.canSpan;
// What to do if the widget is too big for the page?
if (offsetStart! - child.box!.height < offsetEnd) {
// If it is not a multi-page widget and its height
// is smaller than a full new page, we schedule a new page creation
if (child.box!.height <= pageHeight - pageHeightMargin && !canSpan) {
context = null;
continue;
}
// Else we crash if the widget is too big and cannot be separated
if (!canSpan) {
throw Exception(
'Widget won\'t fit into the page as its height (${child.box!.height}) '
'exceed a page height (${pageHeight - pageHeightMargin}). '
'You probably need a SpanningWidget or use a single page layout');
}
final span = child;
if (savedContext != null) {
// Restore saved context
span.applyContext(savedContext);
}
final localConstraints =
constraints.copyWith(maxHeight: offsetStart - offsetEnd);
span.layout(context, localConstraints, parentUsesSize: false);
assert(span.box != null);
widgetContext = span.saveContext();
_pages.last.widgets.add(
_MultiPageWidget(
child: span,
constraints: localConstraints,
widgetContext: widgetContext.clone(),
),
);
// Has it finished spanning?
if (!span.hasMoreWidgets) {
sameCount = 0;
_index++;
}
// Schedule a new page
context = null;
continue;
}
_pages.last.widgets.add(
_MultiPageWidget(
child: child,
constraints: constraints,
widgetContext:
child is SpanningWidget && canSpan ? child.cloneContext() : null,
),
);
offsetStart -= child.box!.height;
sameCount = 0;
_index++;
}
}