e930fc6229c568bd826d2a8f6834817772ee1dfc
[platform/core/uifw/dali-adaptor.git] / platform-abstractions / portable / alpha-mask.cpp
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "pixel-manipulation.h"
18 #include "alpha-mask.h"
19 #include "pixel-buffer-impl.h"
20
21 namespace Dali
22 {
23 namespace Internal
24 {
25 namespace Adaptor
26 {
27
28
29 void ApplyMaskToAlphaChannel( PixelBuffer& buffer, const PixelBuffer& mask )
30 {
31   const float rowFactor = float(mask.GetHeight()) / (1.0f * buffer.GetHeight());
32   const float colFactor = float(mask.GetWidth()) / (1.0f * buffer.GetWidth()) ;
33
34   int numSamples = 1;
35   if( mask.GetHeight() > buffer.GetHeight() || mask.GetWidth() > buffer.GetWidth() )
36   {
37     numSamples = 4;
38   }
39
40   int srcAlphaByteOffset=0;
41   int srcAlphaMask=0;
42   Dali::Pixel::Format srcPixelFormat = mask.GetPixelFormat();
43
44   Channel alphaChannel = ALPHA;
45   if( Pixel::HasAlpha(srcPixelFormat) )
46   {
47     Dali::Pixel::GetAlphaOffsetAndMask( srcPixelFormat, srcAlphaByteOffset, srcAlphaMask );
48   }
49   else if( srcPixelFormat == Pixel::L8 )
50   {
51     srcAlphaMask=0xFF;
52     alphaChannel = LUMINANCE;
53   }
54
55   int destAlphaByteOffset=0;
56   int destAlphaMask=0;
57   Dali::Pixel::GetAlphaOffsetAndMask( buffer.GetPixelFormat(), destAlphaByteOffset, destAlphaMask );
58
59   unsigned int srcBytesPerPixel = Dali::Pixel::GetBytesPerPixel( srcPixelFormat );
60   int srcStride = mask.GetWidth() * srcBytesPerPixel;
61   unsigned char* srcBuffer = mask.GetBuffer();
62   unsigned char* destBuffer = buffer.GetBuffer();
63
64   unsigned int destBytesPerPixel = Dali::Pixel::GetBytesPerPixel( buffer.GetPixelFormat() );
65
66   int srcOffset=0;
67   int destOffset=0;
68
69   float srcAlphaValue = 1.0f;
70
71   for( unsigned int row = 0; row < buffer.GetHeight(); ++row )
72   {
73     for( unsigned int col = 0; col < buffer.GetWidth(); ++col )
74     {
75       if( numSamples == 1 )
76       {
77         srcOffset = floorf(row * rowFactor) * srcStride + floorf(col * colFactor) * srcBytesPerPixel;
78         unsigned char alpha = srcBuffer[srcOffset + srcAlphaByteOffset] & srcAlphaMask;
79         srcAlphaValue = float(alpha)/255.0f;
80       }
81       else
82       {
83         srcAlphaValue = ReadWeightedSample( srcBuffer, srcPixelFormat, srcStride, col*colFactor, row*rowFactor, mask.GetWidth(), mask.GetHeight(), alphaChannel );
84       }
85
86       unsigned char destAlpha = destBuffer[destOffset + destAlphaByteOffset] & destAlphaMask;
87       float destAlphaValue = Clamp(float(destAlpha) * srcAlphaValue, 0.0f, 255.0f);
88       destAlpha = destAlphaValue;
89       destBuffer[destOffset + destAlphaByteOffset] &= ~destAlphaMask;
90       destBuffer[destOffset + destAlphaByteOffset] |= ( destAlpha & destAlphaMask );
91
92       destOffset += destBytesPerPixel;
93     }
94   }
95 }
96
97 PixelBufferPtr CreateNewMaskedBuffer( const PixelBuffer& buffer, const PixelBuffer& mask )
98 {
99   const float rowFactor = float(mask.GetHeight()) / (1.0f * buffer.GetHeight());
100   const float colFactor = float(mask.GetWidth()) / (1.0f * buffer.GetWidth()) ;
101
102   int numSamples = 1;
103   if( mask.GetHeight() > buffer.GetHeight() || mask.GetWidth() > buffer.GetWidth() )
104   {
105     numSamples = 4;
106   }
107
108   // Set up source alpha offsets
109   int srcAlphaByteOffset=0;
110   int srcAlphaMask=0;
111   Dali::Pixel::Format srcPixelFormat = mask.GetPixelFormat();
112   Channel alphaChannel = ALPHA;
113   if( Pixel::HasAlpha(srcPixelFormat) )
114   {
115     Dali::Pixel::GetAlphaOffsetAndMask( srcPixelFormat, srcAlphaByteOffset, srcAlphaMask );
116   }
117   else if( srcPixelFormat == Pixel::L8 )
118   {
119     srcAlphaMask=0xFF;
120     alphaChannel = LUMINANCE;
121   }
122
123   unsigned int srcBytesPerPixel = Dali::Pixel::GetBytesPerPixel( srcPixelFormat );
124   int srcStride = mask.GetWidth() * srcBytesPerPixel;
125   unsigned char* srcBuffer = mask.GetBuffer();
126
127   // Set up source color offsets
128   Dali::Pixel::Format srcColorPixelFormat = buffer.GetPixelFormat();
129   unsigned int srcColorBytesPerPixel = Dali::Pixel::GetBytesPerPixel( srcColorPixelFormat );
130
131   // Setup destination offsets
132   Dali::Pixel::Format destPixelFormat = Dali::Pixel::RGBA8888;
133   unsigned int destBytesPerPixel = Dali::Pixel::GetBytesPerPixel( destPixelFormat );
134   int destAlphaByteOffset=0;
135   int destAlphaMask=0;
136   Dali::Pixel::GetAlphaOffsetAndMask( destPixelFormat, destAlphaByteOffset, destAlphaMask );
137
138   PixelBufferPtr newPixelBuffer = PixelBuffer::New( buffer.GetWidth(), buffer.GetHeight(),
139                                                     destPixelFormat );
140   unsigned char* destBuffer = newPixelBuffer->GetBuffer();
141
142   unsigned char* oldBuffer = buffer.GetBuffer();
143
144   int srcAlphaOffset=0;
145   int srcColorOffset=0;
146   int destOffset=0;
147   bool hasAlpha = Dali::Pixel::HasAlpha(buffer.GetPixelFormat());
148
149   float srcAlphaValue = 1.0f;
150   unsigned char destAlpha = 0;
151
152   for( unsigned int row = 0; row < buffer.GetHeight(); ++row )
153   {
154     for( unsigned int col = 0; col < buffer.GetWidth(); ++col )
155     {
156       if( numSamples == 1 )
157       {
158         srcAlphaOffset = floorf(row * rowFactor) * srcStride + floorf(col * colFactor) * srcBytesPerPixel;
159         unsigned char alpha = srcBuffer[srcAlphaOffset + srcAlphaByteOffset] & srcAlphaMask;
160         srcAlphaValue = float(alpha)/255.0f;
161       }
162       else
163       {
164         srcAlphaValue = ReadWeightedSample( srcBuffer, srcPixelFormat, srcStride, col*colFactor, row*rowFactor, mask.GetWidth(), mask.GetHeight(), alphaChannel );
165       }
166
167       ConvertColorChannelsToRGBA8888(oldBuffer, srcColorOffset, srcColorPixelFormat, destBuffer, destOffset );
168
169       if( hasAlpha )
170       {
171         destAlpha = ConvertAlphaChannelToA8( oldBuffer, srcColorOffset, srcColorPixelFormat );
172         float destAlphaValue = Clamp(float(destAlpha) * srcAlphaValue, 0.0f, 255.0f);
173         destAlpha = destAlphaValue;
174       }
175       else
176       {
177         destAlpha = floorf(Clamp(srcAlphaValue * 255.0f, 0.0f, 255.0f));
178       }
179
180       destBuffer[destOffset + destAlphaByteOffset] &= ~destAlphaMask;
181       destBuffer[destOffset + destAlphaByteOffset] |= ( destAlpha & destAlphaMask );
182
183       srcColorOffset += srcColorBytesPerPixel;
184       destOffset += destBytesPerPixel;
185     }
186   }
187
188   return newPixelBuffer;
189 }
190
191
192 float ReadWeightedSample( unsigned char* buffer, Pixel::Format pixelFormat, int stride, float x, float y, int width, int height, Channel alphaChannel )
193 {
194   int srcRow = floorf( y );
195   int srcCol = floorf( x );
196
197   int bytesPerPixel = Dali::Pixel::GetBytesPerPixel( pixelFormat );
198   int srcOffset = srcRow * stride + srcCol * bytesPerPixel;
199   float samples[4];
200
201   samples[0] = ReadChannel( buffer + srcOffset, pixelFormat, alphaChannel );
202
203   if( srcCol < width-1 )
204   {
205     samples[1] = ReadChannel( buffer + srcOffset+bytesPerPixel, pixelFormat, alphaChannel );
206   }
207   else
208   {
209     samples[1] = samples[0];
210   }
211
212   if( srcRow < height-1 )
213   {
214     samples[2] = ReadChannel( buffer + stride + srcOffset, pixelFormat, alphaChannel );
215   }
216   else
217   {
218     samples[2] = samples[0];
219   }
220
221   if( srcRow < height-1 && srcCol < width-1 )
222   {
223     samples[3] = ReadChannel( buffer + stride + srcOffset + bytesPerPixel, pixelFormat, alphaChannel );
224   }
225   else
226   {
227     samples[3] = samples[2];
228   }
229
230   // Bilinear interpolation:
231   float weight[4];
232   weight[0] = float(srcRow+1.0f) - y;
233   weight[1] = y - float(srcRow);
234   weight[2] = float(srcCol+1.0f) - x;
235   weight[3] = x - float(srcCol);
236
237   return ( weight[2] * (samples[0] * weight[0] + samples[1] * weight[1]) +
238            weight[3] * (samples[2] * weight[0] + samples[3] * weight[1]) ) / 255.0f;
239 }
240
241 } //namespace Adaptor
242
243 }// namespace Internal
244
245 }// namespace Dali