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