diff options
Diffstat (limited to 'src/pdf_bridge.c')
| -rw-r--r-- | src/pdf_bridge.c | 76 |
1 files changed, 62 insertions, 14 deletions
diff --git a/src/pdf_bridge.c b/src/pdf_bridge.c index 2c723dbb..6fdab46c 100644 --- a/src/pdf_bridge.c +++ b/src/pdf_bridge.c @@ -481,6 +481,8 @@ pardes_pdf_render_geometry( int minimum_width, int minimum_height, int max_dimension, + int display_width, + int display_height, fz_matrix *ctm_out, fz_irect *bbox_out) { @@ -488,23 +490,38 @@ pardes_pdf_render_geometry( fz_rect bounds; float page_width; float page_height; - float longest; float scale; + float shown = 0.0f; pardes_pdf_cache_page(document, page_number, 0); bounds = document->cached_bounds; page_width = bounds.x1 - bounds.x0; page_height = bounds.y1 - bounds.y0; - longest = fmaxf(page_width, page_height); - if (!(longest > 0.0f)) + if (!(page_width > 0.0f) || !(page_height > 0.0f)) fz_throw(document->ctx, FZ_ERROR_FORMAT, "PDF page has empty bounds"); scale = (float)dpi / 72.0f; if (minimum_width > 0) scale = fmaxf(scale, (float)minimum_width / page_width); if (minimum_height > 0) scale = fmaxf(scale, (float)minimum_height / page_height); - if (longest * scale > (float)max_dimension) - scale = (float)max_dimension / longest; + /* + * A row of the raster is never longer than max_dimension: every band of + * the page carries whole rows. The height is held to it too, as the + * budget of one whole-page raster, but never below the scale the page is + * shown at: a page taller than that (a poster, a long web capture) is + * drawn in bands at the display's own resolution (pdf_view.zig) instead + * of being squeezed into max_dimension rows and blown up again, blurred. + */ + if (page_width * scale > (float)max_dimension) + scale = (float)max_dimension / page_width; + if (display_width > 0) + shown = fmaxf(shown, (float)display_width / page_width); + if (display_height > 0) + shown = fmaxf(shown, (float)display_height / page_height); + if (page_height * scale > (float)max_dimension) + scale = fminf(scale, fmaxf((float)max_dimension / page_height, shown)); + if (page_height * scale > (float)PARDES_PDF_MAX_RASTER_ROWS) + scale = (float)PARDES_PDF_MAX_RASTER_ROWS / page_height; /* * Keep this identical to fz_new_pixmap_from_page/display_list: transform @@ -526,6 +543,8 @@ pardes_pdf_measure_render( int minimum_width, int minimum_height, int max_dimension, + int display_width, + int display_height, pardes_pdf_raster_layout *out) { fz_context *ctx; @@ -541,14 +560,16 @@ pardes_pdf_measure_render( memset(out, 0, sizeof(*out)); if (document == NULL || page_number < 0 || page_number >= document->page_count || dpi < 1 || - minimum_width < 0 || minimum_height < 0 || max_dimension < 1) + minimum_width < 0 || minimum_height < 0 || max_dimension < 1 || + display_width < 0 || display_height < 0) return PARDES_PDF_ERROR; ctx = document->ctx; fz_try(ctx) { pardes_pdf_render_geometry(document, page_number, dpi, - minimum_width, minimum_height, max_dimension, &ctm, &bbox); + minimum_width, minimum_height, max_dimension, + display_width, display_height, &ctm, &bbox); width = fz_irect_width(bbox); height = fz_irect_height(bbox); if (width > INT_MAX / 4) @@ -629,6 +650,8 @@ pardes_pdf_render_into( int minimum_width, int minimum_height, int max_dimension, + int display_width, + int display_height, const pardes_pdf_highlight *highlights, size_t highlight_count, unsigned char *samples, @@ -649,6 +672,7 @@ pardes_pdf_render_into( if (document == NULL || page_number < 0 || page_number >= document->page_count || dpi < 1 || minimum_width < 0 || minimum_height < 0 || max_dimension < 1 || + display_width < 0 || display_height < 0 || (highlight_count != 0 && highlights == NULL) || highlight_count > PARDES_PDF_MAX_RESULT_QUADS || samples == NULL || width < 1 || height < 1 || stride < 1 || width > INT_MAX / 4 || @@ -664,7 +688,8 @@ pardes_pdf_render_into( fz_try(ctx) { pardes_pdf_render_geometry(document, page_number, dpi, - minimum_width, minimum_height, max_dimension, &ctm, &bbox); + minimum_width, minimum_height, max_dimension, + display_width, display_height, &ctm, &bbox); if (fz_irect_width(bbox) != width || fz_irect_height(bbox) != height) fz_throw(ctx, FZ_ERROR_ARGUMENT, @@ -676,9 +701,13 @@ pardes_pdf_render_into( * discards everything outside these rows. The rows are NOT always * bit-identical to the full page's: rows at the band's edges, and a * resampled image anywhere in it, can differ (measured on - * docs/registry.pdf and docs/design.pdf). Good enough for a band that - * is only shown while flinging; never use a band to patch rows into a - * whole-page raster -- `pardes_pdf_paint_highlights` exists for that. + * docs/registry.pdf and docs/design.pdf), and an edge crossing the + * clip is stepped from a different start along its whole length, + * a level or two off. Good enough for a band shown while flinging, + * and for the chunks of a page too tall to render whole (pdf_view.zig + * renders those past their edges and keeps the middle); never use a + * band to patch rows into a whole-page raster -- + * `pardes_pdf_paint_highlights` exists for that. */ bbox.y0 += band_y; bbox.y1 = bbox.y0 + band_height; @@ -708,10 +737,21 @@ pardes_pdf_render_into( if (document->cached_display_list != NULL || document->display_list_candidate_page_number == page_number) { + /* + * Only the nodes that reach the band: a band of a tall page + * skips the rest of the page instead of handing every node to + * the draw device to clip away. The scissor is in page space + * (the list runs untransformed under the device's CTM), a pixel + * wider than the band all round. Culling never changes a pixel: + * a node outside it draws nothing here. + */ + fz_rect scissor = fz_rect_from_irect(bbox); + scissor.x0 -= 1; scissor.y0 -= 1; scissor.x1 += 1; scissor.y1 += 1; + scissor = fz_transform_rect(scissor, fz_invert_matrix(ctm)); pardes_pdf_cache_display_list(document); device = fz_new_draw_device(ctx, ctm, pixmap); fz_run_display_list(ctx, document->cached_display_list, device, - fz_identity, fz_infinite_rect, NULL); + fz_identity, scissor, NULL); } else { device = fz_new_draw_device(ctx, ctm, pixmap); fz_run_page(ctx, document->cached_page, device, fz_identity, NULL); @@ -767,6 +807,8 @@ pardes_pdf_paint_highlights( int minimum_width, int minimum_height, int max_dimension, + int display_width, + int display_height, const pardes_pdf_highlight *highlights, size_t highlight_count, unsigned char *samples, @@ -786,6 +828,7 @@ pardes_pdf_paint_highlights( if (document == NULL || page_number < 0 || page_number >= document->page_count || dpi < 1 || minimum_width < 0 || minimum_height < 0 || max_dimension < 1 || + display_width < 0 || display_height < 0 || (highlight_count != 0 && highlights == NULL) || highlight_count > PARDES_PDF_MAX_RESULT_QUADS || samples == NULL || width < 1 || height < 1 || width > INT_MAX / 4 || stride != width * 4 || @@ -802,7 +845,8 @@ pardes_pdf_paint_highlights( fz_try(ctx) { pardes_pdf_render_geometry(document, page_number, dpi, - minimum_width, minimum_height, max_dimension, &ctm, &bbox); + minimum_width, minimum_height, max_dimension, + display_width, display_height, &ctm, &bbox); if (fz_irect_width(bbox) != width || fz_irect_height(bbox) != height) fz_throw(ctx, FZ_ERROR_ARGUMENT, "PDF raster layout changed between measure and paint"); @@ -835,6 +879,8 @@ pardes_pdf_highlight_rows( int minimum_width, int minimum_height, int max_dimension, + int display_width, + int display_height, const pardes_pdf_highlight *highlights, size_t highlight_count, int *row_start, @@ -853,6 +899,7 @@ pardes_pdf_highlight_rows( if (document == NULL || page_number < 0 || page_number >= document->page_count || dpi < 1 || minimum_width < 0 || minimum_height < 0 || max_dimension < 1 || + display_width < 0 || display_height < 0 || (highlight_count != 0 && highlights == NULL)) return PARDES_PDF_ERROR; @@ -860,7 +907,8 @@ pardes_pdf_highlight_rows( fz_try(ctx) { pardes_pdf_render_geometry(document, page_number, dpi, - minimum_width, minimum_height, max_dimension, &ctm, &bbox); + minimum_width, minimum_height, max_dimension, + display_width, display_height, &ctm, &bbox); for (i = 0; i < highlight_count; ++i) { fz_rect r; if (highlights[i].rgba[3] == 0 || |
