Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7643 views
1
#include "mupdf/fitz.h"
2
#include "draw-imp.h"
3
4
typedef unsigned char byte;
5
6
static inline float roundup(float x)
7
{
8
return (x < 0) ? floorf(x) : ceilf(x);
9
}
10
11
static inline int lerp(int a, int b, int t)
12
{
13
return a + (((b - a) * t) >> 16);
14
}
15
16
static inline int bilerp(int a, int b, int c, int d, int u, int v)
17
{
18
return lerp(lerp(a, b, u), lerp(c, d, u), v);
19
}
20
21
static inline byte *sample_nearest(byte *s, int w, int h, int n, int u, int v)
22
{
23
if (u < 0) u = 0;
24
if (v < 0) v = 0;
25
if (u >= w) u = w - 1;
26
if (v >= h) v = h - 1;
27
return s + (v * w + u) * n;
28
}
29
30
/* Blend premultiplied source image in constant alpha over destination */
31
32
static inline void
33
fz_paint_affine_alpha_N_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha, byte *hp)
34
{
35
int k;
36
int n1 = n-1;
37
38
while (w--)
39
{
40
int ui = u >> 16;
41
int vi = v >> 16;
42
if (ui >= 0 && ui < sw && vi >= 0 && vi < sh)
43
{
44
int uf = u & 0xffff;
45
int vf = v & 0xffff;
46
byte *a = sample_nearest(sp, sw, sh, n, ui, vi);
47
byte *b = sample_nearest(sp, sw, sh, n, ui+1, vi);
48
byte *c = sample_nearest(sp, sw, sh, n, ui, vi+1);
49
byte *d = sample_nearest(sp, sw, sh, n, ui+1, vi+1);
50
int xa = bilerp(a[n1], b[n1], c[n1], d[n1], uf, vf);
51
int t;
52
xa = fz_mul255(xa, alpha);
53
t = 255 - xa;
54
for (k = 0; k < n1; k++)
55
{
56
int x = bilerp(a[k], b[k], c[k], d[k], uf, vf);
57
dp[k] = fz_mul255(x, alpha) + fz_mul255(dp[k], t);
58
}
59
dp[n1] = xa + fz_mul255(dp[n1], t);
60
if (hp)
61
hp[0] = xa + fz_mul255(hp[0], t);
62
}
63
dp += n;
64
if (hp)
65
hp++;
66
u += fa;
67
v += fb;
68
}
69
}
70
71
/* Special case code for gray -> rgb */
72
static inline void
73
fz_paint_affine_alpha_g2rgb_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int alpha, byte *hp)
74
{
75
while (w--)
76
{
77
int ui = u >> 16;
78
int vi = v >> 16;
79
if (ui >= 0 && ui < sw && vi >= 0 && vi < sh)
80
{
81
int uf = u & 0xffff;
82
int vf = v & 0xffff;
83
byte *a = sample_nearest(sp, sw, sh, 2, ui, vi);
84
byte *b = sample_nearest(sp, sw, sh, 2, ui+1, vi);
85
byte *c = sample_nearest(sp, sw, sh, 2, ui, vi+1);
86
byte *d = sample_nearest(sp, sw, sh, 2, ui+1, vi+1);
87
int y = bilerp(a[1], b[1], c[1], d[1], uf, vf);
88
int x = bilerp(a[0], b[0], c[0], d[0], uf, vf);
89
int t;
90
x = fz_mul255(x, alpha);
91
y = fz_mul255(y, alpha);
92
t = 255 - y;
93
dp[0] = x + fz_mul255(dp[0], t);
94
dp[1] = x + fz_mul255(dp[1], t);
95
dp[2] = x + fz_mul255(dp[2], t);
96
dp[3] = y + fz_mul255(dp[3], t);
97
if (hp)
98
hp[0] = y + fz_mul255(hp[0], t);
99
}
100
dp += 4;
101
if (hp)
102
hp++;
103
u += fa;
104
v += fb;
105
}
106
}
107
108
static inline void
109
fz_paint_affine_alpha_N_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha, byte *hp)
110
{
111
int k;
112
int n1 = n-1;
113
114
if (fa == 0)
115
{
116
int ui = u >> 16;
117
if (ui < 0 || ui >= sw)
118
return;
119
sp += ui * n;
120
sw *= n;
121
while (w--)
122
{
123
int vi = v >> 16;
124
if (vi >= 0 && vi < sh)
125
{
126
byte *sample = sp + (vi * sw);
127
int a = fz_mul255(sample[n-1], alpha);
128
int t = 255 - a;
129
for (k = 0; k < n1; k++)
130
dp[k] = fz_mul255(sample[k], alpha) + fz_mul255(dp[k], t);
131
dp[n1] = a + fz_mul255(dp[n1], t);
132
if (hp)
133
hp[0] = a + fz_mul255(hp[0], t);
134
}
135
dp += n;
136
if (hp)
137
hp++;
138
v += fb;
139
}
140
}
141
else if (fb == 0)
142
{
143
int vi = v >> 16;
144
if (vi < 0 || vi >= sh)
145
return;
146
sp += vi * sw * n;
147
while (w--)
148
{
149
int ui = u >> 16;
150
if (ui >= 0 && ui < sw)
151
{
152
byte *sample = sp + (ui * n);
153
int a = fz_mul255(sample[n-1], alpha);
154
int t = 255 - a;
155
for (k = 0; k < n1; k++)
156
dp[k] = fz_mul255(sample[k], alpha) + fz_mul255(dp[k], t);
157
dp[n1] = a + fz_mul255(dp[n1], t);
158
if (hp)
159
hp[0] = a + fz_mul255(hp[0], t);
160
}
161
dp += n;
162
if (hp)
163
hp++;
164
u += fa;
165
}
166
}
167
else
168
{
169
while (w--)
170
{
171
int ui = u >> 16;
172
int vi = v >> 16;
173
if (ui >= 0 && ui < sw && vi >= 0 && vi < sh)
174
{
175
byte *sample = sp + ((vi * sw + ui) * n);
176
int a = fz_mul255(sample[n-1], alpha);
177
int t = 255 - a;
178
for (k = 0; k < n1; k++)
179
dp[k] = fz_mul255(sample[k], alpha) + fz_mul255(dp[k], t);
180
dp[n1] = a + fz_mul255(dp[n1], t);
181
if (hp)
182
hp[0] = a + fz_mul255(hp[0], t);
183
}
184
dp += n;
185
if (hp)
186
hp++;
187
u += fa;
188
v += fb;
189
}
190
}
191
}
192
193
static inline void
194
fz_paint_affine_alpha_g2rgb_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int alpha, byte *hp)
195
{
196
if (fa == 0)
197
{
198
int ui = u >> 16;
199
if (ui < 0 || ui >= sw)
200
return;
201
sp += ui * 2;
202
sw *= 2;
203
while (w--)
204
{
205
int vi = v >> 16;
206
if (vi >= 0 && vi < sh)
207
{
208
byte *sample = sp + (vi * sw);
209
int x = fz_mul255(sample[0], alpha);
210
int a = fz_mul255(sample[1], alpha);
211
int t = 255 - a;
212
dp[0] = x + fz_mul255(dp[0], t);
213
dp[1] = x + fz_mul255(dp[1], t);
214
dp[2] = x + fz_mul255(dp[2], t);
215
dp[3] = a + fz_mul255(dp[3], t);
216
if (hp)
217
hp[0] = a + fz_mul255(hp[0], t);
218
}
219
dp += 4;
220
if (hp)
221
hp++;
222
v += fb;
223
}
224
}
225
else if (fb == 0)
226
{
227
int vi = v >> 16;
228
if (vi < 0 || vi >= sh)
229
return;
230
sp += vi * sw * 2;
231
while (w--)
232
{
233
int ui = u >> 16;
234
if (ui >= 0 && ui < sw)
235
{
236
byte *sample = sp + (ui * 2);
237
int x = fz_mul255(sample[0], alpha);
238
int a = fz_mul255(sample[1], alpha);
239
int t = 255 - a;
240
dp[0] = x + fz_mul255(dp[0], t);
241
dp[1] = x + fz_mul255(dp[1], t);
242
dp[2] = x + fz_mul255(dp[2], t);
243
dp[3] = a + fz_mul255(dp[3], t);
244
if (hp)
245
hp[0] = a + fz_mul255(hp[0], t);
246
}
247
dp += 4;
248
if (hp)
249
hp++;
250
u += fa;
251
}
252
}
253
else
254
{
255
while (w--)
256
{
257
int ui = u >> 16;
258
int vi = v >> 16;
259
if (ui >= 0 && ui < sw && vi >= 0 && vi < sh)
260
{
261
byte *sample = sp + ((vi * sw + ui) * 2);
262
int x = fz_mul255(sample[0], alpha);
263
int a = fz_mul255(sample[1], alpha);
264
int t = 255 - a;
265
dp[0] = x + fz_mul255(dp[0], t);
266
dp[1] = x + fz_mul255(dp[1], t);
267
dp[2] = x + fz_mul255(dp[2], t);
268
dp[3] = a + fz_mul255(dp[3], t);
269
if (hp)
270
hp[0] = a + fz_mul255(hp[0], t);
271
}
272
dp += 4;
273
if (hp)
274
hp++;
275
u += fa;
276
v += fb;
277
}
278
}
279
}
280
281
/* Blend premultiplied source image over destination */
282
283
static inline void
284
fz_paint_affine_N_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, byte *hp)
285
{
286
int k;
287
int n1 = n-1;
288
289
while (w--)
290
{
291
int ui = u >> 16;
292
int vi = v >> 16;
293
if (ui >= 0 && ui < sw && vi >= 0 && vi < sh)
294
{
295
int uf = u & 0xffff;
296
int vf = v & 0xffff;
297
byte *a = sample_nearest(sp, sw, sh, n, ui, vi);
298
byte *b = sample_nearest(sp, sw, sh, n, ui+1, vi);
299
byte *c = sample_nearest(sp, sw, sh, n, ui, vi+1);
300
byte *d = sample_nearest(sp, sw, sh, n, ui+1, vi+1);
301
int y = bilerp(a[n1], b[n1], c[n1], d[n1], uf, vf);
302
int t = 255 - y;
303
for (k = 0; k < n1; k++)
304
{
305
int x = bilerp(a[k], b[k], c[k], d[k], uf, vf);
306
dp[k] = x + fz_mul255(dp[k], t);
307
}
308
dp[n1] = y + fz_mul255(dp[n1], t);
309
if (hp)
310
hp[0] = y + fz_mul255(hp[0], t);
311
}
312
dp += n;
313
if (hp)
314
hp++;
315
u += fa;
316
v += fb;
317
}
318
}
319
320
static inline void
321
fz_paint_affine_solid_g2rgb_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, byte *hp)
322
{
323
while (w--)
324
{
325
int ui = u >> 16;
326
int vi = v >> 16;
327
if (ui >= 0 && ui < sw && vi >= 0 && vi < sh)
328
{
329
int uf = u & 0xffff;
330
int vf = v & 0xffff;
331
byte *a = sample_nearest(sp, sw, sh, 2, ui, vi);
332
byte *b = sample_nearest(sp, sw, sh, 2, ui+1, vi);
333
byte *c = sample_nearest(sp, sw, sh, 2, ui, vi+1);
334
byte *d = sample_nearest(sp, sw, sh, 2, ui+1, vi+1);
335
int y = bilerp(a[1], b[1], c[1], d[1], uf, vf);
336
int t = 255 - y;
337
int x = bilerp(a[0], b[0], c[0], d[0], uf, vf);
338
dp[0] = x + fz_mul255(dp[0], t);
339
dp[1] = x + fz_mul255(dp[1], t);
340
dp[2] = x + fz_mul255(dp[2], t);
341
dp[3] = y + fz_mul255(dp[3], t);
342
if (hp)
343
hp[0] = y + fz_mul255(hp[0], t);
344
}
345
dp += 4;
346
if (hp)
347
hp++;
348
u += fa;
349
v += fb;
350
}
351
}
352
353
static inline void
354
fz_paint_affine_N_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, byte *hp)
355
{
356
int k;
357
int n1 = n-1;
358
359
if (fa == 0)
360
{
361
int ui = u >> 16;
362
if (ui < 0 || ui >= sw)
363
return;
364
sp += ui*n;
365
sw *= n;
366
while (w--)
367
{
368
int vi = v >> 16;
369
if (vi >= 0 && vi < sh)
370
{
371
byte *sample = sp + (vi * sw);
372
int a = sample[n1];
373
/* If a is 0, then sample[k] = 0 for all k, as premultiplied */
374
if (a != 0)
375
{
376
int t = 255 - a;
377
if (t == 0)
378
{
379
if (n == 4)
380
{
381
*(int *)dp = *(int *)sample;
382
}
383
else
384
{
385
for (k = 0; k < n1; k++)
386
dp[k] = sample[k];
387
dp[n1] = a;
388
}
389
if (hp)
390
hp[0] = a;
391
}
392
else
393
{
394
for (k = 0; k < n1; k++)
395
dp[k] = sample[k] + fz_mul255(dp[k], t);
396
dp[n1] = a + fz_mul255(dp[n1], t);
397
if (hp)
398
hp[0] = a + fz_mul255(hp[0], t);
399
}
400
}
401
}
402
dp += n;
403
if (hp)
404
hp++;
405
v += fb;
406
}
407
}
408
else if (fb == 0)
409
{
410
int vi = v >> 16;
411
if (vi < 0 || vi >= sh)
412
return;
413
sp += vi * sw * n;
414
while (w--)
415
{
416
int ui = u >> 16;
417
if (ui >= 0 && ui < sw)
418
{
419
byte *sample = sp + (ui * n);
420
int a = sample[n1];
421
/* If a is 0, then sample[k] = 0 for all k, as premultiplied */
422
if (a != 0)
423
{
424
int t = 255 - a;
425
if (t == 0)
426
{
427
if (n == 4)
428
{
429
*(int *)dp = *(int *)sample;
430
}
431
else
432
{
433
for (k = 0; k < n1; k++)
434
dp[k] = sample[k];
435
dp[n1] = a;
436
}
437
if (hp)
438
hp[0] = a;
439
}
440
else
441
{
442
for (k = 0; k < n1; k++)
443
dp[k] = sample[k] + fz_mul255(dp[k], t);
444
dp[n1] = a + fz_mul255(dp[n1], t);
445
if (hp)
446
hp[0] = a + fz_mul255(hp[0], t);
447
}
448
}
449
}
450
dp += n;
451
if (hp)
452
hp++;
453
u += fa;
454
}
455
}
456
else
457
{
458
while (w--)
459
{
460
int ui = u >> 16;
461
int vi = v >> 16;
462
if (ui >= 0 && ui < sw && vi >= 0 && vi < sh)
463
{
464
byte *sample = sp + ((vi * sw + ui) * n);
465
int a = sample[n1];
466
/* If a is 0, then sample[k] = 0 for all k, as premultiplied */
467
if (a != 0)
468
{
469
int t = 255 - a;
470
if (t == 0)
471
{
472
if (n == 4)
473
{
474
*(int *)dp = *(int *)sample;
475
}
476
else
477
{
478
for (k = 0; k < n1; k++)
479
dp[k] = sample[k];
480
dp[n1] = a;
481
}
482
if (hp)
483
hp[0] = a;
484
}
485
else
486
{
487
for (k = 0; k < n1; k++)
488
dp[k] = sample[k] + fz_mul255(dp[k], t);
489
dp[n1] = a + fz_mul255(dp[n1], t);
490
if (hp)
491
hp[0] = a + fz_mul255(hp[0], t);
492
}
493
}
494
}
495
dp += n;
496
if (hp)
497
hp++;
498
u += fa;
499
v += fb;
500
}
501
}
502
}
503
504
static inline void
505
fz_paint_affine_solid_g2rgb_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, byte *hp)
506
{
507
if (fa == 0)
508
{
509
int ui = u >> 16;
510
if (ui < 0 || ui >= sw)
511
return;
512
sp += ui * 2;
513
sw *= 2;
514
while (w--)
515
{
516
int vi = v >> 16;
517
if (vi >= 0 && vi < sh)
518
{
519
byte *sample = sp + (vi * sw);
520
int a = sample[1];
521
if (a != 0)
522
{
523
int x = sample[0];
524
int t = 255 - a;
525
if (t == 0)
526
{
527
dp[0] = x;
528
dp[1] = x;
529
dp[2] = x;
530
dp[3] = a;
531
if (hp)
532
hp[0] = a;
533
}
534
else
535
{
536
dp[0] = x + fz_mul255(dp[0], t);
537
dp[1] = x + fz_mul255(dp[1], t);
538
dp[2] = x + fz_mul255(dp[2], t);
539
dp[3] = a + fz_mul255(dp[3], t);
540
if (hp)
541
hp[0] = a + fz_mul255(hp[0], t);
542
}
543
}
544
}
545
dp += 4;
546
if (hp)
547
hp++;
548
v += fb;
549
}
550
}
551
else if (fb == 0)
552
{
553
int vi = v >> 16;
554
if (vi < 0 || vi >= sh)
555
return;
556
sp += vi * sw * 2;
557
while (w--)
558
{
559
int ui = u >> 16;
560
if (ui >= 0 && ui < sw)
561
{
562
byte *sample = sp + (ui * 2);
563
int a = sample[1];
564
if (a != 0)
565
{
566
int x = sample[0];
567
int t = 255 - a;
568
if (t == 0)
569
{
570
dp[0] = x;
571
dp[1] = x;
572
dp[2] = x;
573
dp[3] = a;
574
if (hp)
575
hp[0] = a;
576
}
577
else
578
{
579
dp[0] = x + fz_mul255(dp[0], t);
580
dp[1] = x + fz_mul255(dp[1], t);
581
dp[2] = x + fz_mul255(dp[2], t);
582
dp[3] = a + fz_mul255(dp[3], t);
583
if (hp)
584
hp[0] = a + fz_mul255(hp[0], t);
585
}
586
}
587
}
588
dp += 4;
589
if (hp)
590
hp++;
591
u += fa;
592
}
593
}
594
else
595
{
596
while (w--)
597
{
598
int ui = u >> 16;
599
int vi = v >> 16;
600
if (ui >= 0 && ui < sw && vi >= 0 && vi < sh)
601
{
602
byte *sample = sp + ((vi * sw + ui) * 2);
603
int a = sample[1];
604
if (a != 0)
605
{
606
int x = sample[0];
607
int t = 255 - a;
608
if (t == 0)
609
{
610
dp[0] = x;
611
dp[1] = x;
612
dp[2] = x;
613
dp[3] = a;
614
if (hp)
615
hp[0] = a;
616
}
617
else
618
{
619
dp[0] = x + fz_mul255(dp[0], t);
620
dp[1] = x + fz_mul255(dp[1], t);
621
dp[2] = x + fz_mul255(dp[2], t);
622
dp[3] = a + fz_mul255(dp[3], t);
623
if (hp)
624
hp[0] = a + fz_mul255(hp[0], t);
625
}
626
}
627
}
628
dp += 4;
629
if (hp)
630
hp++;
631
u += fa;
632
v += fb;
633
}
634
}
635
}
636
637
/* Blend non-premultiplied color in source image mask over destination */
638
639
static inline void
640
fz_paint_affine_color_N_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, byte *color, byte *hp)
641
{
642
int n1 = n - 1;
643
int sa = color[n1];
644
int k;
645
646
while (w--)
647
{
648
int ui = u >> 16;
649
int vi = v >> 16;
650
if (ui >= 0 && ui < sw && vi >= 0 && vi < sh)
651
{
652
int uf = u & 0xffff;
653
int vf = v & 0xffff;
654
byte *a = sample_nearest(sp, sw, sh, 1, ui, vi);
655
byte *b = sample_nearest(sp, sw, sh, 1, ui+1, vi);
656
byte *c = sample_nearest(sp, sw, sh, 1, ui, vi+1);
657
byte *d = sample_nearest(sp, sw, sh, 1, ui+1, vi+1);
658
int ma = bilerp(a[0], b[0], c[0], d[0], uf, vf);
659
int masa = FZ_COMBINE(FZ_EXPAND(ma), sa);
660
for (k = 0; k < n1; k++)
661
dp[k] = FZ_BLEND(color[k], dp[k], masa);
662
dp[n1] = FZ_BLEND(255, dp[n1], masa);
663
if (hp)
664
hp[0] = FZ_BLEND(255, hp[0], masa);
665
}
666
dp += n;
667
if (hp)
668
hp++;
669
u += fa;
670
v += fb;
671
}
672
}
673
674
static inline void
675
fz_paint_affine_color_N_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, byte *color, byte *hp)
676
{
677
int n1 = n-1;
678
int sa = color[n1];
679
int k;
680
681
while (w--)
682
{
683
int ui = u >> 16;
684
int vi = v >> 16;
685
if (ui >= 0 && ui < sw && vi >= 0 && vi < sh)
686
{
687
int ma = sp[vi * sw + ui];
688
int masa = FZ_COMBINE(FZ_EXPAND(ma), sa);
689
for (k = 0; k < n1; k++)
690
dp[k] = FZ_BLEND(color[k], dp[k], masa);
691
dp[n1] = FZ_BLEND(255, dp[n1], masa);
692
if (hp)
693
hp[0] = FZ_BLEND(255, hp[0], masa);
694
}
695
dp += n;
696
if (hp)
697
hp++;
698
u += fa;
699
v += fb;
700
}
701
}
702
703
static void
704
fz_paint_affine_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha, byte *color/*unused*/, byte *hp)
705
{
706
if (alpha == 255)
707
{
708
switch (n)
709
{
710
case 1: fz_paint_affine_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 1, hp); break;
711
case 2: fz_paint_affine_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 2, hp); break;
712
case 4: fz_paint_affine_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 4, hp); break;
713
default: fz_paint_affine_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, n, hp); break;
714
}
715
}
716
else if (alpha > 0)
717
{
718
switch (n)
719
{
720
case 1: fz_paint_affine_alpha_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 1, alpha, hp); break;
721
case 2: fz_paint_affine_alpha_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 2, alpha, hp); break;
722
case 4: fz_paint_affine_alpha_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 4, alpha, hp); break;
723
default: fz_paint_affine_alpha_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, n, alpha, hp); break;
724
}
725
}
726
}
727
728
static void
729
fz_paint_affine_g2rgb_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha, byte *color/*unused*/, byte *hp)
730
{
731
if (alpha == 255)
732
{
733
fz_paint_affine_solid_g2rgb_lerp(dp, sp, sw, sh, u, v, fa, fb, w, hp);
734
}
735
else if (alpha > 0)
736
{
737
fz_paint_affine_alpha_g2rgb_lerp(dp, sp, sw, sh, u, v, fa, fb, w, alpha, hp);
738
}
739
}
740
741
static void
742
fz_paint_affine_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha, byte *color/*unused */, byte *hp)
743
{
744
if (alpha == 255)
745
{
746
switch (n)
747
{
748
case 1: fz_paint_affine_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 1, hp); break;
749
case 2: fz_paint_affine_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 2, hp); break;
750
case 4: fz_paint_affine_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 4, hp); break;
751
default: fz_paint_affine_N_near(dp, sp, sw, sh, u, v, fa, fb, w, n, hp); break;
752
}
753
}
754
else if (alpha > 0)
755
{
756
switch (n)
757
{
758
case 1: fz_paint_affine_alpha_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 1, alpha, hp); break;
759
case 2: fz_paint_affine_alpha_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 2, alpha, hp); break;
760
case 4: fz_paint_affine_alpha_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 4, alpha, hp); break;
761
default: fz_paint_affine_alpha_N_near(dp, sp, sw, sh, u, v, fa, fb, w, n, alpha, hp); break;
762
}
763
}
764
}
765
766
static void
767
fz_paint_affine_g2rgb_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha, byte *color/*unused*/, byte *hp)
768
{
769
if (alpha == 255)
770
{
771
fz_paint_affine_solid_g2rgb_near(dp, sp, sw, sh, u, v, fa, fb, w, hp);
772
}
773
else if (alpha > 0)
774
{
775
fz_paint_affine_alpha_g2rgb_near(dp, sp, sw, sh, u, v, fa, fb, w, alpha, hp);
776
}
777
}
778
779
static void
780
fz_paint_affine_color_lerp(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha/*unused*/, byte *color, byte *hp)
781
{
782
switch (n)
783
{
784
case 2: fz_paint_affine_color_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 2, color, hp); break;
785
case 4: fz_paint_affine_color_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, 4, color, hp); break;
786
default: fz_paint_affine_color_N_lerp(dp, sp, sw, sh, u, v, fa, fb, w, n, color, hp); break;
787
}
788
}
789
790
static void
791
fz_paint_affine_color_near(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha/*unused*/, byte *color, byte *hp)
792
{
793
switch (n)
794
{
795
case 2: fz_paint_affine_color_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 2, color, hp); break;
796
case 4: fz_paint_affine_color_N_near(dp, sp, sw, sh, u, v, fa, fb, w, 4, color, hp); break;
797
default: fz_paint_affine_color_N_near(dp, sp, sw, sh, u, v, fa, fb, w, n, color, hp); break;
798
}
799
}
800
801
/* RJW: The following code was originally written to be sensitive to
802
* FLT_EPSILON. Given the way the 'minimum representable difference'
803
* between 2 floats changes size as we scale, we now pick a larger
804
* value to ensure idempotency even with rounding problems. The
805
* value we pick is still far smaller than would ever show up with
806
* antialiasing.
807
*/
808
#define MY_EPSILON 0.001
809
810
void
811
fz_gridfit_matrix(fz_matrix *m)
812
{
813
if (fabsf(m->b) < FLT_EPSILON && fabsf(m->c) < FLT_EPSILON)
814
{
815
if (m->a > 0)
816
{
817
float f;
818
/* Adjust left hand side onto pixel boundary */
819
f = (float)(int)(m->e);
820
if (f - m->e > MY_EPSILON)
821
f -= 1.0; /* Ensure it moves left */
822
m->a += m->e - f; /* width gets wider as f <= m.e */
823
m->e = f;
824
/* Adjust right hand side onto pixel boundary */
825
f = (float)(int)(m->a);
826
if (m->a - f > MY_EPSILON)
827
f += 1.0; /* Ensure it moves right */
828
m->a = f;
829
}
830
else if (m->a < 0)
831
{
832
float f;
833
/* Adjust right hand side onto pixel boundary */
834
f = (float)(int)(m->e);
835
if (m->e - f > MY_EPSILON)
836
f += 1.0; /* Ensure it moves right */
837
m->a += m->e - f; /* width gets wider (more -ve) */
838
m->e = f;
839
/* Adjust left hand side onto pixel boundary */
840
f = (float)(int)(m->a);
841
if (f - m->a > MY_EPSILON)
842
f -= 1.0; /* Ensure it moves left */
843
m->a = f;
844
}
845
if (m->d > 0)
846
{
847
float f;
848
/* Adjust top onto pixel boundary */
849
f = (float)(int)(m->f);
850
if (f - m->f > MY_EPSILON)
851
f -= 1.0; /* Ensure it moves upwards */
852
m->d += m->f - f; /* width gets wider as f <= m.f */
853
m->f = f;
854
/* Adjust bottom onto pixel boundary */
855
f = (float)(int)(m->d);
856
if (m->d - f > MY_EPSILON)
857
f += 1.0; /* Ensure it moves down */
858
m->d = f;
859
}
860
else if (m->d < 0)
861
{
862
float f;
863
/* Adjust bottom onto pixel boundary */
864
f = (float)(int)(m->f);
865
if (m->f - f > MY_EPSILON)
866
f += 1.0; /* Ensure it moves down */
867
m->d += m->f - f; /* width gets wider (more -ve) */
868
m->f = f;
869
/* Adjust top onto pixel boundary */
870
f = (float)(int)(m->d);
871
if (f - m->d > MY_EPSILON)
872
f -= 1.0; /* Ensure it moves up */
873
m->d = f;
874
}
875
}
876
else if (fabsf(m->a) < FLT_EPSILON && fabsf(m->d) < FLT_EPSILON)
877
{
878
if (m->b > 0)
879
{
880
float f;
881
/* Adjust left hand side onto pixel boundary */
882
f = (float)(int)(m->f);
883
if (f - m->f > MY_EPSILON)
884
f -= 1.0; /* Ensure it moves left */
885
m->b += m->f - f; /* width gets wider as f <= m.f */
886
m->f = f;
887
/* Adjust right hand side onto pixel boundary */
888
f = (float)(int)(m->b);
889
if (m->b - f > MY_EPSILON)
890
f += 1.0; /* Ensure it moves right */
891
m->b = f;
892
}
893
else if (m->b < 0)
894
{
895
float f;
896
/* Adjust right hand side onto pixel boundary */
897
f = (float)(int)(m->f);
898
if (m->f - f > MY_EPSILON)
899
f += 1.0; /* Ensure it moves right */
900
m->b += m->f - f; /* width gets wider (more -ve) */
901
m->f = f;
902
/* Adjust left hand side onto pixel boundary */
903
f = (float)(int)(m->b);
904
if (f - m->b > MY_EPSILON)
905
f -= 1.0; /* Ensure it moves left */
906
m->b = f;
907
}
908
if (m->c > 0)
909
{
910
float f;
911
/* Adjust top onto pixel boundary */
912
f = (float)(int)(m->e);
913
if (f - m->e > MY_EPSILON)
914
f -= 1.0; /* Ensure it moves upwards */
915
m->c += m->e - f; /* width gets wider as f <= m.e */
916
m->e = f;
917
/* Adjust bottom onto pixel boundary */
918
f = (float)(int)(m->c);
919
if (m->c - f > MY_EPSILON)
920
f += 1.0; /* Ensure it moves down */
921
m->c = f;
922
}
923
else if (m->c < 0)
924
{
925
float f;
926
/* Adjust bottom onto pixel boundary */
927
f = (float)(int)(m->e);
928
if (m->e - f > MY_EPSILON)
929
f += 1.0; /* Ensure it moves down */
930
m->c += m->e - f; /* width gets wider (more -ve) */
931
m->e = f;
932
/* Adjust top onto pixel boundary */
933
f = (float)(int)(m->c);
934
if (f - m->c > MY_EPSILON)
935
f -= 1.0; /* Ensure it moves up */
936
m->c = f;
937
}
938
}
939
}
940
941
/* Draw an image with an affine transform on destination */
942
943
static void
944
fz_paint_image_imp(fz_pixmap *dst, const fz_irect *scissor, fz_pixmap *shape, fz_pixmap *img, const fz_matrix *ctm, byte *color, int alpha, int lerp_allowed)
945
{
946
byte *dp, *sp, *hp;
947
int u, v, fa, fb, fc, fd;
948
int x, y, w, h;
949
int sw, sh, n, hw;
950
fz_irect bbox;
951
int dolerp;
952
void (*paintfn)(byte *dp, byte *sp, int sw, int sh, int u, int v, int fa, int fb, int w, int n, int alpha, byte *color, byte *hp);
953
fz_matrix local_ctm = *ctm;
954
fz_rect rect;
955
int is_rectilinear;
956
957
/* grid fit the image */
958
fz_gridfit_matrix(&local_ctm);
959
960
/* turn on interpolation for upscaled and non-rectilinear transforms */
961
dolerp = 0;
962
is_rectilinear = fz_is_rectilinear(&local_ctm);
963
if (!is_rectilinear)
964
dolerp = lerp_allowed;
965
if (sqrtf(local_ctm.a * local_ctm.a + local_ctm.b * local_ctm.b) > img->w)
966
dolerp = lerp_allowed;
967
if (sqrtf(local_ctm.c * local_ctm.c + local_ctm.d * local_ctm.d) > img->h)
968
dolerp = lerp_allowed;
969
970
/* except when we shouldn't, at large magnifications */
971
if (!img->interpolate)
972
{
973
if (sqrtf(local_ctm.a * local_ctm.a + local_ctm.b * local_ctm.b) > img->w * 2)
974
dolerp = 0;
975
if (sqrtf(local_ctm.c * local_ctm.c + local_ctm.d * local_ctm.d) > img->h * 2)
976
dolerp = 0;
977
}
978
979
rect = fz_unit_rect;
980
fz_irect_from_rect(&bbox, fz_transform_rect(&rect, &local_ctm));
981
fz_intersect_irect(&bbox, scissor);
982
983
x = bbox.x0;
984
if (shape && shape->x > x)
985
x = shape->x;
986
y = bbox.y0;
987
if (shape && shape->y > y)
988
y = shape->y;
989
w = bbox.x1;
990
if (shape && shape->x + shape->w < w)
991
w = shape->x + shape->w;
992
w -= x;
993
h = bbox.y1;
994
if (shape && shape->y + shape->h < h)
995
h = shape->y + shape->h;
996
h -= y;
997
if (w < 0 || h < 0)
998
return;
999
1000
/* map from screen space (x,y) to image space (u,v) */
1001
fz_pre_scale(&local_ctm, 1.0f / img->w, 1.0f / img->h);
1002
fz_invert_matrix(&local_ctm, &local_ctm);
1003
1004
fa = (int)(local_ctm.a *= 65536.0f);
1005
fb = (int)(local_ctm.b *= 65536.0f);
1006
fc = (int)(local_ctm.c *= 65536.0f);
1007
fd = (int)(local_ctm.d *= 65536.0f);
1008
local_ctm.e *= 65536.0f;
1009
local_ctm.f *= 65536.0f;
1010
1011
/* Calculate initial texture positions. Do a half step to start. */
1012
/* Bug 693021: Keep calculation in float for as long as possible to
1013
* avoid overflow. */
1014
u = (int)((local_ctm.a * x) + (local_ctm.c * y) + local_ctm.e + ((local_ctm.a + local_ctm.c) * .5f));
1015
v = (int)((local_ctm.b * x) + (local_ctm.d * y) + local_ctm.f + ((local_ctm.b + local_ctm.d) * .5f));
1016
1017
/* RJW: The following is voodoo. No idea why it works, but it gives
1018
* the best match between scaled/unscaled/interpolated/non-interpolated
1019
* that we have found. */
1020
if (dolerp) {
1021
u -= 32768;
1022
v -= 32768;
1023
if (is_rectilinear)
1024
{
1025
if (u < 0)
1026
u = 0;
1027
if (v < 0)
1028
v = 0;
1029
}
1030
}
1031
1032
dp = dst->samples + (unsigned int)(((y - dst->y) * dst->w + (x - dst->x)) * dst->n);
1033
n = dst->n;
1034
sp = img->samples;
1035
sw = img->w;
1036
sh = img->h;
1037
if (shape)
1038
{
1039
hw = shape->w;
1040
hp = shape->samples + (unsigned int)(((y - shape->y) * hw) + x - shape->x);
1041
}
1042
else
1043
{
1044
hw = 0;
1045
hp = NULL;
1046
}
1047
1048
/* TODO: if (fb == 0 && fa == 1) call fz_paint_span */
1049
1050
if (dst->n == 4 && img->n == 2)
1051
{
1052
assert(!color);
1053
if (dolerp)
1054
paintfn = fz_paint_affine_g2rgb_lerp;
1055
else
1056
paintfn = fz_paint_affine_g2rgb_near;
1057
}
1058
else
1059
{
1060
if (dolerp)
1061
{
1062
if (color)
1063
paintfn = fz_paint_affine_color_lerp;
1064
else
1065
paintfn = fz_paint_affine_lerp;
1066
}
1067
else
1068
{
1069
if (color)
1070
paintfn = fz_paint_affine_color_near;
1071
else
1072
paintfn = fz_paint_affine_near;
1073
}
1074
}
1075
1076
while (h--)
1077
{
1078
paintfn(dp, sp, sw, sh, u, v, fa, fb, w, n, alpha, color, hp);
1079
dp += dst->w * n;
1080
hp += hw;
1081
u += fc;
1082
v += fd;
1083
}
1084
}
1085
1086
void
1087
fz_paint_image_with_color(fz_pixmap *dst, const fz_irect *scissor, fz_pixmap *shape, fz_pixmap *img, const fz_matrix *ctm, byte *color, int lerp_allowed)
1088
{
1089
assert(img->n == 1);
1090
fz_paint_image_imp(dst, scissor, shape, img, ctm, color, 255, lerp_allowed);
1091
}
1092
1093
void
1094
fz_paint_image(fz_pixmap *dst, const fz_irect *scissor, fz_pixmap *shape, fz_pixmap *img, const fz_matrix *ctm, int alpha, int lerp_allowed)
1095
{
1096
assert(dst->n == img->n || (dst->n == 4 && img->n == 2));
1097
fz_paint_image_imp(dst, scissor, shape, img, ctm, NULL, alpha, lerp_allowed);
1098
}
1099
1100