(Properties) Added ability to add non-animatable event-thread only properties via...
[platform/core/uifw/dali-core.git] / dali / internal / event / actor-attachments / text-attachment-impl.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 // CLASS HEADER
18
19 #include <dali/internal/event/actor-attachments/text-attachment-impl.h>
20
21 // INTERNAL INCLUDES
22
23 #include <dali/public-api/common/dali-common.h>
24 #include <dali/internal/update/node-attachments/scene-graph-text-attachment.h>
25 #include <dali/internal/event/common/stage-impl.h>
26 #include <dali/internal/common/text-parameters.h>
27
28
29 namespace Dali
30 {
31
32 namespace Internal
33 {
34
35 TextAttachmentPtr TextAttachment::New( const SceneGraph::Node& parentNode, const TextArray& text, FontPointer font, bool isLeftToRight )
36 {
37   StagePtr stage = Stage::GetCurrent();
38
39   TextAttachmentPtr attachment( new TextAttachment( *stage ) );
40
41   // Second-phase construction
42
43   attachment->mFont = font;
44   attachment->mText = text;
45   attachment->mIsLeftToRight = isLeftToRight;
46
47   // Transfer object ownership of scene-object to message
48   SceneGraph::TextAttachment* sceneObject = SceneGraph::TextAttachment::New();
49
50   AttachToNodeMessage( stage->GetUpdateManager(), parentNode, sceneObject );
51
52   // Keep raw pointer for message passing
53   attachment->mSceneObject = sceneObject;
54
55   attachment->SetSmoothEdge(attachment->mSmoothing);      // adjust smoothedge for font weight
56
57   return attachment;
58 }
59
60 TextAttachment::TextAttachment( Stage& stage )
61 : RenderableAttachment( stage ),
62   mTextRequestHelper( *this ),
63   mUnderlineEnabled( false ),
64   mIsLeftToRight(true),
65   mTextChanged( true ),
66   mFontChanged( true ),
67   mUnderlineChanged( true ),
68   mItalicsChanged( true ),
69   mItalicsEnabled( false ),
70   mTextureIdSet( false ),
71   mTextureId(0),
72   mSmoothing(Dali::TextStyle::DEFAULT_SMOOTH_EDGE_DISTANCE_FIELD),
73   mItalicsAngle( Radian(0.0f) ),
74   mUnderlineThickness( 0.f ),
75   mUnderlinePosition( 0.f ),
76   mTextSize( Vector3::ZERO ),
77   mWeight( TextStyle::REGULAR ),
78   mTextColor( NULL )
79 {
80 }
81
82 TextAttachment::~TextAttachment()
83 {
84   delete mTextColor;
85 }
86
87 void TextAttachment::SetText(const TextArray& text)
88 {
89   // return if the text hasn't changed
90   if( (text.size() == mText.size() ) &&
91       std::equal(mText.begin(), mText.end(), text.begin ()) )
92   {
93     return;
94   }
95
96   // Cache for public getters
97   mText = text;
98   mTextChanged = true;
99 }
100
101 void TextAttachment::SetFont(Font& font)
102 {
103   if( font == *mFont )
104   {
105     return;
106   }
107   // References the font
108   mFont = &font;
109   mFontChanged = true;
110 }
111
112 void TextAttachment::SetGradientColor( const Vector4& color )
113 {
114   AllocateTextParameters();
115
116   if( mTextParameters->mGradientColor != color )
117   {
118     mTextParameters->mGradientColor = color;
119
120     SetGradientColorMessage( mStage->GetUpdateInterface(), *mSceneObject, color );
121   }
122 }
123
124 const Vector4& TextAttachment::GetGradientColor() const
125 {
126   if( mTextParameters )
127   {
128     return mTextParameters->mGradientColor;
129   }
130   else
131   {
132     return TextStyle::DEFAULT_GRADIENT_COLOR;
133   }
134 }
135
136 void TextAttachment::SetGradientStartPoint( const Vector2& position )
137 {
138   AllocateTextParameters();
139
140   if( mTextParameters->mGradientStartPoint != position )
141   {
142     mTextParameters->mGradientStartPoint = position;
143
144     SetGradientStartPointMessage( mStage->GetUpdateInterface(), *mSceneObject, position );
145   }
146 }
147
148 const Vector2& TextAttachment::GetGradientStartPoint() const
149 {
150   if( mTextParameters )
151   {
152     return mTextParameters->mGradientStartPoint;
153   }
154   else
155   {
156     return TextStyle::DEFAULT_GRADIENT_START_POINT;
157   }
158 }
159
160 void TextAttachment::SetGradientEndPoint( const Vector2& position )
161 {
162   AllocateTextParameters();
163
164   if( mTextParameters->mGradientEndPoint != position )
165   {
166     mTextParameters->mGradientEndPoint = position;
167
168     SetGradientEndPointMessage( mStage->GetUpdateInterface(), *mSceneObject, position );
169   }
170 }
171
172 const Vector2& TextAttachment::GetGradientEndPoint() const
173 {
174   if( mTextParameters )
175   {
176     return mTextParameters->mGradientEndPoint;
177   }
178   else
179   {
180     return TextStyle::DEFAULT_GRADIENT_END_POINT;
181   }
182 }
183
184 void TextAttachment::SetSmoothEdge( float smoothEdge )
185 {
186   mSmoothing = smoothEdge;
187   float weightedSmoothing = smoothEdge;
188
189   // Adjust edge smoothing for font weight
190   const float BOLDER = 0.20f;
191   const float LIGHTER = 1.65f;
192   const float offset = 1.0f - ( ( 1.0f / Dali::TextStyle::EXTRABLACK ) * mWeight );
193   weightedSmoothing *= BOLDER + ( ( LIGHTER - BOLDER ) * offset );
194   weightedSmoothing = std::max( 0.0f, weightedSmoothing );
195   weightedSmoothing = std::min( 1.0f, weightedSmoothing );
196
197   SetSmoothEdgeMessage( mStage->GetUpdateInterface(), *mSceneObject, weightedSmoothing );
198 }
199
200 float TextAttachment::GetSmoothEdge() const
201 {
202   return mSmoothing;
203 }
204
205 void TextAttachment::SetOutline( bool enable, const Vector4& color, const Vector2& thickness )
206 {
207   AllocateTextParameters();
208
209   if (enable != mTextParameters->mOutlineEnabled || color != mTextParameters->mOutlineColor || thickness != mTextParameters->mOutline)
210   {
211     mTextParameters->SetOutline( enable, color, thickness );
212
213     SetOutlineMessage( mStage->GetUpdateInterface(), *mSceneObject, enable, color, thickness );
214   }
215 }
216
217 bool TextAttachment::GetOutline() const
218 {
219   bool result( false );
220
221   if( mTextParameters )
222   {
223     result = mTextParameters->mOutlineEnabled;
224   }
225
226   return result;
227 }
228
229 void TextAttachment::GetOutlineParams( Vector4& color, Vector2& thickness ) const
230 {
231   if( mTextParameters )
232   {
233     color = mTextParameters->mOutlineColor;
234     thickness = mTextParameters->mOutline;
235   }
236   else
237   {
238     color = TextStyle::DEFAULT_OUTLINE_COLOR;
239     thickness = TextStyle::DEFAULT_OUTLINE_THICKNESS;
240   }
241 }
242
243 void TextAttachment::SetGlow( bool enable, const Vector4& color, float intensity )
244 {
245   AllocateTextParameters();
246
247   if (enable != mTextParameters->mGlowEnabled || color != mTextParameters->mGlowColor || fabsf(intensity - mTextParameters->mGlow) > Math::MACHINE_EPSILON_1000)
248   {
249     mTextParameters->SetGlow( enable, color, intensity );
250
251     SetGlowMessage( mStage->GetUpdateInterface(), *mSceneObject, enable, color, intensity );
252   }
253 }
254
255 bool TextAttachment::GetGlow() const
256 {
257   bool result( false );
258
259   if( mTextParameters )
260   {
261     result = mTextParameters->mGlowEnabled;
262   }
263
264   return result;
265 }
266
267 void TextAttachment::GetGlowParams( Vector4& color, float&  intensity) const
268 {
269   if( mTextParameters )
270   {
271     color = mTextParameters->mGlowColor;
272     intensity = mTextParameters->mGlow;
273   }
274   else
275   {
276     color = TextStyle::DEFAULT_GLOW_COLOR;
277     intensity = TextStyle::DEFAULT_GLOW_INTENSITY;
278   }
279 }
280
281 void TextAttachment::SetShadow(bool enable, const Vector4& color, const Vector2& offset, const float size)
282 {
283   AllocateTextParameters();
284
285   if (enable != mTextParameters->mDropShadowEnabled ||
286       color != mTextParameters->mDropShadowColor ||
287       offset != mTextParameters->mDropShadow ||
288       fabsf(size - mTextParameters->mDropShadowSize) > Math::MACHINE_EPSILON_1 )
289   {
290     mTextParameters->SetShadow( enable, color, offset, size );
291
292     const float unitPointSize( 64.0f );
293     const float unitsToPixels( mFont->GetUnitsToPixels());
294
295     float shadowSize( (size * 0.25f) / unitsToPixels );
296
297     Vector2 shadowOffset( offset * ( unitPointSize / mFont->GetPointSize() ) );
298
299     SetDropShadowMessage( mStage->GetUpdateInterface(), *mSceneObject, enable, color, shadowOffset, shadowSize );
300   }
301 }
302
303 bool TextAttachment::GetShadow() const
304 {
305   bool result( false );
306
307   if( mTextParameters )
308   {
309     result = mTextParameters->mDropShadowEnabled;
310   }
311
312   return result;
313 }
314
315 void TextAttachment::GetShadowParams( Vector4& color, Vector2& offset, float& size ) const
316 {
317   if( mTextParameters )
318   {
319     color = mTextParameters->mDropShadowColor;
320     offset = mTextParameters->mDropShadow;
321     size = mTextParameters->mDropShadowSize;
322   }
323   else
324   {
325     color = TextStyle::DEFAULT_SHADOW_COLOR;
326     offset = TextStyle::DEFAULT_SHADOW_OFFSET;
327     size = TextStyle::DEFAULT_SHADOW_SIZE;
328   }
329 }
330
331 void TextAttachment::SetTextColor(const Vector4& color)
332 {
333   bool sendMessage( false );
334
335   if( NULL == mTextColor )
336   {
337     if( color != TextStyle::DEFAULT_TEXT_COLOR )
338     {
339       // A color (different from default) has been set, so allocate storage for the text color
340       mTextColor = new Vector4( color );
341       sendMessage = true;
342     }
343   }
344   else
345   {
346     if( *mTextColor != color )
347     {
348       // text color has changed
349       *mTextColor = color;
350       sendMessage = true;
351     }
352   }
353
354   if( sendMessage )
355   {
356     SetTextColorMessage( mStage->GetUpdateInterface(), *mSceneObject, color );
357   }
358 }
359
360 Vector4 TextAttachment::GetTextColor() const
361 {
362   Vector4 color;
363
364   if( NULL != mTextColor )
365   {
366     color = *mTextColor;
367   }
368   else
369   {
370     color = TextStyle::DEFAULT_TEXT_COLOR;
371   }
372
373   return color;
374 }
375
376 void TextAttachment::SetItalics( const Radian& angle )
377 {
378   if ( angle != mItalicsAngle )
379   {
380     mItalicsChanged = true;
381     mItalicsAngle = angle;
382   }
383   Radian radian0( 0.0f );
384
385   if( radian0 != mItalicsAngle )
386   {
387     mItalicsEnabled = true;
388   }
389   else
390   {
391     mItalicsEnabled = false;
392   }
393 }
394
395 const Radian& TextAttachment::GetItalics() const
396 {
397   return mItalicsAngle;
398 }
399
400 void TextAttachment::SetUnderline( bool enable, float thickness, float position )
401 {
402   if ( enable != mUnderlineEnabled )
403   {
404     mUnderlineEnabled = enable;
405     mUnderlineChanged = true;
406   }
407
408   if( mUnderlineEnabled )
409   {
410     if( fabsf( thickness - mUnderlineThickness ) > Math::MACHINE_EPSILON_0 )
411     {
412       mUnderlineThickness = thickness;
413       mUnderlineChanged = true;
414     }
415
416     if( fabsf( position - mUnderlinePosition ) > Math::MACHINE_EPSILON_0 )
417     {
418       mUnderlinePosition = position;
419       mUnderlineChanged = true;
420     }
421   }
422 }
423
424 bool TextAttachment::GetUnderline() const
425 {
426   return mUnderlineEnabled;
427 }
428
429 float TextAttachment::GetUnderlineThickness() const
430 {
431   return mUnderlineThickness;
432 }
433
434 float TextAttachment::GetUnderlinePosition() const
435 {
436   return mUnderlinePosition;
437 }
438
439 void TextAttachment::SetWeight( TextStyle::Weight weight )
440 {
441   mWeight = weight;
442
443   SetSmoothEdge(mSmoothing);
444 }
445
446 TextStyle::Weight TextAttachment::GetWeight() const
447 {
448   return mWeight;
449 }
450
451 Vector3 TextAttachment::MeasureText() const
452 {
453   return mFont->MeasureText( mText );
454 }
455
456 void TextAttachment::TextChanged()
457 {
458   DALI_LOG_INFO(Debug::Filter::gResource, Debug::Verbose, "TextAttachment::TextChanged()  TextModified:%s  TextEmpty:%s\n", IsTextModified()?"Y":"N", mText.empty()?"Y":"N");
459
460   if( !IsTextModified() )
461   {
462     return;
463   }
464
465   // if the underline or italics have changed we trigger a text request
466   if( mUnderlineChanged || mItalicsChanged )
467   {
468     mTextChanged = true;
469   }
470
471   TextFormat format( mUnderlineEnabled, mIsLeftToRight, mItalicsEnabled, mItalicsAngle, mFont->GetPointSize(), mUnderlineThickness, mUnderlinePosition );
472
473   if ( mTextChanged && mFontChanged )
474   {
475     mVertexBuffer = mTextRequestHelper.SetTextAndFont( mText, mFont, format );
476   }
477   else if( mTextChanged )
478   {
479     mVertexBuffer = mTextRequestHelper.SetText( mText, format );
480   }
481   else if ( mFontChanged )
482   {
483     mVertexBuffer = mTextRequestHelper.SetFont( mFont, format );
484   }
485
486   // sceneObject is being used in a separate thread; queue a message to set
487   SetTextChanges();
488
489   mTextChanged = false;
490   mFontChanged = false;
491   mUnderlineChanged = false;
492   mItalicsChanged = false;
493 }
494
495 bool TextAttachment::IsTextLoaded()
496 {
497   bool loaded = mTextRequestHelper.IsTextLoaded();
498   if( loaded && !mTextureIdSet )
499   {
500     mTextureIdSet = true;
501   }
502
503   return loaded;
504 }
505
506 void TextAttachment::TextureResized( const TextureIdList& oldTextureIds, unsigned int newTextureId )
507 {
508   bool matched( false );
509
510   // check if resized texture is the one we are using
511   for( std::size_t i = 0, count = oldTextureIds.size(); i < count; ++i )
512   {
513     if( oldTextureIds[i] == mTextureId )
514     {
515       matched = true;
516       break;
517     }
518   }
519
520   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "TextAttachment::TextureResized() Current texture: %d  New texture: %d\n", mTextureId, newTextureId);
521
522   if( newTextureId == mTextureId )
523   {
524     // nothing has changed, we are using the new texture already
525     return;
526   }
527
528   // the texture we're using has been replaced
529   // re-request the text vertex information and update the texture id on the scene graph text attachment
530   if( matched )
531   {
532     mTextRequestHelper.TextureChanged( mTextureId, newTextureId );
533     mTextureId = newTextureId;
534     mTextChanged = true;
535     TextChanged();
536     return;
537   }
538 }
539
540 void TextAttachment::TextureSplit( FontId fontId, const TextureIdList& oldTextureIds, unsigned int newTextureId )
541 {
542   // currently not supported.
543   // the implementation will be  if( fontId == mFont->GetId() ) TextureResized(..);
544 }
545
546 bool TextAttachment::IsTextModified()
547 {
548   return ( mTextChanged || mFontChanged || mUnderlineChanged || mItalicsChanged );
549 }
550
551 void TextAttachment::AllocateTextParameters()
552 {
553   if( !mTextParameters )
554   {
555     mTextParameters = new TextParameters;
556   }
557 }
558
559 void TextAttachment::OnStageConnection2()
560 {
561   // do nothing
562 }
563
564 void TextAttachment::OnStageDisconnection2()
565 {
566   // do nothing
567 }
568
569 const SceneGraph::RenderableAttachment& TextAttachment::GetSceneObject() const
570 {
571   DALI_ASSERT_DEBUG( mSceneObject != NULL );
572   return *mSceneObject;
573 }
574
575 void TextAttachment::SetTextChanges()
576 {
577   // record the natural size of the text
578   mTextSize = mVertexBuffer->mVertexMax;
579
580   // remember the texture id, so we can detect atlas resizes / splits
581   mTextureId = mVertexBuffer->mTextureId;
582
583   EventToUpdate& eventToUpdate(  mStage->GetUpdateInterface() );
584   const SceneGraph::TextAttachment& attachment( *mSceneObject );
585
586   if( mTextChanged  || mFontChanged )
587   {
588     DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "TextAttachment::SetTextChanges() Sending VertexBuffer to attachment:%p  textureId:%d\n", &attachment, mVertexBuffer->mTextureId);
589
590     // release the vertex buffer to pass  ownership to the scene-graph-text-attachment
591     SetTextVertexBufferMessage( eventToUpdate, attachment, *mVertexBuffer.Release() );
592   }
593 }
594
595
596 } // namespace Internal
597
598 } // namespace Dali