summaryrefslogtreecommitdiff
path: root/src/pdf_bridge.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pdf_bridge.c')
-rw-r--r--src/pdf_bridge.c76
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 ||