| 1 | #include "mupdf/fitz.h" |
| 2 | |
| 3 | #include <assert.h> |
| 4 | |
| 5 | #define STACK_SIZE 96 |
| 6 | |
| 7 | typedef struct fz_bbox_device_s |
| 8 | { |
| 9 | fz_device super; |
| 10 | |
| 11 | fz_rect *result; |
| 12 | int top; |
| 13 | fz_rect stack[STACK_SIZE]; |
| 14 | /* mask content and tiles are ignored */ |
| 15 | int ignore; |
| 16 | } fz_bbox_device; |
| 17 | |
| 18 | static void |
| 19 | fz_bbox_add_rect(fz_context *ctx, fz_device *dev, fz_rect rect, int clip) |
| 20 | { |
| 21 | fz_bbox_device *bdev = (fz_bbox_device*)dev; |
| 22 | |
| 23 | if (0 < bdev->top && bdev->top <= STACK_SIZE) |
| 24 | { |
| 25 | rect = fz_intersect_rect(rect, bdev->stack[bdev->top-1]); |
| 26 | } |
| 27 | if (!clip && bdev->top <= STACK_SIZE && !bdev->ignore) |
| 28 | { |
| 29 | *bdev->result = fz_union_rect(*bdev->result, rect); |
| 30 | } |
| 31 | if (clip && ++bdev->top <= STACK_SIZE) |
| 32 | { |
| 33 | bdev->stack[bdev->top-1] = rect; |
| 34 | } |
| 35 | } |
| 36 | |
| 37 | static void |
| 38 | fz_bbox_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, fz_matrix ctm, |
| 39 | fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params) |
| 40 | { |
| 41 | fz_bbox_add_rect(ctx, dev, fz_bound_path(ctx, path, NULL, ctm), 0); |
| 42 | } |
| 43 | |
| 44 | static void |
| 45 | fz_bbox_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const fz_stroke_state *stroke, |
| 46 | fz_matrix ctm, fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params) |
| 47 | { |
| 48 | fz_bbox_add_rect(ctx, dev, fz_bound_path(ctx, path, stroke, ctm), 0); |
| 49 | } |
| 50 | |
| 51 | static void |
| 52 | fz_bbox_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, fz_matrix ctm, |
| 53 | fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params) |
| 54 | { |
| 55 | fz_bbox_add_rect(ctx, dev, fz_bound_text(ctx, text, NULL, ctm), 0); |
| 56 | } |
| 57 | |
| 58 | static void |
| 59 | fz_bbox_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke, |
| 60 | fz_matrix ctm, fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params) |
| 61 | { |
| 62 | fz_bbox_add_rect(ctx, dev, fz_bound_text(ctx, text, stroke, ctm), 0); |
| 63 | } |
| 64 | |
| 65 | static void |
| 66 | fz_bbox_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha, fz_color_params color_params) |
| 67 | { |
| 68 | fz_bbox_add_rect(ctx, dev, fz_bound_shade(ctx, shade, ctm), 0); |
| 69 | } |
| 70 | |
| 71 | static void |
| 72 | fz_bbox_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, fz_matrix ctm, float alpha, fz_color_params color_params) |
| 73 | { |
| 74 | fz_bbox_add_rect(ctx, dev, fz_transform_rect(fz_unit_rect, ctm), 0); |
| 75 | } |
| 76 | |
| 77 | static void |
| 78 | fz_bbox_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, fz_matrix ctm, |
| 79 | fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params) |
| 80 | { |
| 81 | fz_bbox_add_rect(ctx, dev, fz_transform_rect(fz_unit_rect, ctm), 0); |
| 82 | } |
| 83 | |
| 84 | static void |
| 85 | fz_bbox_clip_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, fz_matrix ctm, fz_rect scissor) |
| 86 | { |
| 87 | fz_bbox_add_rect(ctx, dev, fz_bound_path(ctx, path, NULL, ctm), 1); |
| 88 | } |
| 89 | |
| 90 | static void |
| 91 | fz_bbox_clip_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const fz_stroke_state *stroke, fz_matrix ctm, fz_rect scissor) |
| 92 | { |
| 93 | fz_bbox_add_rect(ctx, dev, fz_bound_path(ctx, path, stroke, ctm), 1); |
| 94 | } |
| 95 | |
| 96 | static void |
| 97 | fz_bbox_clip_text(fz_context *ctx, fz_device *dev, const fz_text *text, fz_matrix ctm, fz_rect scissor) |
| 98 | { |
| 99 | fz_bbox_add_rect(ctx, dev, fz_bound_text(ctx, text, NULL, ctm), 1); |
| 100 | } |
| 101 | |
| 102 | static void |
| 103 | fz_bbox_clip_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke, fz_matrix ctm, fz_rect scissor) |
| 104 | { |
| 105 | fz_bbox_add_rect(ctx, dev, fz_bound_text(ctx, text, stroke, ctm), 1); |
| 106 | } |
| 107 | |
| 108 | static void |
| 109 | fz_bbox_clip_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, fz_matrix ctm, fz_rect scissor) |
| 110 | { |
| 111 | fz_bbox_add_rect(ctx, dev, fz_transform_rect(fz_unit_rect, ctm), 1); |
| 112 | } |
| 113 | |
| 114 | static void |
| 115 | fz_bbox_pop_clip(fz_context *ctx, fz_device *dev) |
| 116 | { |
| 117 | fz_bbox_device *bdev = (fz_bbox_device*)dev; |
| 118 | if (bdev->top > 0) |
| 119 | bdev->top--; |
| 120 | else |
| 121 | fz_warn(ctx, "unexpected pop clip" ); |
| 122 | } |
| 123 | |
| 124 | static void |
| 125 | fz_bbox_begin_mask(fz_context *ctx, fz_device *dev, fz_rect rect, int luminosity, fz_colorspace *colorspace, const float *color, fz_color_params color_params) |
| 126 | { |
| 127 | fz_bbox_device *bdev = (fz_bbox_device*)dev; |
| 128 | fz_bbox_add_rect(ctx, dev, rect, 1); |
| 129 | bdev->ignore++; |
| 130 | } |
| 131 | |
| 132 | static void |
| 133 | fz_bbox_end_mask(fz_context *ctx, fz_device *dev) |
| 134 | { |
| 135 | fz_bbox_device *bdev = (fz_bbox_device*)dev; |
| 136 | assert(bdev->ignore > 0); |
| 137 | bdev->ignore--; |
| 138 | } |
| 139 | |
| 140 | static void |
| 141 | fz_bbox_begin_group(fz_context *ctx, fz_device *dev, fz_rect rect, fz_colorspace *cs, int isolated, int knockout, int blendmode, float alpha) |
| 142 | { |
| 143 | fz_bbox_add_rect(ctx, dev, rect, 1); |
| 144 | } |
| 145 | |
| 146 | static void |
| 147 | fz_bbox_end_group(fz_context *ctx, fz_device *dev) |
| 148 | { |
| 149 | fz_bbox_pop_clip(ctx, dev); |
| 150 | } |
| 151 | |
| 152 | static int |
| 153 | fz_bbox_begin_tile(fz_context *ctx, fz_device *dev, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm, int id) |
| 154 | { |
| 155 | fz_bbox_device *bdev = (fz_bbox_device*)dev; |
| 156 | fz_bbox_add_rect(ctx, dev, fz_transform_rect(area, ctm), 0); |
| 157 | bdev->ignore++; |
| 158 | return 0; |
| 159 | } |
| 160 | |
| 161 | static void |
| 162 | fz_bbox_end_tile(fz_context *ctx, fz_device *dev) |
| 163 | { |
| 164 | fz_bbox_device *bdev = (fz_bbox_device*)dev; |
| 165 | assert(bdev->ignore > 0); |
| 166 | bdev->ignore--; |
| 167 | } |
| 168 | |
| 169 | /* |
| 170 | Create a device to compute the bounding |
| 171 | box of all marks on a page. |
| 172 | |
| 173 | The returned bounding box will be the union of all bounding |
| 174 | boxes of all objects on a page. |
| 175 | */ |
| 176 | fz_device * |
| 177 | fz_new_bbox_device(fz_context *ctx, fz_rect *result) |
| 178 | { |
| 179 | fz_bbox_device *dev = fz_new_derived_device(ctx, fz_bbox_device); |
| 180 | |
| 181 | dev->super.fill_path = fz_bbox_fill_path; |
| 182 | dev->super.stroke_path = fz_bbox_stroke_path; |
| 183 | dev->super.clip_path = fz_bbox_clip_path; |
| 184 | dev->super.clip_stroke_path = fz_bbox_clip_stroke_path; |
| 185 | |
| 186 | dev->super.fill_text = fz_bbox_fill_text; |
| 187 | dev->super.stroke_text = fz_bbox_stroke_text; |
| 188 | dev->super.clip_text = fz_bbox_clip_text; |
| 189 | dev->super.clip_stroke_text = fz_bbox_clip_stroke_text; |
| 190 | |
| 191 | dev->super.fill_shade = fz_bbox_fill_shade; |
| 192 | dev->super.fill_image = fz_bbox_fill_image; |
| 193 | dev->super.fill_image_mask = fz_bbox_fill_image_mask; |
| 194 | dev->super.clip_image_mask = fz_bbox_clip_image_mask; |
| 195 | |
| 196 | dev->super.pop_clip = fz_bbox_pop_clip; |
| 197 | |
| 198 | dev->super.begin_mask = fz_bbox_begin_mask; |
| 199 | dev->super.end_mask = fz_bbox_end_mask; |
| 200 | dev->super.begin_group = fz_bbox_begin_group; |
| 201 | dev->super.end_group = fz_bbox_end_group; |
| 202 | |
| 203 | dev->super.begin_tile = fz_bbox_begin_tile; |
| 204 | dev->super.end_tile = fz_bbox_end_tile; |
| 205 | |
| 206 | dev->result = result; |
| 207 | dev->top = 0; |
| 208 | dev->ignore = 0; |
| 209 | |
| 210 | *result = fz_empty_rect; |
| 211 | |
| 212 | return (fz_device*)dev; |
| 213 | } |
| 214 | |