2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 // http://floralicense.org/license/
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.
18 #include <dali-toolkit/public-api/markup-processor/markup-processor.h>
21 #include <dali/public-api/text/text.h>
34 namespace MarkupProcessor
39 const std::string WEB_COLOR_TOKEN( "#" );
40 const std::string HEX_COLOR_TOKEN( "0x" );
41 const std::string ALPHA_ONE( "FF" );
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" );
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");
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( '\\' );
79 const std::string LINE_SEPARATOR_LF_STRING(1 , LINE_SEPARATOR_LF); ///< a string with 1 line separator character
81 * Stores a property pair: name, value.
85 Property( const std::string& n, const std::string& v )
96 * Compare if two strings are equal.
98 * The comparison is case insensitive.
100 * @param[in] string1 First of the two strings to be compared.
101 * @param[in] string2 Second of the strings to be compared.
103 * @return \e true if both strings are equal (case insensitive).
105 bool CaseInsensitiveComparison( const std::string& string1, const std::string& string2 )
107 const std::size_t stringSize = string1.size();
108 if( stringSize != string2.size() )
110 // Early return. Strings have different sizes.
115 for( std::size_t index = 0; equal && ( index < stringSize ); ++index )
117 if( std::toupper( *( string1.begin() + index ) ) != std::toupper( *( string2.begin() + index ) ) )
127 * Converts a string into a float value.
128 * @param[in] floatStr A float packed inside a string.
129 * @return The float value.
131 float StringToFloat( const std::string& floatStr )
135 std::istringstream( floatStr ) >> ret;
141 * Converts a float into a string.
142 * @param[in] value. A float.
143 * @return The float packed into a string.
145 std::string FloatToString( float value )
147 std::ostringstream stream;
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.
158 unsigned int StringToHex( const std::string& uintStr )
160 unsigned int ret = 0;
162 std::string str( uintStr );
163 if( uintStr.size() <= 8 )
165 str.insert( 2, std::string( "ff" ) );
168 std::istringstream( str ) >> std::hex >> ret;
174 * Converts an hexadecimal value into a string.
175 * @param[in] value. An hexadecimal value.
176 * @return The hexadecimal value packed inside a string.
178 std::string HexToString( unsigned int value )
180 std::ostringstream stream;
181 stream << std::hex << value;
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.
190 void UintColorToVector4( unsigned int color, Vector4& retColor )
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;
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.
203 unsigned int Vector4ColorToUint( const Vector4& color )
205 unsigned int retColor = 0;
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 );
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.
222 void ColorStringToVector4( const std::string& colorStr, Vector4& retColor )
224 std::string subStr1 = colorStr.substr( 0, 1 );
225 std::string subStr2 = colorStr.substr( 0, 2 );
227 if( WEB_COLOR_TOKEN == subStr1 )
229 std::string webColor( colorStr.begin() + 1, colorStr.end() );
230 if( 3 == webColor.size() ) // 3 component web color #F00 (red)
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 );
237 else if( 6 == webColor.size() ) // 6 component web color #FF0000 (red)
239 webColor.insert( 0, ALPHA_ONE );
241 webColor.insert( 0, HEX_COLOR_TOKEN );
243 UintColorToVector4( StringToHex( webColor ), retColor );
245 else if( CaseInsensitiveComparison( HEX_COLOR_TOKEN, subStr2 ) )
247 UintColorToVector4( StringToHex( colorStr ), retColor );
249 else if( CaseInsensitiveComparison( BLACK_COLOR, colorStr ) )
251 retColor = Color::BLACK;
253 else if( CaseInsensitiveComparison( WHITE_COLOR, colorStr ) )
255 retColor = Color::WHITE;
257 else if( CaseInsensitiveComparison( RED_COLOR, colorStr ) )
259 retColor = Color::RED;
261 else if( CaseInsensitiveComparison( GREEN_COLOR, colorStr ) )
263 retColor = Color::GREEN;
265 else if( CaseInsensitiveComparison( BLUE_COLOR, colorStr ) )
267 retColor = Color::BLUE;
269 else if( CaseInsensitiveComparison( YELLOW_COLOR, colorStr ) )
271 retColor = Color::YELLOW;
273 else if( CaseInsensitiveComparison( MAGENTA_COLOR, colorStr ) )
275 retColor = Color::MAGENTA;
277 else if( CaseInsensitiveComparison( CYAN_COLOR, colorStr ) )
279 retColor = Color::CYAN;
281 else if( CaseInsensitiveComparison( TRANSPARENT_COLOR, colorStr ) )
283 retColor = Color::TRANSPARENT;
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.
294 std::string Vector4ToColorString( const Vector4& color )
296 std::string colorStr;
298 if( Color::BLACK == color )
300 colorStr = BLACK_COLOR;
302 else if( Color::WHITE == color )
304 colorStr = WHITE_COLOR;
306 else if( Color::RED == color )
308 colorStr = RED_COLOR;
310 else if( Color::GREEN == color )
312 colorStr = GREEN_COLOR;
314 else if( Color::BLUE == color )
316 colorStr = BLUE_COLOR;
318 else if( Color::YELLOW == color )
320 colorStr = YELLOW_COLOR;
322 else if( Color::MAGENTA == color )
324 colorStr = MAGENTA_COLOR;
326 else if( Color::CYAN == color )
328 colorStr = CYAN_COLOR;
330 else if( Color::TRANSPARENT == color )
332 colorStr = TRANSPARENT_COLOR;
336 colorStr = HEX_COLOR_TOKEN + HexToString( Vector4ColorToUint( color ) );
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.
347 void SkipWhiteSpace( std::string::const_iterator& it, const std::string::const_iterator& endIt )
350 for( ; ( !found ) && ( it != endIt ); ++it )
352 if( !isspace( *it ) )
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.
365 void AddNewLineChar( const TextStyle& style, StyledTextArray& styledTextArray )
367 const Text text( LINE_SEPARATOR_LF_STRING );
368 styledTextArray.push_back( StyledText( text, style ) );
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.
378 void AddText( const std::string& textToBeStored, const TextStyle& styleToBeStored, StyledTextArray& styledTextArray )
380 const Text text( textToBeStored );
381 for( size_t i = 0, length = text.GetLength(); i < length; ++i )
383 styledTextArray.push_back( StyledText( Text( text[i] ), styleToBeStored ) );
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.
393 void ParseProperties( const std::string& tag, std::string& tagName, std::vector<Property>& properties )
395 // Find first the tag name.
397 bool isQuotationOpen = false;
398 std::string::const_iterator it, endIt;
399 for( it = tag.begin(), endIt = tag.end(); ( !found ) && ( it != endIt ); ++it )
401 const char character( *it );
402 if( !isspace( character ) )
404 tagName += character;
411 SkipWhiteSpace( it, endIt );
413 // Find the properties.
416 bool addToNameValue = true;
417 for( ; it != endIt; ++it )
419 const char character( *it );
420 if( isspace( character ) && !isQuotationOpen )
422 if( !name.empty() && !value.empty() )
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 ) );
428 addToNameValue = true; // next read characters will be added to the name.
431 else if( EQUAL == character ) // '='
433 addToNameValue = false; // next read characters will be added to the value.
434 SkipWhiteSpace( it, endIt );
436 else if( QUOTATION_MARK == character ) // '\''
438 // Do not add quotation marks to neither name nor value.
439 isQuotationOpen = !isQuotationOpen;
443 // Adds characters to the name or the value.
454 if( !name.empty() && !value.empty() )
456 // Checks if the last property needs to be added.
457 properties.push_back( Property( name, value ) );
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.
470 bool IsTag( std::string::const_iterator& it, const std::string::const_iterator& endIt, std::string& tag, bool& isEndTag, std::vector<Property>& properties )
473 bool isQuotationOpen = false;
474 bool propertiesFound = false;
475 std::string tagString;
477 const char character( *it );
478 if( LESS_THAN == character ) // '<'
480 // if the iterator is pointing to a '<' character, then check if it's a markup tag is needed.
484 SkipWhiteSpace( it, endIt );
486 for( ; ( !isTag ) && ( it != endIt ); ++it )
488 const char character( *it );
490 if( SLASH == character ) // '/'
492 // if the tag has a '/' then it's an end or empty tag.
495 if( ( it + 1 != endIt ) && ( isspace( *( it + 1 ) ) ) && ( !isQuotationOpen ) )
498 SkipWhiteSpace( it, endIt );
502 else if( GREATER_THAN == character ) // '>'
506 else if(QUOTATION_MARK == character)
508 isQuotationOpen = !isQuotationOpen;
509 tagString += character;
511 else if( isspace( character ) ) // ' '
513 // If the tag contains white spaces then it may have properties.
514 if ( !isQuotationOpen )
516 propertiesFound = true;
518 tagString += character;
522 // If it's not any of the 'special' characters then just add it to the tag string.
523 tagString += character;
530 // If the tag string has white spaces, then parse the properties is needed.
531 if( propertiesFound )
533 ParseProperties( tagString, tag, properties );
545 static inline bool HasMarkup( const std::string& markupString )
548 unsigned int lessThanCount = 0;
549 unsigned int greaterThanCount = 0;
551 // Check to see if any markup command surrounds are of equal number and not zero
552 for ( std::string::const_iterator it = markupString.begin(); it != markupString.end(); ++it )
554 if ( *it == LESS_THAN )
560 if ( *it == GREATER_THAN )
566 if ( *it == BACK_SLASH )
573 if ( !lessThanCount || !greaterThanCount || lessThanCount != greaterThanCount )
580 void GetStyledTextArray( const std::string& markupString, StyledTextArray& styledTextArray, bool scanForMarkup )
582 styledTextArray.clear();
584 // Scan markup ( if necessary ) to see if the string contains any change in style from default?
585 if ( !scanForMarkup || !HasMarkup( markupString ) )
587 styledTextArray.push_back( StyledText( Text( markupString ), TextStyle() ) );
591 TextStyle defaultStyle;
592 std::stack<TextStyle> styleStack;
594 styleStack.push( defaultStyle );
595 TextStyle currentStyle = styleStack.top();
596 std::string textToBeStored;
597 TextStyle styleToBeStored( currentStyle );
598 for( std::string::const_iterator it = markupString.begin(), endIt = markupString.end(); it != endIt; ++it )
601 bool isEndTag = false;
602 std::vector<Property> tagProperties;
603 if( IsTag( it, endIt, tag, isEndTag, tagProperties ) )
605 if( CaseInsensitiveComparison( XHTML_I_TAG, tag ) )
609 TextStyle newStyle( currentStyle );
610 newStyle.SetItalics( true );
611 styleStack.push( newStyle );
612 currentStyle = styleStack.top();
617 currentStyle = styleStack.top();
620 else if( CaseInsensitiveComparison( XHTML_U_TAG, tag ) )
624 TextStyle newStyle( currentStyle );
625 newStyle.SetUnderline( true );
626 styleStack.push( newStyle );
627 currentStyle = styleStack.top();
632 currentStyle = styleStack.top();
635 else if( CaseInsensitiveComparison( XHTML_B_TAG, tag ) )
639 TextStyle newStyle( currentStyle );
640 newStyle.SetWeight( TextStyle::BOLD );
641 styleStack.push( newStyle );
642 currentStyle = styleStack.top();
647 currentStyle = styleStack.top();
650 else if( CaseInsensitiveComparison( XHTML_BR_TAG, tag ) )
654 AddText( textToBeStored, styleToBeStored, styledTextArray );
655 AddNewLineChar( currentStyle, styledTextArray );
656 textToBeStored.clear();
659 else if( CaseInsensitiveComparison( XHTML_FONT_TAG, tag ) )
663 TextStyle newStyle( currentStyle );
664 for( std::vector<Property>::const_iterator it = tagProperties.begin(), endIt = tagProperties.end(); it != endIt; ++it )
666 const Property& property( *it );
667 if( CaseInsensitiveComparison( XHTML_FACE_PROPERTY, property.name ) )
669 newStyle.SetFontName( property.value );
671 else if( CaseInsensitiveComparison( XHTML_STYLE_PROPERTY, property.name ) )
673 newStyle.SetFontStyle( property.value );
675 else if( CaseInsensitiveComparison( XHTML_COLOR_PROPERTY, property.name ) )
678 ColorStringToVector4( property.value, color );
679 newStyle.SetTextColor( color );
681 else if( CaseInsensitiveComparison( XHTML_SIZE_PROPERTY, property.name ) )
683 newStyle.SetFontPointSize( PointSize( StringToFloat( property.value ) ) );
686 styleStack.push( newStyle );
687 currentStyle = styleStack.top();
692 currentStyle = styleStack.top();
695 else if( CaseInsensitiveComparison( XHTML_SHADOW_TAG, tag ) )
699 TextStyle newStyle( currentStyle );
700 Vector4 color( TextStyle::DEFAULT_SHADOW_COLOR );
701 Vector2 offset( TextStyle::DEFAULT_SHADOW_OFFSET );
702 for( std::vector<Property>::const_iterator it = tagProperties.begin(), endIt = tagProperties.end(); it != endIt; ++it )
704 const Property& property( *it );
705 if( CaseInsensitiveComparison( XHTML_PARAM_X_PROPERTY, property.name ) )
707 offset.x = StringToFloat( property.value );
709 else if( CaseInsensitiveComparison( XHTML_PARAM_Y_PROPERTY, property.name ) )
711 offset.y = StringToFloat( property.value );
713 else if( CaseInsensitiveComparison( XHTML_COLOR_PROPERTY, property.name ) )
715 ColorStringToVector4( property.value, color );
718 newStyle.SetShadow( true, color, offset );
719 styleStack.push( newStyle );
720 currentStyle = styleStack.top();
725 currentStyle = styleStack.top();
727 } // <shadow></shadow>
728 else if( CaseInsensitiveComparison( XHTML_GLOW_TAG, tag ) )
732 TextStyle newStyle( currentStyle );
733 Vector4 color( TextStyle::DEFAULT_GLOW_COLOR );
734 float intensity = TextStyle::DEFAULT_GLOW_INTENSITY;
735 for( std::vector<Property>::const_iterator it = tagProperties.begin(), endIt = tagProperties.end(); it != endIt; ++it )
737 const Property& property( *it );
738 if( CaseInsensitiveComparison( XHTML_PARAM_PROPERTY, property.name ) )
740 intensity = StringToFloat( property.value );
742 else if( CaseInsensitiveComparison( XHTML_COLOR_PROPERTY, property.name ) )
744 ColorStringToVector4( property.value, color );
747 newStyle.SetGlow( true, color, intensity );
748 styleStack.push( newStyle );
749 currentStyle = styleStack.top();
754 currentStyle = styleStack.top();
757 else if( CaseInsensitiveComparison( XHTML_OUTLINE_TAG, tag ) )
761 TextStyle newStyle( currentStyle );
762 Vector4 color( TextStyle::DEFAULT_OUTLINE_COLOR );
763 Vector2 thickness( TextStyle::DEFAULT_OUTLINE_THICKNESS );
764 for( std::vector<Property>::const_iterator it = tagProperties.begin(), endIt = tagProperties.end(); it != endIt; ++it )
766 const Property& property( *it );
767 if( CaseInsensitiveComparison( XHTML_PARAM_X_PROPERTY, property.name ) )
769 thickness.x = StringToFloat( property.value );
771 else if( CaseInsensitiveComparison( XHTML_PARAM_Y_PROPERTY, property.name ) )
773 thickness.y = StringToFloat( property.value );
775 else if( CaseInsensitiveComparison( XHTML_COLOR_PROPERTY, property.name ) )
777 ColorStringToVector4( property.value, color );
780 newStyle.SetOutline( true, color, thickness );
781 styleStack.push( newStyle );
782 currentStyle = styleStack.top();
787 currentStyle = styleStack.top();
789 } // <outline></outline>
790 else if( CaseInsensitiveComparison( XHTML_SMOOTH_EDGE_TAG, tag ) )
794 TextStyle newStyle( currentStyle );
795 for( std::vector<Property>::const_iterator it = tagProperties.begin(), endIt = tagProperties.end(); it != endIt; ++it )
797 const Property& property( *it );
798 if( CaseInsensitiveComparison( XHTML_PARAM_PROPERTY, property.name ) )
800 newStyle.SetSmoothEdge( StringToFloat( property.value ) );
803 styleStack.push( newStyle );
804 currentStyle = styleStack.top();
809 currentStyle = styleStack.top();
811 } // <smooth></smooth>
812 } // end if( IsTag() )
815 char character( *it );
817 // Adding < or > special character.
818 if( ( BACK_SLASH == character ) && ( it + 1 != endIt ) )
820 const char nextChar( *( it + 1 ) );
821 if( ( LESS_THAN == nextChar ) || ( GREATER_THAN == nextChar ) )
823 character = nextChar;
827 else if( ( LINE_SEPARATOR_CR == character ) && ( it + 1 != endIt ) )
829 if( LINE_SEPARATOR_LF == *( it + 1 ) )
831 character = LINE_SEPARATOR_LF;
836 if( styleToBeStored != currentStyle )
838 if( !textToBeStored.empty() )
840 AddText( textToBeStored, styleToBeStored, styledTextArray );
841 textToBeStored.clear();
843 styleToBeStored = currentStyle;
845 textToBeStored.insert( textToBeStored.end(), character );
848 if( !textToBeStored.empty() )
850 AddText( textToBeStored, styleToBeStored, styledTextArray );
851 textToBeStored.clear();
855 void GetPlainString( const StyledTextArray& styledTextArray, std::string& plainString )
857 // First step is put all simultaneous characters with same style together.
858 for( StyledTextArray::const_iterator it = styledTextArray.begin(), endIt = styledTextArray.end(); it != endIt; ++it )
860 const StyledText& styledText( *it );
861 plainString += styledText.mText.GetText();
865 void GetMarkupString( const StyledTextArray& styledTextArray, std::string& markupString )
867 const std::string WHITE_SPACE( " " );
869 TextStyle previousStyle;
870 StyledText newStyledText;
871 StyledTextArray compressedStyledTextArray;
873 markupString.clear();
875 // First step is put all simultaneous characters with same style together.
876 for( StyledTextArray::const_iterator it = styledTextArray.begin(), endIt = styledTextArray.end(); it != endIt; ++it )
878 const StyledText& styledText( *it );
880 if( previousStyle != styledText.mStyle )
882 if( !newStyledText.mText.IsEmpty() )
884 compressedStyledTextArray.push_back( newStyledText );
886 newStyledText = StyledText();
887 newStyledText.mStyle = styledText.mStyle;
890 if( !styledText.mText.IsEmpty() )
892 const char character = styledText.mText.GetText()[0];
893 if( ( character == LESS_THAN ) || ( character == GREATER_THAN ) )
895 newStyledText.mText.Append( Text( std::string( &BACK_SLASH, 1 ) ) );
899 newStyledText.mText.Append( styledText.mText );
901 previousStyle = newStyledText.mStyle;
904 //Add the last characters.
905 if( !newStyledText.mText.IsEmpty() )
907 compressedStyledTextArray.push_back( newStyledText );
910 // Write markup string.
911 const std::string lineSeparatorStr( &LINE_SEPARATOR_LF );
912 const Text lineSeparator( lineSeparatorStr );
914 const TextStyle defaultStyle;
915 for( StyledTextArray::const_iterator it = compressedStyledTextArray.begin(), endIt = compressedStyledTextArray.end(); it != endIt; ++it )
917 const StyledText& styledText( *it );
919 bool isItalics = styledText.mStyle.GetItalics();
920 bool isBold = defaultStyle.GetWeight() != styledText.mStyle.GetWeight();
921 bool isUnderline = styledText.mStyle.GetUnderline();
922 bool hasFontFace = defaultStyle.GetFontName() != styledText.mStyle.GetFontName();
923 bool hasFontStyle = defaultStyle.GetFontStyle() != styledText.mStyle.GetFontStyle();
924 bool hasFontSize = fabsf( defaultStyle.GetFontPointSize() - styledText.mStyle.GetFontPointSize() ) > GetRangedEpsilon( defaultStyle.GetFontPointSize(), styledText.mStyle.GetFontPointSize() );
925 bool hasFontColor = defaultStyle.GetTextColor() != styledText.mStyle.GetTextColor();
927 bool hasSmooth = fabsf( defaultStyle.GetSmoothEdge() - styledText.mStyle.GetSmoothEdge() ) > GetRangedEpsilon( defaultStyle.GetSmoothEdge(), styledText.mStyle.GetSmoothEdge() );
928 bool hasShadowColor = defaultStyle.GetShadowColor() != styledText.mStyle.GetShadowColor();
929 bool hasShadowParams = defaultStyle.GetShadowOffset() != styledText.mStyle.GetShadowOffset();
930 bool hasGlowColor = defaultStyle.GetGlowColor() != styledText.mStyle.GetGlowColor();
931 bool hasGlowParams = fabsf( defaultStyle.GetGlowIntensity() - styledText.mStyle.GetGlowIntensity() ) > GetRangedEpsilon( defaultStyle.GetGlowIntensity(), styledText.mStyle.GetGlowIntensity() );
932 bool hasOutlineColor = defaultStyle.GetOutlineColor() != styledText.mStyle.GetOutlineColor();
933 bool hasOutlineParams = defaultStyle.GetOutlineThickness() != styledText.mStyle.GetOutlineThickness();
936 if( hasFontFace || hasFontStyle || hasFontSize || hasFontColor )
938 markupString += LESS_THAN + XHTML_FONT_TAG;
942 markupString += WHITE_SPACE + XHTML_FACE_PROPERTY + EQUAL + QUOTATION_MARK + styledText.mStyle.GetFontName() + QUOTATION_MARK; // face=''
947 markupString += WHITE_SPACE + XHTML_STYLE_PROPERTY + EQUAL + QUOTATION_MARK + styledText.mStyle.GetFontStyle() + QUOTATION_MARK; // style=''
952 markupString += WHITE_SPACE + XHTML_SIZE_PROPERTY + EQUAL + QUOTATION_MARK + FloatToString( styledText.mStyle.GetFontPointSize() ) + QUOTATION_MARK; // size=''
957 markupString += WHITE_SPACE + XHTML_COLOR_PROPERTY + EQUAL + QUOTATION_MARK + Vector4ToColorString( styledText.mStyle.GetTextColor() ) + QUOTATION_MARK; // color=''
960 markupString += GREATER_THAN;
966 markupString += LESS_THAN + XHTML_I_TAG + GREATER_THAN;
972 markupString += LESS_THAN + XHTML_B_TAG + GREATER_THAN;
978 markupString += LESS_THAN + XHTML_U_TAG + GREATER_THAN;
984 markupString += LESS_THAN + XHTML_SMOOTH_EDGE_TAG + WHITE_SPACE + XHTML_PARAM_PROPERTY + EQUAL + QUOTATION_MARK + FloatToString( styledText.mStyle.GetSmoothEdge() ) + QUOTATION_MARK + GREATER_THAN;
988 if( styledText.mStyle.GetShadow() )
990 markupString += LESS_THAN + XHTML_SHADOW_TAG;
994 markupString += WHITE_SPACE + XHTML_COLOR_PROPERTY + EQUAL + QUOTATION_MARK + Vector4ToColorString( styledText.mStyle.GetShadowColor() ) + QUOTATION_MARK;
997 if( hasShadowParams )
999 markupString += WHITE_SPACE + XHTML_PARAM_X_PROPERTY + EQUAL + QUOTATION_MARK + FloatToString( styledText.mStyle.GetShadowOffset().x ) + QUOTATION_MARK;
1000 markupString += WHITE_SPACE + XHTML_PARAM_Y_PROPERTY + EQUAL + QUOTATION_MARK + FloatToString( styledText.mStyle.GetShadowOffset().y ) + QUOTATION_MARK;
1003 markupString += GREATER_THAN;
1007 if( styledText.mStyle.GetGlow() )
1009 markupString += LESS_THAN + XHTML_GLOW_TAG;
1013 markupString += WHITE_SPACE + XHTML_COLOR_PROPERTY + EQUAL + QUOTATION_MARK + Vector4ToColorString( styledText.mStyle.GetGlowColor() ) + QUOTATION_MARK; // color=''
1018 markupString += WHITE_SPACE + XHTML_PARAM_PROPERTY + EQUAL + QUOTATION_MARK + FloatToString( styledText.mStyle.GetGlowIntensity() ) + QUOTATION_MARK; // param=''
1021 markupString += GREATER_THAN;
1025 if( styledText.mStyle.GetOutline() )
1027 markupString += LESS_THAN + XHTML_OUTLINE_TAG;
1029 if( hasOutlineColor )
1031 markupString += WHITE_SPACE + XHTML_COLOR_PROPERTY + EQUAL + QUOTATION_MARK + Vector4ToColorString( styledText.mStyle.GetOutlineColor() ) + QUOTATION_MARK; // color = ''
1034 if( hasOutlineParams )
1036 markupString += WHITE_SPACE + XHTML_PARAM_X_PROPERTY + EQUAL + QUOTATION_MARK + FloatToString( styledText.mStyle.GetOutlineThickness().x ) + QUOTATION_MARK; // paramx=''
1037 markupString += WHITE_SPACE + XHTML_PARAM_Y_PROPERTY + EQUAL + QUOTATION_MARK + FloatToString( styledText.mStyle.GetOutlineThickness().y ) + QUOTATION_MARK; // paramy=''
1040 markupString += GREATER_THAN;
1044 if( styledText.mText[0] == lineSeparator[0] )
1046 markupString += LESS_THAN + XHTML_BR_TAG + WHITE_SPACE + SLASH + GREATER_THAN; // <br />
1050 markupString += styledText.mText.GetText();
1053 // Write outline close tag.
1054 if( styledText.mStyle.GetOutline() )
1056 markupString += LESS_THAN + ( SLASH + XHTML_OUTLINE_TAG + GREATER_THAN ); // </outline>
1059 // Write glow close tag.
1060 if( styledText.mStyle.GetGlow() )
1062 markupString += LESS_THAN + ( SLASH + XHTML_GLOW_TAG + GREATER_THAN ); // </glow>
1065 // Write shadow close tag.
1066 if( styledText.mStyle.GetShadow() )
1068 markupString += LESS_THAN + ( SLASH + XHTML_SHADOW_TAG + GREATER_THAN ); // </shadow>
1071 // Write smooth close tag.
1074 markupString += LESS_THAN + ( SLASH + XHTML_SMOOTH_EDGE_TAG + GREATER_THAN ); // </smooth>
1077 // Write underline close tag.
1080 markupString += LESS_THAN + ( SLASH + XHTML_U_TAG + GREATER_THAN ); // </u>
1083 // Write bold close tag.
1086 markupString += LESS_THAN + ( SLASH + XHTML_B_TAG + GREATER_THAN ); // </b>
1089 // Write italics close tag.
1092 markupString += LESS_THAN + ( SLASH + XHTML_I_TAG + GREATER_THAN ); // </i>
1095 // Write font close tag.
1096 if( hasFontFace || hasFontStyle || hasFontSize || hasFontColor )
1098 markupString += LESS_THAN + ( SLASH + XHTML_FONT_TAG + GREATER_THAN ); // </font>
1103 void SetTextStyle( StyledTextArray& styledTextArray, const TextStyle& style, const TextStyle::Mask mask )
1105 if( !styledTextArray.empty() )
1107 const size_t size = styledTextArray.size() - 1;
1108 SetTextStyleToRange( styledTextArray, style, mask, 0, size );
1112 void SetTextStyle( const Text& text, StyledTextArray& styledTextArray, const TextStyle& style, const TextStyle::Mask mask )
1114 if( !text.IsEmpty() )
1116 const size_t size = text.GetLength();
1118 for( size_t i = 0; i < size; ++i )
1120 StyledText styledText;
1121 styledText.mText = Text( text[i] );
1122 styledText.mStyle = style;
1124 styledTextArray.push_back( styledText );
1127 SetTextStyleToRange( styledTextArray, style, mask, 0, size - 1 );
1131 void SetTextStyleToRange( StyledTextArray& styledTextArray, const TextStyle& style, const TextStyle::Mask mask, const std::size_t begin, const std::size_t end )
1133 const size_t size = styledTextArray.size();
1134 DALI_ASSERT_ALWAYS( begin < size );
1135 DALI_ASSERT_ALWAYS( end < size );
1137 for( StyledTextArray::iterator it = styledTextArray.begin() + std::min(begin, end), endIt = styledTextArray.begin() + std::max(begin, end) + 1; it != endIt; ++it )
1139 StyledText& styledText( *it );
1141 styledText.mStyle.Copy( style, mask );
1145 } // namespace MarkupProcessor
1147 } // namespace Toolkit