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 | |