generate method

  1. @override
void generate(
  1. Document document, {
  2. bool insert = true,
  3. 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++;
  }
}