sw_composite/
blend.rs

1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7#![allow(non_snake_case)]
8
9use crate::*;
10
11pub trait Blend {
12    fn blend(src: u32, dst: u32) -> u32;
13}
14
15pub struct Dst;
16
17impl Blend for Dst {
18    #[inline]
19    fn blend(_src: u32, dst: u32) -> u32 {
20        dst
21    }
22}
23
24pub struct Src;
25
26impl Blend for Src {
27    #[inline]
28    fn blend(src: u32, _dst: u32) -> u32 {
29        src
30    }
31}
32
33pub struct Clear;
34
35impl Blend for Clear {
36    #[inline]
37    fn blend(_src: u32, _dst: u32) -> u32 {
38        0
39    }
40}
41
42pub struct SrcOver;
43
44impl Blend for SrcOver {
45    #[inline]
46    fn blend(src: u32, dst: u32) -> u32 {
47        over(src, dst)
48    }
49}
50
51pub struct DstOver;
52
53impl Blend for DstOver {
54    #[inline]
55    fn blend(src: u32, dst: u32) -> u32 {
56        over(dst, src)
57    }
58}
59
60pub struct SrcIn;
61
62impl Blend for SrcIn {
63    #[inline]
64    fn blend(src: u32, dst: u32) -> u32 {
65        alpha_mul(src, alpha_to_alpha256(packed_alpha(dst)))
66    }
67}
68
69pub struct DstIn;
70
71impl Blend for DstIn {
72    #[inline]
73    fn blend(src: u32, dst: u32) -> u32 {
74        alpha_mul(dst, alpha_to_alpha256(packed_alpha(src)))
75    }
76}
77
78pub struct SrcOut;
79
80impl Blend for SrcOut {
81    #[inline]
82    fn blend(src: u32, dst: u32) -> u32 {
83        alpha_mul(src, alpha_to_alpha256(255 - packed_alpha(dst)))
84    }
85}
86
87pub struct DstOut;
88
89impl Blend for DstOut {
90    #[inline]
91    fn blend(src: u32, dst: u32) -> u32 {
92        alpha_mul(dst, alpha_to_alpha256(255 - packed_alpha(src)))
93    }
94}
95
96pub struct SrcAtop;
97
98impl Blend for SrcAtop {
99    #[inline]
100    fn blend(src: u32, dst: u32) -> u32 {
101        let sa = packed_alpha(src);
102        let da = packed_alpha(dst);
103        let isa = 255 - sa;
104
105        pack_argb32(
106            da,
107            muldiv255(da, get_packed_r32(src)) + muldiv255(isa, get_packed_r32(dst)),
108            muldiv255(da, get_packed_g32(src)) + muldiv255(isa, get_packed_g32(dst)),
109            muldiv255(da, get_packed_b32(src)) + muldiv255(isa, get_packed_b32(dst))
110        )
111    }
112}
113
114pub struct DstAtop;
115
116impl Blend for DstAtop {
117    #[inline]
118    fn blend(src: u32, dst: u32) -> u32 {
119        let sa = packed_alpha(src);
120        let da = packed_alpha(dst);
121        let ida = 255 - da;
122
123        pack_argb32(
124            sa,
125            muldiv255(ida, get_packed_r32(src)) + muldiv255(sa, get_packed_r32(dst)),
126            muldiv255(ida, get_packed_g32(src)) + muldiv255(sa, get_packed_g32(dst)),
127            muldiv255(ida, get_packed_b32(src)) + muldiv255(sa, get_packed_b32(dst))
128        )
129    }
130}
131
132pub struct Xor;
133
134impl Blend for Xor {
135    #[inline]
136    fn blend(src: u32, dst: u32) -> u32 {
137        let sa = packed_alpha(src);
138        let da = packed_alpha(dst);
139        let isa = 255 - sa;
140        let ida = 255 - da;
141
142        pack_argb32(
143            sa + da - (muldiv255(sa, da) * 2),
144            muldiv255(ida, get_packed_r32(src)) + muldiv255(isa, get_packed_r32(dst)),
145            muldiv255(ida, get_packed_g32(src)) + muldiv255(isa, get_packed_g32(dst)),
146            muldiv255(ida, get_packed_b32(src)) + muldiv255(isa, get_packed_b32(dst))
147        )
148    }
149}
150
151fn saturated_add(a: u32, b: u32) -> u32 {
152    debug_assert!(a <= 255);
153    debug_assert!(b <= 255);
154    let sum = a + b;
155    if sum > 255 {
156        255
157    } else {
158        sum
159    }
160}
161
162pub struct Add;
163
164impl Blend for Add {
165    #[inline]
166    fn blend(src: u32, dst: u32) -> u32 {
167        pack_argb32(
168            saturated_add(get_packed_a32(src), get_packed_a32(dst)),
169            saturated_add(get_packed_r32(src), get_packed_r32(dst)),
170            saturated_add(get_packed_g32(src), get_packed_g32(dst)),
171            saturated_add(get_packed_b32(src), get_packed_b32(dst))
172        )
173    }
174}
175
176// kMultiply_Mode
177// B(Cb, Cs) = Cb x Cs
178// multiply uses its own version of blendfunc_byte because sa and da are not needed
179fn blendfunc_multiply_byte(sc: i32, dc: i32, sa: i32, da: i32) -> u32 {
180    clamp_div255round(sc * (255 - da) + dc * (255 - sa) + sc * dc)
181}
182
183pub struct Multiply;
184
185impl Blend for Multiply {
186    fn blend(src: u32, dst: u32) -> u32 {
187        let sa = get_packed_a32(src) as i32;
188        let da = get_packed_a32(dst) as i32;
189        pack_argb32(
190            srcover_byte(get_packed_a32(src), get_packed_a32(dst)),
191            blendfunc_multiply_byte(get_packed_r32(src) as i32, get_packed_r32(dst) as i32, sa, da),
192            blendfunc_multiply_byte(get_packed_g32(src) as i32, get_packed_g32(dst) as i32, sa, da),
193            blendfunc_multiply_byte(get_packed_b32(src) as i32, get_packed_b32(dst) as i32, sa, da)
194        )
195    }
196}
197
198#[inline]
199fn srcover_byte(a: u32, b: u32) -> u32 {
200    a + b - muldiv255(a, b)
201}
202
203pub struct Screen;
204
205impl Blend for Screen {
206    #[inline]
207    fn blend(src: u32, dst: u32) -> u32 {
208        pack_argb32(
209            srcover_byte(get_packed_a32(src), get_packed_a32(dst)),
210            srcover_byte(get_packed_r32(src), get_packed_r32(dst)),
211            srcover_byte(get_packed_g32(src), get_packed_g32(dst)),
212            srcover_byte(get_packed_b32(src), get_packed_b32(dst))
213        )
214    }
215}
216
217fn clamp_div255round(prod: i32) -> u32 {
218    if prod <= 0 {
219        0
220    } else if prod >= 255 * 255 {
221        255
222    } else {
223        div255(prod as u32)
224    }
225}
226
227fn overlay_byte(sc: u32, dc: u32, sa: u32, da: u32) -> u32 {
228    let tmp = sc * (255 - da) + dc * (255 - sa);
229    let rc;
230    if 2 * dc <= da {
231        rc = 2 * sc * dc;
232    } else {
233        rc = sa * da - 2 * (da - dc) * (sa - sc);
234    }
235    clamp_div255round((rc + tmp) as i32)
236}
237
238pub struct Overlay;
239
240impl Blend for Overlay {
241    fn blend(src: u32, dst: u32) -> u32 {
242        let sa = get_packed_a32(src);
243        let da = get_packed_a32(dst);
244        pack_argb32(
245            srcover_byte(sa, da),
246            overlay_byte(get_packed_r32(src), get_packed_r32(dst), sa, da),
247            overlay_byte(get_packed_g32(src), get_packed_g32(dst), sa, da),
248            overlay_byte(get_packed_b32(src), get_packed_b32(dst), sa, da)
249        )
250    }
251}
252
253fn darken_byte(sc: u32, dc: u32, sa: u32, da: u32) -> u32 {
254    let sd = sc * da;
255    let ds = dc * sa;
256    if sd < ds {
257        // srcover
258        sc + dc - div255(ds)
259    } else {
260        // dstover
261        dc + sc - div255(sd)
262    }
263}
264
265pub struct Darken;
266
267impl Blend for Darken {
268    fn blend(src: u32, dst: u32) -> u32 {
269        let sa = get_packed_a32(src);
270        let da = get_packed_a32(dst);
271        pack_argb32(
272            srcover_byte(sa, da),
273            darken_byte(get_packed_r32(src), get_packed_r32(dst), sa, da),
274            darken_byte(get_packed_g32(src), get_packed_g32(dst), sa, da),
275            darken_byte(get_packed_b32(src), get_packed_b32(dst), sa, da)
276        )
277    }
278}
279
280fn lighten_byte(sc: u32, dc: u32, sa: u32, da: u32) -> u32 {
281    let sd = sc * da;
282    let ds = dc * sa;
283    if sd > ds {
284        // srcover
285        sc + dc - div255(ds)
286    } else {
287        // dstover
288        dc + sc - div255(sd)
289    }
290}
291
292pub struct Lighten;
293
294impl Blend for Lighten {
295    fn blend(src: u32, dst: u32) -> u32 {
296        let sa = get_packed_a32(src);
297        let da = get_packed_a32(dst);
298        pack_argb32(
299            srcover_byte(sa, da),
300            lighten_byte(get_packed_r32(src), get_packed_r32(dst), sa, da),
301            lighten_byte(get_packed_g32(src), get_packed_g32(dst), sa, da),
302            lighten_byte(get_packed_b32(src), get_packed_b32(dst), sa, da)
303        )
304    }
305}
306
307fn colordodge_byte(sc: i32, dc: i32, sa: i32, da: i32) -> u32 {
308    let mut diff = sa - sc;
309    let rc = if 0 == dc {
310        return muldiv255(sc as u32, (255 - da) as u32);
311    } else if 0 == diff {
312        sa * da + sc * (255 - da) + dc * (255 - sa)
313    } else {
314        diff = (dc * sa) / diff;
315        sa * (if da < diff { da } else { diff }) + sc * (255 - da) + dc * (255 - sa)
316    };
317    clamp_div255round(rc)
318}
319
320pub struct ColorDodge;
321
322impl Blend for ColorDodge {
323    fn blend(src: u32, dst: u32) -> u32 {
324        let sa = get_packed_a32(src) as i32;
325        let da = get_packed_a32(dst) as i32;
326        pack_argb32(
327            srcover_byte(sa as u32, da as u32),
328            colordodge_byte(get_packed_r32(src) as i32, get_packed_r32(dst) as i32, sa, da),
329            colordodge_byte(get_packed_g32(src) as i32, get_packed_g32(dst) as i32, sa, da),
330            colordodge_byte(get_packed_b32(src) as i32, get_packed_b32(dst) as i32, sa, da)
331        )
332    }
333}
334
335fn colorburn_byte(sc: i32, dc: i32, sa: i32, da: i32) -> u32 {
336    let rc = if dc == da {
337        sa * da + sc * (255 - da) + dc * (255 - sa)
338    } else if 0 == sc {
339        return muldiv255(dc as u32, (255 - sa) as u32);
340    } else {
341        let tmp = (da - dc) * sa / sc;
342        sa * (da - (if da < tmp { da } else { tmp }))
343           + sc * (255 - da) + dc * (255 - sa)
344    };
345    clamp_div255round(rc)
346}
347
348pub struct ColorBurn;
349
350impl Blend for ColorBurn {
351    fn blend(src: u32, dst: u32) -> u32 {
352        let sa = get_packed_a32(src) as i32;
353        let da = get_packed_a32(dst) as i32;
354        pack_argb32(
355            srcover_byte(sa as u32, da as u32),
356            colorburn_byte(get_packed_r32(src) as i32, get_packed_r32(dst) as i32, sa, da),
357            colorburn_byte(get_packed_g32(src) as i32, get_packed_g32(dst) as i32, sa, da),
358            colorburn_byte(get_packed_b32(src) as i32, get_packed_b32(dst) as i32, sa, da)
359        )
360    }
361}
362
363fn hardlight_byte(sc: i32, dc: i32, sa: i32, da: i32) -> u32 {
364    let rc = if 2 * sc <= sa {
365        2 * sc * dc
366    } else {
367        sa * da - 2 * (da - dc) * (sa - sc)
368    };
369    clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa))
370}
371
372pub struct HardLight;
373
374impl Blend for HardLight {
375    fn blend(src: u32, dst: u32) -> u32 {
376        let sa = get_packed_a32(src) as i32;
377        let da = get_packed_a32(dst) as i32;
378        pack_argb32(
379            srcover_byte(sa as u32, da as u32),
380            hardlight_byte(get_packed_r32(src) as i32, get_packed_r32(dst) as i32, sa, da),
381            hardlight_byte(get_packed_g32(src) as i32, get_packed_g32(dst) as i32, sa, da),
382            hardlight_byte(get_packed_b32(src) as i32, get_packed_b32(dst) as i32, sa, da)
383        )
384    }
385}
386
387// https://web.archive.org/web/20060317035105/www.worldserver.com/turk/computergraphics/FixedSqrt.pdf
388fn sqrt_bits(x: i32, count: i32) -> i32 {
389    debug_assert!(x >= 0 && count > 0 && count <= 30);
390
391    let mut root = 0;
392    let mut rem_hi = 0;
393    let mut rem_lo = x;
394
395    loop {
396        root <<= 1;
397
398        rem_hi = (rem_hi << 2) | (rem_lo >> 30);
399        rem_lo <<= 2;
400
401        let test_div = (root << 1) + 1;
402        if rem_hi >= test_div {
403            rem_hi -= test_div;
404            root += 1;
405        }
406        if -count < 0 {
407            break;
408        }
409    }
410
411    root
412}
413
414type U8Cpu = u32;
415
416// returns 255 * sqrt(n/255)
417fn sqrt_unit_byte(n: U8Cpu) -> U8Cpu {
418    sqrt_bits(n as i32, 15 + 4) as u32
419}
420
421fn softlight_byte(sc: i32, dc: i32, sa: i32, da: i32) -> u32 {
422    let m = if da != 0 { dc * 256 / da } else { 0 };
423    let rc = if 2 * sc <= sa {
424        dc * (sa + ((2 * sc - sa) * (256 - m) >> 8))
425    } else if 4 * dc <= da {
426        let tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m;
427        dc * sa + (da * (2 * sc - sa) * tmp >> 8)
428    } else {
429        let tmp = sqrt_unit_byte(m as u32) as i32 - m;
430        dc * sa + (da * (2 * sc - sa) * tmp >> 8)
431    };
432    clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa))
433}
434
435pub struct SoftLight;
436
437impl Blend for SoftLight {
438    fn blend(src: u32, dst: u32) -> u32 {
439        let sa = get_packed_a32(src) as i32;
440        let da = get_packed_a32(dst) as i32;
441        pack_argb32(
442            srcover_byte(sa as u32, da as u32),
443            softlight_byte(get_packed_r32(src) as i32, get_packed_r32(dst) as i32, sa, da),
444            softlight_byte(get_packed_g32(src) as i32, get_packed_g32(dst) as i32, sa, da),
445            softlight_byte(get_packed_b32(src) as i32, get_packed_b32(dst) as i32, sa, da)
446        )
447    }
448}
449
450
451fn clamp_signed_byte(n: i32) -> u32 {
452    if n < 0 {
453        0
454    } else if n > 255 {
455        255
456    } else {
457        n as u32
458    }
459}
460
461fn difference_byte(sc: i32, dc: i32, sa: i32, da: i32) -> u32 {
462    let tmp = (sc * da).min(dc * sa);
463    clamp_signed_byte(sc + dc - 2 * div255(tmp as u32) as i32)
464}
465
466pub struct Difference;
467
468impl Blend for Difference {
469    fn blend(src: u32, dst: u32) -> u32 {
470        let sa = get_packed_a32(src) as i32;
471        let da = get_packed_a32(dst) as i32;
472        pack_argb32(
473            srcover_byte(sa as u32, da as u32),
474            difference_byte(get_packed_r32(src) as i32, get_packed_r32(dst) as i32, sa, da),
475            difference_byte(get_packed_g32(src) as i32, get_packed_g32(dst) as i32, sa, da),
476            difference_byte(get_packed_b32(src) as i32, get_packed_b32(dst) as i32, sa, da)
477        )
478    }
479}
480
481fn exclusion_byte(sc: i32, dc: i32, _sa: i32, _da: i32) -> u32 {
482    // this equations is wacky, wait for SVG to confirm it
483    //int r = sc * da + dc * sa - 2 * sc * dc + sc * (255 - da) + dc * (255 - sa);
484
485    // The above equation can be simplified as follows
486    let r = 255 * (sc + dc) - 2 * sc * dc;
487    clamp_div255round(r)
488}
489
490pub struct Exclusion;
491
492impl Blend for Exclusion {
493    fn blend(src: u32, dst: u32) -> u32 {
494        let sa = get_packed_a32(src) as i32;
495        let da = get_packed_a32(dst) as i32;
496        pack_argb32(
497            srcover_byte(sa as u32, da as u32),
498            exclusion_byte(get_packed_r32(src) as i32, get_packed_r32(dst) as i32, sa, da),
499            exclusion_byte(get_packed_g32(src) as i32, get_packed_g32(dst) as i32, sa, da),
500            exclusion_byte(get_packed_b32(src) as i32, get_packed_b32(dst) as i32, sa, da)
501        )
502    }
503}
504
505// The CSS compositing spec introduces the following formulas:
506// (See https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnonseparable)
507// SkComputeLuminance is similar to this formula but it uses the new definition from Rec. 709
508// while PDF and CG uses the one from Rec. Rec. 601
509// See http://www.glennchan.info/articles/technical/hd-versus-sd-color-space/hd-versus-sd-color-space.htm
510fn lum(r: i32, g: i32, b: i32) -> i32 {
511    div255((r * 77 + g * 150 + b * 28) as u32) as i32
512}
513
514fn mul_div(numer1: i32, numer2: i32, denom: i32) -> i32 {
515    ((numer1 as i64 * numer2 as i64) / denom as i64) as i32
516}
517
518fn minimum(a: i32, b: i32, c: i32) -> i32 {
519    a.min(b).min(c)
520}
521
522fn maximum(a: i32, b: i32, c: i32) -> i32 {
523    a.max(b).max(c)
524}
525
526fn clip_color(r: &mut i32, g: &mut i32, b: &mut i32, a: i32) {
527    let L = lum(*r, *g, *b);
528    let n = minimum(*r, *g, *b);
529    let x = maximum(*r, *g, *b);
530    let denom = L - n;
531    if (n < 0) && (denom != 0) { // Compute denom and make sure it's non zero
532        *r = L + mul_div(*r - L, L, denom);
533        *g = L + mul_div(*g - L, L, denom);
534        *b = L + mul_div(*b - L, L, denom);
535    }
536
537    let denom = x - L;
538    if (x > a) && (denom != 0) { // Compute denom and make sure it's non zero
539        let numer = a - L;
540        *r = L + mul_div(*r - L, numer, denom);
541        *g = L + mul_div(*g - L, numer, denom);
542        *b = L + mul_div(*b - L, numer, denom);
543    }
544}
545
546fn sat(r: i32, g: i32, b: i32) -> i32 {
547    maximum(r, g, b) - minimum(r, g, b)
548}
549
550fn set_saturation_components(cmin: &mut i32, cmind: &mut i32, cmax: &mut i32, s: i32) {
551    if *cmax > *cmin {
552        *cmind = mul_div(*cmind - *cmin, s, *cmax - *cmin);
553        *cmax = s;
554    } else {
555        *cmax = 0;
556        *cmind = 0;
557    }
558
559    *cmin = 0;
560}
561
562fn set_sat(r: &mut i32, g: &mut i32, b: &mut i32, s: i32) {
563    if *r <= *g {
564        if *g <= *b {
565            set_saturation_components(r, g, b, s);
566        } else if *r <= *b {
567            set_saturation_components(r, b, g, s);
568        } else {
569            set_saturation_components(b, r, g, s);
570        }
571    } else if *r <= *b {
572        set_saturation_components(g, r, b, s);
573    } else if *g <= *b {
574        set_saturation_components(g, b, r, s);
575    } else {
576        set_saturation_components(b, g, r, s);
577    }
578}
579
580fn set_lum(r: &mut i32, g: &mut i32, b: &mut i32, a: i32, l: i32) {
581    let d = l - lum(*r, *g, *b);
582    *r += d;
583    *g += d;
584    *b += d;
585
586    clip_color(r, g, b, a);
587}
588
589// non-separable blend modes are done in non-premultiplied alpha
590fn blendfunc_nonsep_byte(sc: i32, dc: i32, sa: i32, da: i32, blendval: i32) -> u32 {
591    clamp_div255round(sc * (255 - da) + dc * (255 - sa) + blendval)
592}
593
594pub struct Hue;
595
596impl Blend for Hue {
597    fn blend(src: u32, dst: u32) -> u32 {
598        let sr = get_packed_r32(src) as i32;
599        let sg = get_packed_g32(src) as i32;
600        let sb = get_packed_b32(src) as i32;
601        let sa = get_packed_a32(src) as i32;
602
603        let dr = get_packed_r32(dst) as i32;
604        let dg = get_packed_g32(dst) as i32;
605        let db = get_packed_b32(dst) as i32;
606        let da = get_packed_a32(dst) as i32;
607        let mut Sr;
608        let mut Sg;
609        let mut Sb;
610
611        if sa != 0 && da != 0 {
612            Sr = sr * sa;
613            Sg = sg * sa;
614            Sb = sb * sa;
615            set_sat(&mut Sr, &mut Sg, &mut Sb, sat(dr, dg, db) * sa);
616            set_lum(&mut Sr, &mut Sg, &mut Sb, sa * da, lum(dr, dg, db) * sa);
617        } else {
618            Sr = 0;
619            Sg = 0;
620            Sb = 0;
621        }
622
623        pack_argb32(
624            srcover_byte(sa as u32, da as u32),
625            blendfunc_nonsep_byte(sr, dr, sa, da, Sr),
626            blendfunc_nonsep_byte(sg, dg, sa, da, Sg),
627            blendfunc_nonsep_byte(sb, db, sa, da, Sb)
628        )
629    }
630}
631
632pub struct Saturation;
633
634impl Blend for Saturation {
635    fn blend(src: u32, dst: u32) -> u32 {
636        let sr = get_packed_r32(src) as i32;
637        let sg = get_packed_g32(src) as i32;
638        let sb = get_packed_b32(src) as i32;
639        let sa = get_packed_a32(src) as i32;
640
641        let dr = get_packed_r32(dst) as i32;
642        let dg = get_packed_g32(dst) as i32;
643        let db = get_packed_b32(dst) as i32;
644        let da = get_packed_a32(dst) as i32;
645        let mut Dr;
646        let mut Dg;
647        let mut Db;
648
649        if sa != 0 && da != 0 {
650            Dr = dr * sa;
651            Dg = dg * sa;
652            Db = db * sa;
653            set_sat(&mut Dr, &mut Dg, &mut Db, sat(sr, sg, sb) * da);
654            set_lum(&mut Dr, &mut Dg, &mut Db, sa * da, lum(dr, dg, db) * sa);
655        } else {
656            Dr = 0;
657            Dg = 0;
658            Db = 0;
659        }
660
661        pack_argb32(
662            srcover_byte(sa as u32, da as u32),
663            blendfunc_nonsep_byte(sr, dr, sa, da, Dr),
664            blendfunc_nonsep_byte(sg, dg, sa, da, Dg),
665            blendfunc_nonsep_byte(sb, db, sa, da, Db)
666        )
667    }
668}
669
670pub struct Color;
671
672impl Blend for Color {
673    fn blend(src: u32, dst: u32) -> u32 {
674        let sr = get_packed_r32(src) as i32;
675        let sg = get_packed_g32(src) as i32;
676        let sb = get_packed_b32(src) as i32;
677        let sa = get_packed_a32(src) as i32;
678
679        let dr = get_packed_r32(dst) as i32;
680        let dg = get_packed_g32(dst) as i32;
681        let db = get_packed_b32(dst) as i32;
682        let da = get_packed_a32(dst) as i32;
683        let mut Sr;
684        let mut Sg;
685        let mut Sb;
686
687        if sa != 0 && da != 0 {
688            Sr = sr * sa;
689            Sg = sg * sa;
690            Sb = sb * sa;
691            set_lum(&mut Sr, &mut Sg, &mut Sb, sa * da, lum(dr, dg, db) * sa);
692        } else {
693            Sr = 0;
694            Sg = 0;
695            Sb = 0;
696        }
697
698        pack_argb32(
699            srcover_byte(sa as u32, da as u32),
700            blendfunc_nonsep_byte(sr, dr, sa, da, Sr),
701            blendfunc_nonsep_byte(sg, dg, sa, da, Sg),
702            blendfunc_nonsep_byte(sb, db, sa, da, Sb)
703        )
704    }
705}
706
707pub struct Luminosity;
708
709impl Blend for Luminosity {
710    // B(Cb, Cs) = SetLum(Cb, Lum(Cs))
711    // Create a color with the luminosity of the source color and the hue and saturation of the backdrop color.
712    fn blend(src: u32, dst: u32) -> u32 {
713        let sr = get_packed_r32(src) as i32;
714        let sg = get_packed_g32(src) as i32;
715        let sb = get_packed_b32(src) as i32;
716        let sa = get_packed_a32(src) as i32;
717
718        let dr = get_packed_r32(dst) as i32;
719        let dg = get_packed_g32(dst) as i32;
720        let db = get_packed_b32(dst) as i32;
721        let da = get_packed_a32(dst) as i32;
722        let mut Dr;
723        let mut Dg;
724        let mut Db;
725
726        if sa != 0 && da != 0 {
727            Dr = dr * sa;
728            Dg = dg * sa;
729            Db = db * sa;
730            set_lum(&mut Dr, &mut Dg, &mut Db, sa * da, lum(sr, sg, sb) * da);
731        } else {
732            Dr = 0;
733            Dg = 0;
734            Db = 0;
735        }
736
737        pack_argb32(
738            srcover_byte(sa as u32, da as u32),
739            blendfunc_nonsep_byte(sr, dr, sa, da, Dr),
740            blendfunc_nonsep_byte(sg, dg, sa, da, Dg),
741            blendfunc_nonsep_byte(sb, db, sa, da, Db)
742        )
743    }
744}