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