2 * Copyright (c) 2024 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <dali-toolkit/internal/visuals/visual-url.h>
21 #include <dali/devel-api/common/hash.h>
22 #include <cstring> // for toupper()
32 constexpr uint32_t URL_ELLIPSED_LENGTH = 20u;
34 static_assert(URL_ELLIPSED_LENGTH < URL_ELLIPSED_LENGTH + 3u); ///< Guard overflow cases. (for svace)
36 VisualUrl::ProtocolType ResolveLocation(const std::string& url)
38 const char* urlCStr = url.c_str();
39 const uint32_t length = url.size();
40 if((length > 7) && urlCStr[5] == ':' && urlCStr[6] == '/' && urlCStr[7] == '/')
42 // https:// or enbuf://
43 const char hOre = tolower(urlCStr[0]);
44 const char tOrn = tolower(urlCStr[1]);
45 const char tOrb = tolower(urlCStr[2]);
46 const char pOru = tolower(urlCStr[3]);
47 const char sOrf = tolower(urlCStr[4]);
54 return VisualUrl::REMOTE;
62 return VisualUrl::BUFFER;
65 else if((length > 6) && urlCStr[4] == ':' && urlCStr[5] == '/' && urlCStr[6] == '/')
68 const char hOrd = tolower(urlCStr[0]);
69 const char tOra = tolower(urlCStr[1]);
70 const char tOrl = tolower(urlCStr[2]);
71 const char pOri = tolower(urlCStr[3]);
77 return VisualUrl::REMOTE;
84 return VisualUrl::TEXTURE;
87 else if((length > 5) && urlCStr[3] == ':' && urlCStr[4] == '/' && urlCStr[5] == '/')
90 const char fOrs = tolower(urlCStr[0]);
91 const char tOrs = tolower(urlCStr[1]);
92 const char pOrh = tolower(urlCStr[2]);
97 return VisualUrl::REMOTE;
103 return VisualUrl::REMOTE;
106 return VisualUrl::LOCAL;
109 VisualUrl::Type ResolveType(const std::string& url)
111 // if only one char in string, can only be regular image
112 const std::size_t count = url.size();
113 VisualUrl::Type returnType = VisualUrl::REGULAR_IMAGE;
116 // parsing from the end for better chance of early outs
123 char SVG[4] = {'g', 'v', 's', '.'};
124 char GIF[4] = {'f', 'i', 'g', '.'};
125 char WEBP[5] = {'p', 'b', 'e', 'w', '.'};
126 char JSON[5] = {'n', 'o', 's', 'j', '.'};
127 char TVG[4] = {'g', 'v', 't', '.'};
128 unsigned int svgScore = 0;
129 unsigned int tvgScore = 0;
130 unsigned int gifScore = 0;
131 unsigned int webpScore = 0;
132 unsigned int jsonScore = 0;
136 const char currentChar = tolower(url[index]);
137 const std::size_t offsetFromEnd = count - index - 1u;
138 if((offsetFromEnd < sizeof(SVG)) && (currentChar == SVG[offsetFromEnd]))
140 // early out if SVG as can't be used in N patch for now
141 if(++svgScore == sizeof(SVG))
143 return VisualUrl::SVG;
146 if((offsetFromEnd < sizeof(TVG)) && (currentChar == TVG[offsetFromEnd]))
148 // early out if TVG as can't be used in N patch for now
149 if(++tvgScore == sizeof(TVG))
151 return VisualUrl::TVG;
154 if((offsetFromEnd < sizeof(GIF)) && (currentChar == GIF[offsetFromEnd]))
156 //find type, but need to be check used in N patch
157 if(++gifScore == sizeof(GIF))
159 returnType = VisualUrl::GIF;
162 if((offsetFromEnd < sizeof(WEBP)) && (currentChar == WEBP[offsetFromEnd]))
164 if(++webpScore == sizeof(WEBP))
166 //find type, but need to be check used in N patch
167 returnType = VisualUrl::WEBP;
170 if((offsetFromEnd < sizeof(JSON)) && (currentChar == JSON[offsetFromEnd]))
172 // early out if JSON as can't be used in N patch for now
173 if(++jsonScore == sizeof(JSON))
175 return VisualUrl::JSON;
182 if('.' == currentChar)
190 if(('#' == currentChar) || ('9' == currentChar))
196 // early out, not a valid N/9-patch URL
203 if('.' == currentChar)
205 return VisualUrl::N_PATCH;
209 // early out, not a valid N/9-patch URL
217 // if we got here it is a regular image
223 VisualUrl::VisualUrl()
225 mType(VisualUrl::REGULAR_IMAGE),
226 mLocation(VisualUrl::LOCAL),
231 VisualUrl::VisualUrl(const std::string& url)
233 mType(VisualUrl::REGULAR_IMAGE),
234 mLocation(VisualUrl::LOCAL),
239 mLocation = ResolveLocation(url);
240 if(VisualUrl::TEXTURE != mLocation)
242 // TEXTURE location url doesn't need type resolving, REGULAR_IMAGE is fine
243 mType = ResolveType(url);
248 VisualUrl::VisualUrl(const VisualUrl& url)
251 mLocation(url.mLocation),
252 mUrlHash(url.mUrlHash)
256 VisualUrl::VisualUrl(VisualUrl&& url) noexcept
257 : mUrl(std::move(url.mUrl)),
258 mType(std::move(url.mType)),
259 mLocation(std::move(url.mLocation)),
260 mUrlHash(std::move(url.mUrlHash))
265 VisualUrl::~VisualUrl()
269 VisualUrl& VisualUrl::operator=(const VisualUrl& url)
275 mLocation = url.mLocation;
276 mUrlHash = url.mUrlHash;
281 VisualUrl& VisualUrl::operator=(VisualUrl&& url) noexcept
285 mUrl = std::move(url.mUrl);
286 mType = std::move(url.mType);
287 mLocation = std::move(url.mLocation);
288 mUrlHash = std::move(url.mUrlHash);
295 const std::string& VisualUrl::GetUrl() const
300 std::string VisualUrl::GetEllipsedUrl() const
302 if(mUrl.size() > URL_ELLIPSED_LENGTH + 3)
304 std::string ellipsedUrl = "...";
305 ellipsedUrl += mUrl.substr(mUrl.size() - URL_ELLIPSED_LENGTH);
311 std::uint64_t VisualUrl::GetUrlHash() const
313 return DALI_UNLIKELY(mUrlHash == 0) ? (mUrlHash = Dali::CalculateHash(mUrl)) : mUrlHash;
316 VisualUrl::Type VisualUrl::GetType() const
321 VisualUrl::ProtocolType VisualUrl::GetProtocolType() const
326 bool VisualUrl::IsValid() const
328 return mUrl.size() > 0u;
331 bool VisualUrl::IsLocalResource() const
333 return mLocation == VisualUrl::LOCAL;
336 bool VisualUrl::IsBufferResource() const
338 return mLocation == VisualUrl::BUFFER;
341 std::string VisualUrl::GetLocation() const
343 return GetLocation(mUrl);
346 std::string VisualUrl::GetLocationWithoutExtension() const
348 return GetLocationWithoutExtension(mUrl);
351 std::string VisualUrl::CreateTextureUrl(const std::string& location)
353 return "dali://" + location;
356 std::string VisualUrl::CreateBufferUrl(const std::string& location, const std::string_view& extension)
358 return "enbuf://" + location + std::string(extension);
361 VisualUrl::ProtocolType VisualUrl::GetProtocolType(const std::string& url)
363 return ResolveLocation(url);
366 std::string VisualUrl::GetLocation(const std::string& url)
368 const auto location = url.find("://");
369 if(std::string::npos != location)
371 return url.substr(location + 3u); // 3 characters forwards from the start of ://
376 std::string VisualUrl::GetLocationWithoutExtension(const std::string& url)
378 const auto location = url.find("://");
379 if(std::string::npos != location)
381 const auto extension = url.find_last_of("."); // Find last position of '.' keyword.
382 const auto locationLength = extension != std::string::npos ? extension - (location + 3u) : std::string::npos;
383 return url.substr(location + 3u, locationLength); // 3 characters forwards from the start of ://, and end of last '.' keyword.
388 } // namespace Internal
390 } // namespace Toolkit