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
fz_bbox_add_rect(fz_context * ctx,fz_device * dev,fz_rect rect,int clip)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
fz_bbox_fill_path(fz_context * ctx,fz_device * dev,const fz_path * path,int even_odd,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)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
fz_bbox_stroke_path(fz_context * ctx,fz_device * dev,const fz_path * path,const fz_stroke_state * stroke,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)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
fz_bbox_fill_text(fz_context * ctx,fz_device * dev,const fz_text * text,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)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
fz_bbox_stroke_text(fz_context * ctx,fz_device * dev,const fz_text * text,const fz_stroke_state * stroke,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)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
fz_bbox_fill_shade(fz_context * ctx,fz_device * dev,fz_shade * shade,fz_matrix ctm,float alpha,fz_color_params color_params)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
fz_bbox_fill_image(fz_context * ctx,fz_device * dev,fz_image * image,fz_matrix ctm,float alpha,fz_color_params color_params)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
fz_bbox_fill_image_mask(fz_context * ctx,fz_device * dev,fz_image * image,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)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
fz_bbox_clip_path(fz_context * ctx,fz_device * dev,const fz_path * path,int even_odd,fz_matrix ctm,fz_rect scissor)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
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)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
fz_bbox_clip_text(fz_context * ctx,fz_device * dev,const fz_text * text,fz_matrix ctm,fz_rect scissor)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
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)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
fz_bbox_clip_image_mask(fz_context * ctx,fz_device * dev,fz_image * image,fz_matrix ctm,fz_rect scissor)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
fz_bbox_pop_clip(fz_context * ctx,fz_device * dev)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
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)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
fz_bbox_end_mask(fz_context * ctx,fz_device * dev)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
fz_bbox_begin_group(fz_context * ctx,fz_device * dev,fz_rect rect,fz_colorspace * cs,int isolated,int knockout,int blendmode,float alpha)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
fz_bbox_end_group(fz_context * ctx,fz_device * dev)147 fz_bbox_end_group(fz_context *ctx, fz_device *dev)
148 {
149 fz_bbox_pop_clip(ctx, dev);
150 }
151
152 static int
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)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
fz_bbox_end_tile(fz_context * ctx,fz_device * dev)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 fz_device *
fz_new_bbox_device(fz_context * ctx,fz_rect * result)170 fz_new_bbox_device(fz_context *ctx, fz_rect *result)
171 {
172 fz_bbox_device *dev = fz_new_derived_device(ctx, fz_bbox_device);
173
174 dev->super.fill_path = fz_bbox_fill_path;
175 dev->super.stroke_path = fz_bbox_stroke_path;
176 dev->super.clip_path = fz_bbox_clip_path;
177 dev->super.clip_stroke_path = fz_bbox_clip_stroke_path;
178
179 dev->super.fill_text = fz_bbox_fill_text;
180 dev->super.stroke_text = fz_bbox_stroke_text;
181 dev->super.clip_text = fz_bbox_clip_text;
182 dev->super.clip_stroke_text = fz_bbox_clip_stroke_text;
183
184 dev->super.fill_shade = fz_bbox_fill_shade;
185 dev->super.fill_image = fz_bbox_fill_image;
186 dev->super.fill_image_mask = fz_bbox_fill_image_mask;
187 dev->super.clip_image_mask = fz_bbox_clip_image_mask;
188
189 dev->super.pop_clip = fz_bbox_pop_clip;
190
191 dev->super.begin_mask = fz_bbox_begin_mask;
192 dev->super.end_mask = fz_bbox_end_mask;
193 dev->super.begin_group = fz_bbox_begin_group;
194 dev->super.end_group = fz_bbox_end_group;
195
196 dev->super.begin_tile = fz_bbox_begin_tile;
197 dev->super.end_tile = fz_bbox_end_tile;
198
199 dev->result = result;
200 dev->top = 0;
201 dev->ignore = 0;
202
203 *result = fz_empty_rect;
204
205 return (fz_device*)dev;
206 }
207