[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / markup-processor / markup-processor.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/markup-processor.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <climits> // for ULONG_MAX
24 #include <functional>
25
26 // INTERNAL INCLUDES
27 #include <dali-toolkit/internal/text/character-set-conversion.h>
28 #include <dali-toolkit/internal/text/markup-processor/markup-processor-anchor.h>
29 #include <dali-toolkit/internal/text/markup-processor/markup-processor-background.h>
30 #include <dali-toolkit/internal/text/markup-processor/markup-processor-character-spacing.h>
31 #include <dali-toolkit/internal/text/markup-processor/markup-processor-color.h>
32 #include <dali-toolkit/internal/text/markup-processor/markup-processor-embedded-item.h>
33 #include <dali-toolkit/internal/text/markup-processor/markup-processor-font.h>
34 #include <dali-toolkit/internal/text/markup-processor/markup-processor-helper-functions.h>
35 #include <dali-toolkit/internal/text/markup-processor/markup-processor-paragraph.h>
36 #include <dali-toolkit/internal/text/markup-processor/markup-processor-span.h>
37 #include <dali-toolkit/internal/text/markup-processor/markup-processor-strikethrough.h>
38 #include <dali-toolkit/internal/text/markup-processor/markup-processor-underline.h>
39 #include <dali-toolkit/internal/text/markup-tags-and-attributes.h>
40 #include <dali-toolkit/internal/text/xhtml-entities.h>
41
42 namespace Dali
43 {
44 namespace Toolkit
45 {
46 namespace Text
47 {
48 namespace
49 {
50 const char LESS_THAN      = '<';
51 const char GREATER_THAN   = '>';
52 const char EQUAL          = '=';
53 const char QUOTATION_MARK = '\'';
54 const char SLASH          = '/';
55 const char BACK_SLASH     = '\\';
56 const char AMPERSAND      = '&';
57 const char HASH           = '#';
58 const char SEMI_COLON     = ';';
59 const char CHAR_ARRAY_END = '\0';
60 const char HEX_CODE       = 'x';
61
62 const char WHITE_SPACE = 0x20; // ASCII value of the white space.
63 const char NEW_LINE    = 0x0A; // ASCII value of the newline.
64
65 // Range 1 0x0u < XHTML_DECIMAL_ENTITY_RANGE <= 0xD7FFu
66 // Range 2 0xE000u < XHTML_DECIMAL_ENTITY_RANGE <= 0xFFFDu
67 // Range 3 0x10000u < XHTML_DECIMAL_ENTITY_RANGE <= 0x10FFFFu
68 const unsigned long XHTML_DECIMAL_ENTITY_RANGE[] = {0x0u, 0xD7FFu, 0xE000u, 0xFFFDu, 0x10000u, 0x10FFFFu};
69
70 // The MAX_NUM_OF_ATTRIBUTES is the number of attributes in span tag "markup-processor-span.cpp". Because it contains the maximum number of attributes in  all tags.
71 const unsigned int MAX_NUM_OF_ATTRIBUTES = 14u; ///< The span tag has the 'font-family', 'font-size' 'font-weight', 'font-width', 'font-slant','text-color', 'u-color', 'u-height','u-type','u-dash-gap', 'u-dash-width', 's-color', 's-height' and 'char-space-value' attrubutes.
72 const unsigned int DEFAULT_VECTOR_SIZE   = 16u; ///< Default size of run vectors.
73
74 #if defined(DEBUG_ENABLED)
75 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_MARKUP_PROCESSOR");
76 #endif
77
78 typedef VectorBase::SizeType RunIndex;
79
80 /**
81  * @brief Struct used to retrieve the style runs from the mark-up string.
82  */
83 template<typename StyleStackType>
84 struct StyleStack
85 {
86   Vector<StyleStackType> stack;    ///< Use a vector as a style stack.
87   unsigned int           topIndex; ///< Points the top of the stack.
88
89   StyleStack()
90   : stack(),
91     topIndex(0u)
92   {
93     stack.Resize(DEFAULT_VECTOR_SIZE);
94   }
95
96   void Push(StyleStackType item)
97   {
98     // Check if there is space inside the style stack.
99     const VectorBase::SizeType size = stack.Count();
100     if(topIndex >= size)
101     {
102       // Resize the style stack.
103       stack.Resize(2u * size);
104     }
105
106     // Set the item in the top of the stack.
107     *(stack.Begin() + topIndex) = item;
108
109     // Reposition the pointer to the top of the stack.
110     ++topIndex;
111   }
112
113   StyleStackType Pop()
114   {
115     // Pop the top of the stack.
116     --topIndex;
117     return *(stack.Begin() + topIndex);
118   }
119 };
120
121 /**
122  * @brief Struct used to retrieve spans from the mark-up string.
123  */
124 struct Span
125 {
126   RunIndex colorRunIndex;
127   RunIndex fontRunIndex;
128   RunIndex underlinedCharacterRunIndex;
129   RunIndex backgroundColorRunIndex;
130   RunIndex strikethroughCharacterRunIndex;
131   RunIndex characterSpacingCharacterRunIndex;
132
133   bool isColorDefined;
134   bool isFontDefined;
135   bool isUnderlinedCharacterDefined;
136   bool isBackgroundColorDefined;
137   bool isStrikethroughDefined;
138   bool isCharacterSpacingDefined;
139 };
140
141 /**
142  * @brief Struct used to retrieve anchors from the mark-up string.
143  */
144 struct AnchorForStack
145 {
146   RunIndex colorRunIndex;
147   RunIndex underlinedCharacterRunIndex;
148 };
149
150 /**
151  * @brief Initializes a font run description to its defaults.
152  *
153  * @param[in,out] fontRun The font description run to initialize.
154  */
155 void Initialize(FontDescriptionRun& fontRun)
156 {
157   fontRun.characterRun.characterIndex     = 0u;
158   fontRun.characterRun.numberOfCharacters = 0u;
159   fontRun.familyName                      = NULL;
160   fontRun.familyLength                    = 0u;
161   fontRun.weight                          = TextAbstraction::FontWeight::NORMAL;
162   fontRun.width                           = TextAbstraction::FontWidth::NORMAL;
163   fontRun.slant                           = TextAbstraction::FontSlant::NORMAL;
164   fontRun.size                            = 0u;
165   fontRun.familyDefined                   = false;
166   fontRun.weightDefined                   = false;
167   fontRun.widthDefined                    = false;
168   fontRun.slantDefined                    = false;
169   fontRun.sizeDefined                     = false;
170 }
171
172 /**
173  * @brief Initializes a color run description to its defaults.
174  *
175  * @param[in,out] colorRun The font description run to initialize.
176  */
177 void Initialize(ColorRun& colorRun)
178 {
179   colorRun.characterRun.characterIndex     = 0u;
180   colorRun.characterRun.numberOfCharacters = 0u;
181 }
182
183 /**
184  * @brief Initializes a underlined character run to its defaults.
185  *
186  * @param[in,out] underlinedCharacterRun The underelined character run to initialize.
187  */
188 void Initialize(UnderlinedCharacterRun& underlinedCharacterRun)
189 {
190   underlinedCharacterRun.characterRun.characterIndex     = 0u;
191   underlinedCharacterRun.characterRun.numberOfCharacters = 0u;
192 }
193
194 /**
195  * @brief Initializes a span to its defaults.
196  *
197  * @param[in,out] span The span to be initialized.
198  */
199 void Initialize(Span& span)
200 {
201   span.colorRunIndex  = 0u;
202   span.isColorDefined = false;
203
204   span.fontRunIndex  = 0u;
205   span.isFontDefined = false;
206
207   span.underlinedCharacterRunIndex  = 0u;
208   span.isUnderlinedCharacterDefined = false;
209   span.backgroundColorRunIndex      = 0u;
210   span.isBackgroundColorDefined     = false;
211
212   //strikethrough
213   span.strikethroughCharacterRunIndex = 0u;
214   span.isStrikethroughDefined         = false;
215
216   //characterSpacing
217   span.characterSpacingCharacterRunIndex = 0u;
218   span.isCharacterSpacingDefined         = false;
219 }
220
221 /**
222  * @brief Initializes a anchor to its defaults.
223  *
224  * @param[in,out] anchor The anchor to be initialized.
225  */
226 void Initialize(AnchorForStack& anchor)
227 {
228   anchor.colorRunIndex               = 0u;
229   anchor.underlinedCharacterRunIndex = 0u;
230 }
231
232 /**
233  * @brief Initializes a strikethrough character run to its defaults.
234  *
235  * @param[in,out] strikethroughCharacterRun The strikethrough character run to initialize.
236  */
237 void Initialize(StrikethroughCharacterRun& strikethroughCharacterRun)
238 {
239   strikethroughCharacterRun.characterRun.characterIndex     = 0u;
240   strikethroughCharacterRun.characterRun.numberOfCharacters = 0u;
241   strikethroughCharacterRun.properties.colorDefined         = false;
242 }
243
244 /**
245  * @brief Initializes a  bounded-paragraph character run to its defaults.
246  *
247  * @param[in,out] boundedParagraphRun The bounded paragraphRun run to initialize.
248  */
249 void Initialize(BoundedParagraphRun& boundedParagraphRun)
250 {
251   boundedParagraphRun.characterRun.characterIndex     = 0u;
252   boundedParagraphRun.characterRun.numberOfCharacters = 0u;
253 }
254
255 /**
256  * @brief Initializes a character-spacing run to its defaults.
257  *
258  * @param[in,out] characterSpacingCharacterRun The character-spacing run to initialize.
259  */
260 void Initialize(CharacterSpacingCharacterRun& characterSpacingCharacterRun)
261 {
262   characterSpacingCharacterRun.characterRun.characterIndex     = 0u;
263   characterSpacingCharacterRun.characterRun.numberOfCharacters = 0u;
264   characterSpacingCharacterRun.value                           = 0.0f;
265 }
266
267 /**
268  * @brief Splits the tag string into the tag name and its attributes.
269  *
270  * The attributes are stored in a vector in the tag.
271  *
272  * @param[in,out] tag The tag.
273  */
274 void ParseAttributes(Tag& tag)
275 {
276   if(tag.buffer == NULL)
277   {
278     return;
279   }
280
281   tag.attributes.Resize(MAX_NUM_OF_ATTRIBUTES);
282
283   // Find first the tag name.
284   bool isQuotationOpen = false;
285
286   const char*       tagBuffer    = tag.buffer;
287   const char* const tagEndBuffer = tagBuffer + tag.length;
288   tag.length                     = 0u;
289   for(; tagBuffer < tagEndBuffer; ++tagBuffer)
290   {
291     const char character = *tagBuffer;
292     if(WHITE_SPACE < character)
293     {
294       ++tag.length;
295     }
296     else
297     {
298       // Stops counting the length of the tag when a white space is found.
299       // @note a white space is the WHITE_SPACE character and anything below as 'tab', 'return' or 'control characters'.
300       break;
301     }
302   }
303   SkipWhiteSpace(tagBuffer, tagEndBuffer);
304
305   // Find the attributes.
306   unsigned int attributeIndex = 0u;
307   const char*  nameBuffer     = NULL;
308   const char*  valueBuffer    = NULL;
309   Length       nameLength     = 0u;
310   Length       valueLength    = 0u;
311
312   bool   addToNameValue     = true;
313   Length numberOfWhiteSpace = 0u;
314   for(; tagBuffer < tagEndBuffer; ++tagBuffer)
315   {
316     const char character = *tagBuffer;
317     if((WHITE_SPACE >= character) && !isQuotationOpen)
318     {
319       if(NULL != valueBuffer)
320       {
321         // Remove white spaces at the end of the value.
322         valueLength -= numberOfWhiteSpace;
323       }
324
325       if((NULL != nameBuffer) && (NULL != valueBuffer))
326       {
327         // Every time a white space is found, a new attribute is created and stored in the attributes vector.
328         Attribute& attribute = *(tag.attributes.Begin() + attributeIndex);
329         ++attributeIndex;
330
331         attribute.nameBuffer  = nameBuffer;
332         attribute.valueBuffer = valueBuffer;
333         attribute.nameLength  = nameLength;
334         attribute.valueLength = valueLength;
335
336         nameBuffer  = NULL;
337         valueBuffer = NULL;
338         nameLength  = 0u;
339         valueLength = 0u;
340
341         addToNameValue = true; // next read characters will be added to the name.
342       }
343     }
344     else if(EQUAL == character) // '='
345     {
346       if(isQuotationOpen)
347       {
348         ++valueLength;
349       }
350       else
351       {
352         addToNameValue = false; // next read characters will be added to the value.
353         SkipWhiteSpace(tagBuffer, tagEndBuffer);
354       }
355     }
356     else if(QUOTATION_MARK == character) // '\''
357     {
358       // Do not add quotation marks to neither name nor value.
359       isQuotationOpen = !isQuotationOpen;
360
361       if(isQuotationOpen)
362       {
363         ++tagBuffer;
364         SkipWhiteSpace(tagBuffer, tagEndBuffer);
365         --tagBuffer;
366       }
367     }
368     else
369     {
370       // Adds characters to the name or the value.
371       if(addToNameValue)
372       {
373         if(NULL == nameBuffer)
374         {
375           nameBuffer = tagBuffer;
376         }
377         ++nameLength;
378       }
379       else
380       {
381         if(isQuotationOpen)
382         {
383           if(WHITE_SPACE >= character)
384           {
385             ++numberOfWhiteSpace;
386           }
387           else
388           {
389             numberOfWhiteSpace = 0u;
390           }
391         }
392         if(NULL == valueBuffer)
393         {
394           valueBuffer = tagBuffer;
395         }
396         ++valueLength;
397       }
398     }
399   }
400
401   if(NULL != valueBuffer)
402   {
403     // Remove white spaces at the end of the value.
404     valueLength -= numberOfWhiteSpace;
405   }
406
407   if((NULL != nameBuffer) && (NULL != valueBuffer))
408   {
409     // Checks if the last attribute needs to be added.
410     Attribute& attribute = *(tag.attributes.Begin() + attributeIndex);
411     ++attributeIndex;
412
413     attribute.nameBuffer  = nameBuffer;
414     attribute.valueBuffer = valueBuffer;
415     attribute.nameLength  = nameLength;
416     attribute.valueLength = valueLength;
417   }
418
419   // Resize the vector of attributes.
420   tag.attributes.Resize(attributeIndex);
421 }
422
423 /**
424  * @brief It parses a tag and its attributes if the given iterator @e it is pointing at a tag beginning.
425  *
426  * @param[in,out] markupStringBuffer The mark-up string buffer. It's a const iterator pointing the current character.
427  * @param[in] markupStringEndBuffer Pointer to one character after the end of the mark-up string buffer.
428  * @param[out] tag The tag with its attributes.
429  *
430  * @return @e true if the iterator @e it is pointing a mark-up tag. Otherwise @e false.
431  */
432 bool IsTag(const char*&      markupStringBuffer,
433            const char* const markupStringEndBuffer,
434            Tag&              tag)
435 {
436   bool isTag              = false;
437   bool isQuotationOpen    = false;
438   bool attributesFound    = false;
439   tag.isEndTag            = false;
440   bool isPreviousLessThan = false;
441   bool isPreviousSlash    = false;
442
443   const char character = *markupStringBuffer;
444   if(LESS_THAN == character) // '<'
445   {
446     tag.buffer         = NULL;
447     tag.length         = 0u;
448     isPreviousLessThan = true;
449
450     // if the iterator is pointing to a '<' character, then check if it's a mark-up tag is needed.
451     ++markupStringBuffer;
452     if(markupStringBuffer < markupStringEndBuffer)
453     {
454       SkipWhiteSpace(markupStringBuffer, markupStringEndBuffer);
455
456       for(; (!isTag) && (markupStringBuffer < markupStringEndBuffer); ++markupStringBuffer)
457       {
458         const char character = *markupStringBuffer;
459
460         if(!isQuotationOpen && (SLASH == character)) // '/'
461         {
462           if(isPreviousLessThan)
463           {
464             tag.isEndTag = true;
465           }
466           else
467           {
468             // if the tag has a '/' it may be an end tag.
469             isPreviousSlash = true;
470           }
471
472           isPreviousLessThan = false;
473           if((markupStringBuffer + 1u < markupStringEndBuffer) && (WHITE_SPACE >= *(markupStringBuffer + 1u)))
474           {
475             ++markupStringBuffer;
476             SkipWhiteSpace(markupStringBuffer, markupStringEndBuffer);
477             --markupStringBuffer;
478           }
479         }
480         else if(GREATER_THAN == character) // '>'
481         {
482           isTag = true;
483           if(isPreviousSlash)
484           {
485             tag.isEndTag = true;
486           }
487
488           isPreviousSlash    = false;
489           isPreviousLessThan = false;
490         }
491         else if(QUOTATION_MARK == character)
492         {
493           isQuotationOpen = !isQuotationOpen;
494           ++tag.length;
495
496           isPreviousSlash    = false;
497           isPreviousLessThan = false;
498         }
499         else if(WHITE_SPACE >= character) // ' '
500         {
501           // If the tag contains white spaces then it may have attributes.
502           if(!isQuotationOpen)
503           {
504             attributesFound = true;
505           }
506           ++tag.length;
507         }
508         else
509         {
510           if(NULL == tag.buffer)
511           {
512             tag.buffer = markupStringBuffer;
513           }
514
515           // If it's not any of the 'special' characters then just add it to the tag string.
516           ++tag.length;
517
518           isPreviousSlash    = false;
519           isPreviousLessThan = false;
520         }
521       }
522     }
523
524     // If the tag string has white spaces, then parse the attributes is needed.
525     if(attributesFound)
526     {
527       ParseAttributes(tag);
528     }
529   }
530
531   return isTag;
532 }
533
534 /**
535  * @brief Returns length of XHTML entity by parsing the text. It also determines if it is XHTML entity or not.
536  *
537  * @param[in] markupStringBuffer The mark-up string buffer. It's a const iterator pointing the current character.
538  * @param[in] markupStringEndBuffer Pointing to end of mark-up string buffer.
539  *
540  * @return Length of markupText in case of XHTML entity otherwise return 0.
541  */
542 unsigned int GetXHTMLEntityLength(const char*&      markupStringBuffer,
543                                   const char* const markupStringEndBuffer)
544 {
545   char character = *markupStringBuffer;
546   if(AMPERSAND == character) // '&'
547   {
548     // if the iterator is pointing to a '&' character, then check for ';' to find end to XHTML entity.
549     ++markupStringBuffer;
550     if(markupStringBuffer < markupStringEndBuffer)
551     {
552       unsigned int len = 1u;
553       for(; markupStringBuffer < markupStringEndBuffer; ++markupStringBuffer)
554       {
555         character = *markupStringBuffer;
556         ++len;
557         if(SEMI_COLON == character) // ';'
558         {
559           // found end of XHTML entity
560           ++markupStringBuffer;
561           return len;
562         }
563         else if((AMPERSAND == character) || (BACK_SLASH == character) || (LESS_THAN == character))
564         {
565           return 0;
566         }
567       }
568     }
569   }
570   return 0;
571 }
572
573 /**
574  * @brief It parses a XHTML string which has hex/decimal entity and fill its corresponging utf-8 string.
575  *
576  * @param[in] markupText The mark-up text buffer.
577  * @param[out] utf-8 text Corresponding to markup Text
578  *
579  * @return true if string is successfully parsed otherwise false
580  */
581 bool XHTMLNumericEntityToUtf8(const char* markupText, char* utf8)
582 {
583   bool result = false;
584
585   if(NULL != markupText)
586   {
587     bool isHex = false;
588
589     // check if hex or decimal entity
590     if((CHAR_ARRAY_END != *markupText) && (HEX_CODE == *markupText))
591     {
592       isHex = true;
593       ++markupText;
594     }
595
596     char*         end = NULL;
597     unsigned long l   = strtoul(markupText, &end, (isHex ? 16 : 10)); // l contains UTF-32 code in case of correct XHTML entity
598
599     // check for valid XHTML numeric entities (between '#' or "#x" and ';')
600     if((l > 0) && (l < ULONG_MAX) && (*end == SEMI_COLON)) // in case wrong XHTML entity is set eg. "&#23abcdefs;" in that case *end will be 'a'
601     {
602       /* characters XML 1.1 permits */
603       if(((XHTML_DECIMAL_ENTITY_RANGE[0] < l) && (l <= XHTML_DECIMAL_ENTITY_RANGE[1])) ||
604          ((XHTML_DECIMAL_ENTITY_RANGE[2] <= l) && (l <= XHTML_DECIMAL_ENTITY_RANGE[3])) ||
605          ((XHTML_DECIMAL_ENTITY_RANGE[4] <= l) && (l <= XHTML_DECIMAL_ENTITY_RANGE[5])))
606       {
607         // Convert UTF32 code to UTF8
608         Utf32ToUtf8(reinterpret_cast<const uint32_t* const>(&l), 1, reinterpret_cast<uint8_t*>(utf8));
609         result = true;
610       }
611     }
612   }
613   return result;
614 }
615
616 /**
617  * @brief Processes a particular tag for the required run (color-run, font-run or underlined-character-run).
618  *
619  * @tparam RunType Whether ColorRun , FontDescriptionRun or UnderlinedCharacterRun
620  *
621  * @param[in/out] runsContainer The container containing all the runs
622  * @param[in/out] styleStack The style stack
623  * @param[in] tag The tag we are currently processing
624  * @param[in] characterIndex The current character index
625  * @param[in/out] runIndex The run index
626  * @param[in/out] tagReference The tagReference we should increment/decrement
627  * @param[in] parameterSettingFunction This function will be called to set run specific parameters
628  */
629 template<typename RunType>
630 void ProcessTagForRun(
631   Vector<RunType>&                          runsContainer,
632   StyleStack<RunIndex>&                     styleStack,
633   const Tag&                                tag,
634   const CharacterIndex                      characterIndex,
635   RunIndex&                                 runIndex,
636   int&                                      tagReference,
637   std::function<void(const Tag&, RunType&)> parameterSettingFunction)
638 {
639   if(!tag.isEndTag)
640   {
641     // Create a new run.
642     RunType run;
643     Initialize(run);
644
645     // Fill the run with the parameters.
646     run.characterRun.characterIndex = characterIndex;
647     parameterSettingFunction(tag, run);
648
649     // Push the run in the logical model.
650     runsContainer.PushBack(run);
651
652     // Push the index of the run into the stack.
653     styleStack.Push(runIndex);
654
655     // Point the next free run.
656     ++runIndex;
657
658     // Increase reference
659     ++tagReference;
660   }
661   else
662   {
663     if(tagReference > 0)
664     {
665       // Pop the top of the stack and set the number of characters of the run.
666       RunType& run                        = *(runsContainer.Begin() + styleStack.Pop());
667       run.characterRun.numberOfCharacters = characterIndex - run.characterRun.characterIndex;
668       --tagReference;
669     }
670   }
671 }
672
673 /**
674  * @brief Processes the item tag
675  *
676  * @param[in/out] markupProcessData The markup process data
677  * @param[in] tag The current tag
678  * @param[in/out] characterIndex The current character index
679  */
680 void ProcessItemTag(
681   MarkupProcessData& markupProcessData,
682   const Tag          tag,
683   CharacterIndex&    characterIndex)
684 {
685   if(tag.isEndTag)
686   {
687     // Create an embedded item instance.
688     EmbeddedItem item;
689     item.characterIndex = characterIndex;
690     ProcessEmbeddedItem(tag, item);
691
692     markupProcessData.items.PushBack(item);
693
694     // Insert white space character that will be replaced by the item.
695     markupProcessData.markupProcessedText.append(1u, WHITE_SPACE);
696     ++characterIndex;
697   }
698 }
699
700 /**
701  * @brief Processes the paragraph-tag
702  *
703  * @param[in/out] markupProcessData The markup process data
704  * @param[in] tag The current tag
705  * @param[in] isEndBuffer Whether the end of buffer
706  * @param[in/out] characterIndex The current character index
707  */
708 void ProcessParagraphTag(
709   MarkupProcessData& markupProcessData,
710   const Tag          tag,
711   bool               isEndBuffer,
712   CharacterIndex&    characterIndex)
713 {
714   if((characterIndex > 0 &&
715       markupProcessData.markupProcessedText[characterIndex - 1u] != NEW_LINE) &&
716      (!(tag.isEndTag && isEndBuffer)))
717   {
718     // Insert new-line character at the start and end of paragraph.
719     markupProcessData.markupProcessedText.append(1u, NEW_LINE);
720     ++characterIndex;
721   }
722 }
723
724 /**
725  * @brief Processes span tag for the color-run & font-run.
726  *
727  * @param[in] spanTag The tag we are currently processing
728  * @param[inout] spanStack The spans stack
729  * @param[inout] colorRuns The container containing all the color runs
730  * @param[inout] fontRuns The container containing all the font description runs
731  * @param[inout] underlinedCharacterRuns The container containing all the underlined character runs
732  * @param[inout] strikethroughCharacterRuns The container containing all the strikethroughed character runs
733  * @param[inout] colorRunIndex The color run index
734  * @param[inout] fontRunIndex The font run index
735  * @param[inout] underlinedCharacterRunIndex The underlined character run index
736  * @param[inout] strikethroughCharacterRunIndex The strikethroughed character run index
737  * @param[in] characterIndex The current character index
738  * @param[in] tagReference The tagReference we should increment/decrement
739  */
740 void ProcessSpanForRun(
741   const Tag&                            spanTag,
742   StyleStack<Span>&                     spanStack,
743   Vector<ColorRun>&                     colorRuns,
744   Vector<FontDescriptionRun>&           fontRuns,
745   Vector<UnderlinedCharacterRun>&       underlinedCharacterRuns,
746   Vector<ColorRun>&                     backgroundColorRuns,
747   Vector<StrikethroughCharacterRun>&    strikethroughCharacterRuns,
748   Vector<CharacterSpacingCharacterRun>& characterSpacingCharacterRuns,
749   RunIndex&                             colorRunIndex,
750   RunIndex&                             fontRunIndex,
751   RunIndex&                             underlinedCharacterRunIndex,
752   RunIndex&                             backgroundColorRunIndex,
753   RunIndex&                             strikethroughCharacterRunIndex,
754   RunIndex&                             characterSpacingCharacterRunIndex,
755   const CharacterIndex                  characterIndex,
756   int&                                  tagReference)
757 {
758   if(!spanTag.isEndTag)
759   {
760     // Create a new run.
761     ColorRun colorRun;
762     Initialize(colorRun);
763
764     FontDescriptionRun fontRun;
765     Initialize(fontRun);
766
767     UnderlinedCharacterRun underlinedCharacterRun;
768     Initialize(underlinedCharacterRun);
769
770     ColorRun backgroundColorRun;
771     Initialize(backgroundColorRun);
772
773     StrikethroughCharacterRun strikethroughCharacterRun;
774     Initialize(strikethroughCharacterRun);
775
776     CharacterSpacingCharacterRun characterSpacingCharacterRun;
777     Initialize(characterSpacingCharacterRun);
778
779     Span span;
780     Initialize(span);
781
782     // Fill the run with the parameters.
783     colorRun.characterRun.characterIndex                     = characterIndex;
784     fontRun.characterRun.characterIndex                      = characterIndex;
785     underlinedCharacterRun.characterRun.characterIndex       = characterIndex;
786     backgroundColorRun.characterRun.characterIndex           = characterIndex;
787     strikethroughCharacterRun.characterRun.characterIndex    = characterIndex;
788     characterSpacingCharacterRun.characterRun.characterIndex = characterIndex;
789
790     span.colorRunIndex                     = colorRunIndex;
791     span.fontRunIndex                      = fontRunIndex;
792     span.underlinedCharacterRunIndex       = underlinedCharacterRunIndex;
793     span.backgroundColorRunIndex           = backgroundColorRunIndex;
794     span.strikethroughCharacterRunIndex    = strikethroughCharacterRunIndex;
795     span.characterSpacingCharacterRunIndex = characterSpacingCharacterRunIndex;
796
797     ProcessSpanTag(spanTag,
798                    colorRun,
799                    fontRun,
800                    underlinedCharacterRun,
801                    backgroundColorRun,
802                    strikethroughCharacterRun,
803                    characterSpacingCharacterRun,
804                    span.isColorDefined,
805                    span.isFontDefined,
806                    span.isUnderlinedCharacterDefined,
807                    span.isBackgroundColorDefined,
808                    span.isStrikethroughDefined,
809                    span.isCharacterSpacingDefined);
810
811     // Push the span into the stack.
812     spanStack.Push(span);
813
814     // Point the next free run.
815     if(span.isColorDefined)
816     {
817       // Push the run in the logical model.
818       colorRuns.PushBack(colorRun);
819       ++colorRunIndex;
820     }
821
822     if(span.isFontDefined)
823     {
824       // Push the run in the logical model.
825       fontRuns.PushBack(fontRun);
826       ++fontRunIndex;
827     }
828
829     if(span.isUnderlinedCharacterDefined)
830     {
831       // Push the run in the logical model.
832       underlinedCharacterRuns.PushBack(underlinedCharacterRun);
833       ++underlinedCharacterRunIndex;
834     }
835
836     if(span.isBackgroundColorDefined)
837     {
838       // Push the run in the logical model.
839       backgroundColorRuns.PushBack(backgroundColorRun);
840       ++backgroundColorRunIndex;
841     }
842
843     if(span.isStrikethroughDefined)
844     {
845       // Push the run in the logical model.
846       strikethroughCharacterRuns.PushBack(strikethroughCharacterRun);
847       ++strikethroughCharacterRunIndex;
848     }
849
850     if(span.isCharacterSpacingDefined)
851     {
852       // Push the run in the logical model.
853       characterSpacingCharacterRuns.PushBack(characterSpacingCharacterRun);
854       ++characterSpacingCharacterRunIndex;
855     }
856
857     // Increase reference
858     ++tagReference;
859   }
860   else
861   {
862     if(tagReference > 0)
863     {
864       // Pop the top of the stack and set the number of characters of the run.
865       Span span = spanStack.Pop();
866
867       if(span.isColorDefined)
868       {
869         ColorRun& colorRun                       = *(colorRuns.Begin() + span.colorRunIndex);
870         colorRun.characterRun.numberOfCharacters = characterIndex - colorRun.characterRun.characterIndex;
871       }
872
873       if(span.isFontDefined)
874       {
875         FontDescriptionRun& fontRun             = *(fontRuns.Begin() + span.fontRunIndex);
876         fontRun.characterRun.numberOfCharacters = characterIndex - fontRun.characterRun.characterIndex;
877       }
878
879       if(span.isUnderlinedCharacterDefined)
880       {
881         UnderlinedCharacterRun& underlinedCharacterRun         = *(underlinedCharacterRuns.Begin() + span.underlinedCharacterRunIndex);
882         underlinedCharacterRun.characterRun.numberOfCharacters = characterIndex - underlinedCharacterRun.characterRun.characterIndex;
883       }
884
885       if(span.isBackgroundColorDefined)
886       {
887         ColorRun& backgroundColorRun                       = *(backgroundColorRuns.Begin() + span.backgroundColorRunIndex);
888         backgroundColorRun.characterRun.numberOfCharacters = characterIndex - backgroundColorRun.characterRun.characterIndex;
889       }
890
891       if(span.isStrikethroughDefined)
892       {
893         StrikethroughCharacterRun& strikethroughCharacterRun      = *(strikethroughCharacterRuns.Begin() + span.strikethroughCharacterRunIndex);
894         strikethroughCharacterRun.characterRun.numberOfCharacters = characterIndex - strikethroughCharacterRun.characterRun.characterIndex;
895       }
896
897       if(span.isCharacterSpacingDefined)
898       {
899         CharacterSpacingCharacterRun& characterSpacingCharacterRun   = *(characterSpacingCharacterRuns.Begin() + span.characterSpacingCharacterRunIndex);
900         characterSpacingCharacterRun.characterRun.numberOfCharacters = characterIndex - characterSpacingCharacterRun.characterRun.characterIndex;
901       }
902
903       --tagReference;
904     }
905   }
906 }
907
908 /**
909  * @brief Processes anchor tag for the color-run & underline-run.
910  *
911  * @param[in,out] markupProcessData The markup process data
912  * @param[in] markupPropertyData The markup property data
913  * @param[in] tag The tag we are currently processing
914  * @param[in,out] anchorStack The anchors stack
915  * @param[in,out] colorRuns The container containing all the color runs
916  * @param[in,out] underlinedCharacterRuns The container containing all the underlined character runs
917  * @param[in,out] colorRunIndex The color run index
918  * @param[in,out] underlinedCharacterRunIndex The underlined character run index
919  * @param[in] characterIndex The current character index
920  * @param[in] tagReference The tagReference we should increment/decrement
921  */
922 void ProcessAnchorForRun(
923   MarkupProcessData&                    markupProcessData,
924   MarkupPropertyData&                   markupPropertyData,
925   const Tag&                            tag,
926   StyleStack<AnchorForStack>&           anchorStack,
927   Vector<ColorRun>&                     colorRuns,
928   Vector<UnderlinedCharacterRun>&       underlinedCharacterRuns,
929   RunIndex&                             colorRunIndex,
930   RunIndex&                             underlinedCharacterRunIndex,
931   const CharacterIndex                  characterIndex,
932   int&                                  tagReference)
933 {
934   if(!tag.isEndTag)
935   {
936     // Create an anchor instance.
937     Anchor anchor;
938     anchor.href                        = nullptr;
939     anchor.startIndex                  = characterIndex;
940     anchor.endIndex                    = 0u;
941     anchor.colorRunIndex               = colorRunIndex;
942     anchor.underlinedCharacterRunIndex = underlinedCharacterRunIndex;
943     anchor.markupClickedColor          = markupPropertyData.anchorClickedColor;
944
945     // Create a new run.
946     ColorRun colorRun;
947     Initialize(colorRun);
948
949     UnderlinedCharacterRun underlinedCharacterRun;
950     Initialize(underlinedCharacterRun);
951
952     AnchorForStack anchorForStack;
953     Initialize(anchorForStack);
954
955     // Fill the run with the parameters.
956     colorRun.characterRun.characterIndex               = characterIndex;
957     underlinedCharacterRun.characterRun.characterIndex = characterIndex;
958
959     anchorForStack.colorRunIndex               = colorRunIndex;
960     anchorForStack.underlinedCharacterRunIndex = underlinedCharacterRunIndex;
961
962     // Init default color
963     colorRun.color                                 = markupPropertyData.anchorColor;
964     underlinedCharacterRun.properties.color        = markupPropertyData.anchorColor;
965     underlinedCharacterRun.properties.colorDefined = true;
966
967     ProcessAnchorTag(tag, anchor, colorRun, underlinedCharacterRun);
968
969     markupProcessData.anchors.PushBack(anchor);
970
971     // Push the anchor into the stack.
972     anchorStack.Push(anchorForStack);
973
974     // Push the run in the logical model.
975     colorRuns.PushBack(colorRun);
976     ++colorRunIndex;
977
978     // Push the run in the logical model.
979     underlinedCharacterRuns.PushBack(underlinedCharacterRun);
980     ++underlinedCharacterRunIndex;
981
982     // Increase reference
983     ++tagReference;
984   }
985   else
986   {
987     if(tagReference > 0)
988     {
989       // Update end index.
990       unsigned int count = markupProcessData.anchors.Count();
991       if(count > 0)
992       {
993         markupProcessData.anchors[count - 1].endIndex = characterIndex;
994       }
995
996       // Pop the top of the stack and set the number of characters of the run.
997       AnchorForStack anchorForStack = anchorStack.Pop();
998
999       ColorRun& colorRun                       = *(colorRuns.Begin() + anchorForStack.colorRunIndex);
1000       colorRun.characterRun.numberOfCharacters = characterIndex - colorRun.characterRun.characterIndex;
1001
1002       UnderlinedCharacterRun& underlinedCharacterRun         = *(underlinedCharacterRuns.Begin() + anchorForStack.underlinedCharacterRunIndex);
1003       underlinedCharacterRun.characterRun.numberOfCharacters = characterIndex - underlinedCharacterRun.characterRun.characterIndex;
1004
1005       --tagReference;
1006     }
1007   }
1008 }
1009
1010 /**
1011  * @brief Resizes the model's vectors
1012  *
1013  * @param[inout] markupProcessData The markup process data
1014  * @param[in] fontRunIndex The font run index
1015  * @param[in] colorRunIndex The color run index
1016  * @param[in] underlinedCharacterRunIndex The underlined character run index
1017  * @param[in] strikethroughCharacterRunIndex The strikethroughed character run index
1018  * @param[in] backgroundRunIndex The background run index
1019  * @param[in] boundedParagraphRunIndex The bounded paragraph run index
1020  * @param[in] characterSpacingCharacterRunIndex The character-spacing character run index
1021  *
1022  */
1023 void ResizeModelVectors(MarkupProcessData& markupProcessData,
1024                         const RunIndex     fontRunIndex,
1025                         const RunIndex     colorRunIndex,
1026                         const RunIndex     underlinedCharacterRunIndex,
1027                         const RunIndex     strikethroughCharacterRunIndex,
1028                         const RunIndex     backgroundRunIndex,
1029                         const RunIndex     boundedParagraphRunIndex,
1030                         const RunIndex     characterSpacingCharacterRunIndex)
1031 {
1032   markupProcessData.fontRuns.Resize(fontRunIndex);
1033   markupProcessData.colorRuns.Resize(colorRunIndex);
1034   markupProcessData.underlinedCharacterRuns.Resize(underlinedCharacterRunIndex);
1035   markupProcessData.strikethroughCharacterRuns.Resize(strikethroughCharacterRunIndex);
1036   markupProcessData.backgroundColorRuns.Resize(backgroundRunIndex);
1037   markupProcessData.boundedParagraphRuns.Resize(boundedParagraphRunIndex);
1038   markupProcessData.characterSpacingCharacterRuns.Resize(characterSpacingCharacterRunIndex);
1039
1040 #ifdef DEBUG_ENABLED
1041   if(gLogFilter->IsEnabledFor(Debug::Verbose))
1042   {
1043     for(uint32_t i = 0; i < colorRunIndex; ++i)
1044     {
1045       ColorRun& run = markupProcessData.colorRuns[i];
1046       DALI_LOG_INFO(gLogFilter, Debug::Verbose, "run[%d] index: %d, length: %d, color %f,%f,%f,%f\n", i, run.characterRun.characterIndex, run.characterRun.numberOfCharacters, run.color.r, run.color.g, run.color.b, run.color.a);
1047     }
1048   }
1049 #endif
1050 }
1051
1052 /**
1053  * @brief Processes the markup string buffer
1054  *
1055  * @param[in/out] markupProcessData The markup process data
1056  * @param[in/out] markupStringBuffer The markup string buffer pointer
1057  * @param[in] markupStringEndBuffer The markup string end buffer pointer
1058  * @param[in/out] characterIndex The current character index
1059  */
1060 void ProcessMarkupStringBuffer(
1061   MarkupProcessData& markupProcessData,
1062   const char*&       markupStringBuffer,
1063   const char* const  markupStringEndBuffer,
1064   CharacterIndex&    characterIndex)
1065 {
1066   unsigned char character    = *markupStringBuffer;
1067   const char*   markupBuffer = markupStringBuffer;
1068   unsigned char count        = GetUtf8Length(character);
1069   char          utf8[8];
1070
1071   if((BACK_SLASH == character) && (markupStringBuffer + 1u < markupStringEndBuffer))
1072   {
1073     // Adding < , >  or & special character.
1074     const unsigned char nextCharacter = *(markupStringBuffer + 1u);
1075     if((LESS_THAN == nextCharacter) || (GREATER_THAN == nextCharacter) || (AMPERSAND == nextCharacter))
1076     {
1077       character = nextCharacter;
1078       ++markupStringBuffer;
1079
1080       count        = GetUtf8Length(character);
1081       markupBuffer = markupStringBuffer;
1082     }
1083   }
1084   else // checking if contains XHTML entity or not
1085   {
1086     const unsigned int len = GetXHTMLEntityLength(markupStringBuffer, markupStringEndBuffer);
1087
1088     // Parse markupStringTxt if it contains XHTML Entity between '&' and ';'
1089     if(len > 0)
1090     {
1091       char* entityCode = NULL;
1092       bool  result     = false;
1093       count            = 0;
1094
1095       // Checking if XHTML Numeric Entity
1096       if(HASH == *(markupBuffer + 1u))
1097       {
1098         entityCode = &utf8[0];
1099         // markupBuffer is currently pointing to '&'. By adding 2u to markupBuffer it will point to numeric string by skipping "&#'
1100         result = XHTMLNumericEntityToUtf8((markupBuffer + 2u), entityCode);
1101       }
1102       else // Checking if XHTML Named Entity
1103       {
1104         entityCode = const_cast<char*>(NamedEntityToUtf8(markupBuffer, len));
1105         result     = (entityCode != NULL);
1106       }
1107       if(result)
1108       {
1109         markupBuffer = entityCode; //utf8 text assigned to markupBuffer
1110         character    = markupBuffer[0];
1111       }
1112       else
1113       {
1114         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Not valid XHTML entity : (%.*s) \n", len, markupBuffer);
1115         markupBuffer = NULL;
1116       }
1117     }
1118     else // in case string conatins Start of XHTML Entity('&') but not its end character(';')
1119     {
1120       if(character == AMPERSAND)
1121       {
1122         markupBuffer = NULL;
1123         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Not Well formed XHTML content \n");
1124       }
1125     }
1126   }
1127
1128   if(markupBuffer != NULL)
1129   {
1130     const unsigned char numberOfBytes = GetUtf8Length(character);
1131     markupProcessData.markupProcessedText.push_back(character);
1132
1133     for(unsigned char i = 1u; i < numberOfBytes; ++i)
1134     {
1135       ++markupBuffer;
1136       markupProcessData.markupProcessedText.push_back(*markupBuffer);
1137     }
1138
1139     ++characterIndex;
1140     markupStringBuffer += count;
1141   }
1142 }
1143
1144 } // namespace
1145
1146 void ProcessMarkupString(const std::string& markupString, MarkupPropertyData& markupPropertyData, MarkupProcessData& markupProcessData)
1147 {
1148   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "markupString: %s\n", markupString.c_str());
1149
1150   // Reserve space for the plain text.
1151   const Length markupStringSize = markupString.size();
1152   markupProcessData.markupProcessedText.reserve(markupStringSize);
1153
1154   // Stores a struct with the index to the first character of the run, the type of run and its parameters.
1155   StyleStack<RunIndex> styleStack;
1156
1157   // Stores a struct with the index to the first character of the color run & color font for the span.
1158   StyleStack<Span> spanStack;
1159
1160   StyleStack<AnchorForStack> anchorStack;
1161
1162   // Points the next free position in the vector of runs.
1163   RunIndex colorRunIndex                     = 0u;
1164   RunIndex fontRunIndex                      = 0u;
1165   RunIndex underlinedCharacterRunIndex       = 0u;
1166   RunIndex backgroundRunIndex                = 0u;
1167   RunIndex strikethroughCharacterRunIndex    = 0u;
1168   RunIndex boundedParagraphRunIndex          = 0u;
1169   RunIndex characterSpacingCharacterRunIndex = 0u;
1170
1171   // check tag reference
1172   int colorTagReference            = 0u;
1173   int fontTagReference             = 0u;
1174   int iTagReference                = 0u;
1175   int bTagReference                = 0u;
1176   int uTagReference                = 0u;
1177   int backgroundTagReference       = 0u;
1178   int spanTagReference             = 0u;
1179   int sTagReference                = 0u;
1180   int pTagReference                = 0u;
1181   int characterSpacingTagReference = 0u;
1182   int aTagReference                = 0u;
1183
1184   // Give an initial default value to the model's vectors.
1185   markupProcessData.colorRuns.Reserve(DEFAULT_VECTOR_SIZE);
1186   markupProcessData.fontRuns.Reserve(DEFAULT_VECTOR_SIZE);
1187   markupProcessData.underlinedCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
1188   markupProcessData.backgroundColorRuns.Reserve(DEFAULT_VECTOR_SIZE);
1189   markupProcessData.strikethroughCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
1190   markupProcessData.characterSpacingCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
1191
1192   // Get the mark-up string buffer.
1193   const char*       markupStringBuffer    = markupString.c_str();
1194   const char* const markupStringEndBuffer = markupStringBuffer + markupStringSize;
1195
1196   Tag            tag;
1197   CharacterIndex characterIndex = 0u;
1198   for(; markupStringBuffer < markupStringEndBuffer;)
1199   {
1200     tag.attributes.Clear();
1201     if(IsTag(markupStringBuffer,
1202              markupStringEndBuffer,
1203              tag))
1204     {
1205       if(TokenComparison(MARKUP::TAG::COLOR, tag.buffer, tag.length))
1206       {
1207         ProcessTagForRun<ColorRun>(
1208           markupProcessData.colorRuns, styleStack, tag, characterIndex, colorRunIndex, colorTagReference, [](const Tag& tag, ColorRun& run) { ProcessColorTag(tag, run); });
1209       } // <color></color>
1210       else if(TokenComparison(MARKUP::TAG::ITALIC, tag.buffer, tag.length))
1211       {
1212         ProcessTagForRun<FontDescriptionRun>(
1213           markupProcessData.fontRuns, styleStack, tag, characterIndex, fontRunIndex, iTagReference, [](const Tag&, FontDescriptionRun& fontRun) {
1214             fontRun.slant        = TextAbstraction::FontSlant::ITALIC;
1215             fontRun.slantDefined = true;
1216           });
1217       } // <i></i>
1218       else if(TokenComparison(MARKUP::TAG::UNDERLINE, tag.buffer, tag.length))
1219       {
1220         ProcessTagForRun<UnderlinedCharacterRun>(
1221           markupProcessData.underlinedCharacterRuns, styleStack, tag, characterIndex, underlinedCharacterRunIndex, uTagReference, [](const Tag& tag, UnderlinedCharacterRun& run) { ProcessUnderlineTag(tag, run); });
1222       } // <u></u>
1223       else if(TokenComparison(MARKUP::TAG::BOLD, tag.buffer, tag.length))
1224       {
1225         ProcessTagForRun<FontDescriptionRun>(
1226           markupProcessData.fontRuns, styleStack, tag, characterIndex, fontRunIndex, bTagReference, [](const Tag&, FontDescriptionRun& fontRun) {
1227             fontRun.weight        = TextAbstraction::FontWeight::BOLD;
1228             fontRun.weightDefined = true;
1229           });
1230       } // <b></b>
1231       else if(TokenComparison(MARKUP::TAG::FONT, tag.buffer, tag.length))
1232       {
1233         ProcessTagForRun<FontDescriptionRun>(
1234           markupProcessData.fontRuns, styleStack, tag, characterIndex, fontRunIndex, fontTagReference, [](const Tag& tag, FontDescriptionRun& fontRun) { ProcessFontTag(tag, fontRun); });
1235       } // <font></font>
1236       else if(TokenComparison(MARKUP::TAG::ANCHOR, tag.buffer, tag.length))
1237       {
1238         ProcessAnchorForRun(markupProcessData,
1239                             markupPropertyData,
1240                             tag,
1241                             anchorStack,
1242                             markupProcessData.colorRuns,
1243                             markupProcessData.underlinedCharacterRuns,
1244                             colorRunIndex,
1245                             underlinedCharacterRunIndex,
1246                             characterIndex,
1247                             aTagReference);
1248       } // <a href=https://www.tizen.org>tizen</a>
1249       else if(TokenComparison(MARKUP::TAG::SHADOW, tag.buffer, tag.length))
1250       {
1251         // TODO: If !tag.isEndTag, then create a new shadow run.
1252         //       else Pop the top of the stack and set the number of characters of the run.
1253       } // <shadow></shadow>
1254       else if(TokenComparison(MARKUP::TAG::GLOW, tag.buffer, tag.length))
1255       {
1256         // TODO: If !tag.isEndTag, then create a new glow run.
1257         //       else Pop the top of the stack and set the number of characters of the run.
1258       } // <glow></glow>
1259       else if(TokenComparison(MARKUP::TAG::OUTLINE, tag.buffer, tag.length))
1260       {
1261         // TODO: If !tag.isEndTag, then create a new outline run.
1262         //       else Pop the top of the stack and set the number of characters of the run.
1263       } // <outline></outline>
1264       else if(TokenComparison(MARKUP::TAG::EMBEDDED_ITEM, tag.buffer, tag.length))
1265       {
1266         ProcessItemTag(markupProcessData, tag, characterIndex);
1267       }
1268       else if(TokenComparison(MARKUP::TAG::BACKGROUND, tag.buffer, tag.length))
1269       {
1270         ProcessTagForRun<ColorRun>(
1271           markupProcessData.backgroundColorRuns, styleStack, tag, characterIndex, backgroundRunIndex, backgroundTagReference, [](const Tag& tag, ColorRun& run) { ProcessBackground(tag, run); });
1272       }
1273       else if(TokenComparison(MARKUP::TAG::SPAN, tag.buffer, tag.length))
1274       {
1275         ProcessSpanForRun(tag,
1276                           spanStack,
1277                           markupProcessData.colorRuns,
1278                           markupProcessData.fontRuns,
1279                           markupProcessData.underlinedCharacterRuns,
1280                           markupProcessData.backgroundColorRuns,
1281                           markupProcessData.strikethroughCharacterRuns,
1282                           markupProcessData.characterSpacingCharacterRuns,
1283                           colorRunIndex,
1284                           fontRunIndex,
1285                           underlinedCharacterRunIndex,
1286                           backgroundRunIndex,
1287                           strikethroughCharacterRunIndex,
1288                           characterSpacingCharacterRunIndex,
1289                           characterIndex,
1290                           spanTagReference);
1291       }
1292       else if(TokenComparison(MARKUP::TAG::STRIKETHROUGH, tag.buffer, tag.length))
1293       {
1294         ProcessTagForRun<StrikethroughCharacterRun>(
1295           markupProcessData.strikethroughCharacterRuns, styleStack, tag, characterIndex, strikethroughCharacterRunIndex, sTagReference, [](const Tag& tag, StrikethroughCharacterRun& run) { ProcessStrikethroughTag(tag, run); });
1296       } // <s></s>
1297       else if(TokenComparison(MARKUP::TAG::PARAGRAPH, tag.buffer, tag.length))
1298       {
1299         ProcessParagraphTag(markupProcessData, tag, (markupStringBuffer == markupStringEndBuffer), characterIndex);
1300         ProcessTagForRun<BoundedParagraphRun>(
1301           markupProcessData.boundedParagraphRuns, styleStack, tag, characterIndex, boundedParagraphRunIndex, pTagReference, [](const Tag& tag, BoundedParagraphRun& run) { ProcessAttributesOfParagraphTag(tag, run); });
1302       } // <p></p>
1303       else if(TokenComparison(MARKUP::TAG::CHARACTER_SPACING, tag.buffer, tag.length))
1304       {
1305         ProcessTagForRun<CharacterSpacingCharacterRun>(
1306           markupProcessData.characterSpacingCharacterRuns, styleStack, tag, characterIndex, characterSpacingCharacterRunIndex, characterSpacingTagReference, [](const Tag& tag, CharacterSpacingCharacterRun& run) { ProcessCharacterSpacingTag(tag, run); });
1307       } // <char-spacing></char-spacing>
1308     }   // end if( IsTag() )
1309     else if(markupStringBuffer < markupStringEndBuffer)
1310     {
1311       ProcessMarkupStringBuffer(markupProcessData, markupStringBuffer, markupStringEndBuffer, characterIndex);
1312     }
1313   }
1314
1315   // Resize the model's vectors.
1316   ResizeModelVectors(markupProcessData, fontRunIndex, colorRunIndex, underlinedCharacterRunIndex, strikethroughCharacterRunIndex, backgroundRunIndex, boundedParagraphRunIndex, characterSpacingCharacterRunIndex);
1317
1318   // Handle the nested tags
1319   OverrideNestedUnderlinedCharacterRuns(markupProcessData.underlinedCharacterRuns);
1320   OverrideNestedStrikethroughCharacterRuns(markupProcessData.strikethroughCharacterRuns);
1321 }
1322
1323 } // namespace Text
1324
1325 } // namespace Toolkit
1326
1327 } // namespace Dali