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