995253aa52b74d5953021e666f73655203675f53
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / public-api / markup-processor / markup-processor.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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 // HEADER INCLUDE
18 #include <dali-toolkit/public-api/markup-processor/markup-processor.h>
19
20 // INTERNAL INCLUDES
21 #include <dali/public-api/text/text.h>
22
23
24 // EXTERNAL INCLUDES
25 #include <stack>
26 #include <sstream>
27
28 namespace Dali
29 {
30
31 namespace Toolkit
32 {
33
34 namespace MarkupProcessor
35 {
36
37 namespace
38 {
39 const std::string WEB_COLOR_TOKEN( "#" );
40 const std::string HEX_COLOR_TOKEN( "0x" );
41 const std::string ALPHA_ONE( "FF" );
42
43 const std::string BLACK_COLOR( "black" );
44 const std::string WHITE_COLOR( "white" );
45 const std::string RED_COLOR( "red" );
46 const std::string GREEN_COLOR( "green" );
47 const std::string BLUE_COLOR( "blue" );
48 const std::string YELLOW_COLOR( "yellow" );
49 const std::string MAGENTA_COLOR( "magenta" );
50 const std::string CYAN_COLOR( "cyan" );
51 const std::string TRANSPARENT_COLOR( "transparent" );
52
53 const std::string XHTML_B_TAG("b");
54 const std::string XHTML_I_TAG("i");
55 const std::string XHTML_U_TAG("u");
56 const std::string XHTML_BR_TAG("br");
57 const std::string XHTML_FONT_TAG("font");
58 const std::string XHTML_SHADOW_TAG("shadow");
59 const std::string XHTML_GLOW_TAG("glow");
60 const std::string XHTML_OUTLINE_TAG("outline");
61 const std::string XHTML_SMOOTH_EDGE_TAG("smooth");
62 const std::string XHTML_SIZE_PROPERTY("size");
63 const std::string XHTML_COLOR_PROPERTY("color");
64 const std::string XHTML_FACE_PROPERTY("face");
65 const std::string XHTML_STYLE_PROPERTY("style");
66 const std::string XHTML_PARAM_PROPERTY("param");
67 const std::string XHTML_PARAM_X_PROPERTY("paramx");
68 const std::string XHTML_PARAM_Y_PROPERTY("paramy");
69
70 const char LESS_THAN( '<' );
71 const char GREATER_THAN( '>' );
72 const char EQUAL( '=' );
73 const char QUOTATION_MARK( '\'');
74 const char LINE_SEPARATOR_CR( 0x0D ); // Carriage return character  CR
75 const char LINE_SEPARATOR_LF( 0x0A ); // New line character         LF
76 const char SLASH( '/' );
77 const char BACK_SLASH( '\\' );
78
79 const std::string LINE_SEPARATOR_LF_STRING(1 , LINE_SEPARATOR_LF); ///< a string with 1 line separator character
80 /**
81  * Stores a property pair: name, value.
82  */
83 struct Property
84 {
85   Property( const std::string& n, const std::string& v )
86   : name( n ),
87     value( v )
88   {}
89
90   std::string name;
91   std::string value;
92 };
93
94
95 /**
96  * Compare if two strings are equal.
97  *
98  * The comparison is case insensitive.
99  *
100  * @param[in] string1 First of the two strings to be compared.
101  * @param[in] string2 Second of the strings to be compared.
102  *
103  * @return \e true if both strings are equal (case insensitive).
104  */
105 bool CaseInsensitiveComparison( const std::string& string1, const std::string& string2 )
106 {
107   const std::size_t stringSize = string1.size();
108   if( stringSize != string2.size() )
109   {
110     // Early return. Strings have different sizes.
111     return false;
112   }
113
114   bool equal = true;
115   for( std::size_t index = 0; equal && ( index < stringSize ); ++index )
116   {
117     if( std::toupper( *( string1.begin() + index ) ) != std::toupper( *( string2.begin() + index ) ) )
118     {
119       equal = false;
120     }
121   }
122
123   return equal;
124 }
125
126 /**
127  * Converts a string into a float value.
128  * @param[in] floatStr A float packed inside a string.
129  * @return The float value.
130  */
131 float StringToFloat( const std::string& floatStr )
132 {
133   float ret = 0.f;
134
135   std::istringstream( floatStr ) >> ret;
136
137   return ret;
138 }
139
140 /**
141  * Converts a float into a string.
142  * @param[in] value. A float.
143  * @return The float packed into a string.
144  */
145 std::string FloatToString( float value )
146 {
147   std::ostringstream stream;
148   stream << value;
149
150   return stream.str();
151 }
152
153 /**
154  * Converts a string into an hexadecimal unsigned int.
155  * @param[in] uintStr An hexadecimal unsigned int packed inside a string.
156  * @return The hexadecimal value.
157  */
158 unsigned int StringToHex( const std::string& uintStr )
159 {
160   unsigned int ret = 0;
161
162   std::string str( uintStr );
163   if( uintStr.size() <= 8 )
164   {
165     str.insert( 2, std::string( "ff" ) );
166   }
167
168   std::istringstream( str ) >> std::hex >> ret;
169
170   return ret;
171 }
172
173 /**
174  * Converts an hexadecimal value into a string.
175  * @param[in] value. An hexadecimal value.
176  * @return The hexadecimal value packed inside a string.
177  */
178 std::string HexToString( unsigned int value )
179 {
180   std::ostringstream stream;
181   stream << std::hex << value;
182   return stream.str();
183 }
184
185 /**
186  * Converts an ARGB color packed in 4 byte unsigned int into a Vector4 color used in Dali.
187  * @param[in] color An ARGB color packed in an unsigned int.
188  * @param[out] retColor A Vector4 with the converted color.
189  */
190 void UintColorToVector4( unsigned int color, Vector4& retColor )
191 {
192   retColor.a = static_cast<float>( ( color & 0xFF000000 ) >> 24 ) / 255.f;
193   retColor.r = static_cast<float>( ( color & 0x00FF0000 ) >> 16 ) / 255.f;
194   retColor.g = static_cast<float>( ( color & 0x0000FF00 ) >> 8 ) / 255.f;
195   retColor.b = static_cast<float>( color & 0x000000FF ) / 255.f;
196 }
197
198 /**
199  * Converts an ARGB Vector4 color into a 4 byte packed inside an unsigned int.
200  * @param[in] color A Vector4 with an ARGB color.
201  * @return An unsigned int with the converted color.
202  */
203 unsigned int Vector4ColorToUint( const Vector4& color )
204 {
205   unsigned int retColor = 0;
206
207   retColor = static_cast<unsigned int>( color.a * 255.f ) << 24;
208   retColor += static_cast<unsigned int>( color.r * 255.f ) << 16;
209   retColor += static_cast<unsigned int>( color.g * 255.f ) << 8;
210   retColor += static_cast<unsigned int>( color.b * 255.f );
211
212   return retColor;
213 }
214
215 /**
216  * Converts a color packed inside a string into an ARGB Vector4 color.
217  * The string color could be in hexadecimal ( 0xFF0000FF ), webcolor ( #0000FF or #00F ) or some constant values:
218  * black, white, red, green, blue, yellow, magenta, cyan, transparent.
219  * @param[in] colorStr A color packed inside a string..
220  * @param[out] retColor A color packed inside a Vector4.
221  */
222 void ColorStringToVector4( const std::string& colorStr, Vector4& retColor )
223 {
224   std::string subStr1 = colorStr.substr( 0, 1 );
225   std::string subStr2 = colorStr.substr( 0, 2 );
226
227   if( WEB_COLOR_TOKEN == subStr1 )
228   {
229     std::string webColor( colorStr.begin() + 1, colorStr.end() );
230     if( 3 == webColor.size() )                      // 3 component web color #F00 (red)
231     {
232       webColor.insert( 2, &( webColor[2] ), 1 );
233       webColor.insert( 1, &( webColor[1] ), 1 );
234       webColor.insert( 0, &( webColor[0] ), 1 );
235       webColor.insert( 0, ALPHA_ONE );
236     }
237     else if( 6 == webColor.size() )                 // 6 component web color #FF0000 (red)
238     {
239       webColor.insert( 0, ALPHA_ONE );
240     }
241     webColor.insert( 0, HEX_COLOR_TOKEN );
242
243     UintColorToVector4( StringToHex( webColor ), retColor );
244   }
245   else if( CaseInsensitiveComparison( HEX_COLOR_TOKEN, subStr2 ) )
246   {
247     UintColorToVector4( StringToHex( colorStr ), retColor );
248   }
249   else if( CaseInsensitiveComparison( BLACK_COLOR, colorStr ) )
250   {
251     retColor = Color::BLACK;
252   }
253   else if( CaseInsensitiveComparison( WHITE_COLOR, colorStr ) )
254   {
255     retColor = Color::WHITE;
256   }
257   else if( CaseInsensitiveComparison( RED_COLOR, colorStr ) )
258   {
259     retColor = Color::RED;
260   }
261   else if( CaseInsensitiveComparison( GREEN_COLOR, colorStr ) )
262   {
263     retColor = Color::GREEN;
264   }
265   else if( CaseInsensitiveComparison( BLUE_COLOR, colorStr ) )
266   {
267     retColor = Color::BLUE;
268   }
269   else if( CaseInsensitiveComparison( YELLOW_COLOR, colorStr ) )
270   {
271     retColor = Color::YELLOW;
272   }
273   else if( CaseInsensitiveComparison( MAGENTA_COLOR, colorStr ) )
274   {
275     retColor = Color::MAGENTA;
276   }
277   else if( CaseInsensitiveComparison( CYAN_COLOR, colorStr ) )
278   {
279     retColor = Color::CYAN;
280   }
281   else if( CaseInsensitiveComparison( TRANSPARENT_COLOR, colorStr ) )
282   {
283     retColor = Color::TRANSPARENT;
284   }
285 }
286
287 /**
288  * Converts a color packed inside a Vector4 into a string.
289  * The string color could be in hexadecimal ( 0xFF0000FF ), webcolor ( #0000FF or #00F ) or some constant values:
290  * black, white, red, green, blue, yellow, magenta, cyan, transparent.
291  * @param[in] color A color packed inside a Vector4
292  * @return The color packed inside a string.
293  */
294 std::string Vector4ToColorString( const Vector4& color )
295 {
296   std::string colorStr;
297
298   if( Color::BLACK == color )
299   {
300     colorStr = BLACK_COLOR;
301   }
302   else if( Color::WHITE == color )
303   {
304     colorStr = WHITE_COLOR;
305   }
306   else if( Color::RED == color )
307   {
308     colorStr = RED_COLOR;
309   }
310   else if( Color::GREEN == color )
311   {
312     colorStr = GREEN_COLOR;
313   }
314   else if( Color::BLUE == color )
315   {
316     colorStr = BLUE_COLOR;
317   }
318   else if( Color::YELLOW == color )
319   {
320     colorStr = YELLOW_COLOR;
321   }
322   else if( Color::MAGENTA == color )
323   {
324     colorStr = MAGENTA_COLOR;
325   }
326   else if( Color::CYAN == color )
327   {
328     colorStr = CYAN_COLOR;
329   }
330   else if( Color::TRANSPARENT == color )
331   {
332     colorStr = TRANSPARENT_COLOR;
333   }
334   else
335   {
336     colorStr = HEX_COLOR_TOKEN + HexToString( Vector4ColorToUint( color ) );
337   }
338
339   return colorStr;
340 }
341
342 /**
343  * Skips any unnecessary white space.
344  * @param[in,out] it Iterator pointing to the current character of the markup string which is being parsed.
345  * @param[in] endIt Iterator pointing to the end of the markup string.
346  */
347 void SkipWhiteSpace( std::string::const_iterator& it, const std::string::const_iterator& endIt )
348 {
349   bool found = false;
350   for( ; ( !found ) && ( it != endIt ); ++it )
351   {
352     if( !isspace( *it ) )
353     {
354       found = true;
355       --it;
356     }
357   }
358 }
359
360 /**
361  * Adds a line separator 'LF' character to the given styled text array.
362  * @param[in] style The current style.
363  * @param[in,out] styledTextArray The given styled text array.
364  */
365 void AddNewLineChar( const TextStyle& style, StyledTextArray& styledTextArray )
366 {
367   const Text text( LINE_SEPARATOR_LF_STRING );
368   styledTextArray.push_back( StyledText( text, style ) );
369 }
370
371 /**
372  * Adds text to the given styled text array.
373  * It splits the text in characters.
374  * @param[in] textToBeStored The text to be stored.
375  * @param[in] styleToBeStored The current style.
376  * @param[in,out] styledTextArray The given styled text array.
377  */
378 void AddText( const std::string& textToBeStored, const TextStyle& styleToBeStored, StyledTextArray& styledTextArray )
379 {
380   const Text text( textToBeStored );
381   for( size_t i = 0, length = text.GetLength(); i < length; ++i )
382   {
383     styledTextArray.push_back( StyledText( Text( text[i] ), styleToBeStored ) );
384   }
385 }
386
387 /**
388  * Splits the tag string into the tag name and its properties.
389  * @param[in] tag The tag string with its pairs property, value.
390  * @param[out] tagName The name of the tag.
391  * @param[out] properties Vector of properties.
392  */
393 void ParseProperties( const std::string& tag, std::string& tagName, std::vector<Property>& properties )
394 {
395   // Find first the tag name.
396   bool found = false;
397   bool isQuotationOpen = false;
398   std::string::const_iterator it, endIt;
399   for( it = tag.begin(), endIt = tag.end(); ( !found ) && ( it != endIt ); ++it )
400   {
401     const char character( *it );
402     if( !isspace( character ) )
403     {
404       tagName += character;
405     }
406     else
407     {
408       found = true;
409     }
410   }
411   SkipWhiteSpace( it, endIt );
412
413   // Find the properties.
414   std::string name;
415   std::string value;
416   bool addToNameValue = true;
417   for( ; it != endIt; ++it )
418   {
419     const char character( *it );
420     if( isspace( character ) && !isQuotationOpen )
421     {
422       if( !name.empty() && !value.empty() )
423       {
424         // Every time a white space is found, a new property is created and stored in the properties vector.
425         properties.push_back( Property( name, value ) );
426         name .clear();
427         value.clear();
428         addToNameValue = true; // next read characters will be added to the name.
429       }
430     }
431     else if( EQUAL == character ) // '='
432     {
433       addToNameValue = false; // next read characters will be added to the value.
434       SkipWhiteSpace( it, endIt );
435     }
436     else if( QUOTATION_MARK == character ) // '\''
437     {
438       // Do not add quotation marks to neither name nor value.
439       isQuotationOpen = !isQuotationOpen;
440     }
441     else
442     {
443       // Adds characters to the name or the value.
444       if( addToNameValue )
445       {
446         name += character;
447       }
448       else
449       {
450         value += character;
451       }
452     }
453   }
454   if( !name.empty() && !value.empty() )
455   {
456     // Checks if the last property needs to be added.
457     properties.push_back( Property( name, value ) );
458   }
459 }
460
461 /**
462  * It parses a tag and its properties if the given iterator \e it is pointing at a tag beginning.
463  * @param[in,out] it Iterator pointing to the current character of the markup string which is being parsed.
464  * @param[in] endIt Iterator pointing to the end of the markup string.
465  * @param[out] tag Name of the tag.
466  * @param[out] isEndTag Whether the tag is and end tag i.e </tag_name> or not.
467  * @param[out] properties The vector with tag properties.
468  * @return \e true if the iterator \e it is pointing a markup tag. Otherwise \e false.
469  */
470 bool IsTag( std::string::const_iterator& it, const std::string::const_iterator& endIt, std::string& tag, bool& isEndTag, std::vector<Property>& properties )
471 {
472   bool isTag = false;
473   bool isQuotationOpen = false;
474   bool propertiesFound = false;
475   std::string tagString;
476
477   const char character( *it );
478   if( LESS_THAN == character ) // '<'
479   {
480     // if the iterator is pointing to a '<' character, then check if it's a markup tag is needed.
481     ++it;
482     if( it != endIt )
483     {
484       SkipWhiteSpace( it, endIt );
485
486       for( ; ( !isTag ) && ( it != endIt ); ++it )
487       {
488         const char character( *it );
489
490         if( SLASH == character ) // '/'
491         {
492           // if the tag has a '/' then it's an end or empty tag.
493           isEndTag = true;
494
495           if( ( it + 1 != endIt ) && ( isspace( *( it + 1 ) ) )  && ( !isQuotationOpen ) )
496           {
497             ++it;
498             SkipWhiteSpace( it, endIt );
499             --it;
500           }
501         }
502         else if( GREATER_THAN == character ) // '>'
503         {
504           isTag = true;
505         }
506         else if(QUOTATION_MARK == character)
507         {
508           isQuotationOpen = !isQuotationOpen;
509           tagString += character;
510         }
511         else if( isspace( character ) ) // ' '
512         {
513           // If the tag contains white spaces then it may have properties.
514           if ( !isQuotationOpen )
515           {
516             propertiesFound = true;
517           }
518           tagString += character;
519         }
520         else
521         {
522           // If it's not any of the 'special' characters then just add it to the tag string.
523           tagString += character;
524         }
525       }
526       --it;
527     }
528   }
529
530   // If the tag string has white spaces, then parse the properties is needed.
531   if( propertiesFound )
532   {
533     ParseProperties( tagString, tag, properties );
534   }
535   else
536   {
537     tag = tagString;
538   }
539
540   return isTag;
541 }
542
543 } // namespace
544
545 void GetStyledTextArray( const std::string& markupString, StyledTextArray& styledTextArray, bool scanForMarkup )
546 {
547   styledTextArray.clear();
548
549   if ( !scanForMarkup )
550   {
551     styledTextArray.push_back( StyledText( Text( markupString ), TextStyle() ) );
552     return;
553   }
554
555   TextStyle defaultStyle;
556   std::stack<TextStyle> styleStack;
557
558   styleStack.push( defaultStyle );
559   TextStyle currentStyle = styleStack.top();
560   std::string textToBeStored;
561   TextStyle styleToBeStored( currentStyle );
562   for( std::string::const_iterator it = markupString.begin(), endIt = markupString.end(); it != endIt; ++it )
563   {
564     std::string tag;
565     bool isEndTag = false;
566     std::vector<Property> tagProperties;
567     if( IsTag( it, endIt, tag, isEndTag, tagProperties ) )
568     {
569       if( CaseInsensitiveComparison( XHTML_I_TAG, tag ) )
570       {
571         if( !isEndTag )
572         {
573           TextStyle newStyle( currentStyle );
574           newStyle.SetItalics( true );
575           styleStack.push( newStyle );
576           currentStyle = styleStack.top();
577         }
578         else
579         {
580           styleStack.pop();
581           currentStyle = styleStack.top();
582         }
583       } // <i></i>
584       else if( CaseInsensitiveComparison( XHTML_U_TAG, tag ) )
585       {
586         if( !isEndTag )
587         {
588           TextStyle newStyle( currentStyle );
589           newStyle.SetUnderline( true );
590           styleStack.push( newStyle );
591           currentStyle = styleStack.top();
592         }
593         else
594         {
595           styleStack.pop();
596           currentStyle = styleStack.top();
597         }
598       } // <u></u>
599       else if( CaseInsensitiveComparison( XHTML_B_TAG, tag ) )
600       {
601         if( !isEndTag )
602         {
603           TextStyle newStyle( currentStyle );
604           newStyle.SetWeight( TextStyle::BOLD );
605           styleStack.push( newStyle );
606           currentStyle = styleStack.top();
607         }
608         else
609         {
610           styleStack.pop();
611           currentStyle = styleStack.top();
612         }
613       } // <b></b>
614       else if( CaseInsensitiveComparison( XHTML_BR_TAG, tag ) )
615       {
616         if( isEndTag )
617         {
618           AddText( textToBeStored, styleToBeStored, styledTextArray );
619           AddNewLineChar( currentStyle, styledTextArray );
620           textToBeStored.clear();
621         }
622       } // <br/>
623       else if( CaseInsensitiveComparison( XHTML_FONT_TAG, tag ) )
624       {
625         if( !isEndTag )
626         {
627           TextStyle newStyle( currentStyle );
628           for( std::vector<Property>::const_iterator it = tagProperties.begin(), endIt = tagProperties.end(); it != endIt; ++it )
629           {
630             const Property& property( *it );
631             if( CaseInsensitiveComparison( XHTML_FACE_PROPERTY, property.name ) )
632             {
633               newStyle.SetFontName( property.value );
634             }
635             else if( CaseInsensitiveComparison( XHTML_STYLE_PROPERTY, property.name ) )
636             {
637               newStyle.SetFontStyle( property.value );
638             }
639             else if( CaseInsensitiveComparison( XHTML_COLOR_PROPERTY, property.name ) )
640             {
641               Vector4 color;
642               ColorStringToVector4( property.value, color );
643               newStyle.SetTextColor( color );
644             }
645             else if( CaseInsensitiveComparison( XHTML_SIZE_PROPERTY, property.name ) )
646             {
647               newStyle.SetFontPointSize( PointSize( StringToFloat( property.value ) ) );
648             }
649           }
650           styleStack.push( newStyle );
651           currentStyle = styleStack.top();
652         }
653         else
654         {
655           styleStack.pop();
656           currentStyle = styleStack.top();
657         }
658       } // <font></font>
659       else if( CaseInsensitiveComparison( XHTML_SHADOW_TAG, tag ) )
660       {
661         if( !isEndTag )
662         {
663           TextStyle newStyle( currentStyle );
664           Vector4 color( TextStyle::DEFAULT_SHADOW_COLOR );
665           Vector2 offset( TextStyle::DEFAULT_SHADOW_OFFSET );
666           for( std::vector<Property>::const_iterator it = tagProperties.begin(), endIt = tagProperties.end(); it != endIt; ++it )
667           {
668             const Property& property( *it );
669             if( CaseInsensitiveComparison( XHTML_PARAM_X_PROPERTY, property.name ) )
670             {
671               offset.x = StringToFloat( property.value );
672             }
673             else if( CaseInsensitiveComparison( XHTML_PARAM_Y_PROPERTY, property.name ) )
674             {
675               offset.y = StringToFloat( property.value );
676             }
677             else if( CaseInsensitiveComparison( XHTML_COLOR_PROPERTY, property.name ) )
678             {
679               ColorStringToVector4( property.value, color );
680             }
681           }
682           newStyle.SetShadow( true, color, offset );
683           styleStack.push( newStyle );
684           currentStyle = styleStack.top();
685         }
686         else
687         {
688           styleStack.pop();
689           currentStyle = styleStack.top();
690         }
691       } // <shadow></shadow>
692       else if( CaseInsensitiveComparison( XHTML_GLOW_TAG, tag ) )
693       {
694         if( !isEndTag )
695         {
696           TextStyle newStyle( currentStyle );
697           Vector4 color( TextStyle::DEFAULT_GLOW_COLOR );
698           float intensity = TextStyle::DEFAULT_GLOW_INTENSITY;
699           for( std::vector<Property>::const_iterator it = tagProperties.begin(), endIt = tagProperties.end(); it != endIt; ++it )
700           {
701             const Property& property( *it );
702             if( CaseInsensitiveComparison( XHTML_PARAM_PROPERTY, property.name ) )
703             {
704               intensity = StringToFloat( property.value );
705             }
706             else if( CaseInsensitiveComparison( XHTML_COLOR_PROPERTY, property.name ) )
707             {
708               ColorStringToVector4( property.value, color );
709             }
710           }
711           newStyle.SetGlow( true, color, intensity );
712           styleStack.push( newStyle );
713           currentStyle = styleStack.top();
714         }
715         else
716         {
717           styleStack.pop();
718           currentStyle = styleStack.top();
719         }
720       } // <glow></glow>
721       else if( CaseInsensitiveComparison( XHTML_OUTLINE_TAG, tag ) )
722       {
723         if( !isEndTag )
724         {
725           TextStyle newStyle( currentStyle );
726           Vector4 color( TextStyle::DEFAULT_OUTLINE_COLOR );
727           Vector2 thickness( TextStyle::DEFAULT_OUTLINE_THICKNESS );
728           for( std::vector<Property>::const_iterator it = tagProperties.begin(), endIt = tagProperties.end(); it != endIt; ++it )
729           {
730             const Property& property( *it );
731             if( CaseInsensitiveComparison( XHTML_PARAM_X_PROPERTY, property.name ) )
732             {
733               thickness.x = StringToFloat( property.value );
734             }
735             else if( CaseInsensitiveComparison( XHTML_PARAM_Y_PROPERTY, property.name ) )
736             {
737               thickness.y = StringToFloat( property.value );
738             }
739             else if( CaseInsensitiveComparison( XHTML_COLOR_PROPERTY, property.name ) )
740             {
741               ColorStringToVector4( property.value, color );
742             }
743           }
744           newStyle.SetOutline( true, color, thickness );
745           styleStack.push( newStyle );
746           currentStyle = styleStack.top();
747         }
748         else
749         {
750           styleStack.pop();
751           currentStyle = styleStack.top();
752         }
753       } // <outline></outline>
754       else if( CaseInsensitiveComparison( XHTML_SMOOTH_EDGE_TAG, tag ) )
755       {
756         if( !isEndTag )
757         {
758           TextStyle newStyle( currentStyle );
759           for( std::vector<Property>::const_iterator it = tagProperties.begin(), endIt = tagProperties.end(); it != endIt; ++it )
760           {
761             const Property& property( *it );
762             if( CaseInsensitiveComparison( XHTML_PARAM_PROPERTY, property.name ) )
763             {
764               newStyle.SetSmoothEdge( StringToFloat( property.value ) );
765             }
766           }
767           styleStack.push( newStyle );
768           currentStyle = styleStack.top();
769         }
770         else
771         {
772           styleStack.pop();
773           currentStyle = styleStack.top();
774         }
775       } // <smooth></smooth>
776     } // end if( IsTag() )
777     else
778     {
779       char character( *it );
780
781       // Adding < or > special character.
782       if( ( BACK_SLASH == character ) && ( it + 1 != endIt ) )
783       {
784         const char nextChar( *( it + 1 ) );
785         if( ( LESS_THAN == nextChar ) || ( GREATER_THAN == nextChar ) )
786         {
787           character = nextChar;
788           ++it;
789         }
790       }
791       else if( ( LINE_SEPARATOR_CR == character ) && ( it + 1 != endIt ) )
792       {
793         if( LINE_SEPARATOR_LF == *( it + 1 ) )
794         {
795           character = LINE_SEPARATOR_LF;
796           ++it;
797         }
798       }
799
800       if( styleToBeStored != currentStyle )
801       {
802         if( !textToBeStored.empty() )
803         {
804           AddText( textToBeStored, styleToBeStored, styledTextArray );
805           textToBeStored.clear();
806         }
807         styleToBeStored = currentStyle;
808       }
809       textToBeStored.insert( textToBeStored.end(), character );
810     }
811   }
812   if( !textToBeStored.empty() )
813   {
814     AddText( textToBeStored, styleToBeStored, styledTextArray );
815     textToBeStored.clear();
816   }
817 }
818
819 void GetPlainString( const StyledTextArray& styledTextArray, std::string& plainString )
820 {
821   // First step is put all simultaneous characters with same style together.
822   for( StyledTextArray::const_iterator it = styledTextArray.begin(), endIt = styledTextArray.end(); it != endIt; ++it )
823   {
824     const StyledText& styledText( *it );
825     plainString += styledText.mText.GetText();
826   }
827 }
828
829 void GetMarkupString( const StyledTextArray& styledTextArray, std::string& markupString )
830 {
831   const std::string WHITE_SPACE( " " );
832
833   TextStyle previousStyle;
834   StyledText newStyledText;
835   StyledTextArray compressedStyledTextArray;
836
837   markupString.clear();
838
839   // First step is put all simultaneous characters with same style together.
840   for( StyledTextArray::const_iterator it = styledTextArray.begin(), endIt = styledTextArray.end(); it != endIt; ++it )
841   {
842     const StyledText& styledText( *it );
843
844     if( previousStyle != styledText.mStyle )
845     {
846       if( !newStyledText.mText.IsEmpty() )
847       {
848         compressedStyledTextArray.push_back( newStyledText );
849       }
850       newStyledText = StyledText();
851       newStyledText.mStyle = styledText.mStyle;
852     }
853
854     if( !styledText.mText.IsEmpty() )
855     {
856       const char character = styledText.mText.GetText()[0];
857       if( ( character == LESS_THAN ) || ( character == GREATER_THAN ) )
858       {
859         newStyledText.mText.Append( Text( std::string( &BACK_SLASH, 1 ) ) );
860       }
861     }
862
863     newStyledText.mText.Append( styledText.mText );
864
865     previousStyle = newStyledText.mStyle;
866   }
867
868   //Add the last characters.
869   if( !newStyledText.mText.IsEmpty() )
870   {
871     compressedStyledTextArray.push_back( newStyledText );
872   }
873
874   // Write markup string.
875   const std::string lineSeparatorStr( &LINE_SEPARATOR_LF );
876   const Text lineSeparator( lineSeparatorStr );
877
878   const TextStyle defaultStyle;
879   for( StyledTextArray::const_iterator it = compressedStyledTextArray.begin(), endIt = compressedStyledTextArray.end(); it != endIt; ++it )
880   {
881     const StyledText& styledText( *it );
882
883     bool isItalics = styledText.mStyle.GetItalics();
884     bool isBold = defaultStyle.GetWeight() != styledText.mStyle.GetWeight();
885     bool isUnderline = styledText.mStyle.GetUnderline();
886     bool hasFontFace = defaultStyle.GetFontName() != styledText.mStyle.GetFontName();
887     bool hasFontStyle = defaultStyle.GetFontStyle() != styledText.mStyle.GetFontStyle();
888     bool hasFontSize = fabsf( defaultStyle.GetFontPointSize() - styledText.mStyle.GetFontPointSize() ) > GetRangedEpsilon( defaultStyle.GetFontPointSize(), styledText.mStyle.GetFontPointSize() );
889     bool hasFontColor = defaultStyle.GetTextColor() != styledText.mStyle.GetTextColor();
890
891     bool hasSmooth = fabsf( defaultStyle.GetSmoothEdge() - styledText.mStyle.GetSmoothEdge() ) > GetRangedEpsilon( defaultStyle.GetSmoothEdge(), styledText.mStyle.GetSmoothEdge() );
892     bool hasShadowColor = defaultStyle.GetShadowColor() != styledText.mStyle.GetShadowColor();
893     bool hasShadowParams = defaultStyle.GetShadowOffset() != styledText.mStyle.GetShadowOffset();
894     bool hasGlowColor = defaultStyle.GetGlowColor() != styledText.mStyle.GetGlowColor();
895     bool hasGlowParams = fabsf( defaultStyle.GetGlowIntensity() - styledText.mStyle.GetGlowIntensity() ) > GetRangedEpsilon( defaultStyle.GetGlowIntensity(), styledText.mStyle.GetGlowIntensity() );
896     bool hasOutlineColor = defaultStyle.GetOutlineColor() != styledText.mStyle.GetOutlineColor();
897     bool hasOutlineParams = defaultStyle.GetOutlineThickness() != styledText.mStyle.GetOutlineThickness();
898
899     // Write font info.
900     if( hasFontFace || hasFontStyle || hasFontSize || hasFontColor )
901     {
902       markupString += LESS_THAN + XHTML_FONT_TAG;
903
904       if( hasFontFace )
905       {
906         markupString += WHITE_SPACE + XHTML_FACE_PROPERTY + EQUAL + QUOTATION_MARK + styledText.mStyle.GetFontName() + QUOTATION_MARK; // face=''
907       }
908
909       if( hasFontStyle )
910       {
911         markupString += WHITE_SPACE + XHTML_STYLE_PROPERTY + EQUAL + QUOTATION_MARK + styledText.mStyle.GetFontStyle() + QUOTATION_MARK; // style=''
912       }
913
914       if( hasFontSize )
915       {
916         markupString += WHITE_SPACE + XHTML_SIZE_PROPERTY + EQUAL + QUOTATION_MARK + FloatToString( styledText.mStyle.GetFontPointSize() ) + QUOTATION_MARK; // size=''
917       }
918
919       if( hasFontColor )
920       {
921         markupString += WHITE_SPACE + XHTML_COLOR_PROPERTY + EQUAL + QUOTATION_MARK + Vector4ToColorString( styledText.mStyle.GetTextColor() ) + QUOTATION_MARK; // color=''
922       }
923
924       markupString += GREATER_THAN;
925     } // <font>
926
927     // Write italics.
928     if( isItalics )
929     {
930       markupString += LESS_THAN + XHTML_I_TAG + GREATER_THAN;
931     } // <i>
932
933     // Write bold.
934     if( isBold )
935     {
936       markupString += LESS_THAN + XHTML_B_TAG + GREATER_THAN;
937     } // <b>
938
939     // Write underline.
940     if( isUnderline )
941     {
942       markupString += LESS_THAN + XHTML_U_TAG + GREATER_THAN;
943     } // <u>
944
945     // Write smooth.
946     if( hasSmooth )
947     {
948       markupString += LESS_THAN + XHTML_SMOOTH_EDGE_TAG + WHITE_SPACE + XHTML_PARAM_PROPERTY + EQUAL + QUOTATION_MARK + FloatToString( styledText.mStyle.GetSmoothEdge() ) + QUOTATION_MARK + GREATER_THAN;
949     }
950
951     // Write shadow.
952     if( styledText.mStyle.GetShadow() )
953     {
954       markupString += LESS_THAN + XHTML_SHADOW_TAG;
955
956       if( hasShadowColor )
957       {
958         markupString += WHITE_SPACE + XHTML_COLOR_PROPERTY + EQUAL + QUOTATION_MARK + Vector4ToColorString( styledText.mStyle.GetShadowColor() ) + QUOTATION_MARK;
959       }
960
961       if( hasShadowParams )
962       {
963         markupString += WHITE_SPACE + XHTML_PARAM_X_PROPERTY + EQUAL + QUOTATION_MARK + FloatToString( styledText.mStyle.GetShadowOffset().x ) + QUOTATION_MARK;
964         markupString += WHITE_SPACE + XHTML_PARAM_Y_PROPERTY + EQUAL + QUOTATION_MARK + FloatToString( styledText.mStyle.GetShadowOffset().y ) + QUOTATION_MARK;
965       }
966
967       markupString += GREATER_THAN;
968     }
969
970     // Write glow.
971     if( styledText.mStyle.GetGlow() )
972     {
973       markupString += LESS_THAN + XHTML_GLOW_TAG;
974
975       if( hasGlowColor )
976       {
977         markupString += WHITE_SPACE + XHTML_COLOR_PROPERTY + EQUAL + QUOTATION_MARK + Vector4ToColorString( styledText.mStyle.GetGlowColor() ) + QUOTATION_MARK; // color=''
978       }
979
980       if( hasGlowParams )
981       {
982         markupString += WHITE_SPACE + XHTML_PARAM_PROPERTY + EQUAL + QUOTATION_MARK + FloatToString( styledText.mStyle.GetGlowIntensity() ) + QUOTATION_MARK; // param=''
983       }
984
985       markupString += GREATER_THAN;
986     } // <glow>
987
988     // Write outline.
989     if( styledText.mStyle.GetOutline() )
990     {
991       markupString += LESS_THAN + XHTML_OUTLINE_TAG;
992
993       if( hasOutlineColor )
994       {
995         markupString += WHITE_SPACE + XHTML_COLOR_PROPERTY + EQUAL + QUOTATION_MARK + Vector4ToColorString( styledText.mStyle.GetOutlineColor() ) + QUOTATION_MARK; // color = ''
996       }
997
998       if( hasOutlineParams )
999       {
1000         markupString += WHITE_SPACE + XHTML_PARAM_X_PROPERTY + EQUAL + QUOTATION_MARK + FloatToString( styledText.mStyle.GetOutlineThickness().x ) + QUOTATION_MARK; // paramx=''
1001         markupString += WHITE_SPACE + XHTML_PARAM_Y_PROPERTY + EQUAL + QUOTATION_MARK + FloatToString( styledText.mStyle.GetOutlineThickness().y ) + QUOTATION_MARK; // paramy=''
1002       }
1003
1004       markupString += GREATER_THAN;
1005     } // <outline>
1006
1007     // Write text.
1008     if( styledText.mText[0] == lineSeparator[0] )
1009     {
1010       markupString += LESS_THAN + XHTML_BR_TAG + WHITE_SPACE + SLASH + GREATER_THAN; // <br />
1011     }
1012     else
1013     {
1014       markupString += styledText.mText.GetText();
1015     }
1016
1017     // Write outline close tag.
1018     if( styledText.mStyle.GetOutline() )
1019     {
1020       markupString += LESS_THAN + ( SLASH + XHTML_OUTLINE_TAG + GREATER_THAN ); // </outline>
1021     }
1022
1023     // Write glow close tag.
1024     if( styledText.mStyle.GetGlow() )
1025     {
1026       markupString += LESS_THAN + ( SLASH + XHTML_GLOW_TAG + GREATER_THAN ); // </glow>
1027     }
1028
1029     // Write shadow close tag.
1030     if( styledText.mStyle.GetShadow() )
1031     {
1032       markupString += LESS_THAN + ( SLASH + XHTML_SHADOW_TAG + GREATER_THAN ); // </shadow>
1033     }
1034
1035     // Write smooth close tag.
1036     if( hasSmooth )
1037     {
1038       markupString += LESS_THAN + ( SLASH + XHTML_SMOOTH_EDGE_TAG + GREATER_THAN ); // </smooth>
1039     }
1040
1041     // Write underline close tag.
1042     if( isUnderline )
1043     {
1044       markupString += LESS_THAN + ( SLASH + XHTML_U_TAG + GREATER_THAN ); // </u>
1045     }
1046
1047     // Write bold close tag.
1048     if( isBold )
1049     {
1050       markupString += LESS_THAN + ( SLASH + XHTML_B_TAG + GREATER_THAN ); // </b>
1051     }
1052
1053     // Write italics close tag.
1054     if( isItalics )
1055     {
1056       markupString += LESS_THAN + ( SLASH + XHTML_I_TAG + GREATER_THAN ); // </i>
1057     }
1058
1059     // Write font close tag.
1060     if( hasFontFace || hasFontStyle || hasFontSize || hasFontColor )
1061     {
1062       markupString += LESS_THAN + ( SLASH + XHTML_FONT_TAG + GREATER_THAN ); // </font>
1063     }
1064   }
1065 }
1066
1067 void SetTextStyle( StyledTextArray& styledTextArray, const TextStyle& style, const TextStyle::Mask mask )
1068 {
1069   if( !styledTextArray.empty() )
1070   {
1071     const size_t size = styledTextArray.size() - 1;
1072     SetTextStyleToRange( styledTextArray, style, mask, 0, size );
1073   }
1074 }
1075
1076 void SetTextStyle( const Text& text, StyledTextArray& styledTextArray, const TextStyle& style, const TextStyle::Mask mask )
1077 {
1078   if( !text.IsEmpty() )
1079   {
1080     const size_t size = text.GetLength();
1081
1082     for( size_t i = 0; i < size; ++i )
1083     {
1084       StyledText styledText;
1085       styledText.mText = Text( text[i] );
1086       styledText.mStyle = style;
1087
1088       styledTextArray.push_back( styledText );
1089     }
1090
1091     SetTextStyleToRange( styledTextArray, style, mask, 0, size - 1 );
1092   }
1093 }
1094
1095 void SetTextStyleToRange( StyledTextArray& styledTextArray, const TextStyle& style, const TextStyle::Mask mask, const std::size_t begin, const std::size_t end )
1096 {
1097   const size_t size = styledTextArray.size();
1098   DALI_ASSERT_ALWAYS( begin < size );
1099   DALI_ASSERT_ALWAYS( end < size );
1100
1101   for( StyledTextArray::iterator it = styledTextArray.begin() + std::min(begin, end), endIt = styledTextArray.begin() + std::max(begin, end) + 1; it != endIt; ++it )
1102   {
1103     StyledText& styledText( *it );
1104
1105     styledText.mStyle.Copy( style, mask );
1106   } // for loop
1107 }
1108
1109 } // namespace MarkupProcessor
1110
1111 } // namespace Toolkit
1112
1113 } // namespace Dali