2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include <dali/internal/event/actor-attachments/text-attachment-impl.h>
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>
34 TextAttachmentPtr TextAttachment::New( const SceneGraph::Node& parentNode, const Integration::TextArray& text, FontPointer font )
36 StagePtr stage = Stage::GetCurrent();
38 TextAttachmentPtr attachment( new TextAttachment( *stage ) );
40 // Second-phase construction
42 attachment->mFont = font;
43 attachment->mText = text;
45 // Transfer object ownership of scene-object to message
46 SceneGraph::TextAttachment* sceneObject = SceneGraph::TextAttachment::New();
48 AttachToNodeMessage( stage->GetUpdateManager(), parentNode, sceneObject );
50 // Keep raw pointer for message passing
51 attachment->mSceneObject = sceneObject;
53 attachment->CalculateWeightedSmoothing( TextStyle::DEFAULT_FONT_WEIGHT, TextStyle::DEFAULT_SMOOTH_EDGE_DISTANCE_FIELD ); // adjust smoothedge for font weight
58 TextAttachment::TextAttachment( Stage& stage )
59 : RenderableAttachment( stage ),
61 mTextRequestHelper( *this ),
65 mUnderlineChanged( true ),
66 mItalicsChanged( true ),
67 mTextureIdSet( false ),
69 mTextSize( Vector3::ZERO )
73 TextAttachment::~TextAttachment()
78 void TextAttachment::SetText( const Integration::TextArray& text )
80 // return if the text hasn't changed
81 if( ( text.Count() == mText.Count() ) &&
82 std::equal( mText.Begin(), mText.End(), text.Begin () ) )
87 // Cache for public getters
92 void TextAttachment::SetFont(Font& font)
98 // References the font
103 void TextAttachment::SetTextColor( const Vector4& color )
105 bool sendMessage( false );
107 Vector4 clampedColor = Clamp( color, 0.f, 1.f );
109 if( NULL == mTextColor )
111 // A color (different from default) has been set, so allocate storage for the text color
112 mTextColor = new Vector4( clampedColor );
117 if( *mTextColor != clampedColor )
119 // text color has changed
120 *mTextColor = clampedColor;
127 SetTextColorMessage( mStage->GetUpdateInterface(), *mSceneObject, clampedColor );
131 Vector4 TextAttachment::GetTextColor() const
135 if( NULL != mTextColor )
141 color = TextStyle::DEFAULT_TEXT_COLOR;
147 void TextAttachment::ResetTextColor()
149 if( NULL != mTextColor )
154 SetTextColorMessage( mStage->GetUpdateInterface(), *mSceneObject, TextStyle::DEFAULT_TEXT_COLOR );
158 void TextAttachment::SetWeight( TextStyle::Weight weight )
160 if( mStyle.IsFontWeightDefault() ||
161 ( mStyle.GetWeight() != weight ) )
163 mStyle.SetWeight( weight );
165 CalculateWeightedSmoothing( weight, mStyle.GetSmoothEdge() );
169 TextStyle::Weight TextAttachment::GetWeight() const
171 return mStyle.GetWeight();
174 void TextAttachment::ResetWeight()
176 if( !mStyle.IsFontWeightDefault() )
178 mStyle.Reset( TextStyle::WEIGHT );
180 CalculateWeightedSmoothing( TextStyle::DEFAULT_FONT_WEIGHT, mStyle.GetSmoothEdge() );
184 void TextAttachment::SetSmoothEdge( float smoothEdge )
186 if( mStyle.IsSmoothEdgeDefault() ||
187 ( fabsf( smoothEdge - mStyle.GetSmoothEdge() ) > Math::MACHINE_EPSILON_1000 ) )
189 mStyle.SetSmoothEdge( smoothEdge );
190 CalculateWeightedSmoothing( mStyle.GetWeight(), smoothEdge );
194 float TextAttachment::GetSmoothEdge() const
196 return mStyle.GetSmoothEdge();
199 void TextAttachment::ResetSmoothEdge()
201 if( !mStyle.IsSmoothEdgeDefault() )
203 mStyle.Reset( TextStyle::SMOOTH );
205 CalculateWeightedSmoothing( mStyle.GetWeight(), TextStyle::DEFAULT_SMOOTH_EDGE_DISTANCE_FIELD );
209 void TextAttachment::SetItalics( Radian angle )
211 if( mStyle.IsItalicsDefault() ||
212 ( Radian( mStyle.GetItalicsAngle() ) != angle ) )
214 mItalicsChanged = true;
216 const Radian radian0( 0.0f );
217 mStyle.SetItalics( ( radian0 != angle ), Degree( angle ) );
221 bool TextAttachment::GetItalics() const
223 return mStyle.IsItalicsEnabled();
226 Radian TextAttachment::GetItalicsAngle() const
228 return Radian( mStyle.GetItalicsAngle() );
231 void TextAttachment::ResetItalics()
233 if( !mStyle.IsItalicsDefault() )
235 mStyle.Reset( TextStyle::ITALICS );
237 mItalicsChanged = true;
241 void TextAttachment::SetUnderline( bool enable, float thickness, float position )
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 ) )
248 mUnderlineChanged = true;
250 mStyle.SetUnderline( enable, thickness, position );
254 bool TextAttachment::GetUnderline() const
256 return mStyle.IsUnderlineEnabled();
259 float TextAttachment::GetUnderlineThickness() const
261 return mStyle.GetUnderlineThickness();
264 float TextAttachment::GetUnderlinePosition() const
266 return mStyle.GetUnderlinePosition();
269 void TextAttachment::ResetUnderline()
271 if( !mStyle.IsUnderlineDefault() )
273 mStyle.Reset( TextStyle::UNDERLINE );
275 mUnderlineChanged = true;
279 void TextAttachment::SetOutline( bool enable, const Vector4& color, const Vector2& thickness )
281 if( mStyle.IsOutlineDefault() ||
282 ( mStyle.IsOutlineEnabled() != enable ) ||
283 ( mStyle.GetOutlineColor() != color ) ||
284 ( mStyle.GetOutlineThickness() != thickness ) )
286 mStyle.SetOutline( enable, color, thickness );
288 SetOutlineMessage( mStage->GetUpdateInterface(), *mSceneObject, enable, color, thickness );
292 bool TextAttachment::GetOutline() const
294 return mStyle.IsOutlineEnabled();
297 void TextAttachment::GetOutlineParams( Vector4& color, Vector2& thickness ) const
299 color = mStyle.GetOutlineColor();
300 thickness = mStyle.GetOutlineThickness();
303 void TextAttachment::ResetOutline()
305 if( !mStyle.IsOutlineDefault() )
307 mStyle.Reset( TextStyle::OUTLINE );
309 SetOutlineMessage( mStage->GetUpdateInterface(), *mSceneObject, false, TextStyle::DEFAULT_OUTLINE_COLOR, TextStyle::DEFAULT_OUTLINE_THICKNESS );
313 void TextAttachment::SetGlow( bool enable, const Vector4& color, float intensity )
315 if( mStyle.IsGlowDefault() ||
316 ( mStyle.IsGlowEnabled() != enable ) ||
317 ( mStyle.GetGlowColor() != color ) ||
318 ( fabsf( mStyle.GetGlowIntensity() - intensity ) > Math::MACHINE_EPSILON_1000 ) )
320 mStyle.SetGlow( enable, color, intensity );
322 SetGlowMessage( mStage->GetUpdateInterface(), *mSceneObject, enable, color, intensity );
326 bool TextAttachment::GetGlow() const
328 return mStyle.IsGlowEnabled();
331 void TextAttachment::GetGlowParams( Vector4& color, float& intensity) const
333 color = mStyle.GetGlowColor();
334 intensity = mStyle.GetGlowIntensity();
337 void TextAttachment::ResetGlow()
339 if( !mStyle.IsGlowDefault() )
341 mStyle.Reset( TextStyle::GLOW );
343 SetGlowMessage( mStage->GetUpdateInterface(), *mSceneObject, false, TextStyle::DEFAULT_GLOW_COLOR, TextStyle::DEFAULT_GLOW_INTENSITY );
347 void TextAttachment::SetShadow( bool enable, const Vector4& color, const Vector2& offset, float size )
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 ) )
355 mStyle.SetShadow( enable, color, offset, size );
357 const float unitPointSize( 64.0f );
358 const float unitsToPixels( mFont->GetUnitsToPixels());
359 const float fontPointSize( mFont->GetPointSize() );
361 float shadowSize( (size * 0.25f) / unitsToPixels );
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 );
372 bool TextAttachment::GetShadow() const
374 return mStyle.IsShadowEnabled();
377 void TextAttachment::GetShadowParams( Vector4& color, Vector2& offset, float& size ) const
379 color = mStyle.GetShadowColor();
380 offset = mStyle.GetShadowOffset();
381 size = mStyle.GetShadowSize();
384 void TextAttachment::ResetShadow()
386 if( !mStyle.IsShadowDefault() )
388 mStyle.Reset( TextStyle::SHADOW );
390 const float unitPointSize( 64.0f );
391 const float unitsToPixels( mFont->GetUnitsToPixels());
392 const float fontPointSize( mFont->GetPointSize() );
394 float shadowSize( ( TextStyle::DEFAULT_SHADOW_SIZE * 0.25f ) / unitsToPixels );
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 );
405 void TextAttachment::SetGradient( const Vector4& color, const Vector2& startPoint, const Vector2& endPoint )
407 if( mStyle.IsGradientDefault() ||
408 ( mStyle.GetGradientColor() != color ) ||
409 ( mStyle.GetGradientStartPoint() != startPoint ) ||
410 ( mStyle.GetGradientEndPoint() != endPoint ) )
412 mStyle.SetGradient( true, color, startPoint, endPoint );
413 SetGradientMessage( mStage->GetUpdateInterface(), *mSceneObject, color, startPoint, endPoint );
417 const Vector4& TextAttachment::GetGradientColor() const
419 return mStyle.GetGradientColor();
422 const Vector2& TextAttachment::GetGradientStartPoint() const
424 return mStyle.GetGradientStartPoint();
427 const Vector2& TextAttachment::GetGradientEndPoint() const
429 return mStyle.GetGradientEndPoint();
432 void TextAttachment::ResetGradient()
434 if( !mStyle.IsGradientDefault() )
436 mStyle.Reset( TextStyle::GRADIENT );
438 SetGradientMessage( mStage->GetUpdateInterface(), *mSceneObject, TextStyle::DEFAULT_GRADIENT_COLOR, TextStyle::DEFAULT_GRADIENT_START_POINT, TextStyle::DEFAULT_GRADIENT_END_POINT );
442 void TextAttachment::GetTextStyle( TextStyle& style ) const
444 style.Copy( mStyle );
446 // Font name, font style, font point size and color are not store inside the mStyle, so they need to be copied after.
448 if( NULL != mTextColor )
450 style.SetTextColor( *mTextColor );
453 if( !mFont->IsDefaultSystemFont() )
455 style.SetFontName( mFont->GetName() );
456 style.SetFontStyle( mFont->GetStyle() );
459 if( !mFont->IsDefaultSystemSize() )
461 style.SetFontPointSize( PointSize( mFont->GetPointSize() ) );
465 Vector3 TextAttachment::MeasureText() const
467 return mFont->MeasureText( mText );
470 void TextAttachment::TextChanged()
472 DALI_LOG_INFO(Debug::Filter::gResource, Debug::Verbose, "TextAttachment::TextChanged() TextModified:%s TextEmpty:%s\n", IsTextModified()?"Y":"N", ( 0u == mText.Count() )?"Y":"N");
474 if( !IsTextModified() )
479 // if the underline or italics have changed we trigger a text request
480 if( mUnderlineChanged || mItalicsChanged )
485 TextFormat format( mStyle.IsUnderlineEnabled(),
486 mStyle.IsItalicsEnabled(),
487 Radian( mStyle.GetItalicsAngle() ),
488 mFont->GetPointSize(),
489 mStyle.GetUnderlineThickness(),
490 mStyle.GetUnderlinePosition() );
492 if ( mTextChanged && mFontChanged )
494 mVertexBuffer = mTextRequestHelper.SetTextAndFont( mText, mFont, format );
496 else if( mTextChanged )
498 mVertexBuffer = mTextRequestHelper.SetText( mText, format );
500 else if ( mFontChanged )
502 mVertexBuffer = mTextRequestHelper.SetFont( mFont, format );
505 // sceneObject is being used in a separate thread; queue a message to set
508 mTextChanged = false;
509 mFontChanged = false;
510 mUnderlineChanged = false;
511 mItalicsChanged = false;
514 bool TextAttachment::IsTextLoaded()
516 bool loaded = mTextRequestHelper.IsTextLoaded();
517 if( loaded && !mTextureIdSet )
519 mTextureIdSet = true;
525 void TextAttachment::CalculateWeightedSmoothing( TextStyle::Weight weight, float smoothEdge )
527 float weightedSmoothing = smoothEdge;
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 );
537 SetSmoothEdgeMessage( mStage->GetUpdateInterface(), *mSceneObject, weightedSmoothing );
540 void TextAttachment::TextureResized( const TextureIdList& oldTextureIds, unsigned int newTextureId )
542 bool matched( false );
544 // check if resized texture is the one we are using
545 for( std::size_t i = 0, count = oldTextureIds.size(); i < count; ++i )
547 if( oldTextureIds[i] == mTextureId )
554 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "TextAttachment::TextureResized() Current texture: %d New texture: %d\n", mTextureId, newTextureId);
556 if( newTextureId == mTextureId )
558 // nothing has changed, we are using the new texture already
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
566 mTextRequestHelper.TextureChanged( mTextureId, newTextureId );
567 mTextureId = newTextureId;
574 void TextAttachment::TextureSplit( FontId fontId, const TextureIdList& oldTextureIds, unsigned int newTextureId )
576 // currently not supported.
577 // the implementation will be if( fontId == mFont->GetId() ) TextureResized(..);
580 bool TextAttachment::IsTextModified()
582 return ( mTextChanged || mFontChanged || mUnderlineChanged || mItalicsChanged );
585 void TextAttachment::OnStageConnection2()
590 void TextAttachment::OnStageDisconnection2()
595 const SceneGraph::RenderableAttachment& TextAttachment::GetSceneObject() const
597 DALI_ASSERT_DEBUG( mSceneObject != NULL );
598 return *mSceneObject;
601 void TextAttachment::SetTextChanges()
605 // record the natural size of the text
606 mTextSize = mVertexBuffer->mVertexMax;
608 // remember the texture id, so we can detect atlas resizes / splits
609 mTextureId = mVertexBuffer->mTextureId;
611 EventToUpdate& eventToUpdate( mStage->GetUpdateInterface() );
612 const SceneGraph::TextAttachment& attachment( *mSceneObject );
614 if( mTextChanged || mFontChanged )
616 DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "TextAttachment::SetTextChanges() Sending VertexBuffer to attachment:%p textureId:%d\n", &attachment, mVertexBuffer->mTextureId);
618 // release the vertex buffer to pass ownership to the scene-graph-text-attachment
619 SetTextVertexBufferMessage( eventToUpdate, attachment, *mVertexBuffer.Release() );
623 SetTextFontSizeMessage( eventToUpdate, attachment, mFont->GetPixelSize() );
629 } // namespace Internal