File indexing completed on 2024-05-26 04:29:13

0001 /*
0002  *  SPDX-FileCopyrightText: 2014 Nicholas Guttenberg <ngutten@gmail.com>
0003  * 
0004  *  Based on KoCompositeOpBehind.h,
0005  *  SPDX-FileCopyrightText: 2012 José Luis Vergara <pentalis@gmail.com>
0006  *
0007  * SPDX-License-Identifier: LGPL-2.0-or-later
0008  *
0009  * This library is distributed in the hope that it will be useful,
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012  * Lesser General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU Lesser General Public License
0015  * along with this library; see the file COPYING.LIB.  If not, write to
0016  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #ifndef _KOCOMPOSITEOPGREATER_H_
0021 #define _KOCOMPOSITEOPGREATER_H_
0022 
0023 #include "KoCompositeOpBase.h"
0024 
0025 /**
0026  * Greater-than compositor - uses the greater of two alpha values to determine the color
0027  */
0028 template<class CS_Traits, typename BlendingPolicy>
0029 class KoCompositeOpGreater : public KoCompositeOpBase<CS_Traits, KoCompositeOpGreater<CS_Traits, BlendingPolicy>>
0030 {
0031     typedef KoCompositeOpBase<CS_Traits, KoCompositeOpGreater<CS_Traits, BlendingPolicy>> base_class;
0032     typedef typename CS_Traits::channels_type channels_type;
0033     typedef typename KoColorSpaceMathsTraits<typename CS_Traits::channels_type>::compositetype composite_type;
0034    
0035     static const qint8 channels_nb = CS_Traits::channels_nb;
0036     static const qint8 alpha_pos   = CS_Traits::alpha_pos;
0037 
0038 public:
0039     KoCompositeOpGreater(const KoColorSpace * cs)
0040         : base_class(cs, COMPOSITE_GREATER, KoCompositeOp::categoryMix()) { }
0041 
0042 public:
0043     template<bool alphaLocked, bool allChannelFlags>
0044     inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha,
0045                                                      channels_type*       dst, channels_type dstAlpha,
0046                                                      channels_type  maskAlpha, channels_type  opacity,
0047                                                      const QBitArray& channelFlags                    )  {
0048         using namespace Arithmetic;
0049                 
0050         if (dstAlpha     == unitValue<channels_type>()) return dstAlpha;
0051         channels_type appliedAlpha       = mul(maskAlpha, srcAlpha, opacity);
0052         
0053         if (appliedAlpha == zeroValue<channels_type>()) return dstAlpha;
0054         channels_type newDstAlpha;
0055         
0056         float dA = scale<float>(dstAlpha);
0057         
0058         float w = 1.0/(1.0+exp(-40.0*(dA - scale<float>(appliedAlpha))));
0059         float a = dA*w + scale<float>(appliedAlpha)*(1.0-w);               
0060         if (a < 0.0f) {
0061             a = 0.0f; 
0062         }
0063         if (a > 1.0f) {
0064             a = 1.0f;
0065         }
0066         
0067         // For a standard Over, the resulting alpha is: a = opacity*dstAlpha + (1-opacity)*srcAlpha
0068         // Let us assume we're blending with a color with srcAlpha = 1 here
0069         // Therefore, opacity = (1.0 - a)/(1.0 - dstAlpha)
0070         if (a<dA) a = dA;
0071         float fakeOpacity = 1.0f - (1.0f - a)/(1.0f - dA + 1e-16f);
0072         newDstAlpha=scale<channels_type>(a);
0073        
0074         if (dstAlpha != zeroValue<channels_type>()) {      
0075             for (qint8 channel = 0; channel < channels_nb; ++channel)
0076                 if(channel != alpha_pos && (allChannelFlags || channelFlags.testBit(channel)))
0077                 {
0078                     typedef typename KoColorSpaceMathsTraits<channels_type>::compositetype composite_type;
0079 
0080                     channels_type dstMult = mul(BlendingPolicy::toAdditiveSpace(dst[channel]), dstAlpha);
0081                     channels_type srcMult = mul(BlendingPolicy::toAdditiveSpace(src[channel]), unitValue<channels_type>());
0082                     channels_type blendedValue = lerp(dstMult, srcMult, scale<channels_type>(fakeOpacity));
0083                     // CID 249016 (#1 of 15):
0084                     // Division or modulo by zero (DIVIDE_BY_ZERO)12. divide_by_zero: In function call divide, division by expression newDstAlpha which may be zero has undefined behavior.
0085                     if (newDstAlpha == 0) newDstAlpha = 1;
0086                     composite_type normedValue = KoColorSpaceMaths<channels_type>::divide(blendedValue, newDstAlpha);
0087 
0088                     dst[channel] = BlendingPolicy::fromAdditiveSpace(KoColorSpaceMaths<channels_type>::clampAfterScale(normedValue));
0089                 }
0090         }       
0091         else {
0092             // don't blend if the color of the destination is undefined (has zero opacity)
0093             // copy the source channel instead
0094             for (qint8 channel = 0; channel < channels_nb; ++channel)
0095                 if(channel != alpha_pos && (allChannelFlags || channelFlags.testBit(channel)))
0096                     dst[channel] = src[channel];
0097         }
0098 
0099         return newDstAlpha;
0100     }
0101 };
0102 
0103 #endif  // _KOCOMPOSITEOPGREATER_H_