/src/ghostpdl/psi/zmedia2.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2023 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Media matching for setpagedevice */ |
18 | | #include "math_.h" |
19 | | #include "memory_.h" |
20 | | #include "ghost.h" |
21 | | #include "gsmatrix.h" |
22 | | #include "oper.h" |
23 | | #include "idict.h" |
24 | | #include "idparam.h" |
25 | | #include "iname.h" |
26 | | #include "store.h" |
27 | | |
28 | | /* <pagedict> <attrdict> <policydict> <keys> .matchmedia <key> true */ |
29 | | /* <pagedict> <attrdict> <policydict> <keys> .matchmedia false */ |
30 | | /* <pagedict> null <policydict> <keys> .matchmedia null true */ |
31 | | static int zmatch_page_size(const gs_memory_t *mem, |
32 | | const ref * pvreq, const ref * pvmed, |
33 | | int policy, int orient, bool roll, |
34 | | float *best_mismatch, gs_matrix * pmat, |
35 | | gs_point * pmsize); |
36 | | typedef struct match_record_s { |
37 | | ref best_key, match_key; |
38 | | uint priority, no_match_priority; |
39 | | } match_record_t; |
40 | | static void |
41 | | reset_match(match_record_t *match) |
42 | 7.10M | { |
43 | 7.10M | make_null(&match->best_key); |
44 | 7.10M | make_null(&match->match_key); |
45 | 7.10M | match->priority = match->no_match_priority; |
46 | 7.10M | } |
47 | | static int |
48 | | zmatchmedia(i_ctx_t *i_ctx_p) |
49 | 1.57M | { |
50 | 1.57M | os_ptr op = osp; |
51 | 1.57M | os_ptr preq = op - 3; |
52 | 1.57M | os_ptr pattr = op - 2; |
53 | 1.57M | os_ptr ppol = op - 1; |
54 | 1.57M | os_ptr pkeys = op; /* *const */ |
55 | 1.57M | int policy_default; |
56 | 1.57M | float best_mismatch = (float)max_long; /* adhoc */ |
57 | 1.57M | float mepos_penalty; |
58 | 1.57M | float mbest = best_mismatch; |
59 | 1.57M | match_record_t match; |
60 | 1.57M | ref no_priority; |
61 | 1.57M | ref *ppriority; |
62 | 1.57M | int mepos, orient; |
63 | 1.57M | bool roll; |
64 | 1.57M | int code; |
65 | 1.57M | int ai; |
66 | 1.57M | struct mkd_ { |
67 | 1.57M | ref key, dict; |
68 | 1.57M | } aelt; |
69 | 1.57M | if (r_has_type(pattr, t_null)) { |
70 | 0 | check_op(4); |
71 | 0 | make_null(op - 3); |
72 | 0 | make_true(op - 2); |
73 | 0 | pop(2); |
74 | 0 | return 0; |
75 | 0 | } |
76 | 1.57M | check_type(*preq, t_dictionary); |
77 | 1.57M | check_dict_read(*preq); |
78 | 1.57M | check_type(*pattr, t_dictionary); |
79 | 1.57M | check_dict_read(*pattr); |
80 | 1.57M | check_type(*ppol, t_dictionary); |
81 | 1.57M | check_dict_read(*ppol); |
82 | 1.57M | check_array(*pkeys); |
83 | 1.57M | check_read(*pkeys); |
84 | 1.57M | switch (code = dict_int_null_param(preq, "MediaPosition", 0, 0x7fff, |
85 | 1.57M | 0, &mepos)) { |
86 | 0 | default: |
87 | 0 | return code; |
88 | 0 | case 2: |
89 | 1.57M | case 1: |
90 | 1.57M | mepos = -1; |
91 | 1.57M | case 0:; |
92 | 1.57M | } |
93 | 1.57M | switch (code = dict_int_null_param(preq, "Orientation", 0, 3, |
94 | 1.57M | 0, &orient)) { |
95 | 0 | default: |
96 | 0 | return code; |
97 | 0 | case 2: |
98 | 1.57M | case 1: |
99 | 1.57M | orient = -1; |
100 | 1.57M | case 0:; |
101 | 1.57M | } |
102 | 1.57M | code = dict_bool_param(preq, "RollFedMedia", false, &roll); |
103 | 1.57M | if (code < 0) |
104 | 0 | return code; |
105 | 1.57M | code = dict_int_param(ppol, "PolicyNotFound", 0, 7, 0, |
106 | 1.57M | &policy_default); |
107 | 1.57M | if (code < 0) |
108 | 0 | return code; |
109 | 1.57M | if (dict_find_string(pattr, "Priority", &ppriority) > 0) { |
110 | 0 | check_array_only(*ppriority); |
111 | 0 | check_read(*ppriority); |
112 | 1.57M | } else { |
113 | 1.57M | make_empty_array(&no_priority, a_readonly); |
114 | 1.57M | ppriority = &no_priority; |
115 | 1.57M | } |
116 | 1.57M | match.no_match_priority = r_size(ppriority); |
117 | 1.57M | reset_match(&match); |
118 | 1.57M | for (ai = dict_first(pattr); |
119 | 62.3M | (ai = dict_next(pattr, ai, (ref * /*[2]*/)&aelt)) >= 0; |
120 | 60.8M | ) { |
121 | 60.8M | if (r_has_type(&aelt.dict, t_dictionary) && |
122 | 60.8M | r_has_attr(dict_access_ref(&aelt.dict), a_read) && |
123 | 60.8M | r_has_type(&aelt.key, t_integer) |
124 | 60.8M | ) { |
125 | 60.8M | bool match_all; |
126 | 60.8M | uint ki, pi; |
127 | | |
128 | 60.8M | code = dict_bool_param(&aelt.dict, "MatchAll", false, |
129 | 60.8M | &match_all); |
130 | 60.8M | if (code < 0) |
131 | 0 | return code; |
132 | 121M | for (ki = 0; ki < r_size(pkeys); ki++) { |
133 | 60.8M | ref key; |
134 | 60.8M | ref kstr; |
135 | 60.8M | ref *prvalue; |
136 | 60.8M | ref *pmvalue; |
137 | 60.8M | ref *ppvalue; |
138 | 60.8M | int policy; |
139 | | |
140 | 60.8M | array_get(imemory, pkeys, ki, &key); |
141 | 60.8M | if (dict_find(&aelt.dict, &key, &pmvalue) <= 0) |
142 | 789k | continue; |
143 | 60.0M | if (dict_find(preq, &key, &prvalue) <= 0 || |
144 | 60.0M | r_has_type(prvalue, t_null) |
145 | 60.0M | ) { |
146 | 0 | if (match_all) |
147 | 0 | goto no; |
148 | 0 | else |
149 | 0 | continue; |
150 | 0 | } |
151 | | /* Look for the Policies entry for this key. */ |
152 | 60.0M | if (dict_find(ppol, &key, &ppvalue) > 0) { |
153 | 60.0M | check_type_only(*ppvalue, t_integer); |
154 | 60.0M | policy = ppvalue->value.intval; |
155 | 60.0M | } else |
156 | 0 | policy = policy_default; |
157 | | /* |
158 | | * Match a requested attribute value with the attribute value in the |
159 | | * description of a medium. For all attributes except PageSize, |
160 | | * matching means equality. PageSize is special; see match_page_size |
161 | | * below. |
162 | | */ |
163 | 60.0M | if (r_has_type(&key, t_name) && |
164 | 60.0M | (name_string_ref(imemory, &key, &kstr), |
165 | 60.0M | r_size(&kstr) == 8 && |
166 | 60.0M | !memcmp(kstr.value.bytes, "PageSize", 8)) |
167 | 60.0M | ) { |
168 | 60.0M | gs_matrix ignore_mat; |
169 | 60.0M | gs_point ignore_msize; |
170 | | |
171 | 60.0M | if (zmatch_page_size(imemory, prvalue, pmvalue, |
172 | 60.0M | policy, orient, roll, |
173 | 60.0M | &best_mismatch, |
174 | 60.0M | &ignore_mat, |
175 | 60.0M | &ignore_msize) |
176 | 60.0M | <= 0) |
177 | 5.09k | goto no; |
178 | 60.0M | } else if (!obj_eq(imemory, prvalue, pmvalue)) |
179 | 0 | goto no; |
180 | 60.0M | } |
181 | | |
182 | 60.7M | mepos_penalty = (mepos < 0 || aelt.key.value.intval == mepos) ? |
183 | 60.7M | 0 : .001; |
184 | | |
185 | | /* We have a match. Save the match in case no better match is found */ |
186 | 60.7M | if (r_has_type(&match.match_key, t_null)) |
187 | 1.57M | match.match_key = aelt.key; |
188 | | /* |
189 | | * If it is a better match than the current best it supersedes it |
190 | | * regardless of priority. If the match is the same, then update |
191 | | * to the current only if the key value is lower. |
192 | | */ |
193 | 60.7M | if (best_mismatch + mepos_penalty <= mbest) { |
194 | 60.7M | if (best_mismatch + mepos_penalty < mbest || |
195 | 60.7M | (r_has_type(&match.match_key, t_integer) && |
196 | 60.0M | match.match_key.value.intval > aelt.key.value.intval)) { |
197 | 5.52M | reset_match(&match); |
198 | 5.52M | match.match_key = aelt.key; |
199 | 5.52M | mbest = best_mismatch + mepos_penalty; |
200 | 5.52M | } |
201 | 60.7M | } |
202 | | /* In case of a tie, see if the new match has priority. */ |
203 | 60.7M | for (pi = match.priority; pi > 0;) { |
204 | 0 | ref pri; |
205 | |
|
206 | 0 | pi--; |
207 | 0 | array_get(imemory, ppriority, pi, &pri); |
208 | 0 | if (obj_eq(imemory, &aelt.key, &pri)) { /* Yes, higher priority. */ |
209 | 0 | match.best_key = aelt.key; |
210 | 0 | match.priority = pi; |
211 | 0 | break; |
212 | 0 | } |
213 | 0 | } |
214 | 60.8M | no:; |
215 | 60.8M | } |
216 | 60.8M | } |
217 | 1.57M | if (r_has_type(&match.match_key, t_null)) { |
218 | 67 | make_false(op - 3); |
219 | 67 | pop(3); |
220 | 1.57M | } else { |
221 | 1.57M | if (r_has_type(&match.best_key, t_null)) |
222 | 1.57M | op[-3] = match.match_key; |
223 | 0 | else |
224 | 0 | op[-3] = match.best_key; |
225 | 1.57M | make_true(op - 2); |
226 | 1.57M | pop(2); |
227 | 1.57M | } |
228 | 1.57M | return 0; |
229 | 1.57M | } |
230 | | |
231 | | /* [<req_x> <req_y>] [<med_x0> <med_y0> (<med_x1> <med_y1> | )] |
232 | | * <policy> <orient|null> <roll> <matrix|null> .matchpagesize |
233 | | * <matrix|null> <med_x> <med_y> true -or- false |
234 | | */ |
235 | | static int |
236 | | zmatchpagesize(i_ctx_t *i_ctx_p) |
237 | 1.67M | { |
238 | 1.67M | os_ptr op = osp; |
239 | 1.67M | gs_matrix mat; |
240 | 1.67M | float ignore_mismatch = (float)max_long; |
241 | 1.67M | gs_point media_size; |
242 | 1.67M | int orient; |
243 | 1.67M | bool roll; |
244 | 1.67M | int code; |
245 | | |
246 | 1.67M | check_type(op[-3], t_integer); |
247 | 1.67M | if (r_has_type(op - 2, t_null)) |
248 | 1.67M | orient = -1; |
249 | 0 | else { |
250 | 0 | check_int_leu(op[-2], 3); |
251 | 0 | orient = (int)op[-2].value.intval; |
252 | 0 | } |
253 | 1.67M | check_type(op[-1], t_boolean); |
254 | 1.67M | roll = op[-1].value.boolval; |
255 | 1.67M | code = zmatch_page_size(imemory, |
256 | 1.67M | op - 5, op - 4, (int)op[-3].value.intval, |
257 | 1.67M | orient, roll, |
258 | 1.67M | &ignore_mismatch, &mat, &media_size); |
259 | 1.67M | switch (code) { |
260 | 67 | default: |
261 | 67 | return code; |
262 | 0 | case 0: |
263 | 0 | make_false(op - 5); |
264 | 0 | pop(5); |
265 | 0 | break; |
266 | 1.67M | case 1: |
267 | 1.67M | code = write_matrix(op, &mat); |
268 | 1.67M | if (code < 0 && !r_has_type(op, t_null)) |
269 | 0 | return code; |
270 | 1.67M | op[-5] = *op; |
271 | 1.67M | make_real(op - 4, media_size.x); |
272 | 1.67M | make_real(op - 3, media_size.y); |
273 | 1.67M | make_true(op - 2); |
274 | 1.67M | pop(2); |
275 | 1.67M | break; |
276 | 1.67M | } |
277 | 1.67M | return 0; |
278 | 1.67M | } |
279 | | /* Match the PageSize. See below for details. */ |
280 | | static int |
281 | | match_page_size(const gs_point * request, |
282 | | const gs_rect * medium, |
283 | | int policy, int orient, bool roll, |
284 | | float *best_mismatch, gs_matrix * pmat, |
285 | | gs_point * pmsize); |
286 | | static int |
287 | | zmatch_page_size(const gs_memory_t *mem, const ref * pvreq, const ref * pvmed, |
288 | | int policy, int orient, bool roll, |
289 | | float *best_mismatch, gs_matrix * pmat, gs_point * pmsize) |
290 | 61.6M | { |
291 | 61.6M | uint nr, nm; |
292 | 61.6M | int code; |
293 | 61.6M | ref rv[6]; |
294 | | |
295 | | /* array_get checks array types and size. */ |
296 | | /* This allows normal or packed arrays to be used */ |
297 | 61.6M | if ((code = array_get(mem, pvreq, 1, &rv[1])) < 0) |
298 | 0 | return_error(code); |
299 | 61.6M | nr = r_size(pvreq); |
300 | 61.6M | if ((code = array_get(mem, pvmed, 1, &rv[3])) < 0) |
301 | 0 | return_error(code); |
302 | 61.6M | nm = r_size(pvmed); |
303 | 61.6M | if (!((nm == 2 || nm == 4) && (nr == 2 || nr == nm))) |
304 | 0 | return_error(gs_error_rangecheck); |
305 | 61.6M | { |
306 | 61.6M | uint i; |
307 | 61.6M | double v[6]; |
308 | 61.6M | int code; |
309 | | |
310 | 61.6M | array_get(mem, pvreq, 0, &rv[0]); |
311 | 308M | for (i = 0; i < 4; ++i) |
312 | 246M | array_get(mem,pvmed, i % nm, &rv[i + 2]); |
313 | 61.6M | if ((code = num_params(rv + 5, 6, v)) < 0) |
314 | 0 | return code; |
315 | 61.6M | { |
316 | 61.6M | gs_point request; |
317 | 61.6M | gs_rect medium; |
318 | | |
319 | 61.6M | request.x = v[0], request.y = v[1]; |
320 | 61.6M | medium.p.x = v[2], medium.p.y = v[3], |
321 | 61.6M | medium.q.x = v[4], medium.q.y = v[5]; |
322 | 61.6M | return match_page_size(&request, &medium, policy, orient, |
323 | 61.6M | roll, best_mismatch, pmat, pmsize); |
324 | 61.6M | } |
325 | 61.6M | } |
326 | 61.6M | } |
327 | | /* |
328 | | * Match a requested PageSize with the PageSize of a medium. The medium |
329 | | * may specify either a single value [mx my] or a range |
330 | | * [mxmin mymin mxmax mymax]; matching means equality or inclusion |
331 | | * to within a tolerance of 5, possibly swapping the requested X and Y. |
332 | | * Take the Policies value into account, keeping track of the discrepancy |
333 | | * if needed. When a match is found, also return the matrix to be |
334 | | * concatenated after setting up the default matrix, and the actual |
335 | | * media size. |
336 | | * |
337 | | * NOTE: The algorithm here doesn't work properly for variable-size media |
338 | | * when the match isn't exact. We'll fix it if we ever need to. |
339 | | */ |
340 | | static void make_adjustment_matrix(const gs_point * request, |
341 | | const gs_rect * medium, |
342 | | gs_matrix * pmat, |
343 | | bool scale, int rotate); |
344 | | static int |
345 | | match_page_size(const gs_point * request, const gs_rect * medium, int policy, |
346 | | int orient, bool roll, float *best_mismatch, gs_matrix * pmat, |
347 | | gs_point * pmsize) |
348 | 61.6M | { |
349 | 61.6M | double rx = request->x, ry = request->y; |
350 | | |
351 | 61.6M | if ((rx <= 0) || (ry <= 0)) |
352 | 5.15k | return_error(gs_error_rangecheck); |
353 | 61.6M | if (policy == 7) { |
354 | | /* (Adobe) hack: just impose requested values */ |
355 | 61.6M | *best_mismatch = 0; |
356 | 61.6M | gs_make_identity(pmat); |
357 | 61.6M | *pmsize = *request; |
358 | 61.6M | } else { |
359 | 0 | int fit_direct = rx - medium->p.x >= -5 && rx - medium->q.x <= 5 |
360 | 0 | && ry - medium->p.y >= -5 && ry - medium->q.y <= 5; |
361 | 0 | int fit_rotated = rx - medium->p.y >= -5 && rx - medium->q.y <= 5 |
362 | 0 | && ry - medium->p.x >= -5 && ry - medium->q.x <= 5; |
363 | | |
364 | | /* Fudge matches from a non-standard page size match (4 element array) */ |
365 | | /* as worse than an exact match from a standard (2 element array), but */ |
366 | | /* better than for a rotated match to a standard pagesize. This should */ |
367 | | /* prevent rotation unless we have to (particularly for raster file */ |
368 | | /* formats like TIFF, JPEG, PNG, PCX, BMP, etc. and also should allow */ |
369 | | /* exact page size specification when there is a range PageSize entry. */ |
370 | | /* As the comment in gs_setpd.ps says "Devices that care will provide */ |
371 | | /* a real InputAttributes dictionary (most without a range pagesize) */ |
372 | 0 | if ( fit_direct && fit_rotated) { |
373 | 0 | make_adjustment_matrix(request, medium, pmat, false, orient < 0 ? 0 : orient); |
374 | 0 | if (medium->p.x < medium->q.x || medium->p.y < medium->q.y) |
375 | 0 | *best_mismatch = (float)0.001; /* fudge a match to a range as a small number */ |
376 | 0 | else /* should be 0 for an exact match */ |
377 | 0 | *best_mismatch = fabs((rx - medium->p.x) * (medium->q.x - rx)) + |
378 | 0 | fabs((ry - medium->p.y) * (medium->q.y - ry)); |
379 | 0 | } else if ( fit_direct ) { |
380 | 0 | int rotate = orient < 0 ? 0 : orient; |
381 | |
|
382 | 0 | make_adjustment_matrix(request, medium, pmat, false, (rotate + 1) & 2); |
383 | 0 | *best_mismatch = fabs((medium->p.x - rx) * (medium->q.x - rx)) + |
384 | 0 | fabs((medium->p.y - ry) * (medium->q.y - ry)) + |
385 | 0 | (pmat->xx == 0.0 || (rotate & 1) == 1 ? 0.01 : 0); /* rotated */ |
386 | 0 | } else if ( fit_rotated ) { |
387 | 0 | int rotate = (orient < 0 ? 1 : orient); |
388 | |
|
389 | 0 | make_adjustment_matrix(request, medium, pmat, false, rotate | 1); |
390 | 0 | *best_mismatch = fabs((medium->p.y - rx) * (medium->q.y - rx)) + |
391 | 0 | fabs((medium->p.x - ry) * (medium->q.x - ry)) + |
392 | 0 | (pmat->xx == 0.0 || (rotate & 1) == 1 ? 0.01 : 0); /* rotated */ |
393 | 0 | } else { |
394 | 0 | int rotate = 0; |
395 | 0 | bool larger = 0; |
396 | 0 | bool adjust = false; |
397 | 0 | float mismatch = medium->q.x * medium->q.y - rx * ry; |
398 | |
|
399 | 0 | rotate = orient >= 0 ? orient : (rx < ry) ^ (medium->q.x < medium->q.y); |
400 | | |
401 | | /* If either the request or the media is square, there is no point in rotating */ |
402 | 0 | if (rx == ry || medium->q.x == medium->q.y) |
403 | 0 | rotate = 0; |
404 | |
|
405 | 0 | larger = (policy == 13) ? 0 : |
406 | 0 | (rotate & 1 ? medium->q.y >= rx && medium->q.x >= ry : |
407 | 0 | medium->q.x >= rx && medium->q.y >= ry); |
408 | |
|
409 | 0 | switch (policy) { |
410 | 0 | default: /* exact match only */ |
411 | 0 | return 0; |
412 | 0 | case 3: /* nearest match, adjust */ |
413 | 0 | case 13: /* non-standard, nearest match, scale down OR up */ |
414 | 0 | adjust = true; |
415 | | /* fall through */ |
416 | 0 | case 5: /* nearest match, don't adjust */ |
417 | 0 | if (fabs(mismatch) >= fabs(*best_mismatch)) |
418 | 0 | return 0; |
419 | 0 | break; |
420 | 0 | case 4: /* next larger match, adjust */ |
421 | 0 | adjust = true; |
422 | | /* fall through */ |
423 | 0 | case 6: /* next larger match, don't adjust */ |
424 | 0 | if (!larger || mismatch >= *best_mismatch) |
425 | 0 | return 0; |
426 | 0 | break; |
427 | 0 | } |
428 | 0 | if (adjust) |
429 | 0 | make_adjustment_matrix(request, medium, pmat, !larger, rotate); |
430 | 0 | else { |
431 | 0 | gs_rect req_rect; |
432 | 0 | if(rotate & 1) { |
433 | 0 | req_rect.p.x = ry; |
434 | 0 | req_rect.p.y = rx; |
435 | 0 | } else { |
436 | 0 | req_rect.p.x = rx; |
437 | 0 | req_rect.p.y = ry; |
438 | 0 | } |
439 | 0 | req_rect.q = req_rect.p; |
440 | 0 | make_adjustment_matrix(request, &req_rect, pmat, false, rotate); |
441 | 0 | } |
442 | 0 | *best_mismatch = fabs(mismatch); |
443 | 0 | } |
444 | 0 | if (pmat->xx == 0) { /* Swap request X and Y. */ |
445 | 0 | double temp = rx; |
446 | |
|
447 | 0 | rx = ry, ry = temp; |
448 | 0 | } |
449 | 0 | #define ADJUST_INTO(req, mmin, mmax)\ |
450 | 0 | (req < mmin ? mmin : req > mmax ? mmax : req) |
451 | 0 | pmsize->x = ADJUST_INTO(rx, medium->p.x, medium->q.x); |
452 | 0 | pmsize->y = ADJUST_INTO(ry, medium->p.y, medium->q.y); |
453 | 0 | #undef ADJUST_INTO |
454 | 0 | } |
455 | 61.6M | return 1; |
456 | 61.6M | } |
457 | | /* |
458 | | * Compute the adjustment matrix for scaling and/or rotating the page |
459 | | * to match the medium. If the medium is completely flexible in a given |
460 | | * dimension (e.g., roll media in one dimension, or displays in both), |
461 | | * we must adjust its size in that dimension to match the request. |
462 | | * We recognize this by an unreasonably small medium->p.{x,y}. |
463 | | * The PageSize Policy 3 only scales down, so 'scale' will be false if |
464 | | * the medium is larger than the request. Policy 13 scales up OR down. |
465 | | */ |
466 | | static void |
467 | | make_adjustment_matrix(const gs_point * request, const gs_rect * medium, |
468 | | gs_matrix * pmat, bool scale, int rotate) |
469 | 0 | { |
470 | 0 | double rx = request->x, ry = request->y; |
471 | 0 | double mx = medium->q.x, my = medium->q.y; |
472 | | |
473 | | /* Rotate the request if necessary. */ |
474 | 0 | if (rotate & 1) { |
475 | 0 | double temp = rx; |
476 | |
|
477 | 0 | rx = ry, ry = temp; |
478 | 0 | } |
479 | | /* If 'medium' is flexible, adjust 'mx' and 'my' towards 'rx' and 'ry', |
480 | | respectively. Note that 'mx' and 'my' have just acquired the largest |
481 | | permissible value, medium->q. */ |
482 | 0 | if (medium->p.x < mx) { /* non-empty width range */ |
483 | 0 | if (rx < medium->p.x) |
484 | 0 | mx = medium->p.x; /* use minimum of the range */ |
485 | 0 | else if (rx < mx) |
486 | 0 | mx = rx; /* fits */ |
487 | | /* else leave mx == medium->q.x, i.e., the maximum */ |
488 | 0 | } |
489 | 0 | if (medium->p.y < my) { /* non-empty height range */ |
490 | 0 | if (ry < medium->p.y) |
491 | 0 | my = medium->p.y; /* use minimum of the range */ |
492 | 0 | else if (ry < my) |
493 | 0 | my = ry; /* fits */ |
494 | | /* else leave my == medium->q.y, i.e., the maximum */ |
495 | 0 | } |
496 | | |
497 | | /* Translate to align the centers. */ |
498 | 0 | gs_make_translation(mx / 2, my / 2, pmat); |
499 | | |
500 | | /* Rotate if needed. */ |
501 | 0 | if (rotate) |
502 | 0 | gs_matrix_rotate(pmat, 90.0 * rotate, pmat); |
503 | | |
504 | | /* Scale if needed. */ |
505 | 0 | if (scale) { |
506 | 0 | double xfactor = mx / rx; |
507 | 0 | double yfactor = my / ry; |
508 | 0 | double factor = min(xfactor, yfactor); |
509 | |
|
510 | 0 | gs_matrix_scale(pmat, factor, factor, pmat); |
511 | 0 | } |
512 | | /* Now translate the origin back, */ |
513 | | /* using the original, unswapped request. */ |
514 | 0 | gs_matrix_translate(pmat, -request->x / 2, -request->y / 2, pmat); |
515 | 0 | } |
516 | | #undef MIN_MEDIA_SIZE |
517 | | |
518 | | /* ------ Initialization procedure ------ */ |
519 | | |
520 | | const op_def zmedia2_l2_op_defs[] = |
521 | | { |
522 | | op_def_begin_level2(), |
523 | | {"4.matchmedia", zmatchmedia}, |
524 | | {"6.matchpagesize", zmatchpagesize}, |
525 | | op_def_end(0) |
526 | | }; |