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