Fix Coverity issues
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / markup-processor.cpp
1 /*
2  * Copyright (c) 2015 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.h>
20
21 // EXTERNAL INCLUDES
22 #include <climits>  // for ULONG_MAX
23 #include <dali/integration-api/debug.h>
24
25 // INTERNAL INCLUDES
26 #include <dali-toolkit/internal/text/character-set-conversion.h>
27 #include <dali-toolkit/internal/text/markup-processor-color.h>
28 #include <dali-toolkit/internal/text/markup-processor-font.h>
29 #include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
30 #include <dali-toolkit/internal/text/xhtml-entities.h>
31
32
33
34 namespace Dali
35 {
36
37 namespace Toolkit
38 {
39
40 namespace Text
41 {
42
43 namespace
44 {
45 // HTML-ISH tag and attribute constants.
46 // Note they must be lower case in order to make the comparison to work
47 // as the parser converts all the read tags to lower case.
48 const std::string XHTML_COLOR_TAG("color");
49 const std::string XHTML_FONT_TAG("font");
50 const std::string XHTML_B_TAG("b");
51 const std::string XHTML_I_TAG("i");
52 const std::string XHTML_U_TAG("u");
53 const std::string XHTML_SHADOW_TAG("shadow");
54 const std::string XHTML_GLOW_TAG("glow");
55 const std::string XHTML_OUTLINE_TAG("outline");
56
57 const char LESS_THAN      = '<';
58 const char GREATER_THAN   = '>';
59 const char EQUAL          = '=';
60 const char QUOTATION_MARK = '\'';
61 const char SLASH          = '/';
62 const char BACK_SLASH     = '\\';
63 const char AMPERSAND      = '&';
64 const char HASH           = '#';
65 const char SEMI_COLON     = ';';
66 const char CHAR_ARRAY_END = '\0';
67 const char HEX_CODE       = 'x';
68
69 const char WHITE_SPACE    = 0x20; // ASCII value of the white space.
70
71 // Range 1 0x0u < XHTML_DECIMAL_ENTITY_RANGE <= 0xD7FFu
72 // Range 2 0xE000u < XHTML_DECIMAL_ENTITY_RANGE <= 0xFFFDu
73 // Range 3 0x10000u < XHTML_DECIMAL_ENTITY_RANGE <= 0x10FFFFu
74 const unsigned long XHTML_DECIMAL_ENTITY_RANGE[] = { 0x0u, 0xD7FFu, 0xE000u, 0xFFFDu, 0x10000u, 0x10FFFFu };
75
76 const unsigned int MAX_NUM_OF_ATTRIBUTES =  5u; ///< The font tag has the 'family', 'size' 'weight', 'width' and 'slant' attrubutes.
77 const unsigned int DEFAULT_VECTOR_SIZE   = 16u; ///< Default size of run vectors.
78
79 #if defined(DEBUG_ENABLED)
80 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_MARKUP_PROCESSOR");
81 #endif
82
83 /**
84  * @brief Struct used to retrieve the style runs from the mark-up string.
85  */
86 struct StyleStack
87 {
88   typedef VectorBase::SizeType RunIndex;
89
90   Vector<RunIndex>  stack;    ///< Use a vector as a style stack. Stores the indices pointing where the run is stored inside the logical model.
91   unsigned int topIndex; ///< Points the top of the stack.
92
93   StyleStack()
94   : stack(),
95     topIndex( 0u )
96   {
97     stack.Resize( DEFAULT_VECTOR_SIZE );
98   }
99
100   void Push( RunIndex index )
101   {
102     // Check if there is space inside the style stack.
103     const VectorBase::SizeType size = stack.Count();
104     if( topIndex >= size )
105     {
106       // Resize the style stack.
107       stack.Resize( 2u * size );
108     }
109
110     // Set the run index in the top of the stack.
111     *( stack.Begin() + topIndex ) = index;
112
113     // Reposition the pointer to the top of the stack.
114     ++topIndex;
115   }
116
117   RunIndex Pop()
118   {
119     // Pop the top of the stack.
120     --topIndex;
121     return *( stack.Begin() + topIndex );
122   }
123 };
124
125 /**
126  * @brief Initializes a font run description to its defaults.
127  *
128  * @param[in,out] fontRun The font description run to initialize.
129  */
130 void Initialize( FontDescriptionRun& fontRun )
131 {
132   fontRun.characterRun.characterIndex = 0u;
133   fontRun.characterRun.numberOfCharacters = 0u;
134   fontRun.familyName = NULL;
135   fontRun.familyLength = 0u;
136   fontRun.weight = TextAbstraction::FontWeight::NORMAL;
137   fontRun.width = TextAbstraction::FontWidth::NORMAL;
138   fontRun.slant = TextAbstraction::FontSlant::NORMAL;
139   fontRun.size = 0u;
140   fontRun.familyDefined = false;
141   fontRun.weightDefined = false;
142   fontRun.widthDefined = false;
143   fontRun.slantDefined = false;
144   fontRun.sizeDefined = false;
145 }
146
147 /**
148  * @brief Splits the tag string into the tag name and its attributes.
149  *
150  * The attributes are stored in a vector in the tag.
151  *
152  * @param[in,out] tag The tag.
153  */
154 void ParseAttributes( Tag& tag )
155 {
156   if( tag.buffer == NULL )
157   {
158     return;
159   }
160
161   tag.attributes.Resize( MAX_NUM_OF_ATTRIBUTES );
162
163   // Find first the tag name.
164   bool isQuotationOpen = false;
165
166   const char* tagBuffer = tag.buffer;
167   const char* const tagEndBuffer = tagBuffer + tag.length;
168   tag.length = 0u;
169   for( ; tagBuffer < tagEndBuffer; ++tagBuffer )
170   {
171     const char character = *tagBuffer;
172     if( WHITE_SPACE < character )
173     {
174       ++tag.length;
175     }
176     else
177     {
178       // Stops counting the length of the tag when a white space is found.
179       // @note a white space is the WHITE_SPACE character and anything below as 'tab', 'return' or 'control characters'.
180       break;
181     }
182   }
183   SkipWhiteSpace( tagBuffer, tagEndBuffer );
184
185   // Find the attributes.
186   unsigned int attributeIndex = 0u;
187   const char* nameBuffer = NULL;
188   const char* valueBuffer = NULL;
189   Length nameLength = 0u;
190   Length valueLength = 0u;
191
192   bool addToNameValue = true;
193   Length numberOfWhiteSpace = 0u;
194   for( ; tagBuffer < tagEndBuffer; ++tagBuffer )
195   {
196     const char character = *tagBuffer;
197     if( ( WHITE_SPACE >= character ) && !isQuotationOpen )
198     {
199       if( NULL != valueBuffer )
200       {
201         // Remove white spaces at the end of the value.
202         valueLength -= numberOfWhiteSpace;
203       }
204
205       if( ( NULL != nameBuffer ) && ( NULL != valueBuffer ) )
206       {
207         // Every time a white space is found, a new attribute is created and stored in the attributes vector.
208         Attribute& attribute = *( tag.attributes.Begin() + attributeIndex );
209         ++attributeIndex;
210
211         attribute.nameBuffer = nameBuffer;
212         attribute.valueBuffer = valueBuffer;
213         attribute.nameLength = nameLength;
214         attribute.valueLength = valueLength;
215
216         nameBuffer = NULL;
217         valueBuffer = NULL;
218         nameLength = 0u;
219         valueLength = 0u;
220
221         addToNameValue = true; // next read characters will be added to the name.
222       }
223     }
224     else if( EQUAL == character ) // '='
225     {
226       addToNameValue = false; // next read characters will be added to the value.
227       SkipWhiteSpace( tagBuffer, tagEndBuffer );
228     }
229     else if( QUOTATION_MARK == character ) // '\''
230     {
231       // Do not add quotation marks to neither name nor value.
232       isQuotationOpen = !isQuotationOpen;
233
234       if( isQuotationOpen )
235       {
236         ++tagBuffer;
237         SkipWhiteSpace( tagBuffer, tagEndBuffer );
238         --tagBuffer;
239       }
240     }
241     else
242     {
243       // Adds characters to the name or the value.
244       if( addToNameValue )
245       {
246         if( NULL == nameBuffer )
247         {
248           nameBuffer = tagBuffer;
249         }
250         ++nameLength;
251       }
252       else
253       {
254         if( isQuotationOpen )
255         {
256           if( WHITE_SPACE >= character )
257           {
258             ++numberOfWhiteSpace;
259           }
260           else
261           {
262             numberOfWhiteSpace = 0u;
263           }
264         }
265         if( NULL == valueBuffer )
266         {
267           valueBuffer = tagBuffer;
268         }
269         ++valueLength;
270       }
271     }
272   }
273
274   if( NULL != valueBuffer )
275   {
276     // Remove white spaces at the end of the value.
277     valueLength -= numberOfWhiteSpace;
278   }
279
280   if( ( NULL != nameBuffer ) && ( NULL != valueBuffer ) )
281   {
282     // Checks if the last attribute needs to be added.
283     Attribute& attribute = *( tag.attributes.Begin() + attributeIndex );
284     ++attributeIndex;
285
286     attribute.nameBuffer = nameBuffer;
287     attribute.valueBuffer = valueBuffer;
288     attribute.nameLength = nameLength;
289     attribute.valueLength = valueLength;
290   }
291
292   // Resize the vector of attributes.
293   tag.attributes.Resize( attributeIndex );
294 }
295
296 /**
297  * @brief It parses a tag and its attributes if the given iterator @e it is pointing at a tag beginning.
298  *
299  * @param[in,out] markupStringBuffer The mark-up string buffer. It's a const iterator pointing the current character.
300  * @param[in] markupStringEndBuffer Pointer to one character after the end of the mark-up string buffer.
301  * @param[out] tag The tag with its attributes.
302  *
303  * @return @e true if the iterator @e it is pointing a mark-up tag. Otherwise @e false.
304  */
305 bool IsTag( const char*& markupStringBuffer,
306             const char* const markupStringEndBuffer,
307             Tag& tag )
308 {
309   bool isTag = false;
310   bool isQuotationOpen = false;
311   bool attributesFound = false;
312   tag.isEndTag = false;
313
314   const char character = *markupStringBuffer;
315   if( LESS_THAN == character ) // '<'
316   {
317     tag.buffer = NULL;
318     tag.length = 0u;
319
320     // if the iterator is pointing to a '<' character, then check if it's a mark-up tag is needed.
321     ++markupStringBuffer;
322     if( markupStringBuffer < markupStringEndBuffer )
323     {
324       SkipWhiteSpace( markupStringBuffer, markupStringEndBuffer );
325
326       for( ; ( !isTag ) && ( markupStringBuffer < markupStringEndBuffer ); ++markupStringBuffer )
327       {
328         const char character = *markupStringBuffer;
329
330         if( SLASH == character ) // '/'
331         {
332           // if the tag has a '/' then it's an end or empty tag.
333           tag.isEndTag = true;
334
335           if( ( markupStringBuffer + 1u < markupStringEndBuffer ) && ( WHITE_SPACE >= *( markupStringBuffer + 1u ) ) && ( !isQuotationOpen ) )
336           {
337             ++markupStringBuffer;
338             SkipWhiteSpace( markupStringBuffer, markupStringEndBuffer );
339             --markupStringBuffer;
340           }
341         }
342         else if( GREATER_THAN == character ) // '>'
343         {
344           isTag = true;
345         }
346         else if( QUOTATION_MARK == character )
347         {
348           isQuotationOpen = !isQuotationOpen;
349           ++tag.length;
350         }
351         else if( WHITE_SPACE >= character ) // ' '
352         {
353           // If the tag contains white spaces then it may have attributes.
354           if( !isQuotationOpen )
355           {
356             attributesFound = true;
357           }
358           ++tag.length;
359         }
360         else
361         {
362           if( NULL == tag.buffer )
363           {
364             tag.buffer = markupStringBuffer;
365           }
366
367           // If it's not any of the 'special' characters then just add it to the tag string.
368           ++tag.length;
369         }
370       }
371     }
372
373     // If the tag string has white spaces, then parse the attributes is needed.
374     if( attributesFound )
375     {
376       ParseAttributes( tag );
377     }
378   }
379
380   return isTag;
381 }
382
383 /**
384  * @brief Returns length of XHTML entity by parsing the text. It also determines if it is XHTML entity or not.
385  *
386  * @param[in] markupStringBuffer The mark-up string buffer. It's a const iterator pointing the current character.
387  * @param[in] markupStringEndBuffer Pointing to end of mark-up string buffer.
388  *
389  * @return Length of markupText in case of XHTML entity otherwise return 0.
390  */
391 unsigned int GetXHTMLEntityLength( const char*& markupStringBuffer,
392                                    const char* const markupStringEndBuffer )
393 {
394   char character = *markupStringBuffer;
395   if( AMPERSAND == character ) // '&'
396   {
397     // if the iterator is pointing to a '&' character, then check for ';' to find end to XHTML entity.
398     ++markupStringBuffer;
399     if( markupStringBuffer < markupStringEndBuffer )
400     {
401       unsigned int len = 1u;
402       for( ; markupStringBuffer < markupStringEndBuffer ; ++markupStringBuffer )
403       {
404         character = *markupStringBuffer;
405         ++len;
406         if( SEMI_COLON == character ) // ';'
407         {
408           // found end of XHTML entity
409           ++markupStringBuffer;
410           return len;
411         }
412         else if( ( AMPERSAND == character ) || ( BACK_SLASH == character ) || ( LESS_THAN == character ))
413         {
414           return 0;
415         }
416       }
417     }
418   }
419   return 0;
420 }
421
422 /**
423  * @brief It parses a XHTML string which has hex/decimal entity and fill its corresponging utf-8 string.
424  *
425  * @param[in] markupText The mark-up text buffer.
426  * @param[out] utf-8 text Corresponding to markup Text
427  *
428  * @return true if string is successfully parsed otherwise false
429  */
430 bool XHTMLNumericEntityToUtf8 ( const char* markupText, char* utf8 )
431 {
432   bool result = false;
433
434   if( NULL != markupText )
435   {
436     bool isHex = false;
437
438     // check if hex or decimal entity
439     if( ( CHAR_ARRAY_END != *markupText ) && ( HEX_CODE == *markupText ) )
440     {
441       isHex = true;
442       ++markupText;
443     }
444
445     char* end = NULL;
446     unsigned long l = strtoul( markupText, &end, ( isHex ? 16 : 10 ) );  // l contains UTF-32 code in case of correct XHTML entity
447
448     // check for valid XHTML numeric entities (between '#' or "#x" and ';')
449     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'
450     {
451       /* characters XML 1.1 permits */
452       if( ( ( XHTML_DECIMAL_ENTITY_RANGE[0] < l ) && ( l <= XHTML_DECIMAL_ENTITY_RANGE[1] ) ) ||
453         ( ( XHTML_DECIMAL_ENTITY_RANGE[2] <= l ) && ( l <= XHTML_DECIMAL_ENTITY_RANGE[3] ) ) ||
454         ( ( XHTML_DECIMAL_ENTITY_RANGE[4] <= l ) && ( l <= XHTML_DECIMAL_ENTITY_RANGE[5] ) ) )
455       {
456         // Convert UTF32 code to UTF8
457         Utf32ToUtf8( reinterpret_cast<const uint32_t* const>( &l ), 1, reinterpret_cast<uint8_t*>( utf8 ) );
458         result = true;
459        }
460     }
461   }
462   return result;
463 }
464
465 } // namespace
466
467 void ProcessMarkupString( const std::string& markupString, MarkupProcessData& markupProcessData )
468 {
469   // Reserve space for the plain text.
470   const Length markupStringSize = markupString.size();
471   markupProcessData.markupProcessedText.reserve( markupStringSize );
472
473   // Stores a struct with the index to the first character of the run, the type of run and its parameters.
474   StyleStack styleStack;
475
476   // Points the next free position in the vector of runs.
477   StyleStack::RunIndex colorRunIndex = 0u;
478   StyleStack::RunIndex fontRunIndex = 0u;
479
480   // Give an initial default value to the model's vectors.
481   markupProcessData.colorRuns.Reserve( DEFAULT_VECTOR_SIZE );
482   markupProcessData.fontRuns.Reserve( DEFAULT_VECTOR_SIZE );
483
484   // Get the mark-up string buffer.
485   const char* markupStringBuffer = markupString.c_str();
486   const char* const markupStringEndBuffer = markupStringBuffer + markupStringSize;
487
488   Tag tag;
489   CharacterIndex characterIndex = 0u;
490   for( ; markupStringBuffer < markupStringEndBuffer; )
491   {
492     if( IsTag( markupStringBuffer,
493                markupStringEndBuffer,
494                tag ) )
495     {
496       if( TokenComparison( XHTML_COLOR_TAG, tag.buffer, tag.length ) )
497       {
498         if( !tag.isEndTag )
499         {
500           // Create a new color run.
501           ColorRun colorRun;
502           colorRun.characterRun.numberOfCharacters = 0u;
503
504           // Set the start character index.
505           colorRun.characterRun.characterIndex = characterIndex;
506
507           // Fill the run with the attributes.
508           ProcessColorTag( tag, colorRun );
509
510           // Push the color run in the logical model.
511           markupProcessData.colorRuns.PushBack( colorRun );
512
513           // Push the index of the run into the stack.
514           styleStack.Push( colorRunIndex );
515
516           // Point the next color run.
517           ++colorRunIndex;
518         }
519         else
520         {
521           // Pop the top of the stack and set the number of characters of the run.
522           ColorRun& colorRun = *( markupProcessData.colorRuns.Begin() + styleStack.Pop() );
523           colorRun.characterRun.numberOfCharacters = characterIndex - colorRun.characterRun.characterIndex;
524         }
525       } // <color></color>
526       else if( TokenComparison( XHTML_I_TAG, tag.buffer, tag.length ) )
527       {
528         if( !tag.isEndTag )
529         {
530           // Create a new font run.
531           FontDescriptionRun fontRun;
532           Initialize( fontRun );
533
534           // Fill the run with the parameters.
535           fontRun.characterRun.characterIndex = characterIndex;
536           fontRun.slant = TextAbstraction::FontSlant::ITALIC;
537           fontRun.slantDefined = true;
538
539           // Push the font run in the logical model.
540           markupProcessData.fontRuns.PushBack( fontRun );
541
542           // Push the index of the run into the stack.
543           styleStack.Push( fontRunIndex );
544
545           // Point the next free font run.
546           ++fontRunIndex;
547         }
548         else
549         {
550           // Pop the top of the stack and set the number of characters of the run.
551           FontDescriptionRun& fontRun = *( markupProcessData.fontRuns.Begin() + styleStack.Pop() );
552           fontRun.characterRun.numberOfCharacters = characterIndex - fontRun.characterRun.characterIndex;
553         }
554       } // <i></i>
555       else if( TokenComparison( XHTML_U_TAG, tag.buffer, tag.length ) )
556       {
557         if( !tag.isEndTag )
558         {
559           // Create a new underline run.
560         }
561         else
562         {
563           // Pop the top of the stack and set the number of characters of the run.
564         }
565       } // <u></u>
566       else if( TokenComparison( XHTML_B_TAG, tag.buffer, tag.length ) )
567       {
568         if( !tag.isEndTag )
569         {
570           // Create a new font run.
571           FontDescriptionRun fontRun;
572           Initialize( fontRun );
573
574           // Fill the run with the parameters.
575           fontRun.characterRun.characterIndex = characterIndex;
576           fontRun.weight = TextAbstraction::FontWeight::BOLD;
577           fontRun.weightDefined = true;
578
579           // Push the font run in the logical model.
580           markupProcessData.fontRuns.PushBack( fontRun );
581
582           // Push the index of the run into the stack.
583           styleStack.Push( fontRunIndex );
584
585           // Point the next free font run.
586           ++fontRunIndex;
587         }
588         else
589         {
590           // Pop the top of the stack and set the number of characters of the run.
591           FontDescriptionRun& fontRun = *( markupProcessData.fontRuns.Begin() + styleStack.Pop() );
592           fontRun.characterRun.numberOfCharacters = characterIndex - fontRun.characterRun.characterIndex;
593         }
594       } // <b></b>
595       else if( TokenComparison( XHTML_FONT_TAG, tag.buffer, tag.length ) )
596       {
597         if( !tag.isEndTag )
598         {
599           // Create a new font run.
600           FontDescriptionRun fontRun;
601           Initialize( fontRun );
602
603           // Fill the run with the parameters.
604           fontRun.characterRun.characterIndex = characterIndex;
605
606           ProcessFontTag( tag, fontRun );
607
608           // Push the font run in the logical model.
609           markupProcessData.fontRuns.PushBack( fontRun );
610
611           // Push the index of the run into the stack.
612           styleStack.Push( fontRunIndex );
613
614           // Point the next free font run.
615           ++fontRunIndex;
616         }
617         else
618         {
619           // Pop the top of the stack and set the number of characters of the run.
620           FontDescriptionRun& fontRun = *( markupProcessData.fontRuns.Begin() + styleStack.Pop() );
621           fontRun.characterRun.numberOfCharacters = characterIndex - fontRun.characterRun.characterIndex;
622         }
623       } // <font></font>
624       else if( TokenComparison( XHTML_SHADOW_TAG, tag.buffer, tag.length ) )
625       {
626         if( !tag.isEndTag )
627         {
628           // Create a new shadow run.
629         }
630         else
631         {
632           // Pop the top of the stack and set the number of characters of the run.
633         }
634       } // <shadow></shadow>
635       else if( TokenComparison( XHTML_GLOW_TAG, tag.buffer, tag.length ) )
636       {
637         if( !tag.isEndTag )
638         {
639           // Create a new glow run.
640         }
641         else
642         {
643           // Pop the top of the stack and set the number of characters of the run.
644         }
645       } // <glow></glow>
646       else if( TokenComparison( XHTML_OUTLINE_TAG, tag.buffer, tag.length ) )
647       {
648         if( !tag.isEndTag )
649         {
650           // Create a new outline run.
651         }
652         else
653         {
654           // Pop the top of the stack and set the number of characters of the run.
655         }
656       } // <outline></outline>
657     }  // end if( IsTag() )
658     else if( markupStringBuffer < markupStringEndBuffer )
659     {
660       unsigned char character = *markupStringBuffer;
661       const char* markupBuffer = markupStringBuffer;
662       unsigned char count = GetUtf8Length( character );
663       char utf8[8];
664
665       if( ( BACK_SLASH == character ) && ( markupStringBuffer + 1u < markupStringEndBuffer ) )
666       {
667         // Adding < , >  or & special character.
668         const unsigned char nextCharacter = *( markupStringBuffer + 1u );
669         if( ( LESS_THAN == nextCharacter ) || ( GREATER_THAN == nextCharacter ) || ( AMPERSAND == nextCharacter ) )
670         {
671           character = nextCharacter;
672           ++markupStringBuffer;
673
674           count = GetUtf8Length( character );
675           markupBuffer = markupStringBuffer;
676         }
677       }
678       else   // checking if conatins XHTML entity or not
679       {
680         const unsigned int len =  GetXHTMLEntityLength( markupStringBuffer, markupStringEndBuffer);
681
682         // Parse markupStringTxt if it contains XHTML Entity between '&' and ';'
683         if( len > 0 )
684         {
685           char* entityCode = NULL;
686           bool result = false;
687           count = 0;
688
689           // Checking if XHTML Numeric Entity
690           if( HASH == *( markupBuffer + 1u ) )
691           {
692             entityCode = &utf8[0];
693             // markupBuffer is currently pointing to '&'. By adding 2u to markupBuffer it will point to numeric string by skipping "&#'
694             result = XHTMLNumericEntityToUtf8( ( markupBuffer + 2u ), entityCode );
695           }
696           else    // Checking if XHTML Named Entity
697           {
698             entityCode = const_cast<char*> ( NamedEntityToUtf8( markupBuffer, len ) );
699             result = ( entityCode != NULL );
700           }
701           if ( result )
702           {
703             markupBuffer = entityCode; //utf8 text assigned to markupBuffer
704             character = markupBuffer[0];
705           }
706           else
707           {
708             DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Not valid XHTML entity : (%.*s) \n", len, markupBuffer );
709             markupBuffer = NULL;
710           }
711         }
712         else    // in case string conatins Start of XHTML Entity('&') but not its end character(';')
713         {
714           if( character == AMPERSAND )
715           {
716             markupBuffer = NULL;
717             DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Not Well formed XHTML content \n" );
718           }
719         }
720       }
721
722       if( markupBuffer != NULL )
723       {
724         const unsigned char numberOfBytes = GetUtf8Length( character );
725         markupProcessData.markupProcessedText.push_back( character );
726
727         for( unsigned char i = 1u; i < numberOfBytes; ++i )
728         {
729           ++markupBuffer;
730           markupProcessData.markupProcessedText.push_back( *markupBuffer );
731         }
732
733         ++characterIndex;
734         markupStringBuffer += count;
735       }
736     }
737   }
738
739   // Resize the model's vectors.
740   if( 0u == fontRunIndex )
741   {
742     markupProcessData.fontRuns.Clear();
743   }
744   else
745   {
746     markupProcessData.fontRuns.Resize( fontRunIndex );
747   }
748
749   if( 0u == colorRunIndex )
750   {
751     markupProcessData.colorRuns.Clear();
752   }
753   else
754   {
755     markupProcessData.colorRuns.Resize( colorRunIndex );
756   }
757 }
758
759 } // namespace Text
760
761 } // namespace Toolkit
762
763 } // namespace Dali