Support align attribute for paragraph tag in markup
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / markup-processor-helper-functions.cpp
1 /*
2  * Copyright (c) 2022 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 // FILE HEADER
19 #include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/common/constants.h>
23 #include <dali/public-api/math/vector2.h>
24 #include <stdlib.h>
25 #include <iomanip>
26 #include <sstream>
27
28 namespace Dali
29 {
30 namespace Toolkit
31 {
32 namespace Text
33 {
34 namespace
35 {
36 const char WHITE_SPACE      = 0x20; // ASCII value of the white space.
37 const char FIRST_UPPER_CASE = 0x41; // ASCII value of the one after the first upper case character (A).
38 const char LAST_UPPER_CASE  = 0x5b; // ASCII value of the one after the last upper case character (Z).
39 const char TO_LOWER_CASE    = 32;   // Value to add to a upper case character to transform it into a lower case.
40
41 const unsigned int MAX_FLOAT_ATTRIBUTE_SIZE = 17u; ///< The maximum length of any of the possible float values.  +99999.999999999f  (sign, five digits, dot, nine digits, f)
42
43 const char        WEB_COLOR_TOKEN('#');
44 const char* const HEX_COLOR_TOKEN("0x");
45 const char* const ALPHA_ONE("FF");
46
47 const std::string BLACK_COLOR("black");
48 const std::string WHITE_COLOR("white");
49 const std::string RED_COLOR("red");
50 const std::string GREEN_COLOR("green");
51 const std::string BLUE_COLOR("blue");
52 const std::string YELLOW_COLOR("yellow");
53 const std::string MAGENTA_COLOR("magenta");
54 const std::string CYAN_COLOR("cyan");
55 const std::string TRANSPARENT_COLOR("transparent");
56
57 const std::string SOLID_UNDERLINE("solid");
58 const std::string DASHED_UNDERLINE("dashed");
59 const std::string DOUBLE_UNDERLINE("double");
60
61 const std::string BEGIN_HORIZONTAL_ALIGNMENT("begin");
62 const std::string CENTER_HORIZONTAL_ALIGNMENT("center");
63 const std::string END_HORIZONTAL_ALIGNMENT("end");
64
65 } // namespace
66
67 bool TokenComparison(const std::string& string1, const char* const stringBuffer2, Length length)
68 {
69   const Length stringSize = string1.size();
70   if(stringSize != length)
71   {
72     // Early return. Strings have different sizes.
73     return false;
74   }
75
76   const char* const stringBuffer1 = string1.c_str();
77
78   for(std::size_t index = 0; index < stringSize; ++index)
79   {
80     const char character = *(stringBuffer2 + index);
81     const bool toLower   = (character < LAST_UPPER_CASE) && (character >= FIRST_UPPER_CASE);
82     if(*(stringBuffer1 + index) != (toLower ? character + TO_LOWER_CASE : character))
83     {
84       return false;
85     }
86   }
87
88   return true;
89 }
90
91 void SkipWhiteSpace(const char*&      stringBuffer,
92                     const char* const stringEndBuffer)
93 {
94   for(; (WHITE_SPACE >= *stringBuffer) && (stringBuffer < stringEndBuffer); ++stringBuffer)
95     ;
96 }
97
98 void JumpToWhiteSpace(const char*&      stringBuffer,
99                       const char* const stringEndBuffer)
100 {
101   for(; (WHITE_SPACE != *stringBuffer) && (stringBuffer < stringEndBuffer); ++stringBuffer)
102     ;
103 }
104
105 unsigned int StringToUint(const char* const uintStr)
106 {
107   return static_cast<unsigned int>(strtoul(uintStr, NULL, 10));
108 }
109
110 unsigned int StringToHex(const char* const uintStr)
111 {
112   return static_cast<unsigned int>(strtoul(uintStr, NULL, 16));
113 }
114
115 float StringToFloat(const char* const floatStr)
116 {
117   return static_cast<float>(strtod(floatStr, NULL));
118 }
119
120 void FloatToString(float value, std::string& floatStr)
121 {
122   std::stringstream ss;
123   ss << value;
124   floatStr = ss.str();
125 }
126
127 void UintToString(unsigned int value, std::string& uIntStr)
128 {
129   std::stringstream ss;
130   ss << value;
131   uIntStr = ss.str();
132 }
133
134 void UintColorToVector4(unsigned int color, Vector4& retColor)
135 {
136   retColor.a = static_cast<float>((color & 0xFF000000) >> 24u) / 255.f;
137   retColor.r = static_cast<float>((color & 0x00FF0000) >> 16u) / 255.f;
138   retColor.g = static_cast<float>((color & 0x0000FF00) >> 8u) / 255.f;
139   retColor.b = static_cast<float>(color & 0x000000FF) / 255.f;
140 }
141
142 void ColorStringToVector4(const char* const colorStr, Length length, Vector4& retColor)
143 {
144   if(WEB_COLOR_TOKEN == *colorStr)
145   {
146     std::string webColor(colorStr + 1u, length - 1u);
147     if(4u == length) // 3 component web color #F00 (red)
148     {
149       webColor.insert(2u, &(webColor[2]), 1u);
150       webColor.insert(1u, &(webColor[1]), 1u);
151       webColor.insert(0u, &(webColor[0]), 1u);
152       webColor.insert(0u, ALPHA_ONE);
153     }
154     else if(7u == length) // 6 component web color #FF0000 (red)
155     {
156       webColor.insert(0u, ALPHA_ONE);
157     }
158
159     UintColorToVector4(StringToHex(webColor.c_str()), retColor);
160   }
161   else if(TokenComparison(HEX_COLOR_TOKEN, colorStr, 2u))
162   {
163     UintColorToVector4(StringToHex(colorStr + 2u), retColor);
164   }
165   else if(TokenComparison(BLACK_COLOR, colorStr, length))
166   {
167     retColor = Color::BLACK;
168   }
169   else if(TokenComparison(WHITE_COLOR, colorStr, length))
170   {
171     retColor = Color::WHITE;
172   }
173   else if(TokenComparison(RED_COLOR, colorStr, length))
174   {
175     retColor = Color::RED;
176   }
177   else if(TokenComparison(GREEN_COLOR, colorStr, length))
178   {
179     retColor = Color::GREEN;
180   }
181   else if(TokenComparison(BLUE_COLOR, colorStr, length))
182   {
183     retColor = Color::BLUE;
184   }
185   else if(TokenComparison(YELLOW_COLOR, colorStr, length))
186   {
187     retColor = Color::YELLOW;
188   }
189   else if(TokenComparison(MAGENTA_COLOR, colorStr, length))
190   {
191     retColor = Color::MAGENTA;
192   }
193   else if(TokenComparison(CYAN_COLOR, colorStr, length))
194   {
195     retColor = Color::CYAN;
196   }
197   else if(TokenComparison(TRANSPARENT_COLOR, colorStr, length))
198   {
199     retColor = Color::TRANSPARENT;
200   }
201 }
202
203 void Vector4ToColorString(const Vector4& value, std::string& vector2Str)
204 {
205   if(Color::BLACK == value)
206   {
207     vector2Str = BLACK_COLOR;
208     return;
209   }
210
211   if(Color::WHITE == value)
212   {
213     vector2Str = WHITE_COLOR;
214     return;
215   }
216
217   if(Color::RED == value)
218   {
219     vector2Str = RED_COLOR;
220     return;
221   }
222
223   if(Color::GREEN == value)
224   {
225     vector2Str = GREEN_COLOR;
226     return;
227   }
228
229   if(Color::BLUE == value)
230   {
231     vector2Str = BLUE_COLOR;
232     return;
233   }
234
235   if(Color::YELLOW == value)
236   {
237     vector2Str = YELLOW_COLOR;
238     return;
239   }
240
241   if(Color::MAGENTA == value)
242   {
243     vector2Str = MAGENTA_COLOR;
244     return;
245   }
246
247   if(Color::CYAN == value)
248   {
249     vector2Str = CYAN_COLOR;
250     return;
251   }
252
253   if(Color::TRANSPARENT == value)
254   {
255     vector2Str = TRANSPARENT_COLOR;
256     return;
257   }
258
259   const unsigned int alpha = static_cast<unsigned int>(255.f * value.a);
260   const unsigned int red   = static_cast<unsigned int>(255.f * value.r);
261   const unsigned int green = static_cast<unsigned int>(255.f * value.g);
262   const unsigned int blue  = static_cast<unsigned int>(255.f * value.b);
263
264   std::stringstream  ss;
265   const unsigned int size = 2u * sizeof(unsigned char);
266
267   ss << "0x"
268      << std::setfill('0') << std::setw(size)
269      << std::hex << alpha
270      << std::setfill('0') << std::setw(size)
271      << std::hex << red
272      << std::setfill('0') << std::setw(size)
273      << std::hex << green
274      << std::setfill('0') << std::setw(size)
275      << std::hex << blue;
276   vector2Str = ss.str();
277 }
278
279 void StringToVector2(const char* const vectorStr, Length length, Vector2& vector2)
280 {
281   // Points to the first character of the string.
282   const char* strBuffer = vectorStr;
283
284   // Points to the first character of the 'x' value.
285   const char* const xBuffer = strBuffer;
286
287   // Jumps to the next white space.
288   JumpToWhiteSpace(strBuffer, strBuffer + length);
289
290   // Points to the first character of the 'y' value.
291   const char* const yBuffer = strBuffer;
292
293   // Converts the shadow's offset to float.
294   vector2.x = StringToFloat(xBuffer);
295   vector2.y = StringToFloat(yBuffer);
296 }
297
298 void Vector2ToString(const Vector2& value, std::string& vector2Str)
299 {
300   FloatToString(value.x, vector2Str);
301   vector2Str += " ";
302
303   std::string yStr;
304   FloatToString(value.y, yStr);
305
306   vector2Str += yStr;
307 }
308
309 void UnderlineTypeStringToTypeValue(const char* const typeStr, Length length, Text::Underline::Type& retType)
310 {
311   if(TokenComparison(SOLID_UNDERLINE, typeStr, length))
312   {
313     retType = Text::Underline::SOLID;
314   }
315   else if(TokenComparison(DASHED_UNDERLINE, typeStr, length))
316   {
317     retType = Text::Underline::DASHED;
318   }
319   else if(TokenComparison(DOUBLE_UNDERLINE, typeStr, length))
320   {
321     retType = Text::Underline::DOUBLE;
322   }
323 }
324
325 bool HorizontalAlignmentTypeStringToTypeValue(const char* const typeStr, Length length, Text::HorizontalAlignment::Type& retType)
326 {
327   // The string is valid value for HorizontalAlignment
328   bool valid = false;
329   if(TokenComparison(BEGIN_HORIZONTAL_ALIGNMENT, typeStr, length))
330   {
331     retType = Text::HorizontalAlignment::BEGIN;
332     valid   = true;
333   }
334   else if(TokenComparison(CENTER_HORIZONTAL_ALIGNMENT, typeStr, length))
335   {
336     retType = Text::HorizontalAlignment::CENTER;
337     valid   = true;
338   }
339   else if(TokenComparison(END_HORIZONTAL_ALIGNMENT, typeStr, length))
340   {
341     retType = Text::HorizontalAlignment::END;
342     valid   = true;
343   }
344
345   return valid;
346 }
347
348 } // namespace Text
349
350 } // namespace Toolkit
351
352 } // namespace Dali