[dali_1.3.13] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-effects-style.cpp
1 /*
2  * Copyright (c) 2018 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/text-effects-style.h>
20
21 // INTERNAL INCLUDES
22 #include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
23 #include <dali-toolkit/internal/text/property-string-parser.h>
24
25 namespace Dali
26 {
27
28 namespace Toolkit
29 {
30
31 namespace Text
32 {
33
34 namespace
35 {
36 const std::string COLOR_KEY( "color" );
37 const std::string OFFSET_KEY( "offset" );
38 const std::string BLUR_RADIUS_KEY( "blurRadius" );
39 const std::string WIDTH_KEY( "width" );
40 const std::string HEIGHT_KEY( "height" );
41 const std::string ENABLE_KEY( "enable" );
42 const std::string TRUE_TOKEN( "true" );
43 const std::string FALSE_TOKEN( "false" );
44 }
45
46 bool ParseShadowProperties( const Property::Map& shadowPropertiesMap,
47                             bool& colorDefined,
48                             Vector4& color,
49                             bool& offsetDefined,
50                             Vector2& offset,
51                             bool& blurRadiusDefined,
52                             float& blurRadius )
53 {
54   const unsigned int numberOfItems = shadowPropertiesMap.Count();
55
56   // Parses and applies the style.
57   for( unsigned int index = 0u; index < numberOfItems; ++index )
58   {
59     const KeyValuePair& valueGet = shadowPropertiesMap.GetKeyValue( index );
60
61     if( COLOR_KEY == valueGet.first.stringKey )
62     {
63       /// Color key.
64       colorDefined = true;
65
66       if( valueGet.second.GetType() == Dali::Property::STRING )
67       {
68         const std::string colorStr = valueGet.second.Get<std::string>();
69         Text::ColorStringToVector4( colorStr.c_str(), colorStr.size(), color );
70       }
71       else
72       {
73         color = valueGet.second.Get<Vector4>();
74       }
75     }
76     else if( OFFSET_KEY == valueGet.first.stringKey )
77     {
78       /// Offset key.
79       offsetDefined = true;
80
81       if( valueGet.second.GetType() == Dali::Property::STRING )
82       {
83         const std::string offsetStr = valueGet.second.Get<std::string>();
84         StringToVector2( offsetStr.c_str(), offsetStr.size(), offset );
85       }
86       else
87       {
88         offset = valueGet.second.Get<Vector2>();
89       }
90     }
91     else if( BLUR_RADIUS_KEY == valueGet.first.stringKey )
92     {
93       /// Blur radius key.
94       blurRadiusDefined = true;
95
96       if( valueGet.second.GetType() == Dali::Property::STRING )
97       {
98         const std::string blurRadiusStr = valueGet.second.Get<std::string>();
99         blurRadius = StringToFloat( blurRadiusStr.c_str() );
100       }
101       else
102       {
103         blurRadius = valueGet.second.Get<float>();
104       }
105     }
106   }
107
108   return 0u == numberOfItems;
109 }
110
111 bool ParseUnderlineProperties( const Property::Map& underlinePropertiesMap,
112                                bool& enabled,
113                                bool& colorDefined,
114                                Vector4& color,
115                                bool& heightDefined,
116                                float& height )
117 {
118   const unsigned int numberOfItems = underlinePropertiesMap.Count();
119
120   // Parses and applies the style.
121   for( unsigned int index = 0u; index < numberOfItems; ++index )
122   {
123     const KeyValuePair& valueGet = underlinePropertiesMap.GetKeyValue( index );
124
125     if( ENABLE_KEY == valueGet.first.stringKey )
126     {
127       /// Enable key.
128       if( valueGet.second.GetType() == Dali::Property::STRING )
129       {
130         const std::string enableStr = valueGet.second.Get<std::string>();
131         enabled = Text::TokenComparison( TRUE_TOKEN, enableStr.c_str(), enableStr.size() );
132       }
133       else
134       {
135         enabled = valueGet.second.Get<bool>();
136       }
137     }
138     else if( COLOR_KEY == valueGet.first.stringKey )
139     {
140       /// Color key.
141       colorDefined = true;
142
143       if( valueGet.second.GetType() == Dali::Property::STRING )
144       {
145         const std::string colorStr = valueGet.second.Get<std::string>();
146         Text::ColorStringToVector4( colorStr.c_str(), colorStr.size(), color );
147       }
148       else
149       {
150         color = valueGet.second.Get<Vector4>();
151       }
152     }
153     else if( HEIGHT_KEY == valueGet.first.stringKey )
154     {
155       /// Height key.
156       heightDefined = true;
157
158       if( valueGet.second.GetType() == Dali::Property::STRING )
159       {
160         const std::string heightStr = valueGet.second.Get<std::string>();
161         height = StringToFloat( heightStr.c_str() );
162       }
163       else
164       {
165         height = valueGet.second.Get<float>();
166       }
167     }
168   }
169
170   return 0u == numberOfItems;
171 }
172
173 bool ParseOutlineProperties( const Property::Map& underlinePropertiesMap,
174                                bool& colorDefined,
175                                Vector4& color,
176                                bool& widthDefined,
177                                unsigned int& width )
178 {
179   const unsigned int numberOfItems = underlinePropertiesMap.Count();
180
181   // Parses and applies the style.
182   for( unsigned int index = 0u; index < numberOfItems; ++index )
183   {
184     const KeyValuePair& valueGet = underlinePropertiesMap.GetKeyValue( index );
185
186     if( COLOR_KEY == valueGet.first.stringKey )
187     {
188       /// Color key.
189       colorDefined = true;
190       color = valueGet.second.Get<Vector4>();
191     }
192     else if( WIDTH_KEY == valueGet.first.stringKey )
193     {
194       /// Width key.
195       widthDefined = true;
196       width = static_cast<unsigned int>( valueGet.second.Get<float>() );
197     }
198   }
199
200   return 0u == numberOfItems;
201 }
202
203 bool ParseBackgroundProperties( const Property::Map& backgroundProperties,
204                                 bool& enabled,
205                                 bool& colorDefined,
206                                 Vector4& color )
207 {
208   const unsigned int numberOfItems = backgroundProperties.Count();
209
210   // Parses and applies the style.
211   for( unsigned int index = 0u; index < numberOfItems; ++index )
212   {
213     const KeyValuePair& valueGet = backgroundProperties.GetKeyValue( index );
214
215     if( ENABLE_KEY == valueGet.first.stringKey )
216     {
217       /// Enable key.
218       enabled = valueGet.second.Get<bool>();
219     }
220     else if( COLOR_KEY == valueGet.first.stringKey )
221     {
222       /// Color key.
223       colorDefined = true;
224       color = valueGet.second.Get<Vector4>();
225     }
226   }
227
228   return 0u == numberOfItems;
229 }
230
231 bool SetUnderlineProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type )
232 {
233   bool update = false;
234
235   if( controller )
236   {
237     switch( type )
238     {
239       case EffectStyle::DEFAULT:
240       {
241         const Property::Map& propertiesMap = value.Get<Property::Map>();
242
243         bool enabled = false;
244         bool colorDefined = false;
245         Vector4 color;
246         bool heightDefined = false;
247         float height = 0.f;
248
249         bool empty = true;
250
251         if ( propertiesMap.Empty() )
252         {
253           // Map empty so check if a string provided
254           const std::string propertyString = value.Get<std::string>();
255
256           if ( !propertyString.empty() )
257           {
258             Property::Map parsedStringMap;
259             Text::ParsePropertyString( propertyString, parsedStringMap );
260
261             empty = ParseUnderlineProperties( parsedStringMap,
262                                               enabled,
263                                               colorDefined,
264                                               color,
265                                               heightDefined,
266                                               height );
267
268             controller->UnderlineSetByString( !empty );
269           }
270         }
271         else
272         {
273            empty = ParseUnderlineProperties( propertiesMap,
274                                              enabled,
275                                              colorDefined,
276                                              color,
277                                              heightDefined,
278                                              height );
279
280            controller->UnderlineSetByString( false );
281         }
282
283         if( !empty )
284         {
285           if( enabled != controller->IsUnderlineEnabled() )
286           {
287             controller->SetUnderlineEnabled( enabled );
288             update = true;
289           }
290
291           // Sets the default underline values.
292           if( colorDefined && ( controller->GetUnderlineColor() != color ) )
293           {
294             controller->SetUnderlineColor( color );
295             update = true;
296           }
297
298           if( heightDefined && ( fabsf( controller->GetUnderlineHeight() - height ) > Math::MACHINE_EPSILON_1000 ) )
299           {
300             controller->SetUnderlineHeight( height );
301             update = true;
302           }
303         }
304         else
305         {
306           // Disable underline.
307           if( controller->IsUnderlineEnabled() )
308           {
309             controller->SetUnderlineEnabled( false );
310             update = true;
311           }
312         }
313         break;
314       }
315       case EffectStyle::INPUT:
316       {
317         const std::string& underlineProperties = value.Get<std::string>();
318
319         controller->SetInputUnderlineProperties( underlineProperties );
320         break;
321       }
322     } // switch
323   } // if( controller )
324
325   return update;
326 }
327
328 void GetUnderlineProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type )
329 {
330   if( controller )
331   {
332     switch( type )
333     {
334       case EffectStyle::DEFAULT:
335       {
336         const bool enabled = controller->IsUnderlineEnabled();
337         const Vector4& color = controller->GetUnderlineColor();
338         const float height = controller->GetUnderlineHeight();
339
340         if ( controller->IsUnderlineSetByString() )
341         {
342           std::string underlineProperties = "{\"enable\":";
343           const std::string enabledStr = enabled ? "true" : "false";
344           underlineProperties += "\"" + enabledStr + "\",";
345
346           std::string colorStr;
347           Vector4ToColorString( color, colorStr );
348           underlineProperties += "\"color\":\"" + colorStr + "\",";
349
350           std::string heightStr;
351           FloatToString( height, heightStr );
352           underlineProperties += "\"height\":\"" + heightStr + "\"}";
353
354           value = underlineProperties;
355         }
356         else
357         {
358           Property::Map map;
359
360           const std::string enabledStr = enabled ? TRUE_TOKEN : FALSE_TOKEN;
361           map.Insert( ENABLE_KEY, enabledStr );
362
363           std::string colorStr;
364           Vector4ToColorString( color, colorStr );
365           map.Insert( COLOR_KEY, colorStr );
366
367           std::string heightStr;
368           FloatToString( height, heightStr );
369           map.Insert( HEIGHT_KEY, heightStr );
370
371           value = map;
372         }
373
374         break;
375       }
376       case EffectStyle::INPUT:
377       {
378         value = controller->GetInputUnderlineProperties();
379         break;
380       }
381     }
382   }
383 }
384
385 bool SetShadowProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type )
386 {
387   bool update = false;
388
389   if( controller )
390   {
391     switch( type )
392     {
393       case EffectStyle::DEFAULT:
394       {
395         const Property::Map& propertiesMap = value.Get<Property::Map>();
396
397         bool colorDefined = false;
398         Vector4 color;
399         bool offsetDefined = false;
400         Vector2 offset;
401         bool blurRadiusDefined = false;
402         float blurRadius;
403
404         bool empty = true;
405
406         if ( propertiesMap.Empty() )
407         {
408            // Map empty so check if a string provided
409            const std::string propertyString = value.Get<std::string>();
410
411            Property::Map parsedStringMap;
412            Text::ParsePropertyString( propertyString, parsedStringMap );
413
414            empty = ParseShadowProperties( parsedStringMap,
415                                           colorDefined,
416                                           color,
417                                           offsetDefined,
418                                           offset,
419                                           blurRadiusDefined,
420                                           blurRadius );
421
422            controller->ShadowSetByString( !empty );
423
424         }
425         else
426         {
427           empty = ParseShadowProperties( propertiesMap,
428                                          colorDefined,
429                                          color,
430                                          offsetDefined,
431                                          offset,
432                                          blurRadiusDefined,
433                                          blurRadius );
434
435           controller->ShadowSetByString( false );
436         }
437
438         if( !empty )
439         {
440           // Sets the default shadow values.
441           if( colorDefined && ( controller->GetShadowColor() != color ) )
442           {
443             controller->SetShadowColor( color );
444             update = true;
445           }
446
447           if( offsetDefined && ( controller->GetShadowOffset() != offset ) )
448           {
449             controller->SetShadowOffset( offset );
450             update = true;
451           }
452
453           if( blurRadiusDefined && ( controller->GetShadowBlurRadius() != blurRadius ) )
454           {
455             controller->SetShadowBlurRadius( blurRadius );
456             update = true;
457           }
458         }
459         else
460         {
461           // Disable shadow.
462           if( Vector2::ZERO != controller->GetShadowOffset() )
463           {
464             controller->SetShadowOffset( Vector2::ZERO );
465           }
466         }
467         break;
468       }
469       case EffectStyle::INPUT:
470       {
471         const std::string& shadowString = value.Get<std::string>();
472
473         controller->SetInputShadowProperties( shadowString );
474         break;
475       }
476     } // switch
477   } // if( controller )
478
479   return update;
480 }
481
482 void GetShadowProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type )
483 {
484   if( controller )
485   {
486     switch( type )
487     {
488       case EffectStyle::DEFAULT:
489       {
490         const Vector4& color = controller->GetShadowColor();
491         const Vector2& offset = controller->GetShadowOffset();
492         const float& blurRadius = controller->GetShadowBlurRadius();
493
494         if ( controller->IsShadowSetByString() )
495         {
496           std::string shadowProperties = "{";
497
498           std::string colorStr;
499           Vector4ToColorString( color, colorStr );
500           shadowProperties += "\"color\":\"" + colorStr + "\",";
501
502           std::string offsetStr;
503           Vector2ToString( offset, offsetStr );
504           shadowProperties += "\"offset\":\"" + offsetStr + "\",";
505
506           std::string blurRadiusStr;
507           FloatToString( blurRadius, blurRadiusStr );
508           shadowProperties += "\"blurRadius\":\"" + blurRadiusStr + "\"}";
509
510           value = shadowProperties;
511         }
512         else
513         {
514           Property::Map map;
515
516           map.Insert( COLOR_KEY, color );
517           map.Insert( OFFSET_KEY, offset );
518           map.Insert( BLUR_RADIUS_KEY, blurRadius );
519
520           value = map;
521         }
522         break;
523       }
524       case EffectStyle::INPUT:
525       {
526         value = controller->GetInputShadowProperties();
527         break;
528       }
529     }
530   }
531 }
532
533 bool SetEmbossProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type )
534 {
535   bool update = false;
536
537   if( controller )
538   {
539     const std::string properties = value.Get< std::string >();
540
541     switch( type )
542     {
543       case EffectStyle::DEFAULT:
544       {
545         // Stores the default emboss's properties string to be recovered by the GetEmbossProperties() function.
546         controller->SetDefaultEmbossProperties( properties );
547         break;
548       }
549       case EffectStyle::INPUT:
550       {
551         // Stores the input emboss's properties string to be recovered by the GetEmbossProperties() function.
552         controller->SetInputEmbossProperties( properties );
553         break;
554       }
555     }
556   }
557
558   return update;
559 }
560
561 void GetEmbossProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type )
562 {
563   if( controller )
564   {
565     switch( type )
566     {
567       case EffectStyle::DEFAULT:
568       {
569         value = controller->GetDefaultEmbossProperties();
570         break;
571       }
572       case EffectStyle::INPUT:
573       {
574         value = controller->GetInputEmbossProperties();
575         break;
576       }
577     }
578   }
579 }
580
581 bool SetOutlineProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type )
582 {
583   bool update = false;
584
585   if( controller )
586   {
587     switch( type )
588     {
589       case EffectStyle::DEFAULT:
590       {
591         const Property::Map& propertiesMap = value.Get<Property::Map>();
592
593         bool colorDefined = false;
594         Vector4 color;
595         bool widthDefined = false;
596         unsigned int width = 0u;
597
598         bool empty = true;
599
600         if ( propertiesMap.Empty() )
601         {
602            // Map empty so check if a string provided
603            // This is purely to maintain backward compatibility, but we don't parse the string to be a property map.
604            const std::string propertyString = value.Get<std::string>();
605
606            // Stores the default outline's properties string to be recovered by the GetOutlineProperties() function.
607            controller->SetDefaultOutlineProperties( propertyString );
608
609            controller->OutlineSetByString( true );
610         }
611         else
612         {
613            empty = ParseOutlineProperties( propertiesMap,
614                                            colorDefined,
615                                            color,
616                                            widthDefined,
617                                            width );
618
619            controller->OutlineSetByString( false );
620         }
621
622         if( !empty )
623         {
624           // Sets the default outline values.
625           if( colorDefined && ( controller->GetOutlineColor() != color ) )
626           {
627             controller->SetOutlineColor( color );
628             update = true;
629           }
630
631           if( widthDefined && ( controller->GetOutlineWidth() != width ) )
632           {
633             controller->SetOutlineWidth( width );
634             update = true;
635           }
636         }
637         else
638         {
639           // Disable outline
640           if( 0u != controller->GetOutlineWidth() )
641           {
642             controller->SetOutlineWidth( 0u );
643             update = true;
644           }
645         }
646         break;
647       }
648       case EffectStyle::INPUT:
649       {
650         const std::string& outlineProperties = value.Get<std::string>();
651
652         controller->SetInputOutlineProperties( outlineProperties );
653         break;
654       }
655     } // switch
656   } // if( controller )
657
658   return update;
659 }
660
661 void GetOutlineProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type )
662 {
663   if( controller )
664   {
665     switch( type )
666     {
667       case EffectStyle::DEFAULT:
668       {
669         if ( controller->IsOutlineSetByString() )
670         {
671           value = controller->GetDefaultOutlineProperties();
672           break;
673         }
674         else
675         {
676           const Vector4& color = controller->GetOutlineColor();
677           const unsigned int width = controller->GetOutlineWidth();
678
679           Property::Map map;
680           map.Insert( COLOR_KEY, color );
681           map.Insert( WIDTH_KEY, static_cast<int>( width ) );
682
683           value = map;
684
685           break;
686         }
687       }
688       case EffectStyle::INPUT:
689       {
690         value = controller->GetInputOutlineProperties();
691         break;
692       }
693     }
694   }
695 }
696
697 bool SetBackgroundProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type )
698 {
699   bool update = false;
700
701   if( controller )
702   {
703     switch( type )
704     {
705       case EffectStyle::DEFAULT:
706       {
707         const Property::Map& propertiesMap = value.Get<Property::Map>();
708
709         bool enabled = false;
710         bool colorDefined = false;
711         Vector4 color;
712
713         bool empty = true;
714
715         if ( !propertiesMap.Empty() )
716         {
717            empty = ParseBackgroundProperties( propertiesMap,
718                                               enabled,
719                                               colorDefined,
720                                               color );
721         }
722
723         if( !empty )
724         {
725           if( enabled != controller->IsBackgroundEnabled() )
726           {
727             controller->SetBackgroundEnabled( enabled );
728             update = true;
729           }
730
731           if( colorDefined && ( controller->GetBackgroundColor() != color ) )
732           {
733             controller->SetBackgroundColor( color );
734             update = true;
735           }
736         }
737         else
738         {
739           // Disable background.
740           if( controller->IsBackgroundEnabled() )
741           {
742             controller->SetBackgroundEnabled( false );
743             update = true;
744           }
745         }
746         break;
747       }
748       case EffectStyle::INPUT:
749       {
750         // Text background is not supported while inputting yet
751         break;
752       }
753     } // switch
754   } // if( controller )
755
756   return update;
757 }
758
759 void GetBackgroundProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type )
760 {
761   if( controller )
762   {
763     switch( type )
764     {
765       case EffectStyle::DEFAULT:
766       {
767         const bool enabled = controller->IsBackgroundEnabled();
768         const Vector4& color = controller->GetBackgroundColor();
769
770         Property::Map map;
771         map.Insert( ENABLE_KEY, enabled );
772         map.Insert( COLOR_KEY, color );
773
774         value = map;
775
776         break;
777
778       }
779       case EffectStyle::INPUT:
780       {
781         // Text background is not supported while inputting yet
782         break;
783       }
784     }
785   }
786 }
787
788
789 } // namespace Text
790
791 } // namespace Toolkit
792
793 } // namespace Dali