Transfer uploadOnly flag to the core and update manager
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / devel-api / utility / npatch-utilities.cpp
1 /*
2 * Copyright (c) 2021 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
18 // CLASS HEADER
19 #include <dali-toolkit/devel-api/utility/npatch-utilities.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23
24 namespace Dali
25 {
26 namespace Toolkit
27 {
28 namespace NPatchUtility
29 {
30 namespace
31 {
32 Uint16Pair ParseRange(uint32_t& index, uint32_t width, uint8_t*& pixel, uint32_t pixelStride, int32_t testByte, int32_t testBits, int32_t testValue)
33 {
34   unsigned int start = 0xFFFF;
35   for(; index < width; ++index, pixel += pixelStride)
36   {
37     if((pixel[testByte] & testBits) == testValue)
38     {
39       start = index;
40       ++index;
41       pixel += pixelStride;
42       break;
43     }
44   }
45
46   unsigned int end = width;
47   for(; index < width; ++index, pixel += pixelStride)
48   {
49     if((pixel[testByte] & testBits) != testValue)
50     {
51       end = index;
52       ++index;
53       pixel += pixelStride;
54       break;
55     }
56   }
57
58   return Uint16Pair(start, end);
59 }
60
61 } // unnamed namespace
62
63 void GetRedOffsetAndMask(Dali::Pixel::Format pixelFormat, int32_t& byteOffset, int32_t& bitMask)
64 {
65   switch(pixelFormat)
66   {
67     case Dali::Pixel::A8:
68     case Dali::Pixel::L8:
69     case Dali::Pixel::LA88:
70     {
71       byteOffset = 0;
72       bitMask    = 0;
73       break;
74     }
75     case Dali::Pixel::RGB888:
76     case Dali::Pixel::RGB8888:
77     case Dali::Pixel::RGBA8888:
78     {
79       byteOffset = 0;
80       bitMask    = 0xFF;
81       break;
82     }
83     case Dali::Pixel::BGR8888:
84     case Dali::Pixel::BGRA8888:
85     {
86       byteOffset = 2;
87       bitMask    = 0xff;
88       break;
89     }
90     case Dali::Pixel::RGB565:
91     {
92       byteOffset = 0;
93       bitMask    = 0xf8;
94       break;
95     }
96     case Dali::Pixel::BGR565:
97     {
98       byteOffset = 1;
99       bitMask    = 0x1f;
100       break;
101     }
102     case Dali::Pixel::RGBA4444:
103     {
104       byteOffset = 0;
105       bitMask    = 0xf0;
106       break;
107     }
108     case Dali::Pixel::BGRA4444:
109     {
110       byteOffset = 1;
111       bitMask    = 0xf0;
112       break;
113     }
114     case Dali::Pixel::RGBA5551:
115     {
116       byteOffset = 0;
117       bitMask    = 0xf8;
118       break;
119     }
120     case Dali::Pixel::BGRA5551:
121     {
122       byteOffset = 1;
123       bitMask    = 0x1e;
124       break;
125     }
126     case Dali::Pixel::INVALID:
127     case Dali::Pixel::COMPRESSED_R11_EAC:
128     case Dali::Pixel::COMPRESSED_SIGNED_R11_EAC:
129     case Dali::Pixel::COMPRESSED_RG11_EAC:
130     case Dali::Pixel::COMPRESSED_SIGNED_RG11_EAC:
131     case Dali::Pixel::COMPRESSED_RGB8_ETC2:
132     case Dali::Pixel::COMPRESSED_SRGB8_ETC2:
133     case Dali::Pixel::COMPRESSED_RGB8_ETC1:
134     case Dali::Pixel::COMPRESSED_RGB_PVRTC_4BPPV1:
135     case Dali::Pixel::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
136     case Dali::Pixel::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
137     case Dali::Pixel::COMPRESSED_RGBA8_ETC2_EAC:
138     case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
139     case Dali::Pixel::COMPRESSED_RGBA_ASTC_4x4_KHR:
140     case Dali::Pixel::COMPRESSED_RGBA_ASTC_5x4_KHR:
141     case Dali::Pixel::COMPRESSED_RGBA_ASTC_5x5_KHR:
142     case Dali::Pixel::COMPRESSED_RGBA_ASTC_6x5_KHR:
143     case Dali::Pixel::COMPRESSED_RGBA_ASTC_6x6_KHR:
144     case Dali::Pixel::COMPRESSED_RGBA_ASTC_8x5_KHR:
145     case Dali::Pixel::COMPRESSED_RGBA_ASTC_8x6_KHR:
146     case Dali::Pixel::COMPRESSED_RGBA_ASTC_8x8_KHR:
147     case Dali::Pixel::COMPRESSED_RGBA_ASTC_10x5_KHR:
148     case Dali::Pixel::COMPRESSED_RGBA_ASTC_10x6_KHR:
149     case Dali::Pixel::COMPRESSED_RGBA_ASTC_10x8_KHR:
150     case Dali::Pixel::COMPRESSED_RGBA_ASTC_10x10_KHR:
151     case Dali::Pixel::COMPRESSED_RGBA_ASTC_12x10_KHR:
152     case Dali::Pixel::COMPRESSED_RGBA_ASTC_12x12_KHR:
153     case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
154     case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
155     case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
156     case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
157     case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
158     case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
159     case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
160     case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
161     case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
162     case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
163     case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
164     case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
165     case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
166     case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
167     {
168       DALI_LOG_ERROR("Pixel formats for compressed images are not compatible with simple masking-out of per-pixel alpha.\n");
169       byteOffset = 0;
170       bitMask    = 0;
171       break;
172     }
173     case Dali::Pixel::RGB16F:
174     case Dali::Pixel::RGB32F:
175     case Dali::Pixel::DEPTH_UNSIGNED_INT:
176     case Dali::Pixel::DEPTH_FLOAT:
177     case Dali::Pixel::DEPTH_STENCIL:
178     case Dali::Pixel::R11G11B10F:
179     {
180       DALI_LOG_ERROR("Pixel format not compatible.\n");
181       byteOffset = 0;
182       bitMask    = 0;
183       break;
184     }
185   }
186 }
187
188 void ParseBorders(Devel::PixelBuffer& pixelBuffer, StretchRanges& stretchPixelsX, StretchRanges& stretchPixelsY)
189 {
190   stretchPixelsX.Clear();
191   stretchPixelsY.Clear();
192
193   Pixel::Format pixelFormat = pixelBuffer.GetPixelFormat();
194
195   int32_t alphaByte = 0;
196   int32_t alphaBits = 0;
197   Pixel::GetAlphaOffsetAndMask(pixelFormat, alphaByte, alphaBits);
198
199   int32_t testByte  = alphaByte;
200   int32_t testBits  = alphaBits;
201   int32_t testValue = alphaBits; // Opaque == stretch
202   if(!alphaBits)
203   {
204     GetRedOffsetAndMask(pixelFormat, testByte, testBits);
205     testValue = 0; // Black == stretch
206   }
207
208   uint32_t bytesPerPixel = Pixel::GetBytesPerPixel(pixelFormat);
209   uint32_t width         = pixelBuffer.GetWidth();
210   uint32_t height        = pixelBuffer.GetHeight();
211   uint8_t* srcPixels     = pixelBuffer.GetBuffer();
212   uint32_t srcStride     = width * bytesPerPixel;
213
214   // TOP
215   uint8_t* top   = srcPixels + bytesPerPixel;
216   uint32_t index = 0;
217
218   for(; index < width - 2;)
219   {
220     Uint16Pair range = ParseRange(index, width - 2, top, bytesPerPixel, testByte, testBits, testValue);
221     if(range.GetX() != 0xFFFF)
222     {
223       stretchPixelsX.PushBack(range);
224     }
225   }
226
227   // LEFT
228   uint8_t* left = srcPixels + srcStride;
229   index         = 0;
230   for(; index < height - 2;)
231   {
232     Uint16Pair range = ParseRange(index, height - 2, left, srcStride, testByte, testBits, testValue);
233     if(range.GetX() != 0xFFFF)
234     {
235       stretchPixelsY.PushBack(range);
236     }
237   }
238
239   // If there are no stretch pixels then make the entire image stretchable
240   if(stretchPixelsX.Size() == 0)
241   {
242     stretchPixelsX.PushBack(Uint16Pair(0, width - 2));
243   }
244   if(stretchPixelsY.Size() == 0)
245   {
246     stretchPixelsY.PushBack(Uint16Pair(0, height - 2));
247   }
248 }
249
250 bool IsNinePatchUrl(const std::string& url)
251 {
252   bool match = false;
253
254   std::string::const_reverse_iterator iter = url.rbegin();
255   enum
256   {
257     SUFFIX,
258     HASH,
259     HASH_DOT,
260     DONE
261   } state = SUFFIX;
262   while(iter < url.rend())
263   {
264     switch(state)
265     {
266       case SUFFIX:
267       {
268         if(*iter == '.')
269         {
270           state = HASH;
271         }
272         else if(!isalnum(*iter))
273         {
274           state = DONE;
275         }
276       }
277       break;
278       case HASH:
279       {
280         if(*iter == '#' || *iter == '9')
281         {
282           state = HASH_DOT;
283         }
284         else
285         {
286           state = DONE;
287         }
288       }
289       break;
290       case HASH_DOT:
291       {
292         if(*iter == '.')
293         {
294           match = true;
295         }
296         state = DONE; // Stop testing characters
297       }
298       break;
299       case DONE:
300       {
301       }
302       break;
303     }
304
305     // Satisfy prevent
306     if(state == DONE)
307     {
308       break;
309     }
310
311     ++iter;
312   }
313   return match;
314 }
315
316 } // namespace NPatchUtility
317
318 } // namespace Toolkit
319
320 } // namespace Dali