Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7643 views
1
#include "mupdf/fitz.h"
2
#include "draw-imp.h"
3
4
/*
5
6
The functions in this file implement various flavours of Porter-Duff blending.
7
8
We take the following as definitions:
9
10
Cx = Color (from plane x)
11
ax = Alpha (from plane x)
12
cx = Cx.ax = Premultiplied color (from plane x)
13
14
The general PorterDuff blending equation is:
15
16
Blend Z = X op Y cz = Fx.cx + Fy. cy where Fx and Fy depend on op
17
18
The two operations we use in this file are: '(X in Y) over Z' and
19
'S over Z'. The definitions of the 'over' and 'in' operations are as
20
follows:
21
22
For S over Z, Fs = 1, Fz = 1-as
23
For X in Y, Fx = ay, Fy = 0
24
25
We have 2 choices; we can either work with premultiplied data, or non
26
premultiplied data. Our
27
28
First the premultiplied case:
29
30
Let S = (X in Y)
31
Let R = (X in Y) over Z = S over Z
32
33
cs = cx.Fx + cy.Fy (where Fx = ay, Fy = 0)
34
= cx.ay
35
as = ax.Fx + ay.Fy
36
= ax.ay
37
38
cr = cs.Fs + cz.Fz (where Fs = 1, Fz = 1-as)
39
= cs + cz.(1-as)
40
= cx.ay + cz.(1-ax.ay)
41
ar = as.Fs + az.Fz
42
= as + az.(1-as)
43
= ax.ay + az.(1-ax.ay)
44
45
This has various nice properties, like not needing any divisions, and
46
being symmetric in color and alpha, so this is what we use. Because we
47
went through the pain of deriving the non premultiplied forms, we list
48
them here too, though they are not used.
49
50
Non Pre-multiplied case:
51
52
Cs.as = Fx.Cx.ax + Fy.Cy.ay (where Fx = ay, Fy = 0)
53
= Cx.ay.ax
54
Cs = (Cx.ay.ax)/(ay.ax)
55
= Cx
56
Cr.ar = Fs.Cs.as + Fz.Cz.az (where Fs = 1, Fz = 1-as)
57
= Cs.as + (1-as).Cz.az
58
= Cx.ax.ay + Cz.az.(1-ax.ay)
59
Cr = (Cx.ax.ay + Cz.az.(1-ax.ay))/(ax.ay + az.(1-ax-ay))
60
61
Much more complex, it seems. However, if we could restrict ourselves to
62
the case where we were always plotting onto an opaque background (i.e.
63
az = 1), then:
64
65
Cr = Cx.(ax.ay) + Cz.(1-ax.ay)
66
= (Cx-Cz)*(1-ax.ay) + Cz (a single MLA operation)
67
ar = 1
68
69
Sadly, this is not true in the general case, so we abandon this effort
70
and stick to using the premultiplied form.
71
72
*/
73
74
typedef unsigned char byte;
75
76
/* These are used by the non-aa scan converter */
77
78
void
79
fz_paint_solid_alpha(byte * restrict dp, int w, int alpha)
80
{
81
int t = FZ_EXPAND(255 - alpha);
82
while (w--)
83
{
84
*dp = alpha + FZ_COMBINE(*dp, t);
85
dp ++;
86
}
87
}
88
89
static inline void
90
fz_paint_solid_color_2(byte * restrict dp, int w, byte *color)
91
{
92
int sa = FZ_EXPAND(color[1]);
93
if (sa == 0)
94
return;
95
if (sa == 256)
96
{
97
while (w--)
98
{
99
dp[0] = color[0];
100
dp[1] = 255;
101
dp += 2;
102
}
103
}
104
else
105
{
106
while (w--)
107
{
108
dp[0] = FZ_BLEND(color[0], dp[0], sa);
109
dp[1] = FZ_BLEND(255, dp[1], sa);
110
dp += 2;
111
}
112
}
113
}
114
115
static inline int isbigendian(void)
116
{
117
union { int i; char c[sizeof(int)]; } u = {1};
118
return u.c[0] != 1;
119
}
120
121
static inline void
122
fz_paint_solid_color_4(byte * restrict dp, int w, byte *color)
123
{
124
unsigned int rgba = *(int *)color;
125
int sa = FZ_EXPAND(color[3]);
126
if (sa == 0)
127
return;
128
if (isbigendian())
129
rgba |= 0x000000FF;
130
else
131
rgba |= 0xFF000000;
132
if (sa == 256)
133
{
134
while (w--)
135
{
136
*(unsigned int *)dp = rgba;
137
dp += 4;
138
}
139
}
140
else
141
{
142
unsigned int mask = 0xFF00FF00;
143
unsigned int rb = rgba & (mask>>8);
144
unsigned int ga = (rgba & mask)>>8;
145
while (w--)
146
{
147
unsigned int RGBA = *(unsigned int *)dp;
148
unsigned int RB = (RGBA<<8) & mask;
149
unsigned int GA = RGBA & mask;
150
RB += (rb-(RB>>8))*sa;
151
GA += (ga-(GA>>8))*sa;
152
RB &= mask;
153
GA &= mask;
154
*(unsigned int *)dp = (RB>>8) | GA;
155
dp += 4;
156
}
157
}
158
}
159
160
static inline void
161
fz_paint_solid_color_N(byte * restrict dp, int n, int w, byte *color)
162
{
163
int k;
164
int n1 = n - 1;
165
int sa = FZ_EXPAND(color[n1]);
166
if (sa == 0)
167
return;
168
if (sa == 256)
169
{
170
while (w--)
171
{
172
for (k = 0; k < n1; k++)
173
dp[k] = color[k];
174
dp[k] = 255;
175
dp += n;
176
}
177
}
178
else
179
{
180
while (w--)
181
{
182
for (k = 0; k < n1; k++)
183
dp[k] = FZ_BLEND(color[k], dp[k], sa);
184
dp[k] = FZ_BLEND(255, dp[k], sa);
185
dp += n;
186
}
187
}
188
}
189
190
void
191
fz_paint_solid_color(byte * restrict dp, int n, int w, byte *color)
192
{
193
switch (n)
194
{
195
case 2: fz_paint_solid_color_2(dp, w, color); break;
196
case 4: fz_paint_solid_color_4(dp, w, color); break;
197
default: fz_paint_solid_color_N(dp, n, w, color); break;
198
}
199
}
200
201
/* Blend a non-premultiplied color in mask over destination */
202
203
static inline void
204
fz_paint_span_with_color_2(byte * restrict dp, byte * restrict mp, int w, byte *color)
205
{
206
int sa = FZ_EXPAND(color[1]);
207
int g = color[0];
208
if (sa == 256)
209
{
210
while (w--)
211
{
212
int ma = *mp++;
213
ma = FZ_EXPAND(ma);
214
if (ma == 0)
215
{
216
}
217
else if (ma == 256)
218
{
219
dp[0] = g;
220
dp[1] = 255;
221
}
222
else
223
{
224
dp[0] = FZ_BLEND(g, dp[0], ma);
225
dp[1] = FZ_BLEND(255, dp[1], ma);
226
}
227
dp += 2;
228
}
229
}
230
else
231
{
232
while (w--)
233
{
234
int ma = *mp++;
235
ma = FZ_EXPAND(ma);
236
if (ma == 0)
237
{
238
}
239
else
240
{
241
ma = FZ_COMBINE(ma, sa);
242
dp[0] = FZ_BLEND(g, dp[0], ma);
243
dp[1] = FZ_BLEND(255, dp[1], ma);
244
}
245
dp += 2;
246
}
247
}
248
}
249
250
static inline void
251
fz_paint_span_with_color_4(byte * restrict dp, byte * restrict mp, int w, byte *color)
252
{
253
unsigned int rgba = *((unsigned int *)color);
254
unsigned int mask, rb, ga;
255
int sa = FZ_EXPAND(color[3]);
256
if (sa == 0)
257
return;
258
if (isbigendian())
259
rgba |= 0x000000FF;
260
else
261
rgba |= 0xFF000000;
262
mask = 0xFF00FF00;
263
rb = rgba & (mask>>8);
264
ga = (rgba & mask)>>8;
265
if (sa == 256)
266
{
267
while (w--)
268
{
269
unsigned int ma = *mp++;
270
dp += 4;
271
ma = FZ_EXPAND(ma);
272
if (ma == 0)
273
{
274
}
275
else if (ma == 256)
276
{
277
((unsigned int *)dp)[-1] = rgba;
278
}
279
else
280
{
281
unsigned int RGBA = ((unsigned int *)dp)[-1];
282
unsigned int RB = (RGBA<<8) & mask;
283
unsigned int GA = RGBA & mask;
284
RB += (rb-(RB>>8))*ma;
285
GA += (ga-(GA>>8))*ma;
286
RB &= mask;
287
GA &= mask;
288
((unsigned int *)dp)[-1] = (RB>>8) | GA;
289
}
290
}
291
}
292
else
293
{
294
while (w--)
295
{
296
unsigned int ma = *mp++;
297
ma = FZ_COMBINE(FZ_EXPAND(ma), sa);
298
dp += 4;
299
if (ma != 0)
300
{
301
unsigned int RGBA = ((unsigned int*)dp)[-1];
302
unsigned int RB = (RGBA<<8) & mask;
303
unsigned int GA = RGBA & mask;
304
RB += (rb-(RB>>8))*ma;
305
GA += (ga-(GA>>8))*ma;
306
RB &= mask;
307
GA &= mask;
308
((unsigned int *)dp)[-1] = (RB>>8) | GA;
309
}
310
}
311
}
312
}
313
314
static inline void
315
fz_paint_span_with_color_N(byte * restrict dp, byte * restrict mp, int n, int w, byte *color)
316
{
317
int k;
318
int n1 = n - 1;
319
int sa = FZ_EXPAND(color[n1]);
320
if (sa == 0)
321
return;
322
if (sa == 256)
323
{
324
while (w--)
325
{
326
int ma = *mp++;
327
ma = FZ_EXPAND(ma);
328
if (ma == 0)
329
{
330
}
331
else if (ma == 256)
332
{
333
for (k = 0; k < n1; k++)
334
dp[k] = color[k];
335
dp[k] = 255;
336
}
337
else
338
{
339
for (k = 0; k < n1; k++)
340
dp[k] = FZ_BLEND(color[k], dp[k], ma);
341
dp[k] = FZ_BLEND(255, dp[k], ma);
342
}
343
dp += n;
344
}
345
}
346
else
347
{
348
while (w--)
349
{
350
int ma = *mp++;
351
ma = FZ_COMBINE(FZ_EXPAND(ma), sa);
352
for (k = 0; k < n1; k++)
353
dp[k] = FZ_BLEND(color[k], dp[k], ma);
354
dp[k] = FZ_BLEND(255, dp[k], ma);
355
dp += n;
356
}
357
}
358
}
359
360
void
361
fz_paint_span_with_color(byte * restrict dp, byte * restrict mp, int n, int w, byte *color)
362
{
363
switch (n)
364
{
365
case 2: fz_paint_span_with_color_2(dp, mp, w, color); break;
366
case 4: fz_paint_span_with_color_4(dp, mp, w, color); break;
367
default: fz_paint_span_with_color_N(dp, mp, n, w, color); break;
368
}
369
}
370
371
/* Blend source in mask over destination */
372
373
/* FIXME: There is potential for SWAR optimisation here */
374
static inline void
375
fz_paint_span_with_mask_2(byte * restrict dp, byte * restrict sp, byte * restrict mp, int w)
376
{
377
while (w--)
378
{
379
int masa;
380
int ma = *mp++;
381
ma = FZ_EXPAND(ma);
382
if (ma == 0)
383
{
384
dp += 2;
385
sp += 2;
386
}
387
else if (ma == 256)
388
{
389
masa = 255 - sp[1];
390
if (masa == 0)
391
{
392
*dp++ = *sp++;
393
*dp++ = *sp++;
394
}
395
else
396
{
397
masa = FZ_EXPAND(masa);
398
*dp = *sp + FZ_COMBINE(*dp, masa);
399
sp++; dp++;
400
*dp = *sp + FZ_COMBINE(*dp, masa);
401
sp++; dp++;
402
}
403
}
404
else
405
{
406
masa = FZ_COMBINE(sp[1], ma);
407
masa = 255 - masa;
408
masa = FZ_EXPAND(masa);
409
*dp = FZ_COMBINE2(*sp, ma, *dp, masa);
410
sp++; dp++;
411
*dp = FZ_COMBINE2(*sp, ma, *dp, masa);
412
sp++; dp++;
413
}
414
}
415
}
416
417
/* FIXME: There is potential for SWAR optimisation here */
418
static inline void
419
fz_paint_span_with_mask_4(byte * restrict dp, byte * restrict sp, byte * restrict mp, int w)
420
{
421
while (w--)
422
{
423
int masa;
424
int ma = *mp++;
425
ma = FZ_EXPAND(ma);
426
if (ma == 0)
427
{
428
dp += 4;
429
sp += 4;
430
}
431
else if (ma == 256)
432
{
433
masa = 255 - sp[3];
434
if (masa == 0)
435
{
436
*(int*)dp = *(int *)sp;
437
sp += 4; dp += 4;
438
}
439
else
440
{
441
masa = FZ_EXPAND(masa);
442
*dp = *sp + FZ_COMBINE(*dp, masa);
443
sp++; dp++;
444
*dp = *sp + FZ_COMBINE(*dp, masa);
445
sp++; dp++;
446
*dp = *sp + FZ_COMBINE(*dp, masa);
447
sp++; dp++;
448
*dp = *sp + FZ_COMBINE(*dp, masa);
449
sp++; dp++;
450
}
451
}
452
else
453
{
454
/* FIXME: There is potential for SWAR optimisation here */
455
masa = FZ_COMBINE(sp[3], ma);
456
masa = 255 - masa;
457
masa = FZ_EXPAND(masa);
458
*dp = FZ_COMBINE2(*sp, ma, *dp, masa);
459
sp++; dp++;
460
*dp = FZ_COMBINE2(*sp, ma, *dp, masa);
461
sp++; dp++;
462
*dp = FZ_COMBINE2(*sp, ma, *dp, masa);
463
sp++; dp++;
464
*dp = FZ_COMBINE2(*sp, ma, *dp, masa);
465
sp++; dp++;
466
}
467
}
468
}
469
470
static inline void
471
fz_paint_span_with_mask_N(byte * restrict dp, byte * restrict sp, byte * restrict mp, int n, int w)
472
{
473
while (w--)
474
{
475
int ma = *mp++;
476
ma = FZ_EXPAND(ma);
477
if (ma == 0)
478
{
479
dp += n;
480
sp += n;
481
}
482
else if (ma == 256)
483
{
484
int k = n;
485
int masa = 255 - sp[n-1];
486
if (masa == 0)
487
{
488
while (k--)
489
{
490
*dp++ = *sp++;
491
}
492
}
493
else
494
{
495
masa = FZ_EXPAND(masa);
496
while (k--)
497
{
498
*dp = *sp + FZ_COMBINE(*dp, masa);
499
sp++; dp++;
500
}
501
}
502
}
503
else
504
{
505
int k = n;
506
int masa = FZ_COMBINE(sp[n-1], ma);
507
masa = 255-masa;
508
masa = FZ_EXPAND(masa);
509
while (k--)
510
{
511
*dp = FZ_COMBINE2(*sp, ma, *dp, masa);
512
sp++; dp++;
513
}
514
}
515
}
516
}
517
518
static void
519
fz_paint_span_with_mask(byte * restrict dp, byte * restrict sp, byte * restrict mp, int n, int w)
520
{
521
switch (n)
522
{
523
case 2: fz_paint_span_with_mask_2(dp, sp, mp, w); break;
524
case 4: fz_paint_span_with_mask_4(dp, sp, mp, w); break;
525
default: fz_paint_span_with_mask_N(dp, sp, mp, n, w); break;
526
}
527
}
528
529
/* Blend source in constant alpha over destination */
530
531
static inline void
532
fz_paint_span_2_with_alpha(byte * restrict dp, byte * restrict sp, int w, int alpha)
533
{
534
alpha = FZ_EXPAND(alpha);
535
while (w--)
536
{
537
int masa = FZ_COMBINE(sp[1], alpha);
538
*dp = FZ_BLEND(*sp, *dp, masa);
539
dp++; sp++;
540
*dp = FZ_BLEND(*sp, *dp, masa);
541
dp++; sp++;
542
}
543
}
544
545
static inline void
546
fz_paint_span_4_with_alpha(byte * restrict dp, byte * restrict sp, int w, int alpha)
547
{
548
alpha = FZ_EXPAND(alpha);
549
while (w--)
550
{
551
int masa = FZ_COMBINE(sp[3], alpha);
552
*dp = FZ_BLEND(*sp, *dp, masa);
553
sp++; dp++;
554
*dp = FZ_BLEND(*sp, *dp, masa);
555
sp++; dp++;
556
*dp = FZ_BLEND(*sp, *dp, masa);
557
sp++; dp++;
558
*dp = FZ_BLEND(*sp, *dp, masa);
559
sp++; dp++;
560
}
561
}
562
563
static inline void
564
fz_paint_span_N_with_alpha(byte * restrict dp, byte * restrict sp, int n, int w, int alpha)
565
{
566
alpha = FZ_EXPAND(alpha);
567
while (w--)
568
{
569
int masa = FZ_COMBINE(sp[n-1], alpha);
570
int k = n;
571
while (k--)
572
{
573
*dp = FZ_BLEND(*sp++, *dp, masa);
574
dp++;
575
}
576
}
577
}
578
579
/* Blend source over destination */
580
581
static inline void
582
fz_paint_span_1(byte * restrict dp, byte * restrict sp, int w)
583
{
584
while (w--)
585
{
586
int t = FZ_EXPAND(255 - sp[0]);
587
*dp = *sp++ + FZ_COMBINE(*dp, t);
588
dp ++;
589
}
590
}
591
592
static inline void
593
fz_paint_span_2(byte * restrict dp, byte * restrict sp, int w)
594
{
595
while (w--)
596
{
597
int t = FZ_EXPAND(sp[1]);
598
if (t == 0)
599
{
600
dp += 2; sp += 2;
601
}
602
else
603
{
604
t = 256 - t;
605
if (t == 0)
606
{
607
*dp++ = *sp++;
608
*dp++ = *sp++;
609
}
610
else
611
{
612
*dp = *sp++ + FZ_COMBINE(*dp, t);
613
dp++;
614
*dp = *sp++ + FZ_COMBINE(*dp, t);
615
dp++;
616
}
617
}
618
}
619
}
620
621
static inline void
622
fz_paint_span_4(byte * restrict dp, byte * restrict sp, int w)
623
{
624
while (w--)
625
{
626
int t = FZ_EXPAND(sp[3]);
627
if (t == 0)
628
{
629
dp += 4; sp += 4;
630
}
631
else
632
{
633
t = 256 - t;
634
if (t == 0)
635
{
636
*(int *)dp = *(int *)sp;
637
dp += 4; sp += 4;
638
}
639
else
640
{
641
*dp = *sp++ + FZ_COMBINE(*dp, t);
642
dp++;
643
*dp = *sp++ + FZ_COMBINE(*dp, t);
644
dp++;
645
*dp = *sp++ + FZ_COMBINE(*dp, t);
646
dp++;
647
*dp = *sp++ + FZ_COMBINE(*dp, t);
648
dp++;
649
}
650
}
651
}
652
}
653
654
static inline void
655
fz_paint_span_N(byte * restrict dp, byte * restrict sp, int n, int w)
656
{
657
while (w--)
658
{
659
int t = FZ_EXPAND(sp[n-1]);
660
if (t == 0)
661
{
662
dp += n; sp += n;
663
}
664
else
665
{
666
t = 256 - t;
667
if (t == 0)
668
{
669
int k = n;
670
while (k--)
671
{
672
*dp++ = *sp++;
673
}
674
}
675
else
676
{
677
int k = n;
678
while (k--)
679
{
680
*dp = *sp++ + FZ_COMBINE(*dp, t);
681
dp++;
682
}
683
}
684
}
685
}
686
}
687
688
void
689
fz_paint_span(byte * restrict dp, byte * restrict sp, int n, int w, int alpha)
690
{
691
if (alpha == 255)
692
{
693
switch (n)
694
{
695
case 1: fz_paint_span_1(dp, sp, w); break;
696
case 2: fz_paint_span_2(dp, sp, w); break;
697
case 4: fz_paint_span_4(dp, sp, w); break;
698
default: fz_paint_span_N(dp, sp, n, w); break;
699
}
700
}
701
else if (alpha > 0)
702
{
703
switch (n)
704
{
705
case 2: fz_paint_span_2_with_alpha(dp, sp, w, alpha); break;
706
case 4: fz_paint_span_4_with_alpha(dp, sp, w, alpha); break;
707
default: fz_paint_span_N_with_alpha(dp, sp, n, w, alpha); break;
708
}
709
}
710
}
711
712
/*
713
* Pixmap blending functions
714
*/
715
716
void
717
fz_paint_pixmap_with_bbox(fz_pixmap *dst, fz_pixmap *src, int alpha, fz_irect bbox)
718
{
719
unsigned char *sp, *dp;
720
int x, y, w, h, n;
721
fz_irect bbox2;
722
723
assert(dst->n == src->n);
724
725
fz_pixmap_bbox_no_ctx(dst, &bbox2);
726
fz_intersect_irect(&bbox, &bbox2);
727
fz_pixmap_bbox_no_ctx(src, &bbox2);
728
fz_intersect_irect(&bbox, &bbox2);
729
730
x = bbox.x0;
731
y = bbox.y0;
732
w = bbox.x1 - bbox.x0;
733
h = bbox.y1 - bbox.y0;
734
if ((w | h) == 0)
735
return;
736
737
n = src->n;
738
sp = src->samples + (unsigned int)(((y - src->y) * src->w + (x - src->x)) * src->n);
739
dp = dst->samples + (unsigned int)(((y - dst->y) * dst->w + (x - dst->x)) * dst->n);
740
741
while (h--)
742
{
743
fz_paint_span(dp, sp, n, w, alpha);
744
sp += src->w * n;
745
dp += dst->w * n;
746
}
747
}
748
749
void
750
fz_paint_pixmap(fz_pixmap *dst, fz_pixmap *src, int alpha)
751
{
752
unsigned char *sp, *dp;
753
fz_irect bbox;
754
fz_irect bbox2;
755
int x, y, w, h, n;
756
757
assert(dst->n == src->n);
758
759
fz_pixmap_bbox_no_ctx(dst, &bbox);
760
fz_pixmap_bbox_no_ctx(src, &bbox2);
761
fz_intersect_irect(&bbox, &bbox2);
762
763
x = bbox.x0;
764
y = bbox.y0;
765
w = bbox.x1 - bbox.x0;
766
h = bbox.y1 - bbox.y0;
767
if ((w | h) == 0)
768
return;
769
770
n = src->n;
771
sp = src->samples + (unsigned int)(((y - src->y) * src->w + (x - src->x)) * src->n);
772
dp = dst->samples + (unsigned int)(((y - dst->y) * dst->w + (x - dst->x)) * dst->n);
773
774
while (h--)
775
{
776
fz_paint_span(dp, sp, n, w, alpha);
777
sp += src->w * n;
778
dp += dst->w * n;
779
}
780
}
781
782
void
783
fz_paint_pixmap_with_mask(fz_pixmap *dst, fz_pixmap *src, fz_pixmap *msk)
784
{
785
unsigned char *sp, *dp, *mp;
786
fz_irect bbox, bbox2;
787
int x, y, w, h, n;
788
789
assert(dst->n == src->n);
790
assert(msk->n == 1);
791
792
fz_pixmap_bbox_no_ctx(dst, &bbox);
793
fz_pixmap_bbox_no_ctx(src, &bbox2);
794
fz_intersect_irect(&bbox, &bbox2);
795
fz_pixmap_bbox_no_ctx(msk, &bbox2);
796
fz_intersect_irect(&bbox, &bbox2);
797
798
x = bbox.x0;
799
y = bbox.y0;
800
w = bbox.x1 - bbox.x0;
801
h = bbox.y1 - bbox.y0;
802
if ((w | h) == 0)
803
return;
804
805
n = src->n;
806
sp = src->samples + (unsigned int)(((y - src->y) * src->w + (x - src->x)) * src->n);
807
mp = msk->samples + (unsigned int)(((y - msk->y) * msk->w + (x - msk->x)) * msk->n);
808
dp = dst->samples + (unsigned int)(((y - dst->y) * dst->w + (x - dst->x)) * dst->n);
809
810
while (h--)
811
{
812
fz_paint_span_with_mask(dp, sp, mp, n, w);
813
sp += src->w * n;
814
dp += dst->w * n;
815
mp += msk->w;
816
}
817
}
818
819
static inline void
820
fz_paint_glyph_mask(int span, unsigned char *dp, fz_glyph *glyph, int w, int h, int skip_x, int skip_y)
821
{
822
while (h--)
823
{
824
int skip_xx, ww, len, extend;
825
unsigned char *runp;
826
unsigned char *ddp = dp;
827
int offset = ((int *)(glyph->data))[skip_y++];
828
if (offset >= 0)
829
{
830
int eol = 0;
831
runp = &glyph->data[offset];
832
extend = 0;
833
ww = w;
834
skip_xx = skip_x;
835
while (skip_xx)
836
{
837
int v = *runp++;
838
switch (v & 3)
839
{
840
case 0: /* Extend */
841
extend = v>>2;
842
len = 0;
843
break;
844
case 1: /* Transparent */
845
len = (v>>2) + 1 + (extend<<6);
846
extend = 0;
847
if (len > skip_xx)
848
{
849
len -= skip_xx;
850
goto transparent_run;
851
}
852
break;
853
case 2: /* Solid */
854
eol = v & 4;
855
len = (v>>3) + 1 + (extend<<5);
856
extend = 0;
857
if (len > skip_xx)
858
{
859
len -= skip_xx;
860
goto solid_run;
861
}
862
break;
863
default: /* Intermediate */
864
eol = v & 4;
865
len = (v>>3) + 1 + (extend<<5);
866
extend = 0;
867
if (len > skip_xx)
868
{
869
runp += skip_xx;
870
len -= skip_xx;
871
goto intermediate_run;
872
}
873
runp += len;
874
break;
875
}
876
if (eol)
877
{
878
ww = 0;
879
break;
880
}
881
skip_xx -= len;
882
}
883
while (ww > 0)
884
{
885
int v = *runp++;
886
switch(v & 3)
887
{
888
case 0: /* Extend */
889
extend = v>>2;
890
break;
891
case 1: /* Transparent */
892
len = (v>>2) + 1 + (extend<<6);
893
extend = 0;
894
transparent_run:
895
if (len > ww)
896
len = ww;
897
ww -= len;
898
ddp += len;
899
break;
900
case 2: /* Solid */
901
eol = v & 4;
902
len = (v>>3) + 1 + (extend<<5);
903
extend = 0;
904
solid_run:
905
if (len > ww)
906
len = ww;
907
ww -= len;
908
do
909
{
910
*ddp++ = 0xFF;
911
}
912
while (--len);
913
break;
914
default: /* Intermediate */
915
eol = v & 4;
916
len = (v>>3) + 1 + (extend<<5);
917
extend = 0;
918
intermediate_run:
919
if (len > ww)
920
len = ww;
921
ww -= len;
922
do
923
{
924
int v = *ddp;
925
int a = *runp++;
926
if (v == 0)
927
{
928
*ddp++ = a;
929
}
930
else
931
{
932
a = FZ_EXPAND(a);
933
*ddp = FZ_BLEND(0xFF, v, a);
934
ddp++;
935
}
936
}
937
while (--len);
938
break;
939
}
940
if (eol)
941
break;
942
}
943
}
944
dp += span;
945
}
946
}
947
948
static inline void
949
fz_paint_glyph_alpha_N(unsigned char *colorbv, int n, int span, unsigned char *dp, fz_glyph *glyph, int w, int h, int skip_x, int skip_y)
950
{
951
int sa = FZ_EXPAND(colorbv[n-1]);
952
while (h--)
953
{
954
int skip_xx, ww, len, extend;
955
unsigned char *runp;
956
unsigned char *ddp = dp;
957
int offset = ((int *)(glyph->data))[skip_y++];
958
if (offset >= 0)
959
{
960
int eol = 0;
961
runp = &glyph->data[offset];
962
extend = 0;
963
ww = w;
964
skip_xx = skip_x;
965
while (skip_xx)
966
{
967
int v = *runp++;
968
switch (v & 3)
969
{
970
case 0: /* Extend */
971
extend = v>>2;
972
len = 0;
973
break;
974
case 1: /* Transparent */
975
len = (v>>2) + 1 + (extend<<6);
976
extend = 0;
977
if (len > skip_xx)
978
{
979
len -= skip_xx;
980
goto transparent_run;
981
}
982
break;
983
case 2: /* Solid */
984
eol = v & 4;
985
len = (v>>3) + 1 + (extend<<5);
986
extend = 0;
987
if (len > skip_xx)
988
{
989
len -= skip_xx;
990
goto solid_run;
991
}
992
break;
993
default: /* Intermediate */
994
eol = v & 4;
995
len = (v>>3) + 1 + (extend<<5);
996
extend = 0;
997
if (len > skip_xx)
998
{
999
runp += skip_xx;
1000
len -= skip_xx;
1001
goto intermediate_run;
1002
}
1003
runp += len;
1004
break;
1005
}
1006
if (eol)
1007
{
1008
ww = 0;
1009
break;
1010
}
1011
skip_xx -= len;
1012
}
1013
while (ww > 0)
1014
{
1015
int v = *runp++;
1016
switch(v & 3)
1017
{
1018
case 0: /* Extend */
1019
extend = v>>2;
1020
break;
1021
case 1: /* Transparent */
1022
len = (v>>2) + 1 + (extend<<6);
1023
extend = 0;
1024
transparent_run:
1025
if (len > ww)
1026
len = ww;
1027
ww -= len;
1028
ddp += len * n;
1029
break;
1030
case 2: /* Solid */
1031
eol = v & 4;
1032
len = (v>>3) + 1 + (extend<<5);
1033
extend = 0;
1034
solid_run:
1035
if (len > ww)
1036
len = ww;
1037
ww -= len;
1038
do
1039
{
1040
int k = 0;
1041
do
1042
{
1043
*ddp = FZ_BLEND(colorbv[k++], *ddp, sa);
1044
ddp++;
1045
}
1046
while (k != n-1);
1047
*ddp = FZ_BLEND(0xFF, *ddp, sa);
1048
ddp++;
1049
}
1050
while (--len);
1051
break;
1052
default: /* Intermediate */
1053
eol = v & 4;
1054
len = (v>>3) + 1 + (extend<<5);
1055
extend = 0;
1056
intermediate_run:
1057
if (len > ww)
1058
len = ww;
1059
ww -= len;
1060
do
1061
{
1062
int k = 0;
1063
int a = *runp++;
1064
a = FZ_COMBINE(sa, FZ_EXPAND(a));
1065
do
1066
{
1067
*ddp = FZ_BLEND(colorbv[k++], *ddp, a);
1068
ddp++;
1069
}
1070
while (k != n-1);
1071
*ddp = FZ_BLEND(0xFF, *ddp, a);
1072
ddp++;
1073
}
1074
while (--len);
1075
break;
1076
}
1077
if (eol)
1078
break;
1079
}
1080
}
1081
dp += span;
1082
}
1083
}
1084
1085
static inline void
1086
fz_paint_glyph_solid_N(unsigned char *colorbv, int n, int span, unsigned char *dp, fz_glyph *glyph, int w, int h, int skip_x, int skip_y)
1087
{
1088
while (h--)
1089
{
1090
int skip_xx, ww, len, extend;
1091
unsigned char *runp;
1092
unsigned char *ddp = dp;
1093
int offset = ((int *)(glyph->data))[skip_y++];
1094
if (offset >= 0)
1095
{
1096
int eol = 0;
1097
runp = &glyph->data[offset];
1098
extend = 0;
1099
ww = w;
1100
skip_xx = skip_x;
1101
while (skip_xx)
1102
{
1103
int v = *runp++;
1104
switch (v & 3)
1105
{
1106
case 0: /* Extend */
1107
extend = v>>2;
1108
len = 0;
1109
break;
1110
case 1: /* Transparent */
1111
len = (v>>2) + 1 + (extend<<6);
1112
extend = 0;
1113
if (len > skip_xx)
1114
{
1115
len -= skip_xx;
1116
goto transparent_run;
1117
}
1118
break;
1119
case 2: /* Solid */
1120
eol = v & 4;
1121
len = (v>>3) + 1 + (extend<<5);
1122
extend = 0;
1123
if (len > skip_xx)
1124
{
1125
len -= skip_xx;
1126
goto solid_run;
1127
}
1128
break;
1129
default: /* Intermediate */
1130
eol = v & 4;
1131
len = (v>>3) + 1 + (extend<<5);
1132
extend = 0;
1133
if (len > skip_xx)
1134
{
1135
runp += skip_xx;
1136
len -= skip_xx;
1137
goto intermediate_run;
1138
}
1139
runp += len;
1140
break;
1141
}
1142
if (eol)
1143
{
1144
ww = 0;
1145
break;
1146
}
1147
skip_xx -= len;
1148
}
1149
while (ww > 0)
1150
{
1151
int v = *runp++;
1152
switch(v & 3)
1153
{
1154
case 0: /* Extend */
1155
extend = v>>2;
1156
break;
1157
case 1: /* Transparent */
1158
len = (v>>2) + 1 + (extend<<6);
1159
extend = 0;
1160
transparent_run:
1161
if (len > ww)
1162
len = ww;
1163
ww -= len;
1164
ddp += len * n;
1165
break;
1166
case 2: /* Solid */
1167
eol = v & 4;
1168
len = (v>>3) + 1 + (extend<<5);
1169
extend = 0;
1170
solid_run:
1171
if (len > ww)
1172
len = ww;
1173
ww -= len;
1174
do
1175
{
1176
int k = 0;
1177
do
1178
{
1179
*ddp++ = colorbv[k++];
1180
}
1181
while (k != n);
1182
}
1183
while (--len);
1184
break;
1185
default: /* Intermediate */
1186
eol = v & 4;
1187
len = (v>>3) + 1 + (extend<<5);
1188
extend = 0;
1189
intermediate_run:
1190
if (len > ww)
1191
len = ww;
1192
ww -= len;
1193
do
1194
{
1195
int k = 0;
1196
int a = *runp++;
1197
a = FZ_EXPAND(a);
1198
do
1199
{
1200
*ddp = FZ_BLEND(colorbv[k++], *ddp, a);
1201
ddp++;
1202
}
1203
while (k != n-1);
1204
*ddp = FZ_BLEND(0xFF, *ddp, a);
1205
ddp++;
1206
}
1207
while (--len);
1208
break;
1209
}
1210
if (eol)
1211
break;
1212
}
1213
}
1214
dp += span;
1215
}
1216
}
1217
1218
static inline void
1219
fz_paint_glyph_alpha(unsigned char *colorbv, int n, int span, unsigned char *dp, fz_glyph *glyph, int w, int h, int skip_x, int skip_y)
1220
{
1221
switch (n)
1222
{
1223
case 4:
1224
fz_paint_glyph_alpha_N(colorbv, 4, span, dp, glyph, w, h, skip_x, skip_y);
1225
break;
1226
case 2:
1227
fz_paint_glyph_alpha_N(colorbv, 2, span, dp, glyph, w, h, skip_x, skip_y);
1228
break;
1229
default:
1230
fz_paint_glyph_alpha_N(colorbv, n, span, dp, glyph, w, h, skip_x, skip_y);
1231
break;
1232
}
1233
}
1234
1235
static inline void
1236
fz_paint_glyph_solid(unsigned char *colorbv, int n, int span, unsigned char *dp, fz_glyph *glyph, int w, int h, int skip_x, int skip_y)
1237
{
1238
switch (n)
1239
{
1240
case 4:
1241
fz_paint_glyph_solid_N(colorbv, 4, span, dp, glyph, w, h, skip_x, skip_y);
1242
break;
1243
case 2:
1244
fz_paint_glyph_solid_N(colorbv, 2, span, dp, glyph, w, h, skip_x, skip_y);
1245
break;
1246
default:
1247
fz_paint_glyph_solid_N(colorbv, n, span, dp, glyph, w, h, skip_x, skip_y);
1248
break;
1249
}
1250
}
1251
1252
void
1253
fz_paint_glyph(unsigned char *colorbv, fz_pixmap *dst, unsigned char *dp, fz_glyph *glyph, int w, int h, int skip_x, int skip_y)
1254
{
1255
if (dst->colorspace)
1256
{
1257
if (colorbv[dst->n-1] == 255)
1258
fz_paint_glyph_solid(colorbv, dst->n, dst->w * dst->n, dp, glyph, w, h, skip_x, skip_y);
1259
else if (colorbv[dst->n-1] != 0)
1260
fz_paint_glyph_alpha(colorbv, dst->n, dst->w * dst->n, dp, glyph, w, h, skip_x, skip_y);
1261
}
1262
else
1263
fz_paint_glyph_mask(dst->w, dp, glyph, w, h, skip_x, skip_y);
1264
}
1265
1266