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