Fix for TextView's snapshot mode
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / controls / text-view / text-view-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 #include "text-view-impl.h"
20
21 // INTERNAL INCLUDES
22 #include "split-by-new-line-char-policies.h"
23 #include "split-by-word-policies.h"
24 #include "split-by-char-policies.h"
25 #include "text-view-processor.h"
26 #include "text-view-word-processor.h"
27 #include "relayout-utilities.h"
28 #include "text-view-processor-dbg.h"
29
30 namespace Dali
31 {
32
33 namespace Toolkit
34 {
35
36 const Property::Index TextView::PROPERTY_MARKUP_ENABLED( Internal::TextView::TEXTVIEW_PROPERTY_START_INDEX );
37 const Property::Index TextView::PROPERTY_TEXT( Internal::TextView::TEXTVIEW_PROPERTY_START_INDEX + 1 );
38 const Property::Index TextView::PROPERTY_MULTILINE_POLICY( Internal::TextView::TEXTVIEW_PROPERTY_START_INDEX + 2 );
39 const Property::Index TextView::PROPERTY_WIDTH_EXCEED_POLICY( Internal::TextView::TEXTVIEW_PROPERTY_START_INDEX + 3 );
40 const Property::Index TextView::PROPERTY_HEIGHT_EXCEED_POLICY( Internal::TextView::TEXTVIEW_PROPERTY_START_INDEX + 4 );
41 const Property::Index TextView::PROPERTY_LINE_JUSTIFICATION( Internal::TextView::TEXTVIEW_PROPERTY_START_INDEX + 5 );
42 const Property::Index TextView::PROPERTY_FADE_BOUNDARY( Internal::TextView::TEXTVIEW_PROPERTY_START_INDEX + 6 );
43 const Property::Index TextView::PROPERTY_LINE_HEIGHT_OFFSET( Internal::TextView::TEXTVIEW_PROPERTY_START_INDEX + 7 );
44 const Property::Index TextView::PROPERTY_HORIZONTAL_ALIGNMENT( Internal::TextView::TEXTVIEW_PROPERTY_START_INDEX + 8 );
45 const Property::Index TextView::PROPERTY_VERTICAL_ALIGNMENT( Internal::TextView::TEXTVIEW_PROPERTY_START_INDEX + 9 );
46
47 namespace Internal
48 {
49
50 namespace
51 {
52
53 const char* MULTILINE_POLICY_NAME[] = {"SplitByNewLineChar", "SplitByWord", "SplitByChar"};
54 const char* EXCEED_POLICY_NAME[] = {"Original", "Truncate", "Fade", "Split","ShrinkToFit","EllipsizeEnd"};
55 const char* LINE_JUSTIFICATION_NAME[] = {"Left","Center","Right","Justified"};
56
57 // Currently on desktop machines 2k x 2k is the maximum frame buffer size, on target is 4k x 4k.
58 const float MAX_OFFSCREEN_RENDERING_SIZE = 2048.f;
59
60 //Type Registration
61 BaseHandle Create()
62 {
63   return Toolkit::TextView::New();
64 }
65
66 TypeRegistration typeRegistration( typeid(Toolkit::TextView), typeid(Toolkit::Control), Create );
67
68 SignalConnectorType signalConnector1( typeRegistration, Toolkit::TextView::SIGNAL_TEXT_SCROLLED , &TextView::DoConnectSignal );
69
70 PropertyRegistration property1( typeRegistration,  "markup-enabled",       Toolkit::TextView::PROPERTY_MARKUP_ENABLED,       Property::BOOLEAN, &TextView::SetProperty, &TextView::GetProperty );
71 PropertyRegistration property2( typeRegistration,  "text",                 Toolkit::TextView::PROPERTY_TEXT,                 Property::STRING,  &TextView::SetProperty, &TextView::GetProperty );
72 PropertyRegistration property3( typeRegistration,  "multiline-policy",     Toolkit::TextView::PROPERTY_MULTILINE_POLICY,     Property::STRING,  &TextView::SetProperty, &TextView::GetProperty );
73 PropertyRegistration property4( typeRegistration,  "width-exceed-policy",  Toolkit::TextView::PROPERTY_WIDTH_EXCEED_POLICY,  Property::STRING,  &TextView::SetProperty, &TextView::GetProperty );
74 PropertyRegistration property5( typeRegistration,  "height-exceed-policy", Toolkit::TextView::PROPERTY_HEIGHT_EXCEED_POLICY, Property::STRING,  &TextView::SetProperty, &TextView::GetProperty );
75 PropertyRegistration property6( typeRegistration,  "line-justification",   Toolkit::TextView::PROPERTY_LINE_JUSTIFICATION,   Property::STRING,  &TextView::SetProperty, &TextView::GetProperty );
76 PropertyRegistration property7( typeRegistration,  "fade-boundary",        Toolkit::TextView::PROPERTY_FADE_BOUNDARY,        Property::VECTOR4, &TextView::SetProperty, &TextView::GetProperty );
77 PropertyRegistration property8( typeRegistration, "line-height-offset",    Toolkit::TextView::PROPERTY_LINE_HEIGHT_OFFSET,   Property::FLOAT,   &TextView::SetProperty, &TextView::GetProperty );
78 PropertyRegistration property9( typeRegistration, "horizontal-alignment",  Toolkit::TextView::PROPERTY_HORIZONTAL_ALIGNMENT, Property::STRING,  &TextView::SetProperty, &TextView::GetProperty );
79 PropertyRegistration property10( typeRegistration, "vertical-alignment",   Toolkit::TextView::PROPERTY_VERTICAL_ALIGNMENT,   Property::STRING,  &TextView::SetProperty, &TextView::GetProperty );
80
81 /**
82  * Whether the text-view-processor operation sets, inserts, replaces, removes text.
83  *
84  * @param[in] metadata The text-view-processor operation.
85  *
86  * @return \e true if the given text-view-processor operation is modifying the text.
87  */
88 bool IsTextViewProcessorRelayoutOperation( const TextView::TextViewProcessorMetadata& metadata )
89 {
90   return ( ( metadata.mType == TextView::TextSet ) ||
91            ( metadata.mType == TextView::TextInserted ) ||
92            ( metadata.mType == TextView::TextReplaced ) ||
93            ( metadata.mType == TextView::TextRemoved ) ||
94            ( metadata.mType == TextView::NewStyle ));
95 }
96
97 /**
98  * Whether the text-view-processor operation sets a new line height offset.
99  *
100  * @param[in] metadata The text-view-processor operation.
101  *
102  * @return \e true if the given text-view-processor operation sets a new line height offset.
103  */
104 bool IsTextViewProcessorLineHeightOffsetOperation( const TextView::TextViewProcessorMetadata& metadata )
105 {
106   return ( metadata.mType == TextView::NewLineHeight );
107 }
108
109 /**
110  * Whether the text-view-processor operation sets a new style.
111  *
112  * @param[in] metadata The text-view-processor operation.
113  *
114  * @return \e true if the given text-view-processor operation sets a new style.
115  */
116 bool IsTextViewProcessorNewStyleOperation( const TextView::TextViewProcessorMetadata& metadata )
117 {
118   return ( metadata.mType == TextView::NewStyle );
119 }
120
121 } // namespace
122
123 TextView::TextViewProcessorMetadata::TextViewProcessorMetadata()
124 : mType( TextView::TextSet ),
125   mPosition( 0 ),
126   mNumberOfCharacters( 0 ),
127   mText()
128 {
129 }
130
131 Toolkit::TextView TextView::New()
132 {
133   // Create the implementation, temporarily owned on stack
134   IntrusivePtr<TextView> textView = new TextView();
135
136   // Pass ownership to CustomActor
137   Toolkit::TextView handle( *textView );
138
139   // Second-phase init of the implementation
140   // This can only be done after the CustomActor connection has been made...
141   textView->Initialize();
142
143   // Disables by default the offscreen rendering.
144   textView->SetSnapshotModeEnabled( false );
145
146   return handle;
147 }
148
149 void TextView::SetText( const std::string& text )
150 {
151   // Creates a styled text with the markup or plain string.
152   MarkupProcessor::StyledTextArray styledText;
153   MarkupProcessor::GetStyledTextArray( text, styledText, IsMarkupProcessingEnabled() );
154
155   // Calls SetText() with the styled text array.
156   SetText( styledText );
157 }
158
159 void TextView::SetText( const MarkupProcessor::StyledTextArray& text )
160 {
161   // mTextViewProcessorOperations stores the InsertTextAt and RemoveTextFrom operations to transform the initial text to mCurrentStyledText.
162   // Once again, if a new text is set, any previous call to InsertTextAt or RemoveTextFrom can be discarted.
163
164   std::vector<TextViewProcessorMetadata>::iterator it = std::remove_if( mTextViewProcessorOperations.begin(), mTextViewProcessorOperations.end(), IsTextViewProcessorRelayoutOperation );
165   mTextViewProcessorOperations.erase( it, mTextViewProcessorOperations.end() );
166
167   // Creates metadata with the Set operation.
168   TextViewProcessorMetadata metadata;
169   metadata.mType = TextView::TextSet;
170   metadata.mText = text;
171
172   // Store metadata.
173   mTextViewProcessorOperations.push_back( metadata );
174
175   // Updates current styled text.
176   mCurrentStyledText = text;
177
178   // Request to be relaid out
179   RelayoutRequest();
180
181   // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed on order to retrieve the right values.
182   mRelayoutOperations = RELAYOUT_ALL;
183 }
184
185 void TextView::InsertTextAt( std::size_t position, const std::string& text )
186 {
187   // Creates a styled text with the markup or plain string.
188   MarkupProcessor::StyledTextArray styledText;
189   MarkupProcessor::GetStyledTextArray( text, styledText, IsMarkupProcessingEnabled() );
190
191   // Calls InsertTextAt() with the styled text array.
192   InsertTextAt( position, styledText );
193 }
194
195 void TextView::InsertTextAt( std::size_t position, const MarkupProcessor::StyledTextArray& text )
196 {
197   // Creates metadata with the Insert operation.
198   TextViewProcessorMetadata metadata;
199   metadata.mType = TextView::TextInserted;
200   metadata.mPosition = position;
201   metadata.mText = text;
202
203   // Store metadata.
204   mTextViewProcessorOperations.push_back( metadata );
205
206   // Updates current styled text.
207   mCurrentStyledText.insert( mCurrentStyledText.begin() + position, text.begin(), text.end() );
208
209   // Request to be relaid out
210   RelayoutRequest();
211
212   // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed on order to retrieve the right values.
213   mRelayoutOperations = RELAYOUT_ALL;
214 }
215
216 void TextView::ReplaceTextFromTo( std::size_t position, std::size_t numberOfCharacters, const std::string& text )
217 {
218   // Creates a styled text with the markup or plain string.
219   MarkupProcessor::StyledTextArray styledText;
220   MarkupProcessor::GetStyledTextArray( text, styledText, IsMarkupProcessingEnabled() );
221
222   // Calls ReplaceTextFromTo() with the styled text array.
223   ReplaceTextFromTo( position, numberOfCharacters, styledText );
224 }
225
226 void TextView::ReplaceTextFromTo( std::size_t position, std::size_t numberOfCharacters, const MarkupProcessor::StyledTextArray& text )
227 {
228   // Creates metadata with the Insert operation.
229   TextViewProcessorMetadata metadata;
230   metadata.mType = TextView::TextReplaced;
231   metadata.mPosition = position;
232   metadata.mNumberOfCharacters = numberOfCharacters;
233   metadata.mText = text;
234
235   // Store metadata.
236   mTextViewProcessorOperations.push_back( metadata );
237
238   // Updates current styled text.
239   MarkupProcessor::StyledTextArray::iterator it = mCurrentStyledText.begin() + position;
240   mCurrentStyledText.erase( it, it + numberOfCharacters );
241   it = mCurrentStyledText.begin() + position;
242   mCurrentStyledText.insert( it, text.begin(), text.end() );
243
244   // Request to be relaid out
245   RelayoutRequest();
246
247   // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed on order to retrieve the right values.
248   mRelayoutOperations = RELAYOUT_ALL;
249 }
250
251 void TextView::RemoveTextFrom( std::size_t position, std::size_t numberOfCharacters )
252 {
253   // Creates metadata with the Remove operation.
254   TextViewProcessorMetadata metadata;
255   metadata.mType = TextView::TextRemoved;
256   metadata.mPosition = position;
257   metadata.mNumberOfCharacters = numberOfCharacters;
258
259   // Store metadata.
260   mTextViewProcessorOperations.push_back( metadata );
261
262   // Updates current styled text.
263   MarkupProcessor::StyledTextArray::iterator it = mCurrentStyledText.begin() + position;
264   mCurrentStyledText.erase( it, it + numberOfCharacters );
265
266   // Request to be relaid out
267   RelayoutRequest();
268
269   // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed on order to retrieve the right values.
270   mRelayoutOperations = RELAYOUT_ALL;
271 }
272
273 std::string TextView::GetText() const
274 {
275   // Traverses the styled text array getting only the text.
276   //  Note that for some languages a 'character' could be represented by more than one 'char'
277
278   std::string text;
279   for( MarkupProcessor::StyledTextArray::const_iterator it = mCurrentStyledText.begin(), endIt = mCurrentStyledText.end(); it != endIt; ++it )
280   {
281     text.append( (*it).mText.GetText() );
282   }
283
284   return text;
285 }
286
287 void TextView::SetLineHeightOffset( PointSize offset )
288 {
289   if( fabsf( mLayoutParameters.mLineHeightOffset - offset ) > Math::MACHINE_EPSILON_1000 )
290   {
291     // Removes any previous operation which modifies the line height offset.
292     std::vector<TextViewProcessorMetadata>::iterator it = std::remove_if( mTextViewProcessorOperations.begin(), mTextViewProcessorOperations.end(), IsTextViewProcessorLineHeightOffsetOperation );
293     mTextViewProcessorOperations.erase( it, mTextViewProcessorOperations.end() );
294
295     // Creates metadata with the new line height operation.
296     TextViewProcessorMetadata metadata;
297     metadata.mType = TextView::NewLineHeight;
298
299     mTextViewProcessorOperations.push_back( metadata );
300
301     // Updates line height offset.
302     mLayoutParameters.mLineHeightOffset = offset;
303
304     RelayoutRequest();
305
306     // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed on order to retrieve the right values.
307     if( RELAYOUT_ALL != mRelayoutOperations )
308     {
309       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations |
310                                                                 RELAYOUT_REMOVE_TEXT_ACTORS |
311                                                                 RELAYOUT_SIZE_POSITION |
312                                                                 RELAYOUT_ALIGNMENT |
313                                                                 RELAYOUT_VISIBILITY |
314                                                                 RELAYOUT_TEXT_ACTOR_UPDATE |
315                                                                 RELAYOUT_INSERT_TO_TEXT_VIEW |
316                                                                 RELAYOUT_INSERT_TO_TEXT_ACTOR_LIST );
317     }
318   }
319 }
320
321 PointSize TextView::GetLineHeightOffset() const
322 {
323   return PointSize( mLayoutParameters.mLineHeightOffset );
324 }
325
326 void TextView::SetStyleToCurrentText( const TextStyle& style, TextStyle::Mask mask )
327 {
328   if( !mCurrentStyledText.empty() )
329   {
330     const bool checkFontName = mask & TextStyle::FONT;
331     const bool checkFontSize = mask & TextStyle::SIZE;
332     const bool checkFontStyle = mask & TextStyle::STYLE;
333
334     // Check first if metrics have changed.
335     bool metricsChanged = false;
336     for( MarkupProcessor::StyledTextArray::const_iterator it = mCurrentStyledText.begin(), endIt = mCurrentStyledText.end(); ( it != endIt ) && !metricsChanged; ++it )
337     {
338       const MarkupProcessor::StyledText& styledText( *it );
339
340       metricsChanged = ( checkFontName && ( styledText.mStyle.GetFontName() != style.GetFontName() ) ) ||
341                        ( checkFontStyle && ( styledText.mStyle.GetFontStyle() != style.GetFontStyle() ) ) ||
342                        ( checkFontSize && ( fabsf( styledText.mStyle.GetFontPointSize() - style.GetFontPointSize() ) > Math::MACHINE_EPSILON_1000 ) );
343     }
344
345     if( metricsChanged )
346     {
347       MarkupProcessor::SetTextStyle( mCurrentStyledText, style, mask );
348
349       // If metrics change, new text measurements are needed.
350       SetText( mCurrentStyledText );
351     }
352     else
353     {
354       // Deletes any previous operation which sets a new style.
355       std::vector<TextViewProcessorMetadata>::iterator it = std::remove_if( mTextViewProcessorOperations.begin(), mTextViewProcessorOperations.end(), IsTextViewProcessorNewStyleOperation );
356       mTextViewProcessorOperations.erase( it, mTextViewProcessorOperations.end() );
357
358       // Creates metadata with the new style operation.
359       TextViewProcessorMetadata metadata;
360       metadata.mType = TextView::NewStyle;
361
362       MarkupProcessor::StyledText text;
363       text.mStyle = style;
364       metadata.mText.push_back( text );
365       metadata.mStyleMask = mask;
366
367       mTextViewProcessorOperations.push_back( metadata );
368
369       MarkupProcessor::SetTextStyle( mCurrentStyledText, style, mask );
370
371       RelayoutRequest();
372
373       if( RELAYOUT_ALL != mRelayoutOperations )
374       {
375         mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations |
376                                                                   RELAYOUT_TEXT_ACTOR_UPDATE );
377       }
378     }
379   }
380
381   // Sets the new style to the ellipsize text
382   if( !mLayoutParameters.mEllipsizeText.empty() )
383   {
384     for( MarkupProcessor::StyledTextArray::iterator it = mLayoutParameters.mEllipsizeText.begin(), endIt = mLayoutParameters.mEllipsizeText.end(); it != endIt; ++it )
385     {
386       (*it).mStyle.Copy( style, mask );
387     }
388
389     SetEllipsizeText( mLayoutParameters.mEllipsizeText );
390   }
391 }
392
393 void TextView::SetTextAlignment( Toolkit::Alignment::Type align )
394 {
395   if( align != ( mLayoutParameters.mHorizontalAlignment | mLayoutParameters.mVerticalAlignment ) )
396   {
397     Toolkit::Alignment::Type horizontalAlignment( ( align & Toolkit::Alignment::HorizontalLeft ? Toolkit::Alignment::HorizontalLeft :
398                                                     ( align & Toolkit::Alignment::HorizontalCenter ? Toolkit::Alignment::HorizontalCenter :
399                                                       ( align & Toolkit::Alignment::HorizontalRight ? Toolkit::Alignment::HorizontalRight : Toolkit::Alignment::HorizontalCenter ) ) ) );
400     Toolkit::Alignment::Type verticalAlignment( ( align & Toolkit::Alignment::VerticalTop ? Toolkit::Alignment::VerticalTop :
401                                                   ( align & Toolkit::Alignment::VerticalCenter ? Toolkit::Alignment::VerticalCenter :
402                                                     ( align & Toolkit::Alignment::VerticalBottom ? Toolkit::Alignment::VerticalBottom : Toolkit::Alignment::VerticalCenter ) ) ) );
403
404     mLayoutParameters.mHorizontalAlignment = horizontalAlignment;
405     mLayoutParameters.mVerticalAlignment = verticalAlignment;
406
407     RelayoutRequest();
408
409     // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed in order to retrieve the right values.
410     if( RELAYOUT_ALL != mRelayoutOperations )
411     {
412       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations |
413                                                                 RELAYOUT_TEXT_ACTOR_UPDATE |
414                                                                 RELAYOUT_ALIGNMENT |
415                                                                 RELAYOUT_VISIBILITY );
416     }
417   }
418 }
419
420 Toolkit::Alignment::Type TextView::GetTextAlignment() const
421 {
422   return static_cast<Toolkit::Alignment::Type>( mLayoutParameters.mHorizontalAlignment | mLayoutParameters.mVerticalAlignment );
423 }
424
425 void TextView::SetMultilinePolicy( Toolkit::TextView::MultilinePolicy policy )
426 {
427   if( policy != mLayoutParameters.mMultilinePolicy )
428   {
429     mLayoutParameters.mMultilinePolicy = policy;
430
431     // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed on order to retrieve the right values.
432     mRelayoutOperations = RELAYOUT_ALL;
433
434     RelayoutRequest();
435   }
436 }
437
438 Toolkit::TextView::MultilinePolicy TextView::GetMultilinePolicy() const
439 {
440   return mLayoutParameters.mMultilinePolicy;
441 }
442
443 void TextView::SetWidthExceedPolicy( Toolkit::TextView::ExceedPolicy policy )
444 {
445   // The layout info could be invalid depending on the current exceed policy and the new one.
446   // i.e. if the current policy is Split and the new one is ShrinkToFit then
447   // the layout info generated for each char is not needed.
448   if( policy != mLayoutParameters.mWidthExceedPolicy )
449   {
450     mLayoutParameters.mWidthExceedPolicy = policy;
451
452     // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed in order to retrieve the right values.
453     mRelayoutOperations = RELAYOUT_ALL;
454
455     RelayoutRequest();
456   }
457 }
458
459 Toolkit::TextView::ExceedPolicy TextView::GetWidthExceedPolicy() const
460 {
461   return mLayoutParameters.mWidthExceedPolicy;
462 }
463
464 void TextView::SetHeightExceedPolicy( Toolkit::TextView::ExceedPolicy policy )
465 {
466   if( policy != mLayoutParameters.mHeightExceedPolicy )
467   {
468     mLayoutParameters.mHeightExceedPolicy = policy;
469
470     RelayoutRequest();
471
472     // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed in order to retrieve the right values.
473     if( RELAYOUT_ALL != mRelayoutOperations )
474     {
475       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations |
476                                                                 RELAYOUT_REMOVE_TEXT_ACTORS |
477                                                                 RELAYOUT_SIZE_POSITION |
478                                                                 RELAYOUT_ALIGNMENT |
479                                                                 RELAYOUT_VISIBILITY |
480                                                                 RELAYOUT_TEXT_ACTOR_UPDATE |
481                                                                 RELAYOUT_INSERT_TO_TEXT_VIEW |
482                                                                 RELAYOUT_INSERT_TO_TEXT_ACTOR_LIST );
483     }
484   }
485 }
486
487 Toolkit::TextView::ExceedPolicy TextView::GetHeightExceedPolicy() const
488 {
489   return mLayoutParameters.mHeightExceedPolicy;
490 }
491
492 void TextView::SetLineJustification( Toolkit::TextView::LineJustification justification )
493 {
494   if( justification != mLayoutParameters.mLineJustification )
495   {
496     mLayoutParameters.mLineJustification = justification;
497
498     RelayoutRequest();
499
500     // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed in order to retrieve the right values.
501     if( RELAYOUT_ALL != mRelayoutOperations )
502     {
503       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations |
504                                                                 RELAYOUT_REMOVE_TEXT_ACTORS |
505                                                                 RELAYOUT_SIZE_POSITION |
506                                                                 RELAYOUT_ALIGNMENT |
507                                                                 RELAYOUT_VISIBILITY |
508                                                                 RELAYOUT_TEXT_ACTOR_UPDATE |
509                                                                 RELAYOUT_INSERT_TO_TEXT_VIEW |
510                                                                 RELAYOUT_INSERT_TO_TEXT_ACTOR_LIST );
511     }
512   }
513 }
514
515 Toolkit::TextView::LineJustification TextView::GetLineJustification() const
516 {
517   return mLayoutParameters.mLineJustification;
518 }
519
520 void TextView::SetFadeBoundary( const Toolkit::TextView::FadeBoundary& fadeBoundary )
521 {
522   if( ( fadeBoundary.mLeft != mVisualParameters.mFadeBoundary.mLeft )   ||
523       ( fadeBoundary.mRight != mVisualParameters.mFadeBoundary.mRight ) ||
524       ( fadeBoundary.mTop != mVisualParameters.mFadeBoundary.mTop )     ||
525       ( fadeBoundary.mBottom != mVisualParameters.mFadeBoundary.mBottom ) )
526   {
527     mVisualParameters.mFadeBoundary = fadeBoundary;
528
529     RelayoutRequest();
530
531     // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed in order to retrieve the right values.
532     if( RELAYOUT_ALL != mRelayoutOperations )
533     {
534       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations |
535                                                                 RELAYOUT_REMOVE_TEXT_ACTORS |
536                                                                 RELAYOUT_VISIBILITY |
537                                                                 RELAYOUT_TEXT_ACTOR_UPDATE |
538                                                                 RELAYOUT_INSERT_TO_TEXT_VIEW |
539                                                                 RELAYOUT_INSERT_TO_TEXT_ACTOR_LIST );
540     }
541   }
542 }
543
544 const Toolkit::TextView::FadeBoundary& TextView::GetFadeBoundary() const
545 {
546   return mVisualParameters.mFadeBoundary;
547 }
548
549 void TextView::SetEllipsizeText( const std::string& ellipsizeText )
550 {
551   // Creates a styled text with the markup or plain string.
552   MarkupProcessor::StyledTextArray styledText;
553   MarkupProcessor::GetStyledTextArray( ellipsizeText, styledText, IsMarkupProcessingEnabled() );
554
555   SetEllipsizeText( styledText );
556 }
557
558 void TextView::SetEllipsizeText( const MarkupProcessor::StyledTextArray& ellipsizeText )
559 {
560   mLayoutParameters.mEllipsizeText = ellipsizeText;
561
562   mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo = TextViewProcessor::WordLayoutInfo();
563
564   TextViewProcessor::CreateWordTextInfo( mLayoutParameters.mEllipsizeText,
565                                          mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo );
566
567   // Request to be relaid out
568   RelayoutRequest();
569
570   mRelayoutOperations = RELAYOUT_ALL;
571 }
572
573 std::string TextView::GetEllipsizeText() const
574 {
575   std::string text;
576   for( MarkupProcessor::StyledTextArray::const_iterator it = mLayoutParameters.mEllipsizeText.begin(), endIt = mLayoutParameters.mEllipsizeText.end(); it != endIt; ++it )
577   {
578     text.append( (*it).mText.GetText() );
579   }
580
581   return text;
582 }
583
584 void TextView::GetTextLayoutInfo()
585 {
586   const bool relayoutSizeAndPositionNeeded = mRelayoutOperations & RELAYOUT_SIZE_POSITION;
587   const bool relayoutAlignmentNeeded = mRelayoutOperations & RELAYOUT_ALIGNMENT;
588   const bool relayoutVisibilityNeeded = mRelayoutOperations & RELAYOUT_VISIBILITY;
589
590   if( relayoutSizeAndPositionNeeded || relayoutAlignmentNeeded || relayoutVisibilityNeeded )
591   {
592     Vector3 textViewSize = GetControlSize();
593
594     if( ( ( textViewSize.width < Math::MACHINE_EPSILON_1000 ) ||
595           ( textViewSize.height < Math::MACHINE_EPSILON_1000 ) ) &&
596         ( ( Toolkit::TextView::SplitByNewLineChar == mLayoutParameters.mMultilinePolicy ) &&
597           ( Toolkit::TextView::Original == mLayoutParameters.mWidthExceedPolicy ) &&
598           ( Toolkit::TextView::Original == mLayoutParameters.mHeightExceedPolicy ) ) )
599     {
600       // In case the control size is not set but the layout settings are the default (split by new line character and original exceed policies)
601       // the text natural size can be used.
602       textViewSize = GetNaturalSize();
603     }
604
605     if( ( textViewSize.width > Math::MACHINE_EPSILON_1000 ) &&
606         ( textViewSize.height > Math::MACHINE_EPSILON_1000 ) )
607     {
608       // Check if the text-view has glyph-actors.
609       const bool hasGlyphActors = !mRelayoutData.mGlyphActors.empty();
610
611       RelayoutOperationMask mask = NO_RELAYOUT;
612       if( relayoutSizeAndPositionNeeded )
613       {
614         mask = static_cast<RelayoutOperationMask>( mask | RELAYOUT_SIZE_POSITION );
615       }
616       if( relayoutAlignmentNeeded )
617       {
618         mask = static_cast<RelayoutOperationMask>( mask | RELAYOUT_ALIGNMENT );
619       }
620       if( relayoutVisibilityNeeded )
621       {
622         mask = static_cast<RelayoutOperationMask>( mask | RELAYOUT_VISIBILITY );
623       }
624
625       if( hasGlyphActors )
626       {
627         // Remove glyph-actors from the text-view as some text-operation like CreateTextInfo()
628         // add them to the text-actor cache.
629         TextViewRelayout::RemoveGlyphActors( GetRootActor(), mRelayoutData.mGlyphActors );
630         mRelayoutData.mGlyphActors.clear();
631       }
632
633       // Relays-out but doesn't add glyph-actors to the text-view.
634       DoRelayOut( textViewSize.GetVectorXY(), mask );
635
636       if( hasGlyphActors )
637       {
638         mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations | RELAYOUT_INSERT_TO_TEXT_VIEW );
639         mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations | RELAYOUT_INSERT_TO_TEXT_ACTOR_LIST );
640       }
641
642     }
643   }
644 }
645
646 void TextView::GetTextLayoutInfo( Toolkit::TextView::TextLayoutInfo& textLayoutInfo )
647 {
648   GetTextLayoutInfo();
649
650   textLayoutInfo.mCharacterLayoutInfoTable = mRelayoutData.mCharacterLayoutInfoTable;
651   textLayoutInfo.mLines = mRelayoutData.mLines;
652
653   textLayoutInfo.mCharacterLogicalToVisualMap = mRelayoutData.mCharacterLogicalToVisualMap;
654   textLayoutInfo.mCharacterVisualToLogicalMap = mRelayoutData.mCharacterVisualToLogicalMap;
655
656   textLayoutInfo.mTextSize = mRelayoutData.mTextSizeForRelayoutOption;
657
658   textLayoutInfo.mScrollOffset = mVisualParameters.mCameraScrollPosition;
659 }
660
661 void TextView::SetSortModifier( float depthOffset )
662 {
663   mVisualParameters.mSortModifier = depthOffset;
664
665   for( std::vector<RenderableActor>::iterator it = mRelayoutData.mGlyphActors.begin(), endIt = mRelayoutData.mGlyphActors.end();
666        it != endIt;
667        ++it )
668   {
669     ( *it ).SetSortModifier( depthOffset );
670   }
671
672   if( mOffscreenImageActor )
673   {
674     mOffscreenImageActor.SetSortModifier( depthOffset );
675   }
676 }
677
678 void TextView::SetSnapshotModeEnabled( bool enable )
679 {
680   if( enable != mVisualParameters.mSnapshotModeEnabled )
681   {
682     // Remove first all glyph-actors
683     if( !mRelayoutData.mGlyphActors.empty() )
684     {
685       TextViewRelayout::RemoveGlyphActors( GetRootActor(), mRelayoutData.mGlyphActors );
686     }
687
688     mVisualParameters.mSnapshotModeEnabled = enable;
689     if( !mLockPreviousSnapshotMode )
690     {
691       // mPreviousSnapshotModeEnabled stores the snapshot mode value before SetScrollEnabled( true ) is
692       // called. However, if SetSnapshotModeEnabled() is called after SetScrollEnabled() then the stored value
693       // is updated.
694       // As SetSnapshotModeEnabled() is also called from SetScrollEnabled(), the mLockPreviousSnapshotMode prevents
695       // to smash the stored value.
696       mPreviousSnapshotModeEnabled = enable;
697     }
698
699     if( mVisualParameters.mSnapshotModeEnabled )
700     {
701       // Create a root actor and an image actor for offscreen rendering.
702       mOffscreenRootActor = Layer::New();
703       mOffscreenImageActor = ImageActor::New();
704
705       mOffscreenRootActor.SetColorMode( USE_OWN_COLOR );
706       mOffscreenRootActor.SetPositionInheritanceMode( DONT_INHERIT_POSITION );
707       mOffscreenRootActor.SetInheritRotation( false );
708       mOffscreenRootActor.SetInheritScale( false );
709       mOffscreenRootActor.SetDepthTestDisabled( true );
710
711       mOffscreenRootActor.SetPosition( 0.f, 0.f, 0.f );
712
713       mOffscreenImageActor.SetAnchorPoint( ParentOrigin::CENTER );
714       mOffscreenImageActor.SetParentOrigin( ParentOrigin::CENTER );
715       mOffscreenImageActor.SetBlendFunc( BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA,
716                                          BlendingFactor::ONE, BlendingFactor::ONE );
717
718       Actor self = Self();
719       self.Add( mOffscreenRootActor );
720       self.Add( mOffscreenImageActor );
721       mOffscreenImageActor.SetScale( Vector3( 1.f, -1.f, 1.f ) );
722     }
723     else
724     {
725       Actor self = Self();
726
727       if( mOffscreenRootActor )
728       {
729         self.Remove( mOffscreenRootActor );
730       }
731
732       if( mOffscreenImageActor )
733       {
734         self.Remove( mOffscreenImageActor );
735       }
736
737       DestroyOffscreenRenderingResources();
738     }
739
740     if( RELAYOUT_ALL != mRelayoutOperations )
741     {
742       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations |
743                                                                 RELAYOUT_REMOVE_TEXT_ACTORS |
744                                                                 RELAYOUT_TEXT_ACTOR_UPDATE |
745                                                                 RELAYOUT_INSERT_TO_TEXT_VIEW |
746                                                                 RELAYOUT_INSERT_TO_TEXT_ACTOR_LIST );
747     }
748     RelayoutRequest();
749   }
750 }
751
752 bool TextView::IsSnapshotModeEnabled() const
753 {
754   return mVisualParameters.mSnapshotModeEnabled;
755 }
756
757 void TextView::SetMarkupProcessingEnabled( bool enable )
758 {
759   mMarkUpEnabled = enable;
760 }
761
762 bool TextView::IsMarkupProcessingEnabled() const
763 {
764   return mMarkUpEnabled;
765 }
766
767 void TextView::SetScrollEnabled( bool enable )
768 {
769   if( enable != mVisualParameters.mScrollEnabled )
770   {
771     mVisualParameters.mScrollEnabled = enable;
772
773     if( mVisualParameters.mScrollEnabled )
774     {
775       // Offscreen rendering is needed to enable text scroll.
776
777       // Stores previous value of the snapshot mode.
778       mPreviousSnapshotModeEnabled = IsSnapshotModeEnabled();
779
780       {
781         // SetSnapshotModeEnabled() modifies the mPreviousSnapshotModeEnabled just in case it's called after SetScrollEnabled(),
782         // this lock prevents to modify the mPreviousSnapshotModeEnabled when SetSnapshotModeEnabled() from this method.
783         Lock lock( mLockPreviousSnapshotMode );
784         SetSnapshotModeEnabled( true );
785       }
786
787       // Creates the pan gesture detector and attach the text-view.
788       mPanGestureDetector = PanGestureDetector::New();
789       mPanGestureDetector.DetectedSignal().Connect( this, &TextView::OnTextPan );
790       mPanGestureDetector.Attach( Self() );
791     }
792     else
793     {
794       // Removes the pan gesture detector.
795       if( mPanGestureDetector )
796       {
797         mPanGestureDetector.Detach( Self() );
798         mPanGestureDetector.DetectedSignal().Disconnect( this, &TextView::OnTextPan );
799         mPanGestureDetector.Reset();
800       }
801
802       // Restores the previous state for snapshot mode.
803       SetSnapshotModeEnabled( mPreviousSnapshotModeEnabled );
804     }
805   }
806 }
807
808 bool TextView::IsScrollEnabled() const
809 {
810   return mVisualParameters.mScrollEnabled;
811 }
812
813 void TextView::SetScrollPosition( const Vector2& position )
814 {
815   if( position != mVisualParameters.mCameraScrollPosition )
816   {
817     // Guard against destruction during signal emission
818     // Note that Emit() methods are called indirectly from within DoSetScrollPosition()
819     Toolkit::TextView handle( GetOwner() );
820
821     DoSetScrollPosition( position );
822
823     // Check if the new scroll position has been trimmed.
824     mVisualParameters.mScrollPositionTrimmed = ( position != mVisualParameters.mCameraScrollPosition );
825   }
826 }
827
828 const Vector2& TextView::GetScrollPosition() const
829 {
830   return mVisualParameters.mCameraScrollPosition;
831 }
832
833 bool TextView::IsScrollPositionTrimmed() const
834 {
835   return mVisualParameters.mScrollPositionTrimmed;
836 }
837
838 Toolkit::TextView::ScrolledSignalV2& TextView::ScrolledSignal()
839 {
840   return mScrolledSignalV2;
841 }
842
843 bool TextView::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
844 {
845   Dali::BaseHandle handle( object );
846
847   bool connected( true );
848   Toolkit::TextView textView = Toolkit::TextView::DownCast(handle);
849
850   if( Dali::Toolkit::TextView::SIGNAL_TEXT_SCROLLED == signalName )
851   {
852     textView.ScrolledSignal().Connect( tracker, functor );
853   }
854   else
855   {
856     // signalName does not match any signal
857     connected = false;
858   }
859
860   return connected;
861 }
862
863 TextView::LayoutParameters::LayoutParameters()
864 : mMultilinePolicy( Toolkit::TextView::SplitByNewLineChar ),
865   mWidthExceedPolicy( Toolkit::TextView::Original ),
866   mHeightExceedPolicy( Toolkit::TextView::Original ),
867   mHorizontalAlignment( Toolkit::Alignment::HorizontalCenter ),
868   mVerticalAlignment( Toolkit::Alignment::VerticalCenter ),
869   mLineJustification( Toolkit::TextView::Left ),
870   mLineHeightOffset( 0.f ),
871   mEllipsizeText(),
872   mMarkUpEnabled( false )
873 {
874   // Sets ellipsize text
875   MarkupProcessor::StyledTextArray styledEllipsize;
876   MarkupProcessor::GetStyledTextArray( std::string( "..." ), mEllipsizeText, false );
877 }
878
879 TextView::LayoutParameters::LayoutParameters( Toolkit::TextView::MultilinePolicy   multilinePolicy,
880                                               Toolkit::TextView::ExceedPolicy      widthExceedPolicy,
881                                               Toolkit::TextView::ExceedPolicy      heightExceedPolicy,
882                                               Toolkit::Alignment::Type             alignmentType,
883                                               Toolkit::TextView::LineJustification lineJustification,
884                                               float                                lineHeightOffset,
885                                               const std::string&                   ellipsizeText,
886                                               bool                                 markUpEnabled )
887 : mMultilinePolicy( multilinePolicy ),
888   mWidthExceedPolicy( widthExceedPolicy ),
889   mHeightExceedPolicy( heightExceedPolicy ),
890   mHorizontalAlignment(),
891   mVerticalAlignment(),
892   mLineJustification( lineJustification ),
893   mLineHeightOffset( lineHeightOffset ),
894   mEllipsizeText(),
895   mMarkUpEnabled( markUpEnabled )
896 {
897   // Sets alignment
898   Toolkit::Alignment::Type horizontalAlignment( ( alignmentType & Toolkit::Alignment::HorizontalLeft ? Toolkit::Alignment::HorizontalLeft :
899                                                   ( alignmentType & Toolkit::Alignment::HorizontalCenter ? Toolkit::Alignment::HorizontalCenter :
900                                                     ( alignmentType & Toolkit::Alignment::HorizontalRight ? Toolkit::Alignment::HorizontalRight : Toolkit::Alignment::HorizontalCenter ) ) ) );
901   Toolkit::Alignment::Type verticalAlignment( ( alignmentType & Toolkit::Alignment::VerticalTop ? Toolkit::Alignment::VerticalTop :
902                                                 ( alignmentType & Toolkit::Alignment::VerticalCenter ? Toolkit::Alignment::VerticalCenter :
903                                                   ( alignmentType & Toolkit::Alignment::VerticalBottom ? Toolkit::Alignment::VerticalBottom : Toolkit::Alignment::VerticalCenter ) ) ) );
904
905   mHorizontalAlignment = horizontalAlignment;
906   mVerticalAlignment = verticalAlignment;
907
908   // Sets ellipsize text
909   MarkupProcessor::StyledTextArray styledEllipsize;
910   MarkupProcessor::GetStyledTextArray( ellipsizeText, mEllipsizeText, mMarkUpEnabled );
911 }
912
913 TextView::LayoutParameters::LayoutParameters( const TextView::LayoutParameters& layoutParameters )
914 : mMultilinePolicy( layoutParameters.mMultilinePolicy ),
915   mWidthExceedPolicy( layoutParameters.mWidthExceedPolicy ),
916   mHeightExceedPolicy( layoutParameters.mHeightExceedPolicy ),
917   mHorizontalAlignment( layoutParameters.mHorizontalAlignment ),
918   mVerticalAlignment( layoutParameters.mVerticalAlignment ),
919   mLineJustification( layoutParameters.mLineJustification ),
920   mLineHeightOffset( layoutParameters.mLineHeightOffset ),
921   mEllipsizeText( layoutParameters.mEllipsizeText ),
922   mMarkUpEnabled( layoutParameters.mMarkUpEnabled )
923 {
924 }
925
926 TextView::LayoutParameters& TextView::LayoutParameters::operator=( const TextView::LayoutParameters& layoutParameters )
927 {
928   mMultilinePolicy = layoutParameters.mMultilinePolicy;
929   mWidthExceedPolicy = layoutParameters.mWidthExceedPolicy;
930   mHeightExceedPolicy = layoutParameters.mHeightExceedPolicy;
931   mHorizontalAlignment = layoutParameters.mHorizontalAlignment;
932   mVerticalAlignment = layoutParameters.mVerticalAlignment;
933   mLineJustification = layoutParameters.mLineJustification;
934   mLineHeightOffset = layoutParameters.mLineHeightOffset;
935   mEllipsizeText = layoutParameters.mEllipsizeText;
936   mMarkUpEnabled = layoutParameters.mMarkUpEnabled;
937
938   return *this;
939 }
940
941 TextView::VisualParameters::VisualParameters()
942 : mFadeBoundary(),
943   mSortModifier( 0.f ),
944   mCameraScrollPosition( 0.f, 0.f ),
945   mSnapshotModeEnabled( false ),
946   mScrollEnabled( false ),
947   mScrollPositionTrimmed( false )
948 {
949 }
950
951 TextView::VisualParameters::VisualParameters( const VisualParameters& visualParameters )
952 : mFadeBoundary( visualParameters.mFadeBoundary ),
953   mSortModifier( visualParameters.mSortModifier ),
954   mCameraScrollPosition( visualParameters.mCameraScrollPosition ),
955   mSnapshotModeEnabled( visualParameters.mSnapshotModeEnabled ),
956   mScrollEnabled( visualParameters.mScrollEnabled ),
957   mScrollPositionTrimmed( visualParameters.mScrollPositionTrimmed )
958 {
959 }
960
961 TextView::VisualParameters& TextView::VisualParameters::operator=( const TextView::VisualParameters& visualParameters )
962 {
963   mFadeBoundary = visualParameters.mFadeBoundary;
964   mSortModifier = visualParameters.mSortModifier;
965   mCameraScrollPosition = visualParameters.mCameraScrollPosition;
966   mSnapshotModeEnabled = visualParameters.mSnapshotModeEnabled;
967   mScrollEnabled = visualParameters.mScrollEnabled;
968   mScrollPositionTrimmed = visualParameters.mScrollPositionTrimmed;
969
970   return *this;
971 }
972
973 TextView::RelayoutData::RelayoutData()
974 : mTextViewSize(),
975   mShrinkFactor( 1.f ),
976   mTextLayoutInfo(),
977   mCharacterLogicalToVisualMap(),
978   mCharacterVisualToLogicalMap(),
979   mGlyphActors(),
980   mCharacterLayoutInfoTable(),
981   mLines(),
982   mTextSizeForRelayoutOption()
983 {
984 }
985
986 TextView::RelayoutData::RelayoutData( const TextView::RelayoutData& relayoutData )
987 : mTextViewSize( relayoutData.mTextViewSize ),
988   mShrinkFactor( relayoutData.mShrinkFactor ),
989   mTextLayoutInfo( relayoutData.mTextLayoutInfo ),
990   mCharacterLogicalToVisualMap( relayoutData.mCharacterLogicalToVisualMap ),
991   mCharacterVisualToLogicalMap( relayoutData.mCharacterVisualToLogicalMap ),
992   mGlyphActors( relayoutData.mGlyphActors ),
993   mCharacterLayoutInfoTable( relayoutData.mCharacterLayoutInfoTable ),
994   mLines( relayoutData.mLines ),
995   mTextSizeForRelayoutOption( relayoutData.mTextSizeForRelayoutOption )
996 {
997 }
998
999 TextView::RelayoutData& TextView::RelayoutData::operator=( const TextView::RelayoutData& relayoutData )
1000 {
1001   mTextViewSize = relayoutData.mTextViewSize;
1002   mShrinkFactor = relayoutData.mShrinkFactor;
1003   mTextLayoutInfo = relayoutData.mTextLayoutInfo;
1004   mCharacterLogicalToVisualMap = relayoutData.mCharacterLogicalToVisualMap;
1005   mCharacterVisualToLogicalMap = relayoutData.mCharacterVisualToLogicalMap;
1006   mGlyphActors = relayoutData.mGlyphActors;
1007   mCharacterLayoutInfoTable = relayoutData.mCharacterLayoutInfoTable;
1008   mLines = relayoutData.mLines;
1009   mTextSizeForRelayoutOption = relayoutData.mTextSizeForRelayoutOption;
1010
1011   return *this;
1012 }
1013
1014 TextView::TextView()
1015 : Control( REQUIRES_STYLE_CHANGE_SIGNALS  ),
1016   mCurrentStyledText(),
1017   mTextViewProcessorOperations(),
1018   mLayoutParameters( Toolkit::TextView::SplitByNewLineChar,
1019                      Toolkit::TextView::Original,
1020                      Toolkit::TextView::Original,
1021                      static_cast<Toolkit::Alignment::Type>( Toolkit::Alignment::HorizontalCenter | Toolkit::Alignment::VerticalCenter ),
1022                      Toolkit::TextView::Left,
1023                      PointSize( 0.f ),
1024                      std::string( "..." ),
1025                      false ),
1026   mVisualParameters(),
1027   mRelayoutData(),
1028   mRelayoutOperations( NO_RELAYOUT ),
1029   mOffscreenRootActor(),
1030   mOffscreenImageActor(),
1031   mOffscreenCameraActor(),
1032   mCurrentOffscreenSize(),
1033   mFrameBufferImage(),
1034   mRenderTask(),
1035   mPanGestureDetector(),
1036   mLockPreviousSnapshotMode( false ),
1037   mPreviousSnapshotModeEnabled( false ),
1038   mMarkUpEnabled( false )
1039 {
1040   TextViewProcessor::CreateWordTextInfo( mLayoutParameters.mEllipsizeText,
1041                                          mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo );
1042 }
1043
1044 TextView::~TextView()
1045 {
1046   // Destroys offscreen rendering resources.
1047   DestroyOffscreenRenderingResources();
1048
1049   // Destroys scroll pan gesture detector.
1050   if( mPanGestureDetector )
1051   {
1052     mPanGestureDetector.Reset();
1053   }
1054 }
1055
1056 Vector3 TextView::GetNaturalSize()
1057 {
1058   if( !mTextViewProcessorOperations.empty() )
1059   {
1060     // There are SetText, Inserts or Removes to do. It means the current layout info is not updated.
1061
1062     if( !mRelayoutData.mGlyphActors.empty() )
1063     {
1064       // Remove glyph-actors from the text-view as some text-operation like CreateTextInfo()
1065       // add them to the text-actor cache.
1066       TextViewRelayout::RemoveGlyphActors( GetRootActor(), mRelayoutData.mGlyphActors );
1067       mRelayoutData.mGlyphActors.clear();
1068
1069       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations | RELAYOUT_INSERT_TO_TEXT_VIEW );
1070       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations | RELAYOUT_INSERT_TO_TEXT_ACTOR_LIST );
1071     }
1072
1073     PerformTextViewProcessorOperations();
1074   }
1075
1076   return Vector3( mRelayoutData.mTextLayoutInfo.mWholeTextSize.width, mRelayoutData.mTextLayoutInfo.mWholeTextSize.height, 0.f );
1077 }
1078
1079 float TextView::GetHeightForWidth( float width )
1080 {
1081   float height = 0.f;
1082
1083   if( ( Toolkit::TextView::SplitByNewLineChar == mLayoutParameters.mMultilinePolicy ) &&
1084       ( Toolkit::TextView::Original == mLayoutParameters.mWidthExceedPolicy ) &&
1085       ( Toolkit::TextView::Original == mLayoutParameters.mHeightExceedPolicy ) )
1086   {
1087     // If multiline and exceed policies are 'SplitByNewLineChar' and 'Original' is better get the height from the
1088     // natural size. GetNaturalSize() for this configuration is faster than DoRelayOut().
1089     height = GetNaturalSize().height;
1090   }
1091   else
1092   {
1093     // Check if the given width is different than the current one.
1094     const bool differentWidth = ( fabsf( width - mRelayoutData.mTextViewSize.width ) > Math::MACHINE_EPSILON_1000 );
1095
1096     // Check if the text-view has glyph-actors.
1097     const bool hasGlyphActors = !mRelayoutData.mGlyphActors.empty();
1098
1099     // Check which layout operations need to be done.
1100     const bool relayoutSizeAndPositionNeeded = ( mRelayoutOperations & RELAYOUT_SIZE_POSITION ) || differentWidth;
1101
1102     if( relayoutSizeAndPositionNeeded )
1103     {
1104       if( hasGlyphActors )
1105       {
1106         // Remove glyph-actors from the text-view as some text-operation like CreateTextInfo()
1107         // add them to the text-actor cache.
1108         TextViewRelayout::RemoveGlyphActors( GetRootActor(), mRelayoutData.mGlyphActors );
1109         mRelayoutData.mGlyphActors.clear();
1110       }
1111
1112       // Use the given width.
1113       const Vector2 textViewSize( width, GetControlSize().height );
1114
1115       // Relays-out but doesn't add glyph-actors to the text-view.
1116       DoRelayOut( textViewSize, RELAYOUT_SIZE_POSITION );
1117     }
1118
1119     // Retrieve the text height after relayout the text.
1120     height = mRelayoutData.mTextSizeForRelayoutOption.height;
1121
1122     if( differentWidth )
1123     {
1124       // Revert the relayout operation mask
1125       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations | RELAYOUT_SIZE_POSITION );
1126     }
1127
1128     if( hasGlyphActors )
1129     {
1130       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations | RELAYOUT_INSERT_TO_TEXT_VIEW );
1131       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations | RELAYOUT_INSERT_TO_TEXT_ACTOR_LIST );
1132     }
1133
1134     if( differentWidth || hasGlyphActors )
1135     {
1136       RelayoutRequest();
1137     }
1138   }
1139
1140   return height;
1141 }
1142
1143 float TextView::GetWidthForHeight( float height )
1144 {
1145   // TODO: Needs implementing properly, for now just return the natural width.
1146   return GetNaturalSize().width;
1147 }
1148
1149
1150 void TextView::OnInitialize()
1151 {
1152 }
1153
1154
1155 void TextView::OnFontChange( bool defaultFontChange, bool defaultFontSizeChange )
1156 {
1157   mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo = TextViewProcessor::WordLayoutInfo();
1158   TextViewProcessor::CreateWordTextInfo( mLayoutParameters.mEllipsizeText,
1159                                          mRelayoutData.mTextLayoutInfo.mEllipsizeLayoutInfo );
1160
1161   SetText( mCurrentStyledText );
1162 }
1163
1164 void TextView::OnControlSizeSet( const Vector3& size )
1165 {
1166   if( size.GetVectorXY() != mRelayoutData.mTextViewSize )
1167   {
1168     // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed in order to retrieve the right values.
1169     mRelayoutOperations = RELAYOUT_ALL;
1170
1171     // Request to be relaid out
1172     RelayoutRequest();
1173   }
1174 }
1175
1176 void TextView::OnRelaidOut( Vector2 size, ActorSizeContainer& container )
1177 {
1178   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
1179   {
1180     // Not worth to relayout if width or height is equal to zero.
1181     return;
1182   }
1183
1184   if( size != mRelayoutData.mTextViewSize )
1185   {
1186     // if new size is different than the prevoius one, set positions and maybe sizes of all glyph-actor is needed.
1187     if( RELAYOUT_ALL != mRelayoutOperations )
1188     {
1189       mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations |
1190                                                                 RELAYOUT_REMOVE_TEXT_ACTORS |
1191                                                                 RELAYOUT_SIZE_POSITION |
1192                                                                 RELAYOUT_ALIGNMENT |
1193                                                                 RELAYOUT_VISIBILITY |
1194                                                                 RELAYOUT_TEXT_ACTOR_UPDATE |
1195                                                                 RELAYOUT_INSERT_TO_TEXT_VIEW |
1196                                                                 RELAYOUT_INSERT_TO_TEXT_ACTOR_LIST );
1197     }
1198   }
1199
1200   // Remove glyph-actors from text-view
1201   if( !mRelayoutData.mGlyphActors.empty() && ( mRelayoutOperations & RELAYOUT_REMOVE_TEXT_ACTORS ) )
1202   {
1203     TextViewRelayout::RemoveGlyphActors( GetRootActor(), mRelayoutData.mGlyphActors );
1204     mRelayoutData.mGlyphActors.clear();
1205   }
1206
1207   if( NO_RELAYOUT != mRelayoutOperations )
1208   {
1209     // Relays-out and add glyph-actors to the text-view.
1210     DoRelayOut( size, mRelayoutOperations );
1211     ProcessSnapshot( size );
1212   }
1213
1214   // Quite likely the texts of the text-actors are not going to be reused, so clear them.
1215   mRelayoutData.mTextActorCache.ClearTexts();
1216 }
1217
1218 void TextView::PerformTextViewProcessorOperations()
1219 {
1220   // Traverse the relayout operation vector ...
1221
1222   // Optimizes some operations.
1223   OptimizeTextViewProcessorOperations();
1224
1225   for( std::vector<TextViewProcessorMetadata>::const_iterator it = mTextViewProcessorOperations.begin(), endIt = mTextViewProcessorOperations.end(); it != endIt; ++it )
1226   {
1227     const TextViewProcessorMetadata& relayoutMetadata( *it );
1228
1229     switch( relayoutMetadata.mType )
1230     {
1231       case TextView::TextSet:
1232       {
1233         TextViewProcessor::CreateTextInfo( relayoutMetadata.mText,
1234                                            mLayoutParameters,
1235                                            mRelayoutData );
1236         break;
1237       }
1238       case TextView::TextInserted:
1239       {
1240         TextViewProcessor::UpdateTextInfo( relayoutMetadata.mPosition,
1241                                            relayoutMetadata.mText,
1242                                            mLayoutParameters,
1243                                            mRelayoutData );
1244         break;
1245       }
1246       case TextView::TextReplaced:
1247       {
1248         TextViewProcessor::UpdateTextInfo( relayoutMetadata.mPosition,
1249                                            relayoutMetadata.mNumberOfCharacters,
1250                                            relayoutMetadata.mText,
1251                                            mLayoutParameters,
1252                                            mRelayoutData );
1253         break;
1254       }
1255       case TextView::TextRemoved:
1256       {
1257         TextViewProcessor::UpdateTextInfo( relayoutMetadata.mPosition,
1258                                            relayoutMetadata.mNumberOfCharacters,
1259                                            mLayoutParameters,
1260                                            mRelayoutData,
1261                                            TextViewProcessor::CLEAR_TEXT ); // clears the text of the text-actors.
1262         break;
1263       }
1264       case TextView::NewLineHeight:
1265       {
1266         TextViewProcessor::UpdateTextInfo( mLayoutParameters.mLineHeightOffset,
1267                                            mRelayoutData.mTextLayoutInfo );
1268         break;
1269       }
1270       case TextView::NewStyle:
1271       {
1272         TextViewProcessor::UpdateTextInfo( ( *relayoutMetadata.mText.begin() ).mStyle,
1273                                            relayoutMetadata.mStyleMask,
1274                                            mRelayoutData );
1275         break;
1276       }
1277     }
1278   }
1279
1280   // Clear all operations when they are done.
1281   mTextViewProcessorOperations.clear();
1282 }
1283
1284 void TextView::OptimizeTextViewProcessorOperations()
1285 {
1286   // TODO: check if some operation can be discarted. i.e. InsertTextAt( 0, "a" ); RemoveTextFrom( 0, 1 );
1287
1288   // At the moment it only replaces a 'remove 1 character' followed by 'insert 1 character' in the same position by a 'replace' operation.
1289   // This sequence is used by text-input with predictive text. Change this two operations by a replace allows the text-view processor to
1290   // use the cache without clearing the text-actors.
1291
1292   std::vector<TextViewProcessorMetadata> textViewProcessorOperations;
1293
1294   for( std::vector<TextViewProcessorMetadata>::const_iterator it = mTextViewProcessorOperations.begin(), endIt = mTextViewProcessorOperations.end(); it != endIt; ++it )
1295   {
1296     const TextViewProcessorMetadata& relayoutMetadata( *it );
1297
1298     switch( relayoutMetadata.mType )
1299     {
1300       case TextView::TextRemoved:
1301       {
1302         bool optimizationDone = false;
1303
1304         if( it + 1 != endIt )
1305         {
1306           const TextViewProcessorMetadata& nextRelayoutMetadata( *( it + 1 ) );
1307           if( TextView::TextInserted == nextRelayoutMetadata.mType )
1308           {
1309             if( relayoutMetadata.mPosition == nextRelayoutMetadata.mPosition )
1310             {
1311               optimizationDone = true;
1312               TextViewProcessorMetadata newRelayoutMetadata;
1313               newRelayoutMetadata.mType = TextView::TextReplaced;
1314               newRelayoutMetadata.mPosition = relayoutMetadata.mPosition;
1315               newRelayoutMetadata.mNumberOfCharacters = relayoutMetadata.mNumberOfCharacters;
1316               newRelayoutMetadata.mText = nextRelayoutMetadata.mText;
1317               textViewProcessorOperations.push_back( newRelayoutMetadata );
1318
1319               // do not access the TextInserted operation in next iteration.
1320               ++it;
1321             }
1322           }
1323         }
1324
1325         if( !optimizationDone )
1326         {
1327           textViewProcessorOperations.push_back( relayoutMetadata );
1328         }
1329         break;
1330       }
1331       default:
1332       {
1333         textViewProcessorOperations.push_back( relayoutMetadata );
1334       }
1335     }
1336   }
1337
1338   mTextViewProcessorOperations = textViewProcessorOperations;
1339 }
1340
1341 void TextView::DoRelayOut( const Size& textViewSize, RelayoutOperationMask relayoutOperationMask )
1342 {
1343   // Traverse the relayout operation vector. It fills the natural size, layout and glyph-actor data structures.
1344   if( !mTextViewProcessorOperations.empty() )
1345   {
1346     PerformTextViewProcessorOperations();
1347   }
1348
1349   CombineExceedPolicies();
1350
1351   Actor rootActor;
1352   if( mVisualParameters.mSnapshotModeEnabled )
1353   {
1354     rootActor = mOffscreenRootActor;
1355   }
1356   else
1357   {
1358     rootActor = Self();
1359   }
1360
1361   mRelayoutData.mTextViewSize = textViewSize;
1362   switch( mLayoutParameters.mMultilinePolicy )
1363   {
1364     case Toolkit::TextView::SplitByNewLineChar:              // multiline policy == SplitByNewLineChar.
1365     {
1366       SplitByNewLineChar::Relayout( rootActor, relayoutOperationMask, mLayoutParameters, mVisualParameters, mRelayoutData );
1367       break;
1368     } // SplitByNewLineChar
1369
1370     case Toolkit::TextView::SplitByWord:                     // multiline policy == SplitByWord.
1371     {
1372       SplitByWord::Relayout( rootActor, relayoutOperationMask, mLayoutParameters, mVisualParameters, mRelayoutData );
1373       break;
1374     } // SplitByWord
1375
1376     case Toolkit::TextView::SplitByChar:                     // multiline policy == SplitByChar.
1377     {
1378       SplitByChar::Relayout( rootActor, relayoutOperationMask, mLayoutParameters, mVisualParameters, mRelayoutData );
1379       break;
1380     } // SplitByChar
1381   } // switch( mMultilinePolicy )
1382
1383   // Remove done operations from the mask.
1384   mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations & ~relayoutOperationMask );
1385 }
1386
1387 void TextView::ProcessSnapshot( const Size& textViewSize )
1388 {
1389   if( mVisualParameters.mSnapshotModeEnabled )
1390   {
1391     // If layout options change, it's needed generate a new image.
1392
1393     if( mOffscreenRootActor )
1394     {
1395       // Set the root actor visible.
1396       // The root actor is set to non visible after the render task is processed.
1397       mOffscreenRootActor.SetVisible( true );
1398
1399       // The offscreen root actor must have same size as text view. Otherwise, text alignment won't work.
1400       mOffscreenRootActor.SetSize( textViewSize );
1401     }
1402
1403     if( ( mRelayoutData.mTextSizeForRelayoutOption.width > Math::MACHINE_EPSILON_1000 ) &&
1404         ( mRelayoutData.mTextSizeForRelayoutOption.height > Math::MACHINE_EPSILON_1000 ) )
1405     {
1406       // Set the image actor visible.
1407       // The image actor is set to non visible if there is no text to render.
1408       mOffscreenImageActor.SetVisible( true );
1409
1410       // Calculates the offscreen image's size. It takes into account different points:
1411       // * If text has italics, add a small offset is needed in order to not to cut the text next to the right edge.
1412       // * There is a maximum texture size the graphic subsystem can load on the memory.
1413       // * If the scroll is enabled, the offscreen image's size is never bigger than the text-view's size.
1414
1415       const Size offscreenSize( std::min( MAX_OFFSCREEN_RENDERING_SIZE,
1416                                           mVisualParameters.mScrollEnabled ? textViewSize.width : std::max( mRelayoutData.mTextSizeForRelayoutOption.width, textViewSize.width ) + mRelayoutData.mTextLayoutInfo.mMaxItalicsOffset ),
1417                                 std::min( MAX_OFFSCREEN_RENDERING_SIZE,
1418                                           mVisualParameters.mScrollEnabled ? textViewSize.height : std::max( mRelayoutData.mTextSizeForRelayoutOption.height, textViewSize.height ) ) );
1419
1420       const bool sizeChanged = offscreenSize != mCurrentOffscreenSize;
1421
1422       if( sizeChanged )
1423       {
1424         // Creates a frame buffer for offscreen rendering when the size is negotiated.
1425         mFrameBufferImage = FrameBufferImage::New( offscreenSize.width,
1426                                                    offscreenSize.height,
1427                                                    Pixel::RGBA8888 );
1428
1429         // Stores current text-view size to avoid create new Dali resources if text changes.
1430         mCurrentOffscreenSize = offscreenSize;
1431
1432         if( !mOffscreenCameraActor )
1433         {
1434           // Creates a new camera actor.
1435           mOffscreenCameraActor = CameraActor::New();
1436           mOffscreenCameraActor.SetParentOrigin( ParentOrigin::CENTER );
1437           mOffscreenCameraActor.SetAnchorPoint( AnchorPoint::CENTER );
1438           mOffscreenCameraActor.SetRotation(Degree(180.f), Vector3::YAXIS);
1439
1440           mOffscreenCameraActor.SetType( Dali::Camera::FREE_LOOK ); // Inherits position from the offscreen root actor.
1441
1442           mOffscreenRootActor.Add( mOffscreenCameraActor ); // camera to shoot the offscreen text
1443         }
1444
1445         // Calculate camera parameters for current text size.
1446         mOffscreenCameraActor.SetOrthographicProjection( offscreenSize );
1447       }
1448
1449       if( mVisualParameters.mScrollEnabled )
1450       {
1451         // Updates the offscreen camera position with the new scroll offset.
1452         mOffscreenCameraActor.SetX( mVisualParameters.mCameraScrollPosition.x );
1453         mOffscreenCameraActor.SetY( mVisualParameters.mCameraScrollPosition.y );
1454       }
1455       else
1456       {
1457         // Text's size could be bigger than text-view's size. In that case the camera must be aligned to cover the whole text.
1458         AlignOffscreenCameraActor( textViewSize, offscreenSize );
1459       }
1460
1461       if( !mRenderTask )
1462       {
1463         // Creates a new render task.
1464         mRenderTask = Stage::GetCurrent().GetRenderTaskList().CreateTask();
1465
1466         mRenderTask.SetSourceActor( mOffscreenRootActor );
1467         mRenderTask.SetInputEnabled( false );
1468         mRenderTask.SetClearColor( Color::TRANSPARENT );
1469         mRenderTask.SetClearEnabled( true );
1470         mRenderTask.SetExclusive( true );
1471
1472         // Connects the signal to the TextView::RenderTaskFinished method in order to make the root actor non visible when the render task is processed.
1473         mRenderTask.FinishedSignal().Connect( this, &TextView::RenderTaskFinished );
1474       }
1475
1476       if( sizeChanged )
1477       {
1478         mRenderTask.SetCameraActor( mOffscreenCameraActor );
1479         mRenderTask.SetTargetFrameBuffer( mFrameBufferImage );
1480       }
1481
1482       // Process the render task only once every time the text changes or the text-view's size canges.
1483       mRenderTask.SetRefreshRate( RenderTask::REFRESH_ONCE );
1484     }
1485     else
1486     {
1487       // If there is no text just make any previous generated image invisible instead to process a render task with no text.
1488       mOffscreenImageActor.SetVisible( false );
1489     }
1490   }
1491 }
1492
1493 void TextView::AlignOffscreenCameraActor( const Size& textViewSize, const Size& offscreenSize )
1494 {
1495   float xPosition = 0.f;
1496   float yPosition = 0.f;
1497   Vector3 parentOrigin = ParentOrigin::CENTER;
1498   Vector3 anchorPoint = AnchorPoint::CENTER;
1499
1500   switch( mLayoutParameters.mHorizontalAlignment )
1501   {
1502     case Toolkit::Alignment::HorizontalLeft:
1503     {
1504       xPosition = 0.5f * ( offscreenSize.width - textViewSize.width );
1505       parentOrigin.x = 0.f;
1506       anchorPoint.x = 0.f;
1507       break;
1508     }
1509     case Toolkit::Alignment::HorizontalCenter:
1510     {
1511       // nothing to do.
1512       break;
1513     }
1514     case Toolkit::Alignment::HorizontalRight:
1515     {
1516       xPosition = 0.5f * ( textViewSize.width - offscreenSize.width );
1517       parentOrigin.x = 1.f;
1518       anchorPoint.x = 1.f;
1519       break;
1520     }
1521     default:
1522     {
1523       DALI_ASSERT_ALWAYS( !"TextView::AlignOffscreenCameraActor: Invalid alignment option." )
1524     }
1525   }
1526
1527   switch( mLayoutParameters.mVerticalAlignment )
1528   {
1529     case Toolkit::Alignment::VerticalTop:
1530     {
1531       yPosition = 0.5f * ( offscreenSize.height - textViewSize.height );
1532       parentOrigin.y = 0.f;
1533       anchorPoint.y = 0.f;
1534       break;
1535     }
1536     case Toolkit::Alignment::VerticalCenter:
1537     {
1538       // nothing to do.
1539       break;
1540     }
1541     case Toolkit::Alignment::VerticalBottom:
1542     {
1543       yPosition = 0.5f * ( textViewSize.height - offscreenSize.height );
1544       parentOrigin.y = 1.f;
1545       anchorPoint.y = 1.f;
1546       break;
1547     }
1548     default:
1549     {
1550       DALI_ASSERT_ALWAYS( !"TextView::AlignOffscreenCameraActor: Invalid alignment option." )
1551     }
1552   }
1553
1554   mOffscreenCameraActor.SetX( xPosition );
1555   mOffscreenCameraActor.SetY( yPosition );
1556
1557   mOffscreenImageActor.SetParentOrigin( parentOrigin );
1558   mOffscreenImageActor.SetAnchorPoint( anchorPoint );
1559 }
1560
1561 void TextView::RenderTaskFinished( Dali::RenderTask& renderTask )
1562 {
1563   // not to process the offscreen root actor by setting its visibility to false.
1564   mOffscreenRootActor.SetVisible( false );
1565
1566   // Sets the new size and the new frame buffer to the image actor.
1567   // Image actor must have same size as text. Otherwise text can be truncated.
1568   mOffscreenImageActor.SetSize( mCurrentOffscreenSize );
1569   mOffscreenImageActor.SetImage( mFrameBufferImage );
1570 }
1571
1572 void TextView::DestroyOffscreenRenderingResources()
1573 {
1574   if( mRenderTask )
1575   {
1576     mRenderTask.FinishedSignal().Disconnect( this, &TextView::RenderTaskFinished );
1577
1578     if( Stage::IsInstalled() )
1579     {
1580       Stage::GetCurrent().GetRenderTaskList().RemoveTask( mRenderTask );
1581     }
1582
1583     mRenderTask.Reset();
1584   }
1585
1586   // Remove and reset the root actor, image actor and camera actor as text-view is not rendering offscreen.
1587   if( mOffscreenCameraActor )
1588   {
1589     mOffscreenRootActor.Remove( mOffscreenCameraActor );
1590
1591     mOffscreenCameraActor.Reset();
1592   }
1593
1594   if( mOffscreenRootActor )
1595   {
1596     mOffscreenRootActor.Reset();
1597   }
1598
1599   if( mOffscreenImageActor )
1600   {
1601     mOffscreenImageActor.Reset();
1602   }
1603
1604   mCurrentOffscreenSize = Size( 0.f, 0.f );
1605
1606   if( mFrameBufferImage )
1607   {
1608     mFrameBufferImage.Reset();
1609   }
1610 }
1611
1612 void TextView::OnTextPan( Actor actor, PanGesture gesture )
1613 {
1614   if( 1u == gesture.numberOfTouches )
1615   {
1616     DoSetScrollPosition( mVisualParameters.mCameraScrollPosition - gesture.displacement );
1617   }
1618 }
1619
1620 void TextView::TrimScrollPosition()
1621 {
1622   const Vector3& textViewSize = GetControlSize();
1623
1624   // Before use the text's size, relayout the text is needed to get the actual text size.
1625   GetTextLayoutInfo();
1626
1627   // Calculates the range within the text could be scrolled. (When the text is aligned in the center).
1628   float maxHorizontalDisplacement = std::max( 0.f, 0.5f * ( mRelayoutData.mTextSizeForRelayoutOption.width - textViewSize.width ) );
1629   float maxVerticalDisplacement = std::max( 0.f, 0.5f * ( mRelayoutData.mTextSizeForRelayoutOption.height - textViewSize.height ) );
1630   float minHorizontalDisplacement = -maxHorizontalDisplacement;
1631   float minVerticalDisplacement = -maxVerticalDisplacement;
1632
1633   // Updates the range if the text is aligned on the right or left.
1634   switch( mLayoutParameters.mHorizontalAlignment )
1635   {
1636     case Toolkit::Alignment::HorizontalLeft:
1637     {
1638       maxHorizontalDisplacement *= 2.f;
1639       minHorizontalDisplacement = 0.f;
1640       break;
1641     }
1642     case Toolkit::Alignment::HorizontalCenter:
1643     {
1644       // nothing to do.
1645       break;
1646     }
1647     case Toolkit::Alignment::HorizontalRight:
1648     {
1649       maxHorizontalDisplacement = 0.f;
1650       minHorizontalDisplacement *= 2.f;
1651       break;
1652     }
1653     default:
1654     {
1655       DALI_ASSERT_ALWAYS( !"TextView::TrimScrollPosition: Invalid alignment option." )
1656     }
1657   }
1658
1659   // Updates the range if the text is aligned on the top or bottom.
1660   switch( mLayoutParameters.mVerticalAlignment )
1661   {
1662     case Toolkit::Alignment::VerticalTop:
1663     {
1664       maxVerticalDisplacement *= 2.f;
1665       minVerticalDisplacement = 0.f;
1666       break;
1667     }
1668     case Toolkit::Alignment::VerticalCenter:
1669     {
1670       //nothing to do
1671       break;
1672     }
1673     case Toolkit::Alignment::VerticalBottom:
1674     {
1675       maxVerticalDisplacement = 0.f;
1676       minVerticalDisplacement *= 2.f;
1677       break;
1678     }
1679     default:
1680     {
1681       DALI_ASSERT_ALWAYS( !"TextView::TrimScrollPosition: Invalid alignment option." )
1682     }
1683   }
1684
1685   // Trims the scroll position to be within the range.
1686   mVisualParameters.mCameraScrollPosition.x = std::min( maxHorizontalDisplacement, mVisualParameters.mCameraScrollPosition.x );
1687   mVisualParameters.mCameraScrollPosition.x = std::max( minHorizontalDisplacement, mVisualParameters.mCameraScrollPosition.x );
1688
1689   mVisualParameters.mCameraScrollPosition.y = std::min( maxVerticalDisplacement, mVisualParameters.mCameraScrollPosition.y );
1690   mVisualParameters.mCameraScrollPosition.y = std::max( minVerticalDisplacement, mVisualParameters.mCameraScrollPosition.y );
1691 }
1692
1693 void TextView::DoSetScrollPosition( const Vector2& position )
1694 {
1695   // Stores old scroll position.
1696   Vector2 delta( mVisualParameters.mCameraScrollPosition );
1697
1698   // Updates the scroll position
1699   mVisualParameters.mCameraScrollPosition = position;
1700
1701   // Ensures the text-view is covered with text.
1702   TrimScrollPosition();
1703
1704   // Calculate the difference with the previous scroll position
1705   delta.x = mVisualParameters.mCameraScrollPosition.x - delta.x;
1706   delta.y = mVisualParameters.mCameraScrollPosition.y - delta.y;
1707
1708   if( mOffscreenRootActor )
1709   {
1710     // If there is a render-task it needs to be refreshed. Therefore glyph-actors need to be
1711     // set to visible.
1712     mOffscreenRootActor.SetVisible( true );
1713   }
1714
1715   if( mOffscreenCameraActor )
1716   {
1717     // Update the offscreen camera with the new scroll position.
1718     mOffscreenCameraActor.SetX( mVisualParameters.mCameraScrollPosition.x );
1719     mOffscreenCameraActor.SetY( mVisualParameters.mCameraScrollPosition.y );
1720   }
1721
1722   if( mRenderTask )
1723   {
1724     // Refresh the render-task.
1725     mRenderTask.SetRefreshRate( RenderTask::REFRESH_ONCE );
1726   }
1727
1728   // Emit the signal.
1729   Toolkit::TextView handle( GetOwner() );
1730   mScrolledSignalV2.Emit( handle, delta );
1731 }
1732
1733 void TextView::CombineExceedPolicies()
1734 {
1735   // Calculates the combination of exceed policies.
1736
1737   switch( mLayoutParameters.mWidthExceedPolicy )
1738   {
1739     case Toolkit::TextView::Original:
1740     {
1741       switch( mLayoutParameters.mHeightExceedPolicy )
1742       {
1743         case Toolkit::TextView::Original:
1744         {
1745           mLayoutParameters.mExceedPolicy = Original;
1746           break;
1747         }
1748         case Toolkit::TextView::Fade:
1749         {
1750           mLayoutParameters.mExceedPolicy = OriginalFade;
1751           break;
1752         }
1753         case Toolkit::TextView::ShrinkToFit:
1754         {
1755           mLayoutParameters.mExceedPolicy = OriginalShrink;
1756           break;
1757         }
1758         default:
1759         {
1760           DALI_ASSERT_ALWAYS( !"TextView::CombineExceedPolicies() Invalid width and height exceed policies combination" );
1761         }
1762       }
1763       break;
1764     }
1765     case Toolkit::TextView::Split:
1766     {
1767       switch( mLayoutParameters.mHeightExceedPolicy )
1768       {
1769         case Toolkit::TextView::Original:
1770         {
1771           mLayoutParameters.mExceedPolicy = SplitOriginal;
1772           break;
1773         }
1774         case Toolkit::TextView::Fade:
1775         {
1776           mLayoutParameters.mExceedPolicy = SplitFade;
1777           break;
1778         }
1779         case Toolkit::TextView::ShrinkToFit:
1780         {
1781           mLayoutParameters.mExceedPolicy = SplitShrink;
1782           break;
1783         }
1784         case Toolkit::TextView::EllipsizeEnd:
1785         {
1786           mLayoutParameters.mExceedPolicy = SplitEllipsizeEnd;
1787           break;
1788         }
1789         default:
1790         {
1791           DALI_ASSERT_ALWAYS( !"TextView::CombineExceedPolicies() Invalid width and height exceed policies combination" );
1792         }
1793       }
1794       break;
1795     }
1796     case Toolkit::TextView::Fade:
1797     {
1798       switch( mLayoutParameters.mHeightExceedPolicy )
1799       {
1800         case Toolkit::TextView::Original:
1801         {
1802           mLayoutParameters.mExceedPolicy = FadeOriginal;
1803           break;
1804         }
1805         case Toolkit::TextView::Fade:
1806         {
1807           mLayoutParameters.mExceedPolicy = Fade;
1808           break;
1809         }
1810         default:
1811         {
1812           DALI_ASSERT_ALWAYS( !"TextView::CombineExceedPolicies() Invalid width and height exceed policies combination" );
1813         }
1814       }
1815       break;
1816     }
1817     case Toolkit::TextView::ShrinkToFit:
1818     {
1819       switch( mLayoutParameters.mHeightExceedPolicy )
1820       {
1821         case Toolkit::TextView::Original:
1822         {
1823           mLayoutParameters.mExceedPolicy = ShrinkOriginal;
1824           break;
1825         }
1826         case Toolkit::TextView::Fade:
1827         {
1828           mLayoutParameters.mExceedPolicy = ShrinkFade;
1829           break;
1830         }
1831         case Toolkit::TextView::ShrinkToFit:
1832         {
1833           mLayoutParameters.mExceedPolicy = Shrink;
1834           break;
1835         }
1836         default:
1837         {
1838           DALI_ASSERT_ALWAYS( !"TextView::CombineExceedPolicies() Invalid width and height exceed policies combination" );
1839         }
1840       }
1841       break;
1842     }
1843     case Toolkit::TextView::EllipsizeEnd:
1844     {
1845       switch( mLayoutParameters.mHeightExceedPolicy )
1846       {
1847         case Toolkit::TextView::Original:
1848         {
1849           mLayoutParameters.mExceedPolicy = EllipsizeEndOriginal;
1850           break;
1851         }
1852         case Toolkit::TextView::EllipsizeEnd:
1853         {
1854           mLayoutParameters.mExceedPolicy = EllipsizeEnd;
1855           break;
1856         }
1857         default:
1858         {
1859           DALI_ASSERT_ALWAYS( !"TextView::CombineExceedPolicies() Invalid width and height exceed policies combination" );
1860         }
1861       }
1862       break;
1863     }
1864     default:
1865     {
1866       DALI_ASSERT_ALWAYS( !"TextView::CombineExceedPolicies() Invalid width exceed policy" );
1867     }
1868   }
1869 }
1870
1871 Actor TextView::GetRootActor() const
1872 {
1873   // Get the root actor, if text-view was rendering offscreen, or the text-view itself.
1874
1875   Actor rootActor;
1876
1877   if( mVisualParameters.mSnapshotModeEnabled )
1878   {
1879     rootActor = mOffscreenRootActor;
1880   }
1881   else
1882   {
1883     rootActor = Self();
1884   }
1885
1886   return rootActor;
1887 }
1888
1889 void TextView::OnMarkupEnabledPeopertySet( Property::Value propertyValue )
1890 {
1891   bool newValue( propertyValue.Get<bool>() );
1892   if( newValue != IsMarkupProcessingEnabled() )
1893   {
1894     SetMarkupProcessingEnabled( newValue );
1895     if( newValue )
1896     {
1897       // If markup processing has been enabled, Ensure current text is reprocessed.
1898       const std::string& currentText( GetText() );
1899       if( ! currentText.empty() )
1900       {
1901         SetText( currentText );
1902       }
1903     }
1904   }
1905 }
1906
1907 void TextView::OnMultilinePolicyPropertySet( Property::Value propertyValue )
1908 {
1909   std::string policyName( propertyValue.Get<std::string>() );
1910   if(policyName == "SplitByNewLineChar")
1911   {
1912     SetMultilinePolicy(Toolkit::TextView::SplitByNewLineChar);
1913   }
1914   else if(policyName == "SplitByWord")
1915   {
1916     SetMultilinePolicy(Toolkit::TextView::SplitByWord);
1917   }
1918   else if(policyName == "SplitByChar")
1919   {
1920     SetMultilinePolicy(Toolkit::TextView::SplitByChar);
1921   }
1922   else
1923   {
1924     DALI_ASSERT_ALWAYS( !"TextView::OnMultilinePolicyPropertySet(). Invalid Property value." );
1925   }
1926 }
1927
1928 void TextView::OnWidthExceedPolicyPropertySet( Property::Value propertyValue )
1929 {
1930   std::string policyName( propertyValue.Get<std::string>() );
1931   if(policyName == "Original")
1932   {
1933     SetWidthExceedPolicy(Toolkit::TextView::Original);
1934   }
1935   else if(policyName == "Truncate")
1936   {
1937     SetWidthExceedPolicy(Toolkit::TextView::Truncate);
1938   }
1939   else if(policyName == "Fade")
1940   {
1941     SetWidthExceedPolicy(Toolkit::TextView::Fade);
1942   }
1943   else if(policyName == "Split")
1944   {
1945     SetWidthExceedPolicy(Toolkit::TextView::Split);
1946   }
1947   else if(policyName == "ShrinkToFit")
1948   {
1949     SetWidthExceedPolicy(Toolkit::TextView::ShrinkToFit);
1950   }
1951   else if(policyName == "EllipsizeEnd")
1952   {
1953     SetWidthExceedPolicy(Toolkit::TextView::EllipsizeEnd);
1954   }
1955   else
1956   {
1957     DALI_ASSERT_ALWAYS( !"TextView::OnWidthExceedPolicyPropertySet(). Invalid Property value." );
1958   }
1959 }
1960
1961 void TextView::OnHeightExceedPolicyPropertySet( Property::Value propertyValue )
1962 {
1963   std::string policyName( propertyValue.Get<std::string>() );
1964   if(policyName == "Original")
1965   {
1966     SetHeightExceedPolicy(Toolkit::TextView::Original);
1967   }
1968   else if(policyName == "Truncate")
1969   {
1970     SetHeightExceedPolicy(Toolkit::TextView::Truncate);
1971   }
1972   else if(policyName == "Fade")
1973   {
1974     SetHeightExceedPolicy(Toolkit::TextView::Fade);
1975   }
1976   else if(policyName == "Split")
1977   {
1978     SetHeightExceedPolicy(Toolkit::TextView::Split);
1979   }
1980   else if(policyName == "ShrinkToFit")
1981   {
1982     SetHeightExceedPolicy(Toolkit::TextView::ShrinkToFit);
1983   }
1984   else
1985   {
1986     DALI_ASSERT_ALWAYS( !"TextView::OnHeightExceedPolicyPropertySet(). Invalid Property value." );
1987   }
1988 }
1989
1990 void TextView::OnLineJustificationPropertySet( Property::Value propertyValue )
1991 {
1992   std::string policyName( propertyValue.Get<std::string>() );
1993   if(policyName == "Left")
1994   {
1995     SetLineJustification(Toolkit::TextView::Left);
1996   }
1997   else if(policyName == "Center")
1998   {
1999     SetLineJustification(Toolkit::TextView::Center);
2000   }
2001   else if(policyName == "Right")
2002   {
2003     SetLineJustification(Toolkit::TextView::Right);
2004   }
2005   else if(policyName == "Justified")
2006   {
2007     SetLineJustification(Toolkit::TextView::Justified);
2008   }
2009   else
2010   {
2011     DALI_ASSERT_ALWAYS( !"TextView::OnLineJustificationPropertySet(). Invalid Property value." );
2012   }
2013 }
2014
2015 void TextView::OnFadeBoundaryPropertySet( Property::Value propertyValue )
2016 {
2017   Vector4 value( propertyValue.Get<Vector4>() );
2018   DALI_ASSERT_ALWAYS( value.x >= 0 && value.y >= 0 && value.z >= 0 && value.w >= 0
2019                       && "TextView::OnFadeBoundaryPropertySet(). Negative value is invalid. "  );
2020
2021   Toolkit::TextView::FadeBoundary fadeBoundary( PixelSize( static_cast<unsigned int>( value.x ) ),
2022                                                 PixelSize( static_cast<unsigned int>( value.y ) ),
2023                                                 PixelSize( static_cast<unsigned int>( value.z ) ),
2024                                                 PixelSize( static_cast<unsigned int>( value.w ) ) );
2025
2026   SetFadeBoundary( fadeBoundary );
2027 }
2028
2029 void TextView::OnAlignmentPropertySet( Property::Index propertyIndex, Property::Value propertyValue )
2030 {
2031   std::string value( propertyValue.Get<std::string>() );
2032
2033   if( propertyIndex == Toolkit::TextView::PROPERTY_HORIZONTAL_ALIGNMENT )
2034   {
2035     if(value == "HorizontalLeft")
2036     {
2037       mLayoutParameters.mHorizontalAlignment = Toolkit::Alignment::HorizontalLeft;
2038     }
2039     else if( value == "HorizontalCenter")
2040     {
2041       mLayoutParameters.mHorizontalAlignment = Toolkit::Alignment::HorizontalCenter;
2042     }
2043     else if( value == "HorizontalRight")
2044     {
2045       mLayoutParameters.mHorizontalAlignment = Toolkit::Alignment::HorizontalRight;
2046     }
2047     else
2048     {
2049       DALI_ASSERT_ALWAYS( !"TextView::OnAlignmentPropertySet(). Invalid Property value." );
2050     }
2051   }
2052   else if( propertyIndex == Toolkit::TextView::PROPERTY_VERTICAL_ALIGNMENT )
2053   {
2054     if( value == "VerticalTop" )
2055     {
2056       mLayoutParameters.mVerticalAlignment = Toolkit::Alignment::VerticalTop;
2057     }
2058     else if( value == "VerticalCenter")
2059     {
2060       mLayoutParameters.mVerticalAlignment = Toolkit::Alignment::VerticalCenter;
2061     }
2062     else if( value == "VerticalBottom")
2063     {
2064       mLayoutParameters.mVerticalAlignment = Toolkit::Alignment::VerticalBottom;
2065     }
2066     else
2067     {
2068       DALI_ASSERT_ALWAYS( !"TextView::OnAlignmentPropertySet(). Invalid Property value." );
2069     }
2070   }
2071
2072   RelayoutRequest();
2073
2074   // If a GetTextLayoutInfo() or GetHeightForWidth() arrives, relayout the text synchronously is needed in order to retrieve the right values.
2075   if( RELAYOUT_ALL != mRelayoutOperations )
2076   {
2077     mRelayoutOperations = static_cast<RelayoutOperationMask>( mRelayoutOperations |
2078                                                               RELAYOUT_TEXT_ACTOR_UPDATE |
2079                                                               RELAYOUT_ALIGNMENT |
2080                                                               RELAYOUT_VISIBILITY );
2081   }
2082 }
2083
2084 std::string TextView::OnHorizontalAlignmentPropertyGet()
2085 {
2086   if( mLayoutParameters.mHorizontalAlignment == Toolkit::Alignment::HorizontalLeft )
2087   {
2088     return "HorizontalLeft";
2089   }
2090   else if( mLayoutParameters.mHorizontalAlignment == Toolkit::Alignment::HorizontalCenter )
2091   {
2092     return "HorizontalCenter";
2093   }
2094   else if( mLayoutParameters.mHorizontalAlignment == Toolkit::Alignment::HorizontalRight )
2095   {
2096     return "HorizontalRight";
2097   }
2098   else
2099   {
2100     DALI_ASSERT_ALWAYS( !"TextView::OnHorizontalAlignmentPropertyGet(). Invalid value." );
2101   }
2102 }
2103
2104 std::string TextView::OnVerticalAlignmentPropertyGet()
2105 {
2106   if( mLayoutParameters.mVerticalAlignment == Toolkit::Alignment::VerticalTop )
2107    {
2108      return "VerticalTop";
2109    }
2110    else if( mLayoutParameters.mVerticalAlignment == Toolkit::Alignment::VerticalCenter )
2111    {
2112      return "VerticalCenter";
2113    }
2114    else if( mLayoutParameters.mVerticalAlignment == Toolkit::Alignment::VerticalBottom )
2115    {
2116      return "VerticalBottom";
2117    }
2118    else
2119    {
2120      DALI_ASSERT_ALWAYS( !"TextView::OnVerticalAlignmentPropertyGet(). Invalid value." );
2121    }
2122 }
2123
2124 void TextView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
2125 {
2126   Toolkit::TextView textView = Toolkit::TextView::DownCast( Dali::BaseHandle( object ) );
2127
2128   if( textView )
2129   {
2130     TextView& textViewImpl( GetImpl( textView ) );
2131     switch( index )
2132     {
2133       case Toolkit::TextView::PROPERTY_MARKUP_ENABLED:
2134       {
2135         textViewImpl.OnMarkupEnabledPeopertySet( value );
2136         break;
2137       }
2138       case Toolkit::TextView::PROPERTY_TEXT:
2139       {
2140         textViewImpl.SetText( value.Get<std::string>() );
2141         break;
2142       }
2143       case Toolkit::TextView::PROPERTY_MULTILINE_POLICY:
2144       {
2145         textViewImpl.OnMultilinePolicyPropertySet( value );
2146         break;
2147       }
2148       case Toolkit::TextView::PROPERTY_WIDTH_EXCEED_POLICY:
2149       {
2150         textViewImpl.OnWidthExceedPolicyPropertySet( value );
2151         break;
2152       }
2153       case Toolkit::TextView::PROPERTY_HEIGHT_EXCEED_POLICY:
2154       {
2155         textViewImpl.OnHeightExceedPolicyPropertySet( value );
2156         break;
2157       }
2158       case Toolkit::TextView::PROPERTY_LINE_JUSTIFICATION:
2159       {
2160         textViewImpl.OnLineJustificationPropertySet( value );
2161         break;
2162       }
2163       case Toolkit::TextView::PROPERTY_FADE_BOUNDARY:
2164       {
2165         textViewImpl.OnFadeBoundaryPropertySet( value );
2166         break;
2167       }
2168       case Toolkit::TextView::PROPERTY_LINE_HEIGHT_OFFSET:
2169       {
2170         Dali::PointSize pointSize( value.Get<float>() );
2171         textViewImpl.SetLineHeightOffset(pointSize);
2172         break;
2173       }
2174       case Toolkit::TextView::PROPERTY_HORIZONTAL_ALIGNMENT:
2175       case Toolkit::TextView::PROPERTY_VERTICAL_ALIGNMENT:
2176       {
2177         textViewImpl.OnAlignmentPropertySet( index, value );
2178         break;
2179       }
2180     }
2181   }
2182 }
2183
2184 Property::Value TextView::GetProperty( BaseObject* object, Property::Index index )
2185 {
2186   Property::Value value;
2187
2188   Toolkit::TextView textView = Toolkit::TextView::DownCast( Dali::BaseHandle( object ) );
2189
2190   if( textView )
2191   {
2192     TextView& textViewImpl( GetImpl( textView ) );
2193     switch( index )
2194     {
2195       case Toolkit::TextView::PROPERTY_MARKUP_ENABLED:
2196       {
2197         value = textViewImpl.IsMarkupProcessingEnabled();
2198         break;
2199       }
2200       case Toolkit::TextView::PROPERTY_TEXT:
2201       {
2202         value = textViewImpl.GetText();
2203         break;
2204       }
2205       case Toolkit::TextView::PROPERTY_MULTILINE_POLICY:
2206       {
2207         value = MULTILINE_POLICY_NAME[ textViewImpl.GetMultilinePolicy() ];
2208         break;
2209       }
2210       case Toolkit::TextView::PROPERTY_WIDTH_EXCEED_POLICY:
2211       {
2212         value = EXCEED_POLICY_NAME[ textViewImpl.GetWidthExceedPolicy() ];
2213         break;
2214       }
2215       case Toolkit::TextView::PROPERTY_HEIGHT_EXCEED_POLICY:
2216       {
2217         value = EXCEED_POLICY_NAME[ textViewImpl.GetHeightExceedPolicy() ];
2218         break;
2219       }
2220       case Toolkit::TextView::PROPERTY_LINE_JUSTIFICATION:
2221       {
2222         value = LINE_JUSTIFICATION_NAME[ textViewImpl.GetLineJustification() ];
2223         break;
2224       }
2225       case Toolkit::TextView::PROPERTY_FADE_BOUNDARY:
2226       {
2227         Toolkit::TextView::FadeBoundary boundary = textViewImpl.GetFadeBoundary();
2228         value = Vector4( static_cast<float>( boundary.mLeft.value ),
2229                          static_cast<float>( boundary.mRight.value ),
2230                          static_cast<float>( boundary.mTop.value ),
2231                          static_cast<float>( boundary.mBottom.value ) );
2232         break;
2233       }
2234       case Toolkit::TextView::PROPERTY_LINE_HEIGHT_OFFSET:
2235       {
2236         value = textViewImpl.GetLineHeightOffset().value;
2237         break;
2238       }
2239       case Toolkit::TextView::PROPERTY_HORIZONTAL_ALIGNMENT:
2240       {
2241         value = textViewImpl.OnHorizontalAlignmentPropertyGet();
2242         break;
2243       }
2244       case Toolkit::TextView::PROPERTY_VERTICAL_ALIGNMENT:
2245       {
2246         value = textViewImpl.OnVerticalAlignmentPropertyGet();
2247         break;
2248       }
2249     }
2250   }
2251   return value;
2252 }
2253
2254 } // namespace Internal
2255
2256 } // namespace Toolkit
2257
2258 } // namespace Dali