70c6dc23abdf5c6e710dbddd8618900398361879
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / visual-url.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 // CLASS HEADER
18 #include <dali-toolkit/internal/visuals/visual-url.h>
19
20 // EXTERNAL HEADERS
21 #include <cstring> // for toupper()
22
23 // INTERNAL HEADERS
24 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
25 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
26
27 namespace Dali
28 {
29 namespace Toolkit
30 {
31 namespace Internal
32 {
33 namespace
34 {
35 VisualUrl::ProtocolType ResolveLocation(const std::string& url)
36 {
37   const char*    urlCStr = url.c_str();
38   const uint32_t length  = url.size();
39   if((length > 7) && urlCStr[5] == ':' && urlCStr[6] == '/' && urlCStr[7] == '/')
40   {
41     // https:// or enbuf://
42     const char hOre = tolower(urlCStr[0]);
43     const char tOrn = tolower(urlCStr[1]);
44     const char tOrb = tolower(urlCStr[2]);
45     const char pOru = tolower(urlCStr[3]);
46     const char sOrf = tolower(urlCStr[4]);
47     if(('h' == hOre) &&
48        ('t' == tOrn) &&
49        ('t' == tOrb) &&
50        ('p' == pOru) &&
51        ('s' == sOrf))
52     {
53       return VisualUrl::REMOTE;
54     }
55     if(('e' == hOre) &&
56        ('n' == tOrn) &&
57        ('b' == tOrb) &&
58        ('u' == pOru) &&
59        ('f' == sOrf))
60     {
61       return VisualUrl::BUFFER;
62     }
63   }
64   else if((length > 6) && urlCStr[4] == ':' && urlCStr[5] == '/' && urlCStr[6] == '/')
65   {
66     // http:// or dali://
67     const char hOrd = tolower(urlCStr[0]);
68     const char tOra = tolower(urlCStr[1]);
69     const char tOrl = tolower(urlCStr[2]);
70     const char pOri = tolower(urlCStr[3]);
71     if(('h' == hOrd) &&
72        ('t' == tOra) &&
73        ('t' == tOrl) &&
74        ('p' == pOri))
75     {
76       return VisualUrl::REMOTE;
77     }
78     if(('d' == hOrd) &&
79        ('a' == tOra) &&
80        ('l' == tOrl) &&
81        ('i' == pOri))
82     {
83       return VisualUrl::TEXTURE;
84     }
85   }
86   else if((length > 5) && urlCStr[3] == ':' && urlCStr[4] == '/' && urlCStr[5] == '/')
87   {
88     // ftp:// or ssh://
89     const char fOrs = tolower(urlCStr[0]);
90     const char tOrs = tolower(urlCStr[1]);
91     const char pOrh = tolower(urlCStr[2]);
92     if(('f' == fOrs) &&
93        ('t' == tOrs) &&
94        ('p' == pOrh))
95     {
96       return VisualUrl::REMOTE;
97     }
98     if(('s' == fOrs) &&
99        ('s' == tOrs) &&
100        ('h' == pOrh))
101     {
102       return VisualUrl::REMOTE;
103     }
104   }
105   return VisualUrl::LOCAL;
106 }
107
108 VisualUrl::Type ResolveType(const std::string& url)
109 {
110   // if only one char in string, can only be regular image
111   const std::size_t count = url.size();
112   if(count > 0)
113   {
114     // parsing from the end for better chance of early outs
115     enum
116     {
117       SUFFIX,
118       HASH,
119       HASH_DOT
120     } state                = SUFFIX;
121     char         SVG[4]    = {'g', 'v', 's', '.'};
122     char         GIF[4]    = {'f', 'i', 'g', '.'};
123     char         WEBP[5]   = {'p', 'b', 'e', 'w', '.'};
124     char         JSON[5]   = {'n', 'o', 's', 'j', '.'};
125     unsigned int svgScore  = 0;
126     unsigned int gifScore  = 0;
127     unsigned int webpScore = 0;
128     unsigned int jsonScore = 0;
129     int          index     = count;
130     while(--index >= 0)
131     {
132       const char        currentChar   = tolower(url[index]);
133       const std::size_t offsetFromEnd = count - index - 1u;
134       if((offsetFromEnd < sizeof(SVG)) && (currentChar == SVG[offsetFromEnd]))
135       {
136         // early out if SVG as can't be used in N patch for now
137         if(++svgScore == sizeof(SVG))
138         {
139           return VisualUrl::SVG;
140         }
141       }
142       if((offsetFromEnd < sizeof(GIF)) && (currentChar == GIF[offsetFromEnd]))
143       {
144         // early out if GIF as can't be used in N patch for now
145         if(++gifScore == sizeof(GIF))
146         {
147           return VisualUrl::GIF;
148         }
149       }
150       if((offsetFromEnd < sizeof(WEBP)) && (currentChar == WEBP[offsetFromEnd]))
151       {
152         // early out if WEBP as can't be used in N patch for now
153         if(++webpScore == sizeof(WEBP))
154         {
155           return VisualUrl::WEBP;
156         }
157       }
158       if((offsetFromEnd < sizeof(JSON)) && (currentChar == JSON[offsetFromEnd]))
159       {
160         // early out if JSON as can't be used in N patch for now
161         if(++jsonScore == sizeof(JSON))
162         {
163           return VisualUrl::JSON;
164         }
165       }
166       switch(state)
167       {
168         case SUFFIX:
169         {
170           if('.' == currentChar)
171           {
172             state = HASH;
173           }
174           break;
175         }
176         case HASH:
177         {
178           if(('#' == currentChar) || ('9' == currentChar))
179           {
180             state = HASH_DOT;
181           }
182           else
183           {
184             // early out, not a valid N/9-patch URL
185             return VisualUrl::REGULAR_IMAGE;
186           }
187           break;
188         }
189         case HASH_DOT:
190         {
191           if('.' == currentChar)
192           {
193             return VisualUrl::N_PATCH;
194           }
195           else
196           {
197             // early out, not a valid N/9-patch URL
198             return VisualUrl::REGULAR_IMAGE;
199           }
200           break;
201         }
202       }
203     }
204   }
205   // if we got here it is a regular image
206   return VisualUrl::REGULAR_IMAGE;
207 }
208
209 } // namespace
210
211 VisualUrl::VisualUrl()
212 : mUrl(),
213   mType(VisualUrl::REGULAR_IMAGE),
214   mLocation(VisualUrl::LOCAL)
215 {
216 }
217
218 VisualUrl::VisualUrl(const std::string& url)
219 : mUrl(url),
220   mType(VisualUrl::REGULAR_IMAGE),
221   mLocation(VisualUrl::LOCAL)
222 {
223   if(!url.empty())
224   {
225     mLocation = ResolveLocation(url);
226     if(VisualUrl::TEXTURE != mLocation && VisualUrl::BUFFER != mLocation)
227     {
228       // TEXTURE and BUFFER location url doesn't need type resolving, REGULAR_IMAGE is fine
229       mType = ResolveType(url);
230     }
231     else
232     {
233       Toolkit::VisualFactory factory = Toolkit::VisualFactory::Get();
234       if(factory)
235       {
236         GetImplementation(factory).GetTextureManager().UseExternalResource(*this);
237       }
238     }
239   }
240 }
241
242 VisualUrl::VisualUrl(const VisualUrl& url)
243 : mUrl(url.mUrl),
244   mType(url.mType),
245   mLocation(url.mLocation)
246 {
247   if(VisualUrl::TEXTURE == mLocation || VisualUrl::BUFFER == mLocation)
248   {
249     Toolkit::VisualFactory factory = Toolkit::VisualFactory::Get();
250     if(factory)
251     {
252       GetImplementation(factory).GetTextureManager().UseExternalResource(*this);
253     }
254   }
255 }
256
257 VisualUrl::~VisualUrl()
258 {
259   if(VisualUrl::TEXTURE == mLocation)
260   {
261     Toolkit::VisualFactory factory = Toolkit::VisualFactory::Get();
262     if(factory)
263     {
264       GetImplementation(factory).GetTextureManager().RemoveExternalTexture(mUrl);
265     }
266   }
267   else if(VisualUrl::BUFFER == mLocation)
268   {
269     Toolkit::VisualFactory factory = Toolkit::VisualFactory::Get();
270     if(factory)
271     {
272       GetImplementation(factory).GetTextureManager().RemoveExternalEncodedImageBuffer(mUrl);
273     }
274   }
275 }
276
277 VisualUrl& VisualUrl::operator=(const VisualUrl& url)
278 {
279   if(&url != this)
280   {
281     if(VisualUrl::TEXTURE == mLocation)
282     {
283       Toolkit::VisualFactory factory = Toolkit::VisualFactory::Get();
284       if(factory)
285       {
286         GetImplementation(factory).GetTextureManager().RemoveExternalTexture(mUrl);
287       }
288     }
289     else if(VisualUrl::BUFFER == mLocation)
290     {
291       Toolkit::VisualFactory factory = Toolkit::VisualFactory::Get();
292       if(factory)
293       {
294         GetImplementation(factory).GetTextureManager().RemoveExternalEncodedImageBuffer(mUrl);
295       }
296     }
297
298     mUrl      = url.mUrl;
299     mType     = url.mType;
300     mLocation = url.mLocation;
301
302     if(VisualUrl::TEXTURE == mLocation || VisualUrl::BUFFER == mLocation)
303     {
304       Toolkit::VisualFactory factory = Toolkit::VisualFactory::Get();
305       if(factory)
306       {
307         GetImplementation(factory).GetTextureManager().UseExternalResource(*this);
308       }
309     }
310   }
311   return *this;
312 }
313
314 const std::string& VisualUrl::GetUrl() const
315 {
316   return mUrl;
317 }
318
319 VisualUrl::Type VisualUrl::GetType() const
320 {
321   return mType;
322 }
323
324 VisualUrl::ProtocolType VisualUrl::GetProtocolType() const
325 {
326   return mLocation;
327 }
328
329 bool VisualUrl::IsValid() const
330 {
331   return mUrl.size() > 0u;
332 }
333
334 bool VisualUrl::IsLocalResource() const
335 {
336   return mLocation == VisualUrl::LOCAL;
337 }
338
339 bool VisualUrl::IsBufferResource() const
340 {
341   return mLocation == VisualUrl::BUFFER;
342 }
343
344 std::string VisualUrl::GetLocation() const
345 {
346   return GetLocation(mUrl);
347 }
348
349 std::string VisualUrl::CreateTextureUrl(const std::string& location)
350 {
351   return "dali://" + location;
352 }
353
354 std::string VisualUrl::CreateBufferUrl(const std::string& location)
355 {
356   return "enbuf://" + location;
357 }
358
359 VisualUrl::ProtocolType VisualUrl::GetProtocolType(const std::string& url)
360 {
361   return ResolveLocation(url);
362 }
363
364 std::string VisualUrl::GetLocation(const std::string& url)
365 {
366   const auto location = url.find("://");
367   if(std::string::npos != location)
368   {
369     return url.substr(location + 3u); // 3 characters forwards from the start of ://
370   }
371   return url;
372 }
373
374 } // namespace Internal
375
376 } // namespace Toolkit
377
378 } // namespace Dali