1/*
2 * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26
27/*
28 * DESCRIPTION
29 * Calculates cliping boundary for Affine functions.
30 *
31 */
32
33#include "mlib_image.h"
34#include "mlib_SysMath.h"
35#include "mlib_ImageAffine.h"
36#include "safe_math.h"
37
38
39/***************************************************************/
40mlib_status mlib_AffineEdges(mlib_affine_param *param,
41 const mlib_image *dst,
42 const mlib_image *src,
43 void *buff_lcl,
44 mlib_s32 buff_size,
45 mlib_s32 kw,
46 mlib_s32 kh,
47 mlib_s32 kw1,
48 mlib_s32 kh1,
49 mlib_edge edge,
50 const mlib_d64 *mtx,
51 mlib_s32 shiftx,
52 mlib_s32 shifty)
53{
54 mlib_u8 *buff = buff_lcl;
55 mlib_u8 **lineAddr = param->lineAddr;
56 mlib_s32 srcWidth, dstWidth, srcHeight, dstHeight, srcYStride, dstYStride;
57 mlib_s32 *leftEdges, *rightEdges, *xStarts, *yStarts, bsize0, bsize1 = 0;
58 mlib_u8 *srcData, *dstData;
59 mlib_u8 *paddings;
60 void *warp_tbl = NULL;
61 mlib_s32 yStart = 0, yFinish = -1, dX, dY;
62
63 mlib_d64 xClip, yClip, wClip, hClip;
64 mlib_d64 delta = 0.;
65 mlib_d64 minX, minY, maxX, maxY;
66
67 mlib_d64 coords[4][2];
68 mlib_d64 a = mtx[0], b = mtx[1], tx = mtx[2], c = mtx[3], d = mtx[4], ty = mtx[5];
69 mlib_d64 a2, b2, tx2, c2, d2, ty2;
70 mlib_d64 dx, dy, div;
71 mlib_s32 sdx, sdy;
72 mlib_d64 dTop;
73 mlib_d64 val0;
74 mlib_s32 top, bot;
75 mlib_s32 topIdx, max_xsize = 0;
76 mlib_s32 i, j, t;
77
78 srcData = mlib_ImageGetData(src);
79 dstData = mlib_ImageGetData(dst);
80 srcWidth = mlib_ImageGetWidth(src);
81 srcHeight = mlib_ImageGetHeight(src);
82 dstWidth = mlib_ImageGetWidth(dst);
83 dstHeight = mlib_ImageGetHeight(dst);
84 srcYStride = mlib_ImageGetStride(src);
85 dstYStride = mlib_ImageGetStride(dst);
86 paddings = mlib_ImageGetPaddings(src);
87
88 /* All the transformation matrix parameters should be finite. if not, return failure */
89 if (!(IS_FINITE(a) && IS_FINITE(b) && IS_FINITE(c) && IS_FINITE(d) &&
90 IS_FINITE(tx) && IS_FINITE(ty))) {
91 return MLIB_FAILURE;
92 }
93
94 if (srcWidth >= (1 << 15) || srcHeight >= (1 << 15)) {
95 return MLIB_FAILURE;
96 }
97
98 div = a * d - b * c;
99
100 if (div == 0.0) {
101 return MLIB_FAILURE;
102 }
103
104 bsize0 = (dstHeight * sizeof(mlib_s32) + 7) & ~7;
105
106 if (lineAddr == NULL) {
107 bsize1 = ((srcHeight + 4 * kh) * sizeof(mlib_u8 *) + 7) & ~7;
108 }
109
110 param->buff_malloc = NULL;
111
112 if ((4 * bsize0 + bsize1) > buff_size) {
113 buff = param->buff_malloc = mlib_malloc(4 * bsize0 + bsize1);
114
115 if (buff == NULL)
116 return MLIB_FAILURE;
117 }
118
119 leftEdges = (mlib_s32 *) (buff);
120 rightEdges = (mlib_s32 *) (buff += bsize0);
121 xStarts = (mlib_s32 *) (buff += bsize0);
122 yStarts = (mlib_s32 *) (buff += bsize0);
123
124 if (lineAddr == NULL) {
125 mlib_u8 *srcLinePtr = srcData;
126 lineAddr = (mlib_u8 **) (buff += bsize0);
127 for (i = 0; i < 2 * kh; i++)
128 lineAddr[i] = srcLinePtr;
129 lineAddr += 2 * kh;
130 for (i = 0; i < srcHeight - 1; i++) {
131 lineAddr[i] = srcLinePtr;
132 srcLinePtr += srcYStride;
133 }
134
135 for (i = srcHeight - 1; i < srcHeight + 2 * kh; i++)
136 lineAddr[i] = srcLinePtr;
137 }
138
139 if ((mlib_s32) edge < 0) { /* process edges */
140 minX = 0;
141 minY = 0;
142 maxX = srcWidth;
143 maxY = srcHeight;
144 }
145 else {
146
147 if (kw > 1)
148 delta = -0.5; /* for MLIB_NEAREST filter delta = 0. */
149
150 minX = (kw1 - delta);
151 minY = (kh1 - delta);
152 maxX = srcWidth - ((kw - 1) - (kw1 - delta));
153 maxY = srcHeight - ((kh - 1) - (kh1 - delta));
154
155 if (edge == MLIB_EDGE_SRC_PADDED) {
156 if (minX < paddings[0])
157 minX = paddings[0];
158
159 if (minY < paddings[1])
160 minY = paddings[1];
161
162 if (maxX > (srcWidth - paddings[2]))
163 maxX = srcWidth - paddings[2];
164
165 if (maxY > (srcHeight - paddings[3]))
166 maxY = srcHeight - paddings[3];
167 }
168 }
169
170 xClip = minX;
171 yClip = minY;
172 wClip = maxX;
173 hClip = maxY;
174
175/*
176 * STORE_PARAM(param, src);
177 * STORE_PARAM(param, dst);
178 */
179 param->src = (void *)src;
180 param->dst = (void *)dst;
181 STORE_PARAM(param, lineAddr);
182 STORE_PARAM(param, dstData);
183 STORE_PARAM(param, srcYStride);
184 STORE_PARAM(param, dstYStride);
185 STORE_PARAM(param, leftEdges);
186 STORE_PARAM(param, rightEdges);
187 STORE_PARAM(param, xStarts);
188 STORE_PARAM(param, yStarts);
189 STORE_PARAM(param, max_xsize);
190 STORE_PARAM(param, yStart);
191 STORE_PARAM(param, yFinish);
192 STORE_PARAM(param, warp_tbl);
193
194 if ((xClip >= wClip) || (yClip >= hClip)) {
195 return MLIB_SUCCESS;
196 }
197
198 a2 = d;
199 b2 = -b;
200 tx2 = (-d * tx + b * ty);
201 c2 = -c;
202 d2 = a;
203 ty2 = (c * tx - a * ty);
204
205 dx = a2;
206 dy = c2;
207
208 tx -= 0.5;
209 ty -= 0.5;
210
211 coords[0][0] = xClip * a + yClip * b + tx;
212 coords[0][1] = xClip * c + yClip * d + ty;
213
214 coords[2][0] = wClip * a + hClip * b + tx;
215 coords[2][1] = wClip * c + hClip * d + ty;
216
217 if (div > 0) {
218 coords[1][0] = wClip * a + yClip * b + tx;
219 coords[1][1] = wClip * c + yClip * d + ty;
220
221 coords[3][0] = xClip * a + hClip * b + tx;
222 coords[3][1] = xClip * c + hClip * d + ty;
223 }
224 else {
225 coords[3][0] = wClip * a + yClip * b + tx;
226 coords[3][1] = wClip * c + yClip * d + ty;
227
228 coords[1][0] = xClip * a + hClip * b + tx;
229 coords[1][1] = xClip * c + hClip * d + ty;
230 }
231
232 topIdx = 0;
233 for (i = 1; i < 4; i++) {
234
235 if (coords[i][1] < coords[topIdx][1])
236 topIdx = i;
237 }
238
239 dTop = coords[topIdx][1];
240 val0 = dTop;
241 SAT32(top);
242 bot = -1;
243
244 if (top >= dstHeight) {
245 return MLIB_SUCCESS;
246 }
247
248 if (dTop >= 0.0) {
249 mlib_d64 xLeft, xRight, x;
250 mlib_s32 nextIdx;
251
252 if (dTop == top) {
253 xLeft = coords[topIdx][0];
254 xRight = coords[topIdx][0];
255 nextIdx = (topIdx + 1) & 0x3;
256
257 if (dTop == coords[nextIdx][1]) {
258 x = coords[nextIdx][0];
259 xLeft = (xLeft <= x) ? xLeft : x;
260 xRight = (xRight >= x) ? xRight : x;
261 }
262
263 nextIdx = (topIdx - 1) & 0x3;
264
265 if (dTop == coords[nextIdx][1]) {
266 x = coords[nextIdx][0];
267 xLeft = (xLeft <= x) ? xLeft : x;
268 xRight = (xRight >= x) ? xRight : x;
269 }
270
271 val0 = xLeft;
272 SAT32(t);
273 leftEdges[top] = (t >= xLeft) ? t : ++t;
274
275 if (xLeft >= MLIB_S32_MAX)
276 leftEdges[top] = MLIB_S32_MAX;
277
278 val0 = xRight;
279 SAT32(rightEdges[top]);
280 }
281 else
282 top++;
283 }
284 else
285 top = 0;
286
287 for (i = 0; i < 2; i++) {
288 mlib_d64 dY1 = coords[(topIdx - i) & 0x3][1];
289 mlib_d64 dX1 = coords[(topIdx - i) & 0x3][0];
290 mlib_d64 dY2 = coords[(topIdx - i - 1) & 0x3][1];
291 mlib_d64 dX2 = coords[(topIdx - i - 1) & 0x3][0];
292 mlib_d64 x = dX1, slope = (dX2 - dX1) / (dY2 - dY1);
293 mlib_s32 y1;
294 mlib_s32 y2;
295
296 if (dY1 == dY2)
297 continue;
298
299 if (!(IS_FINITE(slope))) {
300 continue;
301 }
302
303 if (dY1 < 0.0)
304 y1 = 0;
305 else {
306 val0 = dY1 + 1;
307 SAT32(y1);
308 }
309
310 val0 = dY2;
311 SAT32(y2);
312
313 if (y2 >= dstHeight)
314 y2 = (mlib_s32) (dstHeight - 1);
315
316 x += slope * (y1 - dY1);
317#ifdef __SUNPRO_C
318#pragma pipeloop(0)
319#endif /* __SUNPRO_C */
320 for (j = y1; j <= y2; j++) {
321 val0 = x;
322 SAT32(t);
323 leftEdges[j] = (t >= x) ? t : ++t;
324
325 if (x >= MLIB_S32_MAX)
326 leftEdges[j] = MLIB_S32_MAX;
327 x += slope;
328 }
329 }
330
331 for (i = 0; i < 2; i++) {
332 mlib_d64 dY1 = coords[(topIdx + i) & 0x3][1];
333 mlib_d64 dX1 = coords[(topIdx + i) & 0x3][0];
334 mlib_d64 dY2 = coords[(topIdx + i + 1) & 0x3][1];
335 mlib_d64 dX2 = coords[(topIdx + i + 1) & 0x3][0];
336 mlib_d64 x = dX1, slope = (dX2 - dX1) / (dY2 - dY1);
337 mlib_s32 y1;
338 mlib_s32 y2;
339
340 if (dY1 == dY2)
341 continue;
342
343 if (!(IS_FINITE(slope))) {
344 continue;
345 }
346
347 if (dY1 < 0.0)
348 y1 = 0;
349 else {
350 val0 = dY1 + 1;
351 SAT32(y1);
352 }
353
354 val0 = dY2;
355 SAT32(y2);
356
357 if (y2 >= dstHeight)
358 y2 = (mlib_s32) (dstHeight - 1);
359
360 x += slope * (y1 - dY1);
361#ifdef __SUNPRO_C
362#pragma pipeloop(0)
363#endif /* __SUNPRO_C */
364 for (j = y1; j <= y2; j++) {
365 val0 = x;
366 SAT32(rightEdges[j]);
367 x += slope;
368 }
369
370 bot = y2;
371 }
372
373 {
374 mlib_d64 dxCl = xClip * div;
375 mlib_d64 dyCl = yClip * div;
376 mlib_d64 dwCl = wClip * div;
377 mlib_d64 dhCl = hClip * div;
378
379 mlib_s32 xCl = (mlib_s32) (xClip + delta);
380 mlib_s32 yCl = (mlib_s32) (yClip + delta);
381 mlib_s32 wCl = (mlib_s32) (wClip + delta);
382 mlib_s32 hCl = (mlib_s32) (hClip + delta);
383
384 /*
385 * mlib_s32 xCl = (mlib_s32)(xClip + delta);
386 * mlib_s32 yCl = (mlib_s32)(yClip + delta);
387 * mlib_s32 wCl = (mlib_s32)(wClip);
388 * mlib_s32 hCl = (mlib_s32)(hClip);
389 */
390
391 if (edge == MLIB_EDGE_SRC_PADDED) {
392 xCl = kw1;
393 yCl = kh1;
394 wCl = (mlib_s32) (srcWidth - ((kw - 1) - kw1));
395 hCl = (mlib_s32) (srcHeight - ((kh - 1) - kh1));
396 }
397
398 div = 1.0 / div;
399
400 sdx = (mlib_s32) (a2 * div * (1 << shiftx));
401 sdy = (mlib_s32) (c2 * div * (1 << shifty));
402
403 if (div > 0) {
404
405#ifdef __SUNPRO_C
406#pragma pipeloop(0)
407#endif /* __SUNPRO_C */
408 for (i = top; i <= bot; i++) {
409 mlib_s32 xLeft = leftEdges[i];
410 mlib_s32 xRight = rightEdges[i];
411 mlib_s32 xs, ys, x_e, y_e, x_s, y_s;
412 mlib_d64 dxs, dys, dxe, dye;
413 mlib_d64 xl, ii, xr;
414
415 xLeft = (xLeft < 0) ? 0 : xLeft;
416 xRight = (xRight >= dstWidth) ? (mlib_s32) (dstWidth - 1) : xRight;
417
418 xl = xLeft + 0.5;
419 ii = i + 0.5;
420 xr = xRight + 0.5;
421 dxs = xl * a2 + ii * b2 + tx2;
422 dys = xl * c2 + ii * d2 + ty2;
423
424 if ((dxs < dxCl) || (dxs >= dwCl) || (dys < dyCl) || (dys >= dhCl)) {
425 dxs += dx;
426 dys += dy;
427 xLeft++;
428
429 if ((dxs < dxCl) || (dxs >= dwCl) || (dys < dyCl) || (dys >= dhCl))
430 xRight = -1;
431 }
432
433 dxe = xr * a2 + ii * b2 + tx2;
434 dye = xr * c2 + ii * d2 + ty2;
435
436 if ((dxe < dxCl) || (dxe >= dwCl) || (dye < dyCl) || (dye >= dhCl)) {
437 dxe -= dx;
438 dye -= dy;
439 xRight--;
440
441 if ((dxe < dxCl) || (dxe >= dwCl) || (dye < dyCl) || (dye >= dhCl))
442 xRight = -1;
443 }
444
445 xs = (mlib_s32) ((dxs * div + delta) * (1 << shiftx));
446 x_s = xs >> shiftx;
447
448 ys = (mlib_s32) ((dys * div + delta) * (1 << shifty));
449 y_s = ys >> shifty;
450
451 if (x_s < xCl)
452 xs = (xCl << shiftx);
453 else if (x_s >= wCl)
454 xs = ((wCl << shiftx) - 1);
455
456 if (y_s < yCl)
457 ys = (yCl << shifty);
458 else if (y_s >= hCl)
459 ys = ((hCl << shifty) - 1);
460
461 if (xRight >= xLeft) {
462 x_e = ((xRight - xLeft) * sdx + xs) >> shiftx;
463 y_e = ((xRight - xLeft) * sdy + ys) >> shifty;
464
465 if ((x_e < xCl) || (x_e >= wCl)) {
466 if (sdx > 0)
467 sdx -= 1;
468 else
469 sdx += 1;
470 }
471
472 if ((y_e < yCl) || (y_e >= hCl)) {
473 if (sdy > 0)
474 sdy -= 1;
475 else
476 sdy += 1;
477 }
478 }
479
480 leftEdges[i] = xLeft;
481 rightEdges[i] = xRight;
482 xStarts[i] = xs;
483 yStarts[i] = ys;
484
485 if ((xRight - xLeft + 1) > max_xsize)
486 max_xsize = (xRight - xLeft + 1);
487 }
488 }
489 else {
490
491#ifdef __SUNPRO_C
492#pragma pipeloop(0)
493#endif /* __SUNPRO_C */
494 for (i = top; i <= bot; i++) {
495 mlib_s32 xLeft = leftEdges[i];
496 mlib_s32 xRight = rightEdges[i];
497 mlib_s32 xs, ys, x_e, y_e, x_s, y_s;
498 mlib_d64 dxs, dys, dxe, dye;
499 mlib_d64 xl, ii, xr;
500
501 xLeft = (xLeft < 0) ? 0 : xLeft;
502 xRight = (xRight >= dstWidth) ? (mlib_s32) (dstWidth - 1) : xRight;
503
504 xl = xLeft + 0.5;
505 ii = i + 0.5;
506 xr = xRight + 0.5;
507 dxs = xl * a2 + ii * b2 + tx2;
508 dys = xl * c2 + ii * d2 + ty2;
509
510 if ((dxs > dxCl) || (dxs <= dwCl) || (dys > dyCl) || (dys <= dhCl)) {
511 dxs += dx;
512 dys += dy;
513 xLeft++;
514
515 if ((dxs > dxCl) || (dxs <= dwCl) || (dys > dyCl) || (dys <= dhCl))
516 xRight = -1;
517 }
518
519 dxe = xr * a2 + ii * b2 + tx2;
520 dye = xr * c2 + ii * d2 + ty2;
521
522 if ((dxe > dxCl) || (dxe <= dwCl) || (dye > dyCl) || (dye <= dhCl)) {
523 dxe -= dx;
524 dye -= dy;
525 xRight--;
526
527 if ((dxe > dxCl) || (dxe <= dwCl) || (dye > dyCl) || (dye <= dhCl))
528 xRight = -1;
529 }
530
531 xs = (mlib_s32) ((dxs * div + delta) * (1 << shiftx));
532 x_s = xs >> shiftx;
533
534 if (x_s < xCl)
535 xs = (xCl << shiftx);
536 else if (x_s >= wCl)
537 xs = ((wCl << shiftx) - 1);
538
539 ys = (mlib_s32) ((dys * div + delta) * (1 << shifty));
540 y_s = ys >> shifty;
541
542 if (y_s < yCl)
543 ys = (yCl << shifty);
544 else if (y_s >= hCl)
545 ys = ((hCl << shifty) - 1);
546
547 if (xRight >= xLeft) {
548 x_e = ((xRight - xLeft) * sdx + xs) >> shiftx;
549 y_e = ((xRight - xLeft) * sdy + ys) >> shifty;
550
551 if ((x_e < xCl) || (x_e >= wCl)) {
552 if (sdx > 0)
553 sdx -= 1;
554 else
555 sdx += 1;
556 }
557
558 if ((y_e < yCl) || (y_e >= hCl)) {
559 if (sdy > 0)
560 sdy -= 1;
561 else
562 sdy += 1;
563 }
564 }
565
566 leftEdges[i] = xLeft;
567 rightEdges[i] = xRight;
568 xStarts[i] = xs;
569 yStarts[i] = ys;
570
571 if ((xRight - xLeft + 1) > max_xsize)
572 max_xsize = (xRight - xLeft + 1);
573 }
574 }
575 }
576
577 while (leftEdges[top] > rightEdges[top] && top <= bot)
578 top++;
579
580 if (top < bot)
581 while (leftEdges[bot] > rightEdges[bot])
582 bot--;
583
584 yStart = top;
585 yFinish = bot;
586 dX = sdx;
587 dY = sdy;
588
589 dstData += (yStart - 1) * dstYStride;
590
591 STORE_PARAM(param, dstData);
592 STORE_PARAM(param, yStart);
593 STORE_PARAM(param, yFinish);
594 STORE_PARAM(param, max_xsize);
595 STORE_PARAM(param, dX);
596 STORE_PARAM(param, dY);
597
598 return MLIB_SUCCESS;
599}
600
601/***************************************************************/
602