Soft shadow support in text visual
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-effects-style.cpp
1 /*
2  * Copyright (c) 2016 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       const std::string enableStr = valueGet.second.Get<std::string>();
129       enabled = Text::TokenComparison( TRUE_TOKEN, enableStr.c_str(), enableStr.size() );
130     }
131     else if( COLOR_KEY == valueGet.first.stringKey )
132     {
133       /// Color key.
134       colorDefined = true;
135
136       const std::string colorStr = valueGet.second.Get<std::string>();
137
138       Text::ColorStringToVector4( colorStr.c_str(), colorStr.size(), color );
139     }
140     else if( HEIGHT_KEY == valueGet.first.stringKey )
141     {
142       /// Height key.
143       heightDefined = true;
144
145       const std::string heightStr = valueGet.second.Get<std::string>();
146
147       height = StringToFloat( heightStr.c_str() );
148     }
149   }
150
151   return 0u == numberOfItems;
152 }
153
154 bool ParseOutlineProperties( const Property::Map& underlinePropertiesMap,
155                                bool& colorDefined,
156                                Vector4& color,
157                                bool& widthDefined,
158                                float& width )
159 {
160   const unsigned int numberOfItems = underlinePropertiesMap.Count();
161
162   // Parses and applies the style.
163   for( unsigned int index = 0u; index < numberOfItems; ++index )
164   {
165     const KeyValuePair& valueGet = underlinePropertiesMap.GetKeyValue( index );
166
167     if( COLOR_KEY == valueGet.first.stringKey )
168     {
169       /// Color key.
170       colorDefined = true;
171       color = valueGet.second.Get<Vector4>();
172     }
173     else if( WIDTH_KEY == valueGet.first.stringKey )
174     {
175       /// Width key.
176       widthDefined = true;
177       width = valueGet.second.Get<float>();
178     }
179   }
180
181   return 0u == numberOfItems;
182 }
183
184 bool SetUnderlineProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type )
185 {
186   bool update = false;
187
188   if( controller )
189   {
190     switch( type )
191     {
192       case EffectStyle::DEFAULT:
193       {
194         const Property::Map& propertiesMap = value.Get<Property::Map>();
195
196         bool enabled = false;
197         bool colorDefined = false;
198         Vector4 color;
199         bool heightDefined = false;
200         float height = 0.f;
201
202         bool empty = true;
203
204         if ( propertiesMap.Empty() )
205         {
206           // Map empty so check if a string provided
207           const std::string propertyString = value.Get<std::string>();
208
209           if ( !propertyString.empty() )
210           {
211             Property::Map parsedStringMap;
212             Text::ParsePropertyString( propertyString, parsedStringMap );
213
214             empty = ParseUnderlineProperties( parsedStringMap,
215                                               enabled,
216                                               colorDefined,
217                                               color,
218                                               heightDefined,
219                                               height );
220
221             controller->UnderlineSetByString( !empty);
222           }
223         }
224         else
225         {
226            empty = ParseUnderlineProperties( propertiesMap,
227                                              enabled,
228                                              colorDefined,
229                                              color,
230                                              heightDefined,
231                                              height );
232
233            controller->UnderlineSetByString( false );
234         }
235
236         if( !empty )
237         {
238           if( enabled != controller->IsUnderlineEnabled() )
239           {
240             controller->SetUnderlineEnabled( enabled );
241             update = true;
242           }
243
244           // Sets the default underline values.
245           if( colorDefined && ( controller->GetUnderlineColor() != color ) )
246           {
247             controller->SetUnderlineColor( color );
248             update = true;
249           }
250
251           if( heightDefined && ( fabsf( controller->GetUnderlineHeight() - height ) > Math::MACHINE_EPSILON_1000 ) )
252           {
253             controller->SetUnderlineHeight( height );
254             update = true;
255           }
256         }
257         else
258         {
259           // Disable underline.
260           if( controller->IsUnderlineEnabled() )
261           {
262             controller->SetUnderlineEnabled( false );
263             update = true;
264           }
265         }
266         break;
267       }
268       case EffectStyle::INPUT:
269       {
270         const std::string& underlineProperties = value.Get<std::string>();
271
272         controller->SetInputUnderlineProperties( underlineProperties );
273         break;
274       }
275     } // switch
276   } // if( controller )
277
278   return update;
279 }
280
281 void GetUnderlineProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type )
282 {
283   if( controller )
284   {
285     switch( type )
286     {
287       case EffectStyle::DEFAULT:
288       {
289         const bool enabled = controller->IsUnderlineEnabled();
290         const Vector4& color = controller->GetUnderlineColor();
291         const float height = controller->GetUnderlineHeight();
292
293         if ( controller->IsUnderlineSetByString() )
294         {
295           std::string underlineProperties = "{\"enable\":";
296           const std::string enabledStr = enabled ? "true" : "false";
297           underlineProperties += "\"" + enabledStr + "\",";
298
299           std::string colorStr;
300           Vector4ToColorString( color, colorStr );
301           underlineProperties += "\"color\":\"" + colorStr + "\",";
302
303           std::string heightStr;
304           FloatToString( height, heightStr );
305           underlineProperties += "\"height\":\"" + heightStr + "\"}";
306
307           value = underlineProperties;
308         }
309         else
310         {
311           Property::Map map;
312
313           const std::string enabledStr = enabled ? TRUE_TOKEN : FALSE_TOKEN;
314           map.Insert( ENABLE_KEY, enabledStr );
315
316           std::string colorStr;
317           Vector4ToColorString( color, colorStr );
318           map.Insert( COLOR_KEY, colorStr );
319
320           std::string heightStr;
321           FloatToString( height, heightStr );
322           map.Insert( HEIGHT_KEY, heightStr );
323
324           value = map;
325         }
326
327         break;
328       }
329       case EffectStyle::INPUT:
330       {
331         value = controller->GetInputUnderlineProperties();
332         break;
333       }
334     }
335   }
336 }
337
338 bool SetShadowProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type )
339 {
340   bool update = false;
341
342   if( controller )
343   {
344     switch( type )
345     {
346       case EffectStyle::DEFAULT:
347       {
348         const Property::Map& propertiesMap = value.Get<Property::Map>();
349
350         bool colorDefined = false;
351         Vector4 color;
352         bool offsetDefined = false;
353         Vector2 offset;
354         bool blurRadiusDefined = false;
355         float blurRadius;
356
357         bool empty = true;
358
359         if ( propertiesMap.Empty() )
360         {
361            // Map empty so check if a string provided
362            const std::string propertyString = value.Get<std::string>();
363
364            Property::Map parsedStringMap;
365            Text::ParsePropertyString( propertyString, parsedStringMap );
366
367            empty = ParseShadowProperties( parsedStringMap,
368                                           colorDefined,
369                                           color,
370                                           offsetDefined,
371                                           offset,
372                                           blurRadiusDefined,
373                                           blurRadius );
374
375            controller->ShadowSetByString( !empty );
376
377         }
378         else
379         {
380           empty = ParseShadowProperties( propertiesMap,
381                                          colorDefined,
382                                          color,
383                                          offsetDefined,
384                                          offset,
385                                          blurRadiusDefined,
386                                          blurRadius );
387
388           controller->ShadowSetByString( false );
389         }
390
391         if( !empty )
392         {
393           // Sets the default shadow values.
394           if( colorDefined && ( controller->GetShadowColor() != color ) )
395           {
396             controller->SetShadowColor( color );
397             update = true;
398           }
399
400           if( offsetDefined && ( controller->GetShadowOffset() != offset ) )
401           {
402             controller->SetShadowOffset( offset );
403             update = true;
404           }
405
406           if( blurRadiusDefined && ( controller->GetShadowBlurRadius() != blurRadius ) )
407           {
408             controller->SetShadowBlurRadius( blurRadius );
409             update = true;
410           }
411         }
412         else
413         {
414           // Disable shadow.
415           if( Vector2::ZERO != controller->GetShadowOffset() )
416           {
417             controller->SetShadowOffset( Vector2::ZERO );
418           }
419         }
420         break;
421       }
422       case EffectStyle::INPUT:
423       {
424         const std::string& shadowString = value.Get<std::string>();
425
426         controller->SetInputShadowProperties( shadowString );
427         break;
428       }
429     } // switch
430   } // if( controller )
431
432   return update;
433 }
434
435 void GetShadowProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type )
436 {
437   if( controller )
438   {
439     switch( type )
440     {
441       case EffectStyle::DEFAULT:
442       {
443         const Vector4& color = controller->GetShadowColor();
444         const Vector2& offset = controller->GetShadowOffset();
445         const float& blurRadius = controller->GetShadowBlurRadius();
446
447         if ( controller->IsShadowSetByString() )
448         {
449           std::string shadowProperties = "{";
450
451           std::string colorStr;
452           Vector4ToColorString( color, colorStr );
453           shadowProperties += "\"color\":\"" + colorStr + "\",";
454
455           std::string offsetStr;
456           Vector2ToString( offset, offsetStr );
457           shadowProperties += "\"offset\":\"" + offsetStr + "\",";
458
459           std::string blurRadiusStr;
460           FloatToString( blurRadius, blurRadiusStr );
461           shadowProperties += "\"blurRadius\":\"" + blurRadiusStr + "\"}";
462
463           value = shadowProperties;
464         }
465         else
466         {
467           Property::Map map;
468
469           map.Insert( COLOR_KEY, color );
470           map.Insert( OFFSET_KEY, offset );
471           map.Insert( BLUR_RADIUS_KEY, blurRadius );
472
473           value = map;
474         }
475         break;
476       }
477       case EffectStyle::INPUT:
478       {
479         value = controller->GetInputShadowProperties();
480         break;
481       }
482     }
483   }
484 }
485
486 bool SetEmbossProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type )
487 {
488   bool update = false;
489
490   if( controller )
491   {
492     const std::string properties = value.Get< std::string >();
493
494     switch( type )
495     {
496       case EffectStyle::DEFAULT:
497       {
498         // Stores the default emboss's properties string to be recovered by the GetEmbossProperties() function.
499         controller->SetDefaultEmbossProperties( properties );
500         break;
501       }
502       case EffectStyle::INPUT:
503       {
504         // Stores the input emboss's properties string to be recovered by the GetEmbossProperties() function.
505         controller->SetInputEmbossProperties( properties );
506         break;
507       }
508     }
509   }
510
511   return update;
512 }
513
514 void GetEmbossProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type )
515 {
516   if( controller )
517   {
518     switch( type )
519     {
520       case EffectStyle::DEFAULT:
521       {
522         value = controller->GetDefaultEmbossProperties();
523         break;
524       }
525       case EffectStyle::INPUT:
526       {
527         value = controller->GetInputEmbossProperties();
528         break;
529       }
530     }
531   }
532 }
533
534 bool SetOutlineProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type )
535 {
536   bool update = false;
537
538   if( controller )
539   {
540     switch( type )
541     {
542       case EffectStyle::DEFAULT:
543       {
544         const Property::Map& propertiesMap = value.Get<Property::Map>();
545
546         bool colorDefined = false;
547         Vector4 color;
548         bool widthDefined = false;
549         float width = 0.f;
550
551         bool empty = true;
552
553         if ( propertiesMap.Empty() )
554         {
555            // Map empty so check if a string provided
556            // This is purely to maintain backward compatibility, but we don't parse the string to be a property map.
557            const std::string propertyString = value.Get<std::string>();
558
559            // Stores the default outline's properties string to be recovered by the GetOutlineProperties() function.
560            controller->SetDefaultOutlineProperties( propertyString );
561
562            controller->OutlineSetByString( true );
563         }
564         else
565         {
566            empty = ParseOutlineProperties( propertiesMap,
567                                            colorDefined,
568                                            color,
569                                            widthDefined,
570                                            width );
571
572            controller->OutlineSetByString( false );
573         }
574
575         if( !empty )
576         {
577           // Sets the default outline values.
578           if( colorDefined && ( controller->GetOutlineColor() != color ) )
579           {
580             controller->SetOutlineColor( color );
581             update = true;
582           }
583
584           if( widthDefined && ( fabsf( controller->GetOutlineWidth() - width ) > Math::MACHINE_EPSILON_1000 ) )
585           {
586             controller->SetOutlineWidth( width );
587             update = true;
588           }
589         }
590         else
591         {
592           // Disable outline
593           if( fabsf( controller->GetOutlineWidth() ) > Math::MACHINE_EPSILON_1000 )
594           {
595             controller->SetOutlineWidth( 0.0f );
596             update = true;
597           }
598         }
599         break;
600       }
601       case EffectStyle::INPUT:
602       {
603         const std::string& outlineProperties = value.Get<std::string>();
604
605         controller->SetInputOutlineProperties( outlineProperties );
606         break;
607       }
608     } // switch
609   } // if( controller )
610
611   return update;
612 }
613
614 void GetOutlineProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type )
615 {
616   if( controller )
617   {
618     switch( type )
619     {
620       case EffectStyle::DEFAULT:
621       {
622         if ( controller->IsOutlineSetByString() )
623         {
624           value = controller->GetDefaultOutlineProperties();
625           break;
626         }
627         else
628         {
629           const Vector4& color = controller->GetOutlineColor();
630           const float width = controller->GetOutlineWidth();
631
632           Property::Map map;
633
634           std::string colorStr;
635           Vector4ToColorString( color, colorStr );
636           map.Insert( COLOR_KEY, colorStr );
637
638           std::string widthStr;
639           FloatToString( width, widthStr );
640           map.Insert( WIDTH_KEY, widthStr );
641
642           value = map;
643
644           break;
645         }
646       }
647       case EffectStyle::INPUT:
648       {
649         value = controller->GetInputOutlineProperties();
650         break;
651       }
652     }
653   }
654 }
655
656 } // namespace Text
657
658 } // namespace Toolkit
659
660 } // namespace Dali