Add color tag for text markup anchor
[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       addToNameValue = false; // next read characters will be added to the value.
347       SkipWhiteSpace(tagBuffer, tagEndBuffer);
348     }
349     else if(QUOTATION_MARK == character) // '\''
350     {
351       // Do not add quotation marks to neither name nor value.
352       isQuotationOpen = !isQuotationOpen;
353
354       if(isQuotationOpen)
355       {
356         ++tagBuffer;
357         SkipWhiteSpace(tagBuffer, tagEndBuffer);
358         --tagBuffer;
359       }
360     }
361     else
362     {
363       // Adds characters to the name or the value.
364       if(addToNameValue)
365       {
366         if(NULL == nameBuffer)
367         {
368           nameBuffer = tagBuffer;
369         }
370         ++nameLength;
371       }
372       else
373       {
374         if(isQuotationOpen)
375         {
376           if(WHITE_SPACE >= character)
377           {
378             ++numberOfWhiteSpace;
379           }
380           else
381           {
382             numberOfWhiteSpace = 0u;
383           }
384         }
385         if(NULL == valueBuffer)
386         {
387           valueBuffer = tagBuffer;
388         }
389         ++valueLength;
390       }
391     }
392   }
393
394   if(NULL != valueBuffer)
395   {
396     // Remove white spaces at the end of the value.
397     valueLength -= numberOfWhiteSpace;
398   }
399
400   if((NULL != nameBuffer) && (NULL != valueBuffer))
401   {
402     // Checks if the last attribute needs to be added.
403     Attribute& attribute = *(tag.attributes.Begin() + attributeIndex);
404     ++attributeIndex;
405
406     attribute.nameBuffer  = nameBuffer;
407     attribute.valueBuffer = valueBuffer;
408     attribute.nameLength  = nameLength;
409     attribute.valueLength = valueLength;
410   }
411
412   // Resize the vector of attributes.
413   tag.attributes.Resize(attributeIndex);
414 }
415
416 /**
417  * @brief It parses a tag and its attributes if the given iterator @e it is pointing at a tag beginning.
418  *
419  * @param[in,out] markupStringBuffer The mark-up string buffer. It's a const iterator pointing the current character.
420  * @param[in] markupStringEndBuffer Pointer to one character after the end of the mark-up string buffer.
421  * @param[out] tag The tag with its attributes.
422  *
423  * @return @e true if the iterator @e it is pointing a mark-up tag. Otherwise @e false.
424  */
425 bool IsTag(const char*&      markupStringBuffer,
426            const char* const markupStringEndBuffer,
427            Tag&              tag)
428 {
429   bool isTag              = false;
430   bool isQuotationOpen    = false;
431   bool attributesFound    = false;
432   tag.isEndTag            = false;
433   bool isPreviousLessThan = false;
434   bool isPreviousSlash    = false;
435
436   const char character = *markupStringBuffer;
437   if(LESS_THAN == character) // '<'
438   {
439     tag.buffer         = NULL;
440     tag.length         = 0u;
441     isPreviousLessThan = true;
442
443     // if the iterator is pointing to a '<' character, then check if it's a mark-up tag is needed.
444     ++markupStringBuffer;
445     if(markupStringBuffer < markupStringEndBuffer)
446     {
447       SkipWhiteSpace(markupStringBuffer, markupStringEndBuffer);
448
449       for(; (!isTag) && (markupStringBuffer < markupStringEndBuffer); ++markupStringBuffer)
450       {
451         const char character = *markupStringBuffer;
452
453         if(!isQuotationOpen && (SLASH == character)) // '/'
454         {
455           if(isPreviousLessThan)
456           {
457             tag.isEndTag = true;
458           }
459           else
460           {
461             // if the tag has a '/' it may be an end tag.
462             isPreviousSlash = true;
463           }
464
465           isPreviousLessThan = false;
466           if((markupStringBuffer + 1u < markupStringEndBuffer) && (WHITE_SPACE >= *(markupStringBuffer + 1u)))
467           {
468             ++markupStringBuffer;
469             SkipWhiteSpace(markupStringBuffer, markupStringEndBuffer);
470             --markupStringBuffer;
471           }
472         }
473         else if(GREATER_THAN == character) // '>'
474         {
475           isTag = true;
476           if(isPreviousSlash)
477           {
478             tag.isEndTag = true;
479           }
480
481           isPreviousSlash    = false;
482           isPreviousLessThan = false;
483         }
484         else if(QUOTATION_MARK == character)
485         {
486           isQuotationOpen = !isQuotationOpen;
487           ++tag.length;
488
489           isPreviousSlash    = false;
490           isPreviousLessThan = false;
491         }
492         else if(WHITE_SPACE >= character) // ' '
493         {
494           // If the tag contains white spaces then it may have attributes.
495           if(!isQuotationOpen)
496           {
497             attributesFound = true;
498           }
499           ++tag.length;
500         }
501         else
502         {
503           if(NULL == tag.buffer)
504           {
505             tag.buffer = markupStringBuffer;
506           }
507
508           // If it's not any of the 'special' characters then just add it to the tag string.
509           ++tag.length;
510
511           isPreviousSlash    = false;
512           isPreviousLessThan = false;
513         }
514       }
515     }
516
517     // If the tag string has white spaces, then parse the attributes is needed.
518     if(attributesFound)
519     {
520       ParseAttributes(tag);
521     }
522   }
523
524   return isTag;
525 }
526
527 /**
528  * @brief Returns length of XHTML entity by parsing the text. It also determines if it is XHTML entity or not.
529  *
530  * @param[in] markupStringBuffer The mark-up string buffer. It's a const iterator pointing the current character.
531  * @param[in] markupStringEndBuffer Pointing to end of mark-up string buffer.
532  *
533  * @return Length of markupText in case of XHTML entity otherwise return 0.
534  */
535 unsigned int GetXHTMLEntityLength(const char*&      markupStringBuffer,
536                                   const char* const markupStringEndBuffer)
537 {
538   char character = *markupStringBuffer;
539   if(AMPERSAND == character) // '&'
540   {
541     // if the iterator is pointing to a '&' character, then check for ';' to find end to XHTML entity.
542     ++markupStringBuffer;
543     if(markupStringBuffer < markupStringEndBuffer)
544     {
545       unsigned int len = 1u;
546       for(; markupStringBuffer < markupStringEndBuffer; ++markupStringBuffer)
547       {
548         character = *markupStringBuffer;
549         ++len;
550         if(SEMI_COLON == character) // ';'
551         {
552           // found end of XHTML entity
553           ++markupStringBuffer;
554           return len;
555         }
556         else if((AMPERSAND == character) || (BACK_SLASH == character) || (LESS_THAN == character))
557         {
558           return 0;
559         }
560       }
561     }
562   }
563   return 0;
564 }
565
566 /**
567  * @brief It parses a XHTML string which has hex/decimal entity and fill its corresponging utf-8 string.
568  *
569  * @param[in] markupText The mark-up text buffer.
570  * @param[out] utf-8 text Corresponding to markup Text
571  *
572  * @return true if string is successfully parsed otherwise false
573  */
574 bool XHTMLNumericEntityToUtf8(const char* markupText, char* utf8)
575 {
576   bool result = false;
577
578   if(NULL != markupText)
579   {
580     bool isHex = false;
581
582     // check if hex or decimal entity
583     if((CHAR_ARRAY_END != *markupText) && (HEX_CODE == *markupText))
584     {
585       isHex = true;
586       ++markupText;
587     }
588
589     char*         end = NULL;
590     unsigned long l   = strtoul(markupText, &end, (isHex ? 16 : 10)); // l contains UTF-32 code in case of correct XHTML entity
591
592     // check for valid XHTML numeric entities (between '#' or "#x" and ';')
593     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'
594     {
595       /* characters XML 1.1 permits */
596       if(((XHTML_DECIMAL_ENTITY_RANGE[0] < l) && (l <= XHTML_DECIMAL_ENTITY_RANGE[1])) ||
597          ((XHTML_DECIMAL_ENTITY_RANGE[2] <= l) && (l <= XHTML_DECIMAL_ENTITY_RANGE[3])) ||
598          ((XHTML_DECIMAL_ENTITY_RANGE[4] <= l) && (l <= XHTML_DECIMAL_ENTITY_RANGE[5])))
599       {
600         // Convert UTF32 code to UTF8
601         Utf32ToUtf8(reinterpret_cast<const uint32_t* const>(&l), 1, reinterpret_cast<uint8_t*>(utf8));
602         result = true;
603       }
604     }
605   }
606   return result;
607 }
608
609 /**
610  * @brief Processes a particular tag for the required run (color-run, font-run or underlined-character-run).
611  *
612  * @tparam RunType Whether ColorRun , FontDescriptionRun or UnderlinedCharacterRun
613  *
614  * @param[in/out] runsContainer The container containing all the runs
615  * @param[in/out] styleStack The style stack
616  * @param[in] tag The tag we are currently processing
617  * @param[in] characterIndex The current character index
618  * @param[in/out] runIndex The run index
619  * @param[in/out] tagReference The tagReference we should increment/decrement
620  * @param[in] parameterSettingFunction This function will be called to set run specific parameters
621  */
622 template<typename RunType>
623 void ProcessTagForRun(
624   Vector<RunType>&                          runsContainer,
625   StyleStack<RunIndex>&                     styleStack,
626   const Tag&                                tag,
627   const CharacterIndex                      characterIndex,
628   RunIndex&                                 runIndex,
629   int&                                      tagReference,
630   std::function<void(const Tag&, RunType&)> parameterSettingFunction)
631 {
632   if(!tag.isEndTag)
633   {
634     // Create a new run.
635     RunType run;
636     Initialize(run);
637
638     // Fill the run with the parameters.
639     run.characterRun.characterIndex = characterIndex;
640     parameterSettingFunction(tag, run);
641
642     // Push the run in the logical model.
643     runsContainer.PushBack(run);
644
645     // Push the index of the run into the stack.
646     styleStack.Push(runIndex);
647
648     // Point the next free run.
649     ++runIndex;
650
651     // Increase reference
652     ++tagReference;
653   }
654   else
655   {
656     if(tagReference > 0)
657     {
658       // Pop the top of the stack and set the number of characters of the run.
659       RunType& run                        = *(runsContainer.Begin() + styleStack.Pop());
660       run.characterRun.numberOfCharacters = characterIndex - run.characterRun.characterIndex;
661       --tagReference;
662     }
663   }
664 }
665
666 /**
667  * @brief Processes the item tag
668  *
669  * @param[in/out] markupProcessData The markup process data
670  * @param[in] tag The current tag
671  * @param[in/out] characterIndex The current character index
672  */
673 void ProcessItemTag(
674   MarkupProcessData& markupProcessData,
675   const Tag          tag,
676   CharacterIndex&    characterIndex)
677 {
678   if(tag.isEndTag)
679   {
680     // Create an embedded item instance.
681     EmbeddedItem item;
682     item.characterIndex = characterIndex;
683     ProcessEmbeddedItem(tag, item);
684
685     markupProcessData.items.PushBack(item);
686
687     // Insert white space character that will be replaced by the item.
688     markupProcessData.markupProcessedText.append(1u, WHITE_SPACE);
689     ++characterIndex;
690   }
691 }
692
693 /**
694  * @brief Processes the paragraph-tag
695  *
696  * @param[in/out] markupProcessData The markup process data
697  * @param[in] tag The current tag
698  * @param[in] isEndBuffer Whether the end of buffer
699  * @param[in/out] characterIndex The current character index
700  */
701 void ProcessParagraphTag(
702   MarkupProcessData& markupProcessData,
703   const Tag          tag,
704   bool               isEndBuffer,
705   CharacterIndex&    characterIndex)
706 {
707   if((characterIndex > 0 &&
708       markupProcessData.markupProcessedText[characterIndex - 1u] != NEW_LINE) &&
709      (!(tag.isEndTag && isEndBuffer)))
710   {
711     // Insert new-line character at the start and end of paragraph.
712     markupProcessData.markupProcessedText.append(1u, NEW_LINE);
713     ++characterIndex;
714   }
715 }
716
717 /**
718  * @brief Processes span tag for the color-run & font-run.
719  *
720  * @param[in] spanTag The tag we are currently processing
721  * @param[inout] spanStack The spans stack
722  * @param[inout] colorRuns The container containing all the color runs
723  * @param[inout] fontRuns The container containing all the font description runs
724  * @param[inout] underlinedCharacterRuns The container containing all the underlined character runs
725  * @param[inout] strikethroughCharacterRuns The container containing all the strikethroughed character runs
726  * @param[inout] colorRunIndex The color run index
727  * @param[inout] fontRunIndex The font run index
728  * @param[inout] underlinedCharacterRunIndex The underlined character run index
729  * @param[inout] strikethroughCharacterRunIndex The strikethroughed character run index
730  * @param[in] characterIndex The current character index
731  * @param[in] tagReference The tagReference we should increment/decrement
732  */
733 void ProcessSpanForRun(
734   const Tag&                            spanTag,
735   StyleStack<Span>&                     spanStack,
736   Vector<ColorRun>&                     colorRuns,
737   Vector<FontDescriptionRun>&           fontRuns,
738   Vector<UnderlinedCharacterRun>&       underlinedCharacterRuns,
739   Vector<ColorRun>&                     backgroundColorRuns,
740   Vector<StrikethroughCharacterRun>&    strikethroughCharacterRuns,
741   Vector<CharacterSpacingCharacterRun>& characterSpacingCharacterRuns,
742   RunIndex&                             colorRunIndex,
743   RunIndex&                             fontRunIndex,
744   RunIndex&                             underlinedCharacterRunIndex,
745   RunIndex&                             backgroundColorRunIndex,
746   RunIndex&                             strikethroughCharacterRunIndex,
747   RunIndex&                             characterSpacingCharacterRunIndex,
748   const CharacterIndex                  characterIndex,
749   int&                                  tagReference)
750 {
751   if(!spanTag.isEndTag)
752   {
753     // Create a new run.
754     ColorRun colorRun;
755     Initialize(colorRun);
756
757     FontDescriptionRun fontRun;
758     Initialize(fontRun);
759
760     UnderlinedCharacterRun underlinedCharacterRun;
761     Initialize(underlinedCharacterRun);
762
763     ColorRun backgroundColorRun;
764     Initialize(backgroundColorRun);
765
766     StrikethroughCharacterRun strikethroughCharacterRun;
767     Initialize(strikethroughCharacterRun);
768
769     CharacterSpacingCharacterRun characterSpacingCharacterRun;
770     Initialize(characterSpacingCharacterRun);
771
772     Span span;
773     Initialize(span);
774
775     // Fill the run with the parameters.
776     colorRun.characterRun.characterIndex                     = characterIndex;
777     fontRun.characterRun.characterIndex                      = characterIndex;
778     underlinedCharacterRun.characterRun.characterIndex       = characterIndex;
779     backgroundColorRun.characterRun.characterIndex           = characterIndex;
780     strikethroughCharacterRun.characterRun.characterIndex    = characterIndex;
781     characterSpacingCharacterRun.characterRun.characterIndex = characterIndex;
782
783     span.colorRunIndex                     = colorRunIndex;
784     span.fontRunIndex                      = fontRunIndex;
785     span.underlinedCharacterRunIndex       = underlinedCharacterRunIndex;
786     span.backgroundColorRunIndex           = backgroundColorRunIndex;
787     span.strikethroughCharacterRunIndex    = strikethroughCharacterRunIndex;
788     span.characterSpacingCharacterRunIndex = characterSpacingCharacterRunIndex;
789
790     ProcessSpanTag(spanTag,
791                    colorRun,
792                    fontRun,
793                    underlinedCharacterRun,
794                    backgroundColorRun,
795                    strikethroughCharacterRun,
796                    characterSpacingCharacterRun,
797                    span.isColorDefined,
798                    span.isFontDefined,
799                    span.isUnderlinedCharacterDefined,
800                    span.isBackgroundColorDefined,
801                    span.isStrikethroughDefined,
802                    span.isCharacterSpacingDefined);
803
804     // Push the span into the stack.
805     spanStack.Push(span);
806
807     // Point the next free run.
808     if(span.isColorDefined)
809     {
810       // Push the run in the logical model.
811       colorRuns.PushBack(colorRun);
812       ++colorRunIndex;
813     }
814
815     if(span.isFontDefined)
816     {
817       // Push the run in the logical model.
818       fontRuns.PushBack(fontRun);
819       ++fontRunIndex;
820     }
821
822     if(span.isUnderlinedCharacterDefined)
823     {
824       // Push the run in the logical model.
825       underlinedCharacterRuns.PushBack(underlinedCharacterRun);
826       ++underlinedCharacterRunIndex;
827     }
828
829     if(span.isBackgroundColorDefined)
830     {
831       // Push the run in the logical model.
832       backgroundColorRuns.PushBack(backgroundColorRun);
833       ++backgroundColorRunIndex;
834     }
835
836     if(span.isStrikethroughDefined)
837     {
838       // Push the run in the logical model.
839       strikethroughCharacterRuns.PushBack(strikethroughCharacterRun);
840       ++strikethroughCharacterRunIndex;
841     }
842
843     if(span.isCharacterSpacingDefined)
844     {
845       // Push the run in the logical model.
846       characterSpacingCharacterRuns.PushBack(characterSpacingCharacterRun);
847       ++characterSpacingCharacterRunIndex;
848     }
849
850     // Increase reference
851     ++tagReference;
852   }
853   else
854   {
855     if(tagReference > 0)
856     {
857       // Pop the top of the stack and set the number of characters of the run.
858       Span span = spanStack.Pop();
859
860       if(span.isColorDefined)
861       {
862         ColorRun& colorRun                       = *(colorRuns.Begin() + span.colorRunIndex);
863         colorRun.characterRun.numberOfCharacters = characterIndex - colorRun.characterRun.characterIndex;
864       }
865
866       if(span.isFontDefined)
867       {
868         FontDescriptionRun& fontRun             = *(fontRuns.Begin() + span.fontRunIndex);
869         fontRun.characterRun.numberOfCharacters = characterIndex - fontRun.characterRun.characterIndex;
870       }
871
872       if(span.isUnderlinedCharacterDefined)
873       {
874         UnderlinedCharacterRun& underlinedCharacterRun         = *(underlinedCharacterRuns.Begin() + span.underlinedCharacterRunIndex);
875         underlinedCharacterRun.characterRun.numberOfCharacters = characterIndex - underlinedCharacterRun.characterRun.characterIndex;
876       }
877
878       if(span.isBackgroundColorDefined)
879       {
880         ColorRun& backgroundColorRun                       = *(backgroundColorRuns.Begin() + span.backgroundColorRunIndex);
881         backgroundColorRun.characterRun.numberOfCharacters = characterIndex - backgroundColorRun.characterRun.characterIndex;
882       }
883
884       if(span.isStrikethroughDefined)
885       {
886         StrikethroughCharacterRun& strikethroughCharacterRun      = *(strikethroughCharacterRuns.Begin() + span.strikethroughCharacterRunIndex);
887         strikethroughCharacterRun.characterRun.numberOfCharacters = characterIndex - strikethroughCharacterRun.characterRun.characterIndex;
888       }
889
890       if(span.isCharacterSpacingDefined)
891       {
892         CharacterSpacingCharacterRun& characterSpacingCharacterRun   = *(characterSpacingCharacterRuns.Begin() + span.characterSpacingCharacterRunIndex);
893         characterSpacingCharacterRun.characterRun.numberOfCharacters = characterIndex - characterSpacingCharacterRun.characterRun.characterIndex;
894       }
895
896       --tagReference;
897     }
898   }
899 }
900
901 /**
902  * @brief Processes anchor tag for the color-run & underline-run.
903  *
904  * @param[in,out] markupProcessData The markup process data
905  * @param[in] tag The tag we are currently processing
906  * @param[in,out] anchorStack The anchors stack
907  * @param[in,out] colorRuns The container containing all the color runs
908  * @param[in,out] underlinedCharacterRuns The container containing all the underlined character runs
909  * @param[in,out] colorRunIndex The color run index
910  * @param[in,out] underlinedCharacterRunIndex The underlined character run index
911  * @param[in] characterIndex The current character index
912  * @param[in] tagReference The tagReference we should increment/decrement
913  */
914 void ProcessAnchorForRun(
915   MarkupProcessData&                    markupProcessData,
916   const Tag&                            tag,
917   StyleStack<AnchorForStack>&           anchorStack,
918   Vector<ColorRun>&                     colorRuns,
919   Vector<UnderlinedCharacterRun>&       underlinedCharacterRuns,
920   RunIndex&                             colorRunIndex,
921   RunIndex&                             underlinedCharacterRunIndex,
922   const CharacterIndex                  characterIndex,
923   int&                                  tagReference)
924 {
925   if(!tag.isEndTag)
926   {
927     // Create an anchor instance.
928     Anchor anchor;
929     anchor.href                        = nullptr;
930     anchor.startIndex                  = characterIndex;
931     anchor.endIndex                    = 0u;
932     anchor.colorRunIndex               = colorRunIndex;
933     anchor.underlinedCharacterRunIndex = underlinedCharacterRunIndex;
934
935     // Create a new run.
936     ColorRun colorRun;
937     Initialize(colorRun);
938
939     UnderlinedCharacterRun underlinedCharacterRun;
940     Initialize(underlinedCharacterRun);
941
942     AnchorForStack anchorForStack;
943     Initialize(anchorForStack);
944
945     // Fill the run with the parameters.
946     colorRun.characterRun.characterIndex               = characterIndex;
947     underlinedCharacterRun.characterRun.characterIndex = characterIndex;
948
949     anchorForStack.colorRunIndex               = colorRunIndex;
950     anchorForStack.underlinedCharacterRunIndex = underlinedCharacterRunIndex;
951
952     // Init default color
953     colorRun.color                                 = Color::MEDIUM_BLUE;
954     underlinedCharacterRun.properties.color        = Color::MEDIUM_BLUE;
955     underlinedCharacterRun.properties.colorDefined = true;
956
957     ProcessAnchorTag(tag, anchor, colorRun, underlinedCharacterRun);
958
959     markupProcessData.anchors.PushBack(anchor);
960
961     // Push the anchor into the stack.
962     anchorStack.Push(anchorForStack);
963
964     // Push the run in the logical model.
965     colorRuns.PushBack(colorRun);
966     ++colorRunIndex;
967
968     // Push the run in the logical model.
969     underlinedCharacterRuns.PushBack(underlinedCharacterRun);
970     ++underlinedCharacterRunIndex;
971
972     // Increase reference
973     ++tagReference;
974   }
975   else
976   {
977     if(tagReference > 0)
978     {
979       // Update end index.
980       unsigned int count = markupProcessData.anchors.Count();
981       if(count > 0)
982       {
983         markupProcessData.anchors[count - 1].endIndex = characterIndex;
984       }
985
986       // Pop the top of the stack and set the number of characters of the run.
987       AnchorForStack anchorForStack = anchorStack.Pop();
988
989       ColorRun& colorRun                       = *(colorRuns.Begin() + anchorForStack.colorRunIndex);
990       colorRun.characterRun.numberOfCharacters = characterIndex - colorRun.characterRun.characterIndex;
991
992       UnderlinedCharacterRun& underlinedCharacterRun         = *(underlinedCharacterRuns.Begin() + anchorForStack.underlinedCharacterRunIndex);
993       underlinedCharacterRun.characterRun.numberOfCharacters = characterIndex - underlinedCharacterRun.characterRun.characterIndex;
994
995       --tagReference;
996     }
997   }
998 }
999
1000 /**
1001  * @brief Resizes the model's vectors
1002  *
1003  * @param[inout] markupProcessData The markup process data
1004  * @param[in] fontRunIndex The font run index
1005  * @param[in] colorRunIndex The color run index
1006  * @param[in] underlinedCharacterRunIndex The underlined character run index
1007  * @param[in] strikethroughCharacterRunIndex The strikethroughed character run index
1008  * @param[in] backgroundRunIndex The background run index
1009  * @param[in] boundedParagraphRunIndex The bounded paragraph run index
1010  * @param[in] characterSpacingCharacterRunIndex The character-spacing character run index
1011  *
1012  */
1013 void ResizeModelVectors(MarkupProcessData& markupProcessData,
1014                         const RunIndex     fontRunIndex,
1015                         const RunIndex     colorRunIndex,
1016                         const RunIndex     underlinedCharacterRunIndex,
1017                         const RunIndex     strikethroughCharacterRunIndex,
1018                         const RunIndex     backgroundRunIndex,
1019                         const RunIndex     boundedParagraphRunIndex,
1020                         const RunIndex     characterSpacingCharacterRunIndex)
1021 {
1022   markupProcessData.fontRuns.Resize(fontRunIndex);
1023   markupProcessData.colorRuns.Resize(colorRunIndex);
1024   markupProcessData.underlinedCharacterRuns.Resize(underlinedCharacterRunIndex);
1025   markupProcessData.strikethroughCharacterRuns.Resize(strikethroughCharacterRunIndex);
1026   markupProcessData.backgroundColorRuns.Resize(backgroundRunIndex);
1027   markupProcessData.boundedParagraphRuns.Resize(boundedParagraphRunIndex);
1028   markupProcessData.characterSpacingCharacterRuns.Resize(characterSpacingCharacterRunIndex);
1029
1030 #ifdef DEBUG_ENABLED
1031   if(gLogFilter->IsEnabledFor(Debug::Verbose))
1032   {
1033     for(uint32_t i = 0; i < colorRunIndex; ++i)
1034     {
1035       ColorRun& run = markupProcessData.colorRuns[i];
1036       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);
1037     }
1038   }
1039 #endif
1040 }
1041
1042 /**
1043  * @brief Processes the markup string buffer
1044  *
1045  * @param[in/out] markupProcessData The markup process data
1046  * @param[in/out] markupStringBuffer The markup string buffer pointer
1047  * @param[in] markupStringEndBuffer The markup string end buffer pointer
1048  * @param[in/out] characterIndex The current character index
1049  */
1050 void ProcessMarkupStringBuffer(
1051   MarkupProcessData& markupProcessData,
1052   const char*&       markupStringBuffer,
1053   const char* const  markupStringEndBuffer,
1054   CharacterIndex&    characterIndex)
1055 {
1056   unsigned char character    = *markupStringBuffer;
1057   const char*   markupBuffer = markupStringBuffer;
1058   unsigned char count        = GetUtf8Length(character);
1059   char          utf8[8];
1060
1061   if((BACK_SLASH == character) && (markupStringBuffer + 1u < markupStringEndBuffer))
1062   {
1063     // Adding < , >  or & special character.
1064     const unsigned char nextCharacter = *(markupStringBuffer + 1u);
1065     if((LESS_THAN == nextCharacter) || (GREATER_THAN == nextCharacter) || (AMPERSAND == nextCharacter))
1066     {
1067       character = nextCharacter;
1068       ++markupStringBuffer;
1069
1070       count        = GetUtf8Length(character);
1071       markupBuffer = markupStringBuffer;
1072     }
1073   }
1074   else // checking if contains XHTML entity or not
1075   {
1076     const unsigned int len = GetXHTMLEntityLength(markupStringBuffer, markupStringEndBuffer);
1077
1078     // Parse markupStringTxt if it contains XHTML Entity between '&' and ';'
1079     if(len > 0)
1080     {
1081       char* entityCode = NULL;
1082       bool  result     = false;
1083       count            = 0;
1084
1085       // Checking if XHTML Numeric Entity
1086       if(HASH == *(markupBuffer + 1u))
1087       {
1088         entityCode = &utf8[0];
1089         // markupBuffer is currently pointing to '&'. By adding 2u to markupBuffer it will point to numeric string by skipping "&#'
1090         result = XHTMLNumericEntityToUtf8((markupBuffer + 2u), entityCode);
1091       }
1092       else // Checking if XHTML Named Entity
1093       {
1094         entityCode = const_cast<char*>(NamedEntityToUtf8(markupBuffer, len));
1095         result     = (entityCode != NULL);
1096       }
1097       if(result)
1098       {
1099         markupBuffer = entityCode; //utf8 text assigned to markupBuffer
1100         character    = markupBuffer[0];
1101       }
1102       else
1103       {
1104         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Not valid XHTML entity : (%.*s) \n", len, markupBuffer);
1105         markupBuffer = NULL;
1106       }
1107     }
1108     else // in case string conatins Start of XHTML Entity('&') but not its end character(';')
1109     {
1110       if(character == AMPERSAND)
1111       {
1112         markupBuffer = NULL;
1113         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Not Well formed XHTML content \n");
1114       }
1115     }
1116   }
1117
1118   if(markupBuffer != NULL)
1119   {
1120     const unsigned char numberOfBytes = GetUtf8Length(character);
1121     markupProcessData.markupProcessedText.push_back(character);
1122
1123     for(unsigned char i = 1u; i < numberOfBytes; ++i)
1124     {
1125       ++markupBuffer;
1126       markupProcessData.markupProcessedText.push_back(*markupBuffer);
1127     }
1128
1129     ++characterIndex;
1130     markupStringBuffer += count;
1131   }
1132 }
1133
1134 } // namespace
1135
1136 void ProcessMarkupString(const std::string& markupString, MarkupProcessData& markupProcessData)
1137 {
1138   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "markupString: %s\n", markupString.c_str());
1139
1140   // Reserve space for the plain text.
1141   const Length markupStringSize = markupString.size();
1142   markupProcessData.markupProcessedText.reserve(markupStringSize);
1143
1144   // Stores a struct with the index to the first character of the run, the type of run and its parameters.
1145   StyleStack<RunIndex> styleStack;
1146
1147   // Stores a struct with the index to the first character of the color run & color font for the span.
1148   StyleStack<Span> spanStack;
1149
1150   StyleStack<AnchorForStack> anchorStack;
1151
1152   // Points the next free position in the vector of runs.
1153   RunIndex colorRunIndex                     = 0u;
1154   RunIndex fontRunIndex                      = 0u;
1155   RunIndex underlinedCharacterRunIndex       = 0u;
1156   RunIndex backgroundRunIndex                = 0u;
1157   RunIndex strikethroughCharacterRunIndex    = 0u;
1158   RunIndex boundedParagraphRunIndex          = 0u;
1159   RunIndex characterSpacingCharacterRunIndex = 0u;
1160
1161   // check tag reference
1162   int colorTagReference            = 0u;
1163   int fontTagReference             = 0u;
1164   int iTagReference                = 0u;
1165   int bTagReference                = 0u;
1166   int uTagReference                = 0u;
1167   int backgroundTagReference       = 0u;
1168   int spanTagReference             = 0u;
1169   int sTagReference                = 0u;
1170   int pTagReference                = 0u;
1171   int characterSpacingTagReference = 0u;
1172   int aTagReference                = 0u;
1173
1174   // Give an initial default value to the model's vectors.
1175   markupProcessData.colorRuns.Reserve(DEFAULT_VECTOR_SIZE);
1176   markupProcessData.fontRuns.Reserve(DEFAULT_VECTOR_SIZE);
1177   markupProcessData.underlinedCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
1178   markupProcessData.backgroundColorRuns.Reserve(DEFAULT_VECTOR_SIZE);
1179   markupProcessData.strikethroughCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
1180   markupProcessData.characterSpacingCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
1181
1182   // Get the mark-up string buffer.
1183   const char*       markupStringBuffer    = markupString.c_str();
1184   const char* const markupStringEndBuffer = markupStringBuffer + markupStringSize;
1185
1186   Tag            tag;
1187   CharacterIndex characterIndex = 0u;
1188   for(; markupStringBuffer < markupStringEndBuffer;)
1189   {
1190     tag.attributes.Clear();
1191     if(IsTag(markupStringBuffer,
1192              markupStringEndBuffer,
1193              tag))
1194     {
1195       if(TokenComparison(MARKUP::TAG::COLOR, tag.buffer, tag.length))
1196       {
1197         ProcessTagForRun<ColorRun>(
1198           markupProcessData.colorRuns, styleStack, tag, characterIndex, colorRunIndex, colorTagReference, [](const Tag& tag, ColorRun& run) { ProcessColorTag(tag, run); });
1199       } // <color></color>
1200       else if(TokenComparison(MARKUP::TAG::ITALIC, tag.buffer, tag.length))
1201       {
1202         ProcessTagForRun<FontDescriptionRun>(
1203           markupProcessData.fontRuns, styleStack, tag, characterIndex, fontRunIndex, iTagReference, [](const Tag&, FontDescriptionRun& fontRun) {
1204             fontRun.slant        = TextAbstraction::FontSlant::ITALIC;
1205             fontRun.slantDefined = true;
1206           });
1207       } // <i></i>
1208       else if(TokenComparison(MARKUP::TAG::UNDERLINE, tag.buffer, tag.length))
1209       {
1210         ProcessTagForRun<UnderlinedCharacterRun>(
1211           markupProcessData.underlinedCharacterRuns, styleStack, tag, characterIndex, underlinedCharacterRunIndex, uTagReference, [](const Tag& tag, UnderlinedCharacterRun& run) { ProcessUnderlineTag(tag, run); });
1212       } // <u></u>
1213       else if(TokenComparison(MARKUP::TAG::BOLD, tag.buffer, tag.length))
1214       {
1215         ProcessTagForRun<FontDescriptionRun>(
1216           markupProcessData.fontRuns, styleStack, tag, characterIndex, fontRunIndex, bTagReference, [](const Tag&, FontDescriptionRun& fontRun) {
1217             fontRun.weight        = TextAbstraction::FontWeight::BOLD;
1218             fontRun.weightDefined = true;
1219           });
1220       } // <b></b>
1221       else if(TokenComparison(MARKUP::TAG::FONT, tag.buffer, tag.length))
1222       {
1223         ProcessTagForRun<FontDescriptionRun>(
1224           markupProcessData.fontRuns, styleStack, tag, characterIndex, fontRunIndex, fontTagReference, [](const Tag& tag, FontDescriptionRun& fontRun) { ProcessFontTag(tag, fontRun); });
1225       } // <font></font>
1226       else if(TokenComparison(MARKUP::TAG::ANCHOR, tag.buffer, tag.length))
1227       {
1228         ProcessAnchorForRun(markupProcessData,
1229                             tag,
1230                             anchorStack,
1231                             markupProcessData.colorRuns,
1232                             markupProcessData.underlinedCharacterRuns,
1233                             colorRunIndex,
1234                             underlinedCharacterRunIndex,
1235                             characterIndex,
1236                             aTagReference);
1237       } // <a href=https://www.tizen.org>tizen</a>
1238       else if(TokenComparison(MARKUP::TAG::SHADOW, tag.buffer, tag.length))
1239       {
1240         // TODO: If !tag.isEndTag, then create a new shadow run.
1241         //       else Pop the top of the stack and set the number of characters of the run.
1242       } // <shadow></shadow>
1243       else if(TokenComparison(MARKUP::TAG::GLOW, tag.buffer, tag.length))
1244       {
1245         // TODO: If !tag.isEndTag, then create a new glow run.
1246         //       else Pop the top of the stack and set the number of characters of the run.
1247       } // <glow></glow>
1248       else if(TokenComparison(MARKUP::TAG::OUTLINE, tag.buffer, tag.length))
1249       {
1250         // TODO: If !tag.isEndTag, then create a new outline run.
1251         //       else Pop the top of the stack and set the number of characters of the run.
1252       } // <outline></outline>
1253       else if(TokenComparison(MARKUP::TAG::EMBEDDED_ITEM, tag.buffer, tag.length))
1254       {
1255         ProcessItemTag(markupProcessData, tag, characterIndex);
1256       }
1257       else if(TokenComparison(MARKUP::TAG::BACKGROUND, tag.buffer, tag.length))
1258       {
1259         ProcessTagForRun<ColorRun>(
1260           markupProcessData.backgroundColorRuns, styleStack, tag, characterIndex, backgroundRunIndex, backgroundTagReference, [](const Tag& tag, ColorRun& run) { ProcessBackground(tag, run); });
1261       }
1262       else if(TokenComparison(MARKUP::TAG::SPAN, tag.buffer, tag.length))
1263       {
1264         ProcessSpanForRun(tag,
1265                           spanStack,
1266                           markupProcessData.colorRuns,
1267                           markupProcessData.fontRuns,
1268                           markupProcessData.underlinedCharacterRuns,
1269                           markupProcessData.backgroundColorRuns,
1270                           markupProcessData.strikethroughCharacterRuns,
1271                           markupProcessData.characterSpacingCharacterRuns,
1272                           colorRunIndex,
1273                           fontRunIndex,
1274                           underlinedCharacterRunIndex,
1275                           backgroundRunIndex,
1276                           strikethroughCharacterRunIndex,
1277                           characterSpacingCharacterRunIndex,
1278                           characterIndex,
1279                           spanTagReference);
1280       }
1281       else if(TokenComparison(MARKUP::TAG::STRIKETHROUGH, tag.buffer, tag.length))
1282       {
1283         ProcessTagForRun<StrikethroughCharacterRun>(
1284           markupProcessData.strikethroughCharacterRuns, styleStack, tag, characterIndex, strikethroughCharacterRunIndex, sTagReference, [](const Tag& tag, StrikethroughCharacterRun& run) { ProcessStrikethroughTag(tag, run); });
1285       } // <s></s>
1286       else if(TokenComparison(MARKUP::TAG::PARAGRAPH, tag.buffer, tag.length))
1287       {
1288         ProcessParagraphTag(markupProcessData, tag, (markupStringBuffer == markupStringEndBuffer), characterIndex);
1289         ProcessTagForRun<BoundedParagraphRun>(
1290           markupProcessData.boundedParagraphRuns, styleStack, tag, characterIndex, boundedParagraphRunIndex, pTagReference, [](const Tag& tag, BoundedParagraphRun& run) { ProcessAttributesOfParagraphTag(tag, run); });
1291       } // <p></p>
1292       else if(TokenComparison(MARKUP::TAG::CHARACTER_SPACING, tag.buffer, tag.length))
1293       {
1294         ProcessTagForRun<CharacterSpacingCharacterRun>(
1295           markupProcessData.characterSpacingCharacterRuns, styleStack, tag, characterIndex, characterSpacingCharacterRunIndex, characterSpacingTagReference, [](const Tag& tag, CharacterSpacingCharacterRun& run) { ProcessCharacterSpacingTag(tag, run); });
1296       } // <char-spacing></char-spacing>
1297     }   // end if( IsTag() )
1298     else if(markupStringBuffer < markupStringEndBuffer)
1299     {
1300       ProcessMarkupStringBuffer(markupProcessData, markupStringBuffer, markupStringEndBuffer, characterIndex);
1301     }
1302   }
1303
1304   // Resize the model's vectors.
1305   ResizeModelVectors(markupProcessData, fontRunIndex, colorRunIndex, underlinedCharacterRunIndex, strikethroughCharacterRunIndex, backgroundRunIndex, boundedParagraphRunIndex, characterSpacingCharacterRunIndex);
1306
1307   // Handle the nested tags
1308   OverrideNestedUnderlinedCharacterRuns(markupProcessData.underlinedCharacterRuns);
1309   OverrideNestedStrikethroughCharacterRuns(markupProcessData.strikethroughCharacterRuns);
1310 }
1311
1312 } // namespace Text
1313
1314 } // namespace Toolkit
1315
1316 } // namespace Dali