1#include "mupdf/fitz.h"
2
3#include <assert.h>
4
5#define STACK_SIZE 96
6
7typedef 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
18static void
19fz_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
37static void
38fz_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
44static void
45fz_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
51static void
52fz_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
58static void
59fz_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
65static void
66fz_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
71static void
72fz_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
77static void
78fz_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
84static void
85fz_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
90static void
91fz_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
96static void
97fz_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
102static void
103fz_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
108static void
109fz_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
114static void
115fz_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
124static void
125fz_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
132static void
133fz_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
140static void
141fz_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
146static void
147fz_bbox_end_group(fz_context *ctx, fz_device *dev)
148{
149 fz_bbox_pop_clip(ctx, dev);
150}
151
152static int
153fz_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
161static void
162fz_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*/
176fz_device *
177fz_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