Merge "DALi Version 1.9.36" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller.cpp
1 /*
2  * Copyright (c) 2020 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/text/text-controller.h>
20
21 // EXTERNAL INCLUDES
22 #include <limits>
23 #include <cmath>
24 #include <memory.h>
25 #include <dali/integration-api/debug.h>
26
27 // INTERNAL INCLUDES
28 #include <dali-toolkit/internal/text/character-set-conversion.h>
29 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
30 #include <dali-toolkit/internal/text/markup-processor.h>
31 #include <dali-toolkit/internal/text/text-controller-event-handler.h>
32 #include <dali-toolkit/internal/text/text-controller-impl.h>
33 #include <dali-toolkit/internal/text/text-controller-input-font-handler.h>
34 #include <dali-toolkit/internal/text/text-controller-placeholder-handler.h>
35 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
36
37 namespace
38 {
39
40 #if defined(DEBUG_ENABLED)
41 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
42 #endif
43
44 const float MAX_FLOAT = std::numeric_limits<float>::max();
45
46 const std::string EMPTY_STRING("");
47
48 float ConvertToEven( float value )
49 {
50   int intValue(static_cast<int>( value ));
51   return static_cast<float>( intValue + ( intValue & 1 ) );
52 }
53
54 int ConvertPixelToPint( float pixel )
55 {
56   unsigned int horizontalDpi = 0u;
57   unsigned int verticalDpi = 0u;
58   Dali::TextAbstraction::FontClient fontClient = Dali::TextAbstraction::FontClient::Get();
59   fontClient.GetDpi( horizontalDpi, verticalDpi );
60
61   return ( pixel * 72.f ) / static_cast< float >( horizontalDpi );
62 }
63
64 } // namespace
65
66 namespace Dali
67 {
68
69 namespace Toolkit
70 {
71
72 namespace Text
73 {
74
75 // public : Constructor.
76
77 ControllerPtr Controller::New()
78 {
79   return ControllerPtr( new Controller() );
80 }
81
82 ControllerPtr Controller::New( ControlInterface* controlInterface )
83 {
84   return ControllerPtr( new Controller( controlInterface ) );
85 }
86
87 ControllerPtr Controller::New( ControlInterface* controlInterface,
88                                EditableControlInterface* editableControlInterface,
89                                SelectableControlInterface* selectableControlInterface )
90 {
91   return ControllerPtr( new Controller( controlInterface,
92                                         editableControlInterface,
93                                         selectableControlInterface ) );
94 }
95
96 // public : Configure the text controller.
97
98 void Controller::EnableTextInput( DecoratorPtr decorator, InputMethodContext& inputMethodContext )
99 {
100   if( !decorator )
101   {
102     delete mImpl->mEventData;
103     mImpl->mEventData = NULL;
104
105     // Nothing else to do.
106     return;
107   }
108
109   if( NULL == mImpl->mEventData )
110   {
111     mImpl->mEventData = new EventData( decorator, inputMethodContext );
112   }
113 }
114
115 void Controller::SetGlyphType( TextAbstraction::GlyphType glyphType )
116 {
117   // Metrics for bitmap & vector based glyphs are different
118   mImpl->mMetrics->SetGlyphType( glyphType );
119
120   // Clear the font-specific data
121   ClearFontData();
122
123   mImpl->RequestRelayout();
124 }
125
126 void Controller::SetMarkupProcessorEnabled( bool enable )
127 {
128   if( enable != mImpl->mMarkupProcessorEnabled )
129   {
130     //If Text was already set, call the SetText again for enabling or disabling markup
131     mImpl->mMarkupProcessorEnabled = enable;
132     std::string text;
133     GetText( text );
134     SetText( text );
135   }
136 }
137
138 bool Controller::IsMarkupProcessorEnabled() const
139 {
140   return mImpl->mMarkupProcessorEnabled;
141 }
142
143 void Controller::SetAutoScrollEnabled( bool enable )
144 {
145   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled[%s] SingleBox[%s]-> [%p]\n", (enable)?"true":"false", ( mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX)?"true":"false", this );
146
147   if( mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX )
148   {
149     if( enable )
150     {
151       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n" );
152       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
153                                                                LAYOUT                    |
154                                                                ALIGN                     |
155                                                                UPDATE_LAYOUT_SIZE        |
156                                                                UPDATE_DIRECTION          |
157                                                                REORDER );
158
159     }
160     else
161     {
162       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n");
163       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
164                                                                LAYOUT                    |
165                                                                ALIGN                     |
166                                                                UPDATE_LAYOUT_SIZE        |
167                                                                REORDER );
168     }
169
170     mImpl->mIsAutoScrollEnabled = enable;
171     mImpl->RequestRelayout();
172   }
173   else
174   {
175     DALI_LOG_WARNING( "Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored\n" );
176     mImpl->mIsAutoScrollEnabled = false;
177   }
178 }
179
180 bool Controller::IsAutoScrollEnabled() const
181 {
182   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::IsAutoScrollEnabled[%s]\n", mImpl->mIsAutoScrollEnabled?"true":"false" );
183
184   return mImpl->mIsAutoScrollEnabled;
185 }
186
187 CharacterDirection Controller::GetAutoScrollDirection() const
188 {
189   return mImpl->mIsTextDirectionRTL;
190 }
191
192 float Controller::GetAutoScrollLineAlignment() const
193 {
194   float offset = 0.f;
195
196   if( mImpl->mModel->mVisualModel &&
197       ( 0u != mImpl->mModel->mVisualModel->mLines.Count() ) )
198   {
199     offset = ( *mImpl->mModel->mVisualModel->mLines.Begin() ).alignmentOffset;
200   }
201
202   return offset;
203 }
204
205 void Controller::SetHorizontalScrollEnabled( bool enable )
206 {
207   if( ( NULL != mImpl->mEventData ) &&
208       mImpl->mEventData->mDecorator )
209   {
210     mImpl->mEventData->mDecorator->SetHorizontalScrollEnabled( enable );
211   }
212 }
213 bool Controller::IsHorizontalScrollEnabled() const
214 {
215   if( ( NULL != mImpl->mEventData ) &&
216       mImpl->mEventData->mDecorator )
217   {
218     return mImpl->mEventData->mDecorator->IsHorizontalScrollEnabled();
219   }
220
221   return false;
222 }
223
224 void Controller::SetVerticalScrollEnabled( bool enable )
225 {
226   if( ( NULL != mImpl->mEventData ) &&
227       mImpl->mEventData->mDecorator )
228   {
229     if( mImpl->mEventData->mDecorator )
230     {
231       mImpl->mEventData->mDecorator->SetVerticalScrollEnabled( enable );
232     }
233   }
234 }
235
236 bool Controller::IsVerticalScrollEnabled() const
237 {
238   if( ( NULL != mImpl->mEventData ) &&
239       mImpl->mEventData->mDecorator )
240   {
241     return mImpl->mEventData->mDecorator->IsVerticalScrollEnabled();
242   }
243
244   return false;
245 }
246
247 void Controller::SetSmoothHandlePanEnabled( bool enable )
248 {
249   if( ( NULL != mImpl->mEventData ) &&
250       mImpl->mEventData->mDecorator )
251   {
252     mImpl->mEventData->mDecorator->SetSmoothHandlePanEnabled( enable );
253   }
254 }
255
256 bool Controller::IsSmoothHandlePanEnabled() const
257 {
258   if( ( NULL != mImpl->mEventData ) &&
259       mImpl->mEventData->mDecorator )
260   {
261     return mImpl->mEventData->mDecorator->IsSmoothHandlePanEnabled();
262   }
263
264   return false;
265 }
266
267 void Controller::SetMaximumNumberOfCharacters( Length maxCharacters )
268 {
269   mImpl->mMaximumNumberOfCharacters = maxCharacters;
270 }
271
272 int Controller::GetMaximumNumberOfCharacters()
273 {
274   return mImpl->mMaximumNumberOfCharacters;
275 }
276
277 void Controller::SetEnableCursorBlink( bool enable )
278 {
279   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" );
280
281   if( NULL != mImpl->mEventData )
282   {
283     mImpl->mEventData->mCursorBlinkEnabled = enable;
284
285     if( !enable &&
286         mImpl->mEventData->mDecorator )
287     {
288       mImpl->mEventData->mDecorator->StopCursorBlink();
289     }
290   }
291 }
292
293 bool Controller::GetEnableCursorBlink() const
294 {
295   if( NULL != mImpl->mEventData )
296   {
297     return mImpl->mEventData->mCursorBlinkEnabled;
298   }
299
300   return false;
301 }
302
303 void Controller::SetMultiLineEnabled( bool enable )
304 {
305   const Layout::Engine::Type layout = enable ? Layout::Engine::MULTI_LINE_BOX : Layout::Engine::SINGLE_LINE_BOX;
306
307   if( layout != mImpl->mLayoutEngine.GetLayout() )
308   {
309     // Set the layout type.
310     mImpl->mLayoutEngine.SetLayout( layout );
311
312     // Set the flags to redo the layout operations
313     const OperationsMask layoutOperations =  static_cast<OperationsMask>( LAYOUT             |
314                                                                           UPDATE_LAYOUT_SIZE |
315                                                                           ALIGN              |
316                                                                           REORDER );
317
318     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
319     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | layoutOperations );
320
321     // Need to recalculate natural size
322     mImpl->mRecalculateNaturalSize = true;
323
324     mImpl->RequestRelayout();
325   }
326 }
327
328 bool Controller::IsMultiLineEnabled() const
329 {
330   return Layout::Engine::MULTI_LINE_BOX == mImpl->mLayoutEngine.GetLayout();
331 }
332
333 void Controller::SetHorizontalAlignment( Text::HorizontalAlignment::Type alignment )
334 {
335   if( alignment != mImpl->mModel->mHorizontalAlignment )
336   {
337     // Set the alignment.
338     mImpl->mModel->mHorizontalAlignment = alignment;
339
340     // Set the flag to redo the alignment operation.
341     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
342
343     if( mImpl->mEventData )
344     {
345       mImpl->mEventData->mUpdateAlignment = true;
346
347       // Update the cursor if it's in editing mode
348       if( EventData::IsEditingState( mImpl->mEventData->mState ) )
349       {
350         mImpl->ChangeState( EventData::EDITING );
351         mImpl->mEventData->mUpdateCursorPosition = true;
352       }
353     }
354
355     mImpl->RequestRelayout();
356   }
357 }
358
359 Text::HorizontalAlignment::Type Controller::GetHorizontalAlignment() const
360 {
361   return mImpl->mModel->mHorizontalAlignment;
362 }
363
364 void Controller::SetVerticalAlignment( VerticalAlignment::Type alignment )
365 {
366   if( alignment != mImpl->mModel->mVerticalAlignment )
367   {
368     // Set the alignment.
369     mImpl->mModel->mVerticalAlignment = alignment;
370
371     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
372
373     mImpl->RequestRelayout();
374   }
375 }
376
377 VerticalAlignment::Type Controller::GetVerticalAlignment() const
378 {
379   return mImpl->mModel->mVerticalAlignment;
380 }
381
382 bool Controller::IsIgnoreSpacesAfterText() const
383 {
384   return mImpl->mModel->mIgnoreSpacesAfterText;
385 }
386
387 void Controller::SetIgnoreSpacesAfterText( bool ignore )
388 {
389   mImpl->mModel->mIgnoreSpacesAfterText = ignore;
390 }
391
392 bool Controller::IsMatchSystemLanguageDirection() const
393 {
394   return mImpl->mModel->mMatchSystemLanguageDirection;
395 }
396
397 void Controller::SetMatchSystemLanguageDirection( bool match )
398 {
399   mImpl->mModel->mMatchSystemLanguageDirection = match;
400 }
401
402 void Controller::SetLayoutDirection( Dali::LayoutDirection::Type layoutDirection )
403 {
404   mImpl->mLayoutDirection = layoutDirection;
405 }
406
407 bool Controller::IsShowingRealText() const
408 {
409   return mImpl->IsShowingRealText();
410 }
411
412
413 void Controller::SetLineWrapMode( Text::LineWrap::Mode lineWrapMode )
414 {
415   if( lineWrapMode != mImpl->mModel->mLineWrapMode )
416   {
417     // Set the text wrap mode.
418     mImpl->mModel->mLineWrapMode = lineWrapMode;
419
420
421     // Update Text layout for applying wrap mode
422     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
423                                                              ALIGN                     |
424                                                              LAYOUT                    |
425                                                              UPDATE_LAYOUT_SIZE        |
426                                                              REORDER                   );
427     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
428     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
429     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
430
431     // Request relayout
432     mImpl->RequestRelayout();
433   }
434 }
435
436 Text::LineWrap::Mode Controller::GetLineWrapMode() const
437 {
438   return mImpl->mModel->mLineWrapMode;
439 }
440
441 void Controller::SetTextElideEnabled( bool enabled )
442 {
443   mImpl->mModel->mElideEnabled = enabled;
444 }
445
446 bool Controller::IsTextElideEnabled() const
447 {
448   return mImpl->mModel->mElideEnabled;
449 }
450
451 void Controller::SetTextFitEnabled(bool enabled)
452 {
453   mImpl->mTextFitEnabled = enabled;
454 }
455
456 bool Controller::IsTextFitEnabled() const
457 {
458   return mImpl->mTextFitEnabled;
459 }
460
461 void Controller::SetTextFitMinSize( float minSize, FontSizeType type )
462 {
463   switch( type )
464   {
465     case POINT_SIZE:
466     {
467       mImpl->mTextFitMinSize = minSize;
468       break;
469     }
470     case PIXEL_SIZE:
471     {
472       mImpl->mTextFitMinSize = ConvertPixelToPint( minSize );
473       break;
474     }
475   }
476 }
477
478 float Controller::GetTextFitMinSize() const
479 {
480   return mImpl->mTextFitMinSize;
481 }
482
483 void Controller::SetTextFitMaxSize( float maxSize, FontSizeType type )
484 {
485   switch( type )
486   {
487     case POINT_SIZE:
488     {
489       mImpl->mTextFitMaxSize = maxSize;
490       break;
491     }
492     case PIXEL_SIZE:
493     {
494       mImpl->mTextFitMaxSize = ConvertPixelToPint( maxSize );
495       break;
496     }
497   }
498 }
499
500 float Controller::GetTextFitMaxSize() const
501 {
502   return mImpl->mTextFitMaxSize;
503 }
504
505 void Controller::SetTextFitStepSize( float step, FontSizeType type )
506 {
507   switch( type )
508   {
509     case POINT_SIZE:
510     {
511       mImpl->mTextFitStepSize = step;
512       break;
513     }
514     case PIXEL_SIZE:
515     {
516       mImpl->mTextFitStepSize = ConvertPixelToPint( step );
517       break;
518     }
519   }
520 }
521
522 float Controller::GetTextFitStepSize() const
523 {
524   return mImpl->mTextFitStepSize;
525 }
526
527 void Controller::SetTextFitContentSize(Vector2 size)
528 {
529   mImpl->mTextFitContentSize = size;
530 }
531
532 Vector2 Controller::GetTextFitContentSize() const
533 {
534   return mImpl->mTextFitContentSize;
535 }
536
537 void Controller::SetPlaceholderTextElideEnabled( bool enabled )
538 {
539   PlaceholderHandler::SetPlaceholderTextElideEnabled(*this, enabled);
540 }
541
542 bool Controller::IsPlaceholderTextElideEnabled() const
543 {
544   return PlaceholderHandler::IsPlaceholderTextElideEnabled(*this);
545 }
546
547 void Controller::SetSelectionEnabled( bool enabled )
548 {
549   mImpl->mEventData->mSelectionEnabled = enabled;
550 }
551
552 bool Controller::IsSelectionEnabled() const
553 {
554   return mImpl->mEventData->mSelectionEnabled;
555 }
556
557 void Controller::SetShiftSelectionEnabled( bool enabled )
558 {
559   mImpl->mEventData->mShiftSelectionFlag = enabled;
560 }
561
562 bool Controller::IsShiftSelectionEnabled() const
563 {
564   return mImpl->mEventData->mShiftSelectionFlag;
565 }
566
567 void Controller::SetGrabHandleEnabled( bool enabled )
568 {
569   mImpl->mEventData->mGrabHandleEnabled = enabled;
570 }
571
572 bool Controller::IsGrabHandleEnabled() const
573 {
574   return mImpl->mEventData->mGrabHandleEnabled;
575 }
576
577 void Controller::SetGrabHandlePopupEnabled(bool enabled)
578 {
579   mImpl->mEventData->mGrabHandlePopupEnabled = enabled;
580 }
581
582 bool Controller::IsGrabHandlePopupEnabled() const
583 {
584   return mImpl->mEventData->mGrabHandlePopupEnabled;
585 }
586
587 // public : Update
588
589 void Controller::SetText( const std::string& text )
590 {
591   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText\n" );
592
593   // Reset keyboard as text changed
594   mImpl->ResetInputMethodContext();
595
596   // Remove the previously set text and style.
597   ResetText();
598
599   // Remove the style.
600   ClearStyleData();
601
602   CharacterIndex lastCursorIndex = 0u;
603
604   if( NULL != mImpl->mEventData )
605   {
606     // If popup shown then hide it by switching to Editing state
607     if( ( EventData::SELECTING == mImpl->mEventData->mState )          ||
608         ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
609         ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) ||
610         ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) )
611     {
612       mImpl->ChangeState( EventData::EDITING );
613     }
614   }
615
616   if( !text.empty() )
617   {
618     mImpl->mModel->mVisualModel->SetTextColor( mImpl->mTextColor );
619
620     MarkupProcessData markupProcessData( mImpl->mModel->mLogicalModel->mColorRuns,
621                                          mImpl->mModel->mLogicalModel->mFontDescriptionRuns,
622                                          mImpl->mModel->mLogicalModel->mEmbeddedItems );
623
624     Length textSize = 0u;
625     const uint8_t* utf8 = NULL;
626     if( mImpl->mMarkupProcessorEnabled )
627     {
628       ProcessMarkupString( text, markupProcessData );
629       textSize = markupProcessData.markupProcessedText.size();
630
631       // This is a bit horrible but std::string returns a (signed) char*
632       utf8 = reinterpret_cast<const uint8_t*>( markupProcessData.markupProcessedText.c_str() );
633     }
634     else
635     {
636       textSize = text.size();
637
638       // This is a bit horrible but std::string returns a (signed) char*
639       utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
640     }
641
642     //  Convert text into UTF-32
643     Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
644     utf32Characters.Resize( textSize );
645
646     // Transform a text array encoded in utf8 into an array encoded in utf32.
647     // It returns the actual number of characters.
648     Length characterCount = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() );
649     utf32Characters.Resize( characterCount );
650
651     DALI_ASSERT_DEBUG( textSize >= characterCount && "Invalid UTF32 conversion length" );
652     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, textSize, mImpl->mModel->mLogicalModel->mText.Count() );
653
654     // The characters to be added.
655     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
656
657     // To reset the cursor position
658     lastCursorIndex = characterCount;
659
660     // Update the rest of the model during size negotiation
661     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
662
663     // The natural size needs to be re-calculated.
664     mImpl->mRecalculateNaturalSize = true;
665
666     // The text direction needs to be updated.
667     mImpl->mUpdateTextDirection = true;
668
669     // Apply modifications to the model
670     mImpl->mOperationsPending = ALL_OPERATIONS;
671   }
672   else
673   {
674     ShowPlaceholderText();
675   }
676
677   // Resets the cursor position.
678   ResetCursorPosition( lastCursorIndex );
679
680   // Scrolls the text to make the cursor visible.
681   ResetScrollPosition();
682
683   mImpl->RequestRelayout();
684
685   if( NULL != mImpl->mEventData )
686   {
687     // Cancel previously queued events
688     mImpl->mEventData->mEventQueue.clear();
689   }
690
691   // Do this last since it provides callbacks into application code.
692   if( NULL != mImpl->mEditableControlInterface )
693   {
694     mImpl->mEditableControlInterface->TextChanged();
695   }
696 }
697
698 void Controller::GetText( std::string& text ) const
699 {
700   if( !mImpl->IsShowingPlaceholderText() )
701   {
702     // Retrieves the text string.
703     mImpl->GetText( 0u, text );
704   }
705   else
706   {
707     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this );
708   }
709 }
710
711 void Controller::SetPlaceholderText( PlaceholderType type, const std::string& text )
712 {
713   PlaceholderHandler::SetPlaceholderText(*this, type, text);
714 }
715
716 void Controller::GetPlaceholderText( PlaceholderType type, std::string& text ) const
717 {
718   PlaceholderHandler::GetPlaceholderText(*this, type, text );
719 }
720
721 void Controller::UpdateAfterFontChange( const std::string& newDefaultFont )
722 {
723   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange\n");
724
725   if( !mImpl->mFontDefaults->familyDefined ) // If user defined font then should not update when system font changes
726   {
727     DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str() );
728     mImpl->mFontDefaults->mFontDescription.family = newDefaultFont;
729
730     ClearFontData();
731
732     mImpl->RequestRelayout();
733   }
734 }
735
736 void Controller::RetrieveSelection( std::string& selectedText ) const
737 {
738   mImpl->RetrieveSelection( selectedText, false );
739 }
740
741 void Controller::SetSelection( int start, int end )
742 {
743   mImpl->SetSelection( start, end );
744 }
745
746 std::pair< int, int > Controller::GetSelectionIndexes() const
747 {
748   return mImpl->GetSelectionIndexes();
749 }
750
751 void Controller::CopyStringToClipboard( const std::string& source )
752 {
753   mImpl->CopyStringToClipboard( source );
754 }
755
756 void Controller::SendSelectionToClipboard( bool deleteAfterSending )
757 {
758   mImpl->SendSelectionToClipboard( deleteAfterSending );
759 }
760
761 // public : Default style & Input style
762
763 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
764 {
765   if( NULL == mImpl->mFontDefaults )
766   {
767     mImpl->mFontDefaults = new FontDefaults();
768   }
769
770   mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
771   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str());
772   mImpl->mFontDefaults->familyDefined = !defaultFontFamily.empty();
773
774   if( mImpl->mEventData )
775   {
776     // Update the cursor position if it's in editing mode
777     if( EventData::IsEditingState( mImpl->mEventData->mState ) )
778     {
779       mImpl->mEventData->mDecoratorUpdated = true;
780       mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font family is updated.
781     }
782   }
783
784   // Clear the font-specific data
785   ClearFontData();
786
787   mImpl->RequestRelayout();
788 }
789
790 const std::string& Controller::GetDefaultFontFamily() const
791 {
792   if( NULL != mImpl->mFontDefaults )
793   {
794     return mImpl->mFontDefaults->mFontDescription.family;
795   }
796
797   return EMPTY_STRING;
798 }
799
800 void Controller::SetPlaceholderFontFamily( const std::string& placeholderTextFontFamily )
801 {
802   PlaceholderHandler::SetPlaceholderFontFamily(*this, placeholderTextFontFamily);
803 }
804
805 const std::string& Controller::GetPlaceholderFontFamily() const
806 {
807   return PlaceholderHandler::GetPlaceholderFontFamily(*this);
808 }
809
810 void Controller::SetDefaultFontWeight( FontWeight weight )
811 {
812   if( NULL == mImpl->mFontDefaults )
813   {
814     mImpl->mFontDefaults = new FontDefaults();
815   }
816
817   mImpl->mFontDefaults->mFontDescription.weight = weight;
818   mImpl->mFontDefaults->weightDefined = true;
819
820   if( mImpl->mEventData )
821   {
822     // Update the cursor position if it's in editing mode
823     if( EventData::IsEditingState( mImpl->mEventData->mState ) )
824     {
825       mImpl->mEventData->mDecoratorUpdated = true;
826       mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font weight is updated.
827     }
828   }
829
830   // Clear the font-specific data
831   ClearFontData();
832
833   mImpl->RequestRelayout();
834 }
835
836 bool Controller::IsDefaultFontWeightDefined() const
837 {
838   if( NULL != mImpl->mFontDefaults )
839   {
840     return mImpl->mFontDefaults->weightDefined;
841   }
842
843   return false;
844 }
845
846 FontWeight Controller::GetDefaultFontWeight() const
847 {
848   if( NULL != mImpl->mFontDefaults )
849   {
850     return mImpl->mFontDefaults->mFontDescription.weight;
851   }
852
853   return TextAbstraction::FontWeight::NORMAL;
854 }
855
856 void Controller::SetPlaceholderTextFontWeight( FontWeight weight )
857 {
858   PlaceholderHandler::SetPlaceholderTextFontWeight(*this, weight);
859 }
860
861 bool Controller::IsPlaceholderTextFontWeightDefined() const
862 {
863   return PlaceholderHandler::IsPlaceholderTextFontWeightDefined(*this);;
864 }
865
866 FontWeight Controller::GetPlaceholderTextFontWeight() const
867 {
868   return PlaceholderHandler::GetPlaceholderTextFontWeight(*this);
869 }
870
871 void Controller::SetDefaultFontWidth( FontWidth width )
872 {
873   if( NULL == mImpl->mFontDefaults )
874   {
875     mImpl->mFontDefaults = new FontDefaults();
876   }
877
878   mImpl->mFontDefaults->mFontDescription.width = width;
879   mImpl->mFontDefaults->widthDefined = true;
880
881   if( mImpl->mEventData )
882   {
883     // Update the cursor position if it's in editing mode
884     if( EventData::IsEditingState( mImpl->mEventData->mState ) )
885     {
886       mImpl->mEventData->mDecoratorUpdated = true;
887       mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font width is updated.
888     }
889   }
890
891   // Clear the font-specific data
892   ClearFontData();
893
894   mImpl->RequestRelayout();
895 }
896
897 bool Controller::IsDefaultFontWidthDefined() const
898 {
899   if( NULL != mImpl->mFontDefaults )
900   {
901     return mImpl->mFontDefaults->widthDefined;
902   }
903
904   return false;
905 }
906
907 FontWidth Controller::GetDefaultFontWidth() const
908 {
909   if( NULL != mImpl->mFontDefaults )
910   {
911     return mImpl->mFontDefaults->mFontDescription.width;
912   }
913
914   return TextAbstraction::FontWidth::NORMAL;
915 }
916
917 void Controller::SetPlaceholderTextFontWidth( FontWidth width )
918 {
919   PlaceholderHandler::SetPlaceholderTextFontWidth(*this, width);
920 }
921
922 bool Controller::IsPlaceholderTextFontWidthDefined() const
923 {
924   return PlaceholderHandler::IsPlaceholderTextFontWidthDefined(*this);
925 }
926
927 FontWidth Controller::GetPlaceholderTextFontWidth() const
928 {
929   return PlaceholderHandler::GetPlaceholderTextFontWidth(*this);
930 }
931
932 void Controller::SetDefaultFontSlant( FontSlant slant )
933 {
934   if( NULL == mImpl->mFontDefaults )
935   {
936     mImpl->mFontDefaults = new FontDefaults();
937   }
938
939   mImpl->mFontDefaults->mFontDescription.slant = slant;
940   mImpl->mFontDefaults->slantDefined = true;
941
942   if( mImpl->mEventData )
943   {
944     // Update the cursor position if it's in editing mode
945     if( EventData::IsEditingState( mImpl->mEventData->mState ) )
946     {
947       mImpl->mEventData->mDecoratorUpdated = true;
948       mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font slant is updated.
949     }
950   }
951
952   // Clear the font-specific data
953   ClearFontData();
954
955   mImpl->RequestRelayout();
956 }
957
958 bool Controller::IsDefaultFontSlantDefined() const
959 {
960   if( NULL != mImpl->mFontDefaults )
961   {
962     return mImpl->mFontDefaults->slantDefined;
963   }
964   return false;
965 }
966
967 FontSlant Controller::GetDefaultFontSlant() const
968 {
969   if( NULL != mImpl->mFontDefaults )
970   {
971     return mImpl->mFontDefaults->mFontDescription.slant;
972   }
973
974   return TextAbstraction::FontSlant::NORMAL;
975 }
976
977 void Controller::SetPlaceholderTextFontSlant( FontSlant slant )
978 {
979   PlaceholderHandler::SetPlaceholderTextFontSlant(*this, slant);
980 }
981
982 bool Controller::IsPlaceholderTextFontSlantDefined() const
983 {
984   return PlaceholderHandler::IsPlaceholderTextFontSlantDefined(*this);
985 }
986
987 FontSlant Controller::GetPlaceholderTextFontSlant() const
988 {
989   return PlaceholderHandler::GetPlaceholderTextFontSlant(*this);
990 }
991
992 void Controller::SetDefaultFontSize( float fontSize, FontSizeType type )
993 {
994   if( NULL == mImpl->mFontDefaults )
995   {
996     mImpl->mFontDefaults = new FontDefaults();
997   }
998
999   switch( type )
1000   {
1001     case POINT_SIZE:
1002     {
1003       mImpl->mFontDefaults->mDefaultPointSize = fontSize;
1004       mImpl->mFontDefaults->sizeDefined = true;
1005       break;
1006     }
1007     case PIXEL_SIZE:
1008     {
1009       // Point size = Pixel size * 72.f / DPI
1010       unsigned int horizontalDpi = 0u;
1011       unsigned int verticalDpi = 0u;
1012       TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
1013       fontClient.GetDpi( horizontalDpi, verticalDpi );
1014
1015       mImpl->mFontDefaults->mDefaultPointSize = ( fontSize * 72.f ) / static_cast< float >( horizontalDpi );
1016       mImpl->mFontDefaults->sizeDefined = true;
1017       break;
1018     }
1019   }
1020
1021   if( mImpl->mEventData )
1022   {
1023     // Update the cursor position if it's in editing mode
1024     if( EventData::IsEditingState( mImpl->mEventData->mState ) )
1025     {
1026       mImpl->mEventData->mDecoratorUpdated = true;
1027       mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font size is updated.
1028     }
1029   }
1030
1031   // Clear the font-specific data
1032   ClearFontData();
1033
1034   mImpl->RequestRelayout();
1035 }
1036
1037 float Controller::GetDefaultFontSize( FontSizeType type ) const
1038 {
1039   float value = 0.0f;
1040   if( NULL != mImpl->mFontDefaults )
1041   {
1042     switch( type )
1043     {
1044       case POINT_SIZE:
1045       {
1046         value = mImpl->mFontDefaults->mDefaultPointSize;
1047         break;
1048       }
1049       case PIXEL_SIZE:
1050       {
1051         // Pixel size = Point size * DPI / 72.f
1052         unsigned int horizontalDpi = 0u;
1053         unsigned int verticalDpi = 0u;
1054         TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
1055         fontClient.GetDpi( horizontalDpi, verticalDpi );
1056
1057         value = mImpl->mFontDefaults->mDefaultPointSize * static_cast< float >( horizontalDpi ) / 72.f;
1058         break;
1059       }
1060     }
1061     return value;
1062   }
1063
1064   return value;
1065 }
1066
1067 void Controller::SetPlaceholderTextFontSize( float fontSize, FontSizeType type )
1068 {
1069   PlaceholderHandler::SetPlaceholderTextFontSize(*this, fontSize, type);
1070 }
1071
1072 float Controller::GetPlaceholderTextFontSize( FontSizeType type ) const
1073 {
1074   return PlaceholderHandler::GetPlaceholderTextFontSize(*this, type);
1075 }
1076
1077 void Controller::SetDefaultColor( const Vector4& color )
1078 {
1079   mImpl->mTextColor = color;
1080
1081   if( !mImpl->IsShowingPlaceholderText() )
1082   {
1083     mImpl->mModel->mVisualModel->SetTextColor( color );
1084
1085     mImpl->mModel->mLogicalModel->mColorRuns.Clear();
1086
1087     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
1088
1089     mImpl->RequestRelayout();
1090   }
1091 }
1092
1093 const Vector4& Controller::GetDefaultColor() const
1094 {
1095   return mImpl->mTextColor;
1096 }
1097
1098 void Controller::SetPlaceholderTextColor( const Vector4& textColor )
1099 {
1100   PlaceholderHandler::SetPlaceholderTextColor(*this, textColor);
1101 }
1102
1103 const Vector4& Controller::GetPlaceholderTextColor() const
1104 {
1105   return PlaceholderHandler::GetPlaceholderTextColor(*this);
1106 }
1107
1108 void Controller::SetShadowOffset( const Vector2& shadowOffset )
1109 {
1110   mImpl->mModel->mVisualModel->SetShadowOffset( shadowOffset );
1111
1112   mImpl->RequestRelayout();
1113 }
1114
1115 const Vector2& Controller::GetShadowOffset() const
1116 {
1117   return mImpl->mModel->mVisualModel->GetShadowOffset();
1118 }
1119
1120 void Controller::SetShadowColor( const Vector4& shadowColor )
1121 {
1122   mImpl->mModel->mVisualModel->SetShadowColor( shadowColor );
1123
1124   mImpl->RequestRelayout();
1125 }
1126
1127 const Vector4& Controller::GetShadowColor() const
1128 {
1129   return mImpl->mModel->mVisualModel->GetShadowColor();
1130 }
1131
1132 void Controller::SetShadowBlurRadius( const float& shadowBlurRadius )
1133 {
1134   if ( fabsf( GetShadowBlurRadius() - shadowBlurRadius ) > Math::MACHINE_EPSILON_1 )
1135   {
1136     mImpl->mModel->mVisualModel->SetShadowBlurRadius( shadowBlurRadius );
1137
1138     mImpl->RequestRelayout();
1139   }
1140 }
1141
1142 const float& Controller::GetShadowBlurRadius() const
1143 {
1144   return mImpl->mModel->mVisualModel->GetShadowBlurRadius();
1145 }
1146
1147 void Controller::SetUnderlineColor( const Vector4& color )
1148 {
1149   mImpl->mModel->mVisualModel->SetUnderlineColor( color );
1150
1151   mImpl->RequestRelayout();
1152 }
1153
1154 const Vector4& Controller::GetUnderlineColor() const
1155 {
1156   return mImpl->mModel->mVisualModel->GetUnderlineColor();
1157 }
1158
1159 void Controller::SetUnderlineEnabled( bool enabled )
1160 {
1161   mImpl->mModel->mVisualModel->SetUnderlineEnabled( enabled );
1162
1163   mImpl->RequestRelayout();
1164 }
1165
1166 bool Controller::IsUnderlineEnabled() const
1167 {
1168   return mImpl->mModel->mVisualModel->IsUnderlineEnabled();
1169 }
1170
1171 void Controller::SetUnderlineHeight( float height )
1172 {
1173   mImpl->mModel->mVisualModel->SetUnderlineHeight( height );
1174
1175   mImpl->RequestRelayout();
1176 }
1177
1178 float Controller::GetUnderlineHeight() const
1179 {
1180   return mImpl->mModel->mVisualModel->GetUnderlineHeight();
1181 }
1182
1183 void Controller::SetOutlineColor( const Vector4& color )
1184 {
1185   mImpl->mModel->mVisualModel->SetOutlineColor( color );
1186
1187   mImpl->RequestRelayout();
1188 }
1189
1190 const Vector4& Controller::GetOutlineColor() const
1191 {
1192   return mImpl->mModel->mVisualModel->GetOutlineColor();
1193 }
1194
1195 void Controller::SetOutlineWidth( uint16_t width )
1196 {
1197   mImpl->mModel->mVisualModel->SetOutlineWidth( width );
1198
1199   mImpl->RequestRelayout();
1200 }
1201
1202 uint16_t Controller::GetOutlineWidth() const
1203 {
1204   return mImpl->mModel->mVisualModel->GetOutlineWidth();
1205 }
1206
1207 void Controller::SetBackgroundColor( const Vector4& color )
1208 {
1209   mImpl->mModel->mVisualModel->SetBackgroundColor( color );
1210
1211   mImpl->RequestRelayout();
1212 }
1213
1214 const Vector4& Controller::GetBackgroundColor() const
1215 {
1216   return mImpl->mModel->mVisualModel->GetBackgroundColor();
1217 }
1218
1219 void Controller::SetBackgroundEnabled( bool enabled )
1220 {
1221   mImpl->mModel->mVisualModel->SetBackgroundEnabled( enabled );
1222
1223   mImpl->RequestRelayout();
1224 }
1225
1226 bool Controller::IsBackgroundEnabled() const
1227 {
1228   return mImpl->mModel->mVisualModel->IsBackgroundEnabled();
1229 }
1230
1231 void Controller::SetDefaultEmbossProperties( const std::string& embossProperties )
1232 {
1233   if( NULL == mImpl->mEmbossDefaults )
1234   {
1235     mImpl->mEmbossDefaults = new EmbossDefaults();
1236   }
1237
1238   mImpl->mEmbossDefaults->properties = embossProperties;
1239 }
1240
1241 const std::string& Controller::GetDefaultEmbossProperties() const
1242 {
1243   if( NULL != mImpl->mEmbossDefaults )
1244   {
1245     return mImpl->mEmbossDefaults->properties;
1246   }
1247
1248   return EMPTY_STRING;
1249 }
1250
1251 void Controller::SetDefaultOutlineProperties( const std::string& outlineProperties )
1252 {
1253   if( NULL == mImpl->mOutlineDefaults )
1254   {
1255     mImpl->mOutlineDefaults = new OutlineDefaults();
1256   }
1257
1258   mImpl->mOutlineDefaults->properties = outlineProperties;
1259 }
1260
1261 const std::string& Controller::GetDefaultOutlineProperties() const
1262 {
1263   if( NULL != mImpl->mOutlineDefaults )
1264   {
1265     return mImpl->mOutlineDefaults->properties;
1266   }
1267
1268   return EMPTY_STRING;
1269 }
1270
1271 bool Controller::SetDefaultLineSpacing( float lineSpacing )
1272 {
1273   if( std::fabs( lineSpacing - mImpl->mLayoutEngine.GetDefaultLineSpacing() ) > Math::MACHINE_EPSILON_1000 )
1274   {
1275     mImpl->mLayoutEngine.SetDefaultLineSpacing(lineSpacing);
1276     mImpl->mRecalculateNaturalSize = true;
1277     return true;
1278   }
1279   return false;
1280 }
1281
1282 float Controller::GetDefaultLineSpacing() const
1283 {
1284   return mImpl->mLayoutEngine.GetDefaultLineSpacing();
1285 }
1286
1287 bool Controller::SetDefaultLineSize( float lineSize )
1288 {
1289   if( std::fabs( lineSize - mImpl->mLayoutEngine.GetDefaultLineSize() ) > Math::MACHINE_EPSILON_1000 )
1290   {
1291     mImpl->mLayoutEngine.SetDefaultLineSize(lineSize);
1292     mImpl->mRecalculateNaturalSize = true;
1293     return true;
1294   }
1295   return false;
1296 }
1297
1298 float Controller::GetDefaultLineSize() const
1299 {
1300   return mImpl->mLayoutEngine.GetDefaultLineSize();
1301 }
1302
1303 void Controller::SetInputColor( const Vector4& color )
1304 {
1305   if( NULL != mImpl->mEventData )
1306   {
1307     mImpl->mEventData->mInputStyle.textColor = color;
1308     mImpl->mEventData->mInputStyle.isDefaultColor = false;
1309
1310     if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState )
1311     {
1312       const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition;
1313
1314       // Get start and end position of selection
1315       const CharacterIndex startOfSelectedText = handlesCrossed ? mImpl->mEventData->mRightSelectionPosition : mImpl->mEventData->mLeftSelectionPosition;
1316       const Length lengthOfSelectedText = ( handlesCrossed ? mImpl->mEventData->mLeftSelectionPosition : mImpl->mEventData->mRightSelectionPosition ) - startOfSelectedText;
1317
1318       // Add the color run.
1319       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
1320       mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
1321
1322       ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
1323       colorRun.color = color;
1324       colorRun.characterRun.characterIndex = startOfSelectedText;
1325       colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
1326
1327       // Request to relayout.
1328       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
1329       mImpl->RequestRelayout();
1330
1331       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1332       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1333       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1334     }
1335   }
1336 }
1337
1338 const Vector4& Controller::GetInputColor() const
1339 {
1340   if( NULL != mImpl->mEventData )
1341   {
1342     return mImpl->mEventData->mInputStyle.textColor;
1343   }
1344
1345   // Return the default text's color if there is no EventData.
1346   return mImpl->mTextColor;
1347
1348 }
1349
1350 void Controller::SetInputFontFamily( const std::string& fontFamily )
1351 {
1352   InputFontHandler::SetInputFontFamily(*this, fontFamily);
1353 }
1354
1355 const std::string& Controller::GetInputFontFamily() const
1356 {
1357   return InputFontHandler::GetInputFontFamily(*this);
1358 }
1359
1360 void Controller::SetInputFontWeight( FontWeight weight )
1361 {
1362   InputFontHandler::SetInputFontWeight(*this, weight);
1363 }
1364
1365 bool Controller::IsInputFontWeightDefined() const
1366 {
1367   return InputFontHandler::IsInputFontWeightDefined(*this);
1368 }
1369
1370 FontWeight Controller::GetInputFontWeight() const
1371 {
1372   return InputFontHandler::GetInputFontWeight(*this);
1373 }
1374
1375 void Controller::SetInputFontWidth( FontWidth width )
1376 {
1377   InputFontHandler::SetInputFontWidth(*this, width);
1378 }
1379
1380 bool Controller::IsInputFontWidthDefined() const
1381 {
1382   return InputFontHandler::IsInputFontWidthDefined(*this);
1383 }
1384
1385 FontWidth Controller::GetInputFontWidth() const
1386 {
1387   return InputFontHandler::GetInputFontWidth(*this);
1388 }
1389
1390 void Controller::SetInputFontSlant( FontSlant slant )
1391 {
1392   InputFontHandler::SetInputFontSlant(*this, slant);
1393 }
1394
1395 bool Controller::IsInputFontSlantDefined() const
1396 {
1397   return InputFontHandler::IsInputFontSlantDefined(*this);
1398 }
1399
1400 FontSlant Controller::GetInputFontSlant() const
1401 {
1402   return InputFontHandler::GetInputFontSlant(*this);
1403 }
1404
1405 void Controller::SetInputFontPointSize( float size )
1406 {
1407   InputFontHandler::SetInputFontPointSize(*this, size);
1408 }
1409
1410 float Controller::GetInputFontPointSize() const
1411 {
1412   return InputFontHandler::GetInputFontPointSize(*this);
1413 }
1414
1415 void Controller::SetInputLineSpacing( float lineSpacing )
1416 {
1417   if( NULL != mImpl->mEventData )
1418   {
1419     mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing;
1420     mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
1421   }
1422 }
1423
1424 float Controller::GetInputLineSpacing() const
1425 {
1426   if( NULL != mImpl->mEventData )
1427   {
1428     return mImpl->mEventData->mInputStyle.lineSpacing;
1429   }
1430
1431   return 0.f;
1432 }
1433
1434 void Controller::SetInputShadowProperties( const std::string& shadowProperties )
1435 {
1436   if( NULL != mImpl->mEventData )
1437   {
1438     mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
1439   }
1440 }
1441
1442 const std::string& Controller::GetInputShadowProperties() const
1443 {
1444   if( NULL != mImpl->mEventData )
1445   {
1446     return mImpl->mEventData->mInputStyle.shadowProperties;
1447   }
1448
1449   return EMPTY_STRING;
1450 }
1451
1452 void Controller::SetInputUnderlineProperties( const std::string& underlineProperties )
1453 {
1454   if( NULL != mImpl->mEventData )
1455   {
1456     mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
1457   }
1458 }
1459
1460 const std::string& Controller::GetInputUnderlineProperties() const
1461 {
1462   if( NULL != mImpl->mEventData )
1463   {
1464     return mImpl->mEventData->mInputStyle.underlineProperties;
1465   }
1466
1467   return EMPTY_STRING;
1468 }
1469
1470 void Controller::SetInputEmbossProperties( const std::string& embossProperties )
1471 {
1472   if( NULL != mImpl->mEventData )
1473   {
1474     mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
1475   }
1476 }
1477
1478 const std::string& Controller::GetInputEmbossProperties() const
1479 {
1480   if( NULL != mImpl->mEventData )
1481   {
1482     return mImpl->mEventData->mInputStyle.embossProperties;
1483   }
1484
1485   return GetDefaultEmbossProperties();
1486 }
1487
1488 void Controller::SetInputOutlineProperties( const std::string& outlineProperties )
1489 {
1490   if( NULL != mImpl->mEventData )
1491   {
1492     mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
1493   }
1494 }
1495
1496 const std::string& Controller::GetInputOutlineProperties() const
1497 {
1498   if( NULL != mImpl->mEventData )
1499   {
1500     return mImpl->mEventData->mInputStyle.outlineProperties;
1501   }
1502
1503   return GetDefaultOutlineProperties();
1504 }
1505
1506 void Controller::SetInputModePassword( bool passwordInput )
1507 {
1508   if( NULL != mImpl->mEventData )
1509   {
1510     mImpl->mEventData->mPasswordInput = passwordInput;
1511   }
1512 }
1513
1514 bool Controller::IsInputModePassword()
1515 {
1516   if( NULL != mImpl->mEventData )
1517   {
1518     return mImpl->mEventData->mPasswordInput;
1519   }
1520   return false;
1521 }
1522
1523 void Controller::SetNoTextDoubleTapAction( NoTextTap::Action action )
1524 {
1525   if( NULL != mImpl->mEventData )
1526   {
1527     mImpl->mEventData->mDoubleTapAction = action;
1528   }
1529 }
1530
1531 Controller::NoTextTap::Action Controller::GetNoTextDoubleTapAction() const
1532 {
1533   NoTextTap::Action action = NoTextTap::NO_ACTION;
1534
1535   if( NULL != mImpl->mEventData )
1536   {
1537     action = mImpl->mEventData->mDoubleTapAction;
1538   }
1539
1540   return action;
1541 }
1542
1543 void Controller::SetNoTextLongPressAction( NoTextTap::Action action )
1544 {
1545   if( NULL != mImpl->mEventData )
1546   {
1547     mImpl->mEventData->mLongPressAction = action;
1548   }
1549 }
1550
1551 Controller::NoTextTap::Action Controller::GetNoTextLongPressAction() const
1552 {
1553   NoTextTap::Action action = NoTextTap::NO_ACTION;
1554
1555   if( NULL != mImpl->mEventData )
1556   {
1557     action = mImpl->mEventData->mLongPressAction;
1558   }
1559
1560   return action;
1561 }
1562
1563 bool Controller::IsUnderlineSetByString()
1564 {
1565   return mImpl->mUnderlineSetByString;
1566 }
1567
1568 void Controller::UnderlineSetByString( bool setByString )
1569 {
1570   mImpl->mUnderlineSetByString = setByString;
1571 }
1572
1573 bool Controller::IsShadowSetByString()
1574 {
1575   return mImpl->mShadowSetByString;
1576 }
1577
1578 void Controller::ShadowSetByString( bool setByString )
1579 {
1580   mImpl->mShadowSetByString = setByString;
1581 }
1582
1583 bool Controller::IsOutlineSetByString()
1584 {
1585   return mImpl->mOutlineSetByString;
1586 }
1587
1588 void Controller::OutlineSetByString( bool setByString )
1589 {
1590   mImpl->mOutlineSetByString = setByString;
1591 }
1592
1593 bool Controller::IsFontStyleSetByString()
1594 {
1595   return mImpl->mFontStyleSetByString;
1596 }
1597
1598 void Controller::FontStyleSetByString( bool setByString )
1599 {
1600   mImpl->mFontStyleSetByString = setByString;
1601 }
1602
1603 // public : Queries & retrieves.
1604
1605 Layout::Engine& Controller::GetLayoutEngine()
1606 {
1607   return mImpl->mLayoutEngine;
1608 }
1609
1610 View& Controller::GetView()
1611 {
1612   return mImpl->mView;
1613 }
1614
1615 Vector3 Controller::GetNaturalSize()
1616 {
1617   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n" );
1618   Vector3 naturalSize;
1619
1620   // Make sure the model is up-to-date before layouting
1621   ProcessModifyEvents();
1622
1623   if( mImpl->mRecalculateNaturalSize )
1624   {
1625     // Operations that can be done only once until the text changes.
1626     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1627                                                                            GET_SCRIPTS       |
1628                                                                            VALIDATE_FONTS    |
1629                                                                            GET_LINE_BREAKS   |
1630                                                                            BIDI_INFO         |
1631                                                                            SHAPE_TEXT        |
1632                                                                            GET_GLYPH_METRICS );
1633
1634     // Set the update info to relayout the whole text.
1635     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1636     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1637
1638     // Make sure the model is up-to-date before layouting
1639     mImpl->UpdateModel( onlyOnceOperations );
1640
1641     // Layout the text for the new width.
1642     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT | REORDER );
1643
1644     // Store the actual control's size to restore later.
1645     const Size actualControlSize = mImpl->mModel->mVisualModel->mControlSize;
1646
1647     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
1648                 static_cast<OperationsMask>( onlyOnceOperations |
1649                                              LAYOUT | REORDER ),
1650                 naturalSize.GetVectorXY() );
1651
1652     // Do not do again the only once operations.
1653     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1654
1655     // Do the size related operations again.
1656     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1657                                                                         ALIGN  |
1658                                                                         REORDER );
1659     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1660
1661     // Stores the natural size to avoid recalculate it again
1662     // unless the text/style changes.
1663     mImpl->mModel->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
1664
1665     mImpl->mRecalculateNaturalSize = false;
1666
1667     // Clear the update info. This info will be set the next time the text is updated.
1668     mImpl->mTextUpdateInfo.Clear();
1669     mImpl->mTextUpdateInfo.mClearAll = true;
1670
1671     // Restore the actual control's size.
1672     mImpl->mModel->mVisualModel->mControlSize = actualControlSize;
1673
1674     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1675   }
1676   else
1677   {
1678     naturalSize = mImpl->mModel->mVisualModel->GetNaturalSize();
1679
1680     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1681   }
1682
1683   naturalSize.x = ConvertToEven( naturalSize.x );
1684   naturalSize.y = ConvertToEven( naturalSize.y );
1685
1686   return naturalSize;
1687 }
1688
1689 bool Controller::CheckForTextFit( float pointSize, Size& layoutSize )
1690 {
1691   Size textSize;
1692   mImpl->mFontDefaults->mFitPointSize = pointSize;
1693   mImpl->mFontDefaults->sizeDefined = true;
1694   ClearFontData();
1695
1696   // Operations that can be done only once until the text changes.
1697   const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
1698                                                                               GET_SCRIPTS |
1699                                                                            VALIDATE_FONTS |
1700                                                                           GET_LINE_BREAKS |
1701                                                                                 BIDI_INFO |
1702                                                                                 SHAPE_TEXT|
1703                                                                          GET_GLYPH_METRICS );
1704
1705   mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1706   mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1707
1708   // Make sure the model is up-to-date before layouting
1709   mImpl->UpdateModel( onlyOnceOperations );
1710
1711   DoRelayout( Size( layoutSize.width, MAX_FLOAT ),
1712               static_cast<OperationsMask>( onlyOnceOperations | LAYOUT),
1713               textSize);
1714
1715   // Clear the update info. This info will be set the next time the text is updated.
1716   mImpl->mTextUpdateInfo.Clear();
1717   mImpl->mTextUpdateInfo.mClearAll = true;
1718
1719   if( textSize.width > layoutSize.width || textSize.height > layoutSize.height )
1720   {
1721     return false;
1722   }
1723   return true;
1724 }
1725
1726 void Controller::FitPointSizeforLayout( Size layoutSize )
1727 {
1728   const OperationsMask operations  = mImpl->mOperationsPending;
1729   if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) || mImpl->mTextFitContentSize != layoutSize )
1730   {
1731     bool actualellipsis = mImpl->mModel->mElideEnabled;
1732     float minPointSize = mImpl->mTextFitMinSize;
1733     float maxPointSize = mImpl->mTextFitMaxSize;
1734     float pointInterval = mImpl->mTextFitStepSize;
1735
1736     mImpl->mModel->mElideEnabled = false;
1737     Vector<float> pointSizeArray;
1738
1739     // check zero value
1740     if( pointInterval < 1.f )
1741     {
1742       mImpl->mTextFitStepSize = pointInterval = 1.0f;
1743     }
1744
1745     pointSizeArray.Reserve( static_cast< unsigned int >( ceil( ( maxPointSize - minPointSize ) / pointInterval ) ) );
1746
1747     for( float i = minPointSize; i < maxPointSize; i += pointInterval )
1748     {
1749       pointSizeArray.PushBack( i );
1750     }
1751
1752     pointSizeArray.PushBack( maxPointSize );
1753
1754     int bestSizeIndex = 0;
1755     int min = bestSizeIndex + 1;
1756     int max = pointSizeArray.Size() - 1;
1757     while( min <= max )
1758     {
1759       int destI = ( min + max ) / 2;
1760
1761       if( CheckForTextFit( pointSizeArray[destI], layoutSize ) )
1762       {
1763         bestSizeIndex = min;
1764         min = destI + 1;
1765       }
1766       else
1767       {
1768         max = destI - 1;
1769         bestSizeIndex = max;
1770       }
1771     }
1772
1773     mImpl->mModel->mElideEnabled = actualellipsis;
1774     mImpl->mFontDefaults->mFitPointSize = pointSizeArray[bestSizeIndex];
1775     mImpl->mFontDefaults->sizeDefined = true;
1776     ClearFontData();
1777   }
1778 }
1779
1780 float Controller::GetHeightForWidth( float width )
1781 {
1782   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width );
1783   // Make sure the model is up-to-date before layouting
1784   ProcessModifyEvents();
1785
1786   Size layoutSize;
1787   if( fabsf( width - mImpl->mModel->mVisualModel->mControlSize.width ) > Math::MACHINE_EPSILON_1000 ||
1788                                                          mImpl->mTextUpdateInfo.mFullRelayoutNeeded ||
1789                                                          mImpl->mTextUpdateInfo.mClearAll            )
1790   {
1791     // Operations that can be done only once until the text changes.
1792     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1793                                                                            GET_SCRIPTS       |
1794                                                                            VALIDATE_FONTS    |
1795                                                                            GET_LINE_BREAKS   |
1796                                                                            BIDI_INFO         |
1797                                                                            SHAPE_TEXT        |
1798                                                                            GET_GLYPH_METRICS );
1799
1800     // Set the update info to relayout the whole text.
1801     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1802     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1803
1804     // Make sure the model is up-to-date before layouting
1805     mImpl->UpdateModel( onlyOnceOperations );
1806
1807
1808     // Layout the text for the new width.
1809     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
1810
1811     // Store the actual control's width.
1812     const float actualControlWidth = mImpl->mModel->mVisualModel->mControlSize.width;
1813
1814     DoRelayout( Size( width, MAX_FLOAT ),
1815                 static_cast<OperationsMask>( onlyOnceOperations |
1816                                              LAYOUT ),
1817                 layoutSize );
1818
1819     // Do not do again the only once operations.
1820     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1821
1822     // Do the size related operations again.
1823     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1824                                                                         ALIGN  |
1825                                                                         REORDER );
1826
1827     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1828
1829     // Clear the update info. This info will be set the next time the text is updated.
1830     mImpl->mTextUpdateInfo.Clear();
1831     mImpl->mTextUpdateInfo.mClearAll = true;
1832
1833     // Restore the actual control's width.
1834     mImpl->mModel->mVisualModel->mControlSize.width = actualControlWidth;
1835
1836     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height );
1837   }
1838   else
1839   {
1840     layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
1841     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height );
1842   }
1843
1844   return layoutSize.height;
1845 }
1846
1847 int Controller::GetLineCount( float width )
1848 {
1849   GetHeightForWidth( width );
1850   int numberofLines = mImpl->mModel->GetNumberOfLines();
1851   return numberofLines;
1852 }
1853
1854 const ModelInterface* const Controller::GetTextModel() const
1855 {
1856   return mImpl->mModel.Get();
1857 }
1858
1859 float Controller::GetScrollAmountByUserInput()
1860 {
1861   float scrollAmount = 0.0f;
1862
1863   if (NULL != mImpl->mEventData && mImpl->mEventData->mCheckScrollAmount)
1864   {
1865     scrollAmount = mImpl->mModel->mScrollPosition.y -  mImpl->mModel->mScrollPositionLast.y;
1866     mImpl->mEventData->mCheckScrollAmount = false;
1867   }
1868   return scrollAmount;
1869 }
1870
1871 bool Controller::GetTextScrollInfo( float& scrollPosition, float& controlHeight, float& layoutHeight )
1872 {
1873   const Vector2& layout = mImpl->mModel->mVisualModel->GetLayoutSize();
1874   bool isScrolled;
1875
1876   controlHeight = mImpl->mModel->mVisualModel->mControlSize.height;
1877   layoutHeight = layout.height;
1878   scrollPosition = mImpl->mModel->mScrollPosition.y;
1879   isScrolled = !Equals( mImpl->mModel->mScrollPosition.y, mImpl->mModel->mScrollPositionLast.y, Math::MACHINE_EPSILON_1 );
1880   return isScrolled;
1881 }
1882
1883 void Controller::SetHiddenInputOption(const Property::Map& options )
1884 {
1885   if( NULL == mImpl->mHiddenInput )
1886   {
1887     mImpl->mHiddenInput = new HiddenText( this );
1888   }
1889   mImpl->mHiddenInput->SetProperties(options);
1890 }
1891
1892 void Controller::GetHiddenInputOption(Property::Map& options )
1893 {
1894   if( NULL != mImpl->mHiddenInput )
1895   {
1896     mImpl->mHiddenInput->GetProperties(options);
1897   }
1898 }
1899
1900 void Controller::SetPlaceholderProperty( const Property::Map& map )
1901 {
1902   PlaceholderHandler::SetPlaceholderProperty(*this, map);
1903 }
1904
1905 void Controller::GetPlaceholderProperty( Property::Map& map )
1906 {
1907   PlaceholderHandler::GetPlaceholderProperty(*this, map);
1908 }
1909
1910 Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection()
1911 {
1912   // Make sure the model is up-to-date before layouting
1913   ProcessModifyEvents();
1914
1915   if ( mImpl->mUpdateTextDirection )
1916   {
1917     // Operations that can be done only once until the text changes.
1918     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1919                                                                            GET_SCRIPTS       |
1920                                                                            VALIDATE_FONTS    |
1921                                                                            GET_LINE_BREAKS   |
1922                                                                            BIDI_INFO         |
1923                                                                            SHAPE_TEXT        |
1924                                                                            GET_GLYPH_METRICS );
1925
1926     // Set the update info to relayout the whole text.
1927     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1928     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1929
1930     // Make sure the model is up-to-date before layouting
1931     mImpl->UpdateModel( onlyOnceOperations );
1932
1933     Vector3 naturalSize;
1934     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
1935                 static_cast<OperationsMask>( onlyOnceOperations |
1936                                              LAYOUT | REORDER | UPDATE_DIRECTION ),
1937                 naturalSize.GetVectorXY() );
1938
1939     // Do not do again the only once operations.
1940     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1941
1942     // Clear the update info. This info will be set the next time the text is updated.
1943     mImpl->mTextUpdateInfo.Clear();
1944
1945     // FullRelayoutNeeded should be true because DoRelayout is MAX_FLOAT, MAX_FLOAT.
1946     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
1947
1948     mImpl->mUpdateTextDirection = false;
1949   }
1950
1951   return mImpl->mIsTextDirectionRTL ? Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT : Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
1952 }
1953
1954 Toolkit::DevelText::VerticalLineAlignment::Type Controller::GetVerticalLineAlignment() const
1955 {
1956   return mImpl->mModel->GetVerticalLineAlignment();
1957 }
1958
1959 void Controller::SetVerticalLineAlignment( Toolkit::DevelText::VerticalLineAlignment::Type alignment )
1960 {
1961   mImpl->mModel->mVerticalLineAlignment = alignment;
1962 }
1963
1964 // public : Relayout.
1965
1966 Controller::UpdateTextType Controller::Relayout( const Size& size, Dali::LayoutDirection::Type layoutDirection )
1967 {
1968   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, mImpl->mIsAutoScrollEnabled ?"true":"false"  );
1969
1970   UpdateTextType updateTextType = NONE_UPDATED;
1971
1972   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
1973   {
1974     if( 0u != mImpl->mModel->mVisualModel->mGlyphPositions.Count() )
1975     {
1976       mImpl->mModel->mVisualModel->mGlyphPositions.Clear();
1977       updateTextType = MODEL_UPDATED;
1978     }
1979
1980     // Clear the update info. This info will be set the next time the text is updated.
1981     mImpl->mTextUpdateInfo.Clear();
1982
1983     // Not worth to relayout if width or height is equal to zero.
1984     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
1985
1986     return updateTextType;
1987   }
1988
1989   // Whether a new size has been set.
1990   const bool newSize = ( size != mImpl->mModel->mVisualModel->mControlSize );
1991
1992   if( newSize )
1993   {
1994     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mModel->mVisualModel->mControlSize.width, mImpl->mModel->mVisualModel->mControlSize.height );
1995
1996     if( ( 0 == mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd ) &&
1997         ( 0 == mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) &&
1998         ( ( mImpl->mModel->mVisualModel->mControlSize.width < Math::MACHINE_EPSILON_1000 ) || ( mImpl->mModel->mVisualModel->mControlSize.height < Math::MACHINE_EPSILON_1000 ) ) )
1999     {
2000       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
2001     }
2002
2003     // Layout operations that need to be done if the size changes.
2004     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2005                                                              LAYOUT                    |
2006                                                              ALIGN                     |
2007                                                              UPDATE_LAYOUT_SIZE        |
2008                                                              REORDER );
2009     // Set the update info to relayout the whole text.
2010     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2011     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2012
2013     // Store the size used to layout the text.
2014     mImpl->mModel->mVisualModel->mControlSize = size;
2015   }
2016
2017   // Whether there are modify events.
2018   if( 0u != mImpl->mModifyEvents.Count() )
2019   {
2020     // Style operations that need to be done if the text is modified.
2021     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2022                                                              COLOR );
2023   }
2024
2025   // Set the update info to elide the text.
2026   if( mImpl->mModel->mElideEnabled ||
2027       ( ( NULL != mImpl->mEventData ) && mImpl->mEventData->mIsPlaceholderElideEnabled ) )
2028   {
2029     // Update Text layout for applying elided
2030     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2031                                                              ALIGN                     |
2032                                                              LAYOUT                    |
2033                                                              UPDATE_LAYOUT_SIZE        |
2034                                                              REORDER );
2035     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2036     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2037   }
2038
2039   if( mImpl->mModel->mMatchSystemLanguageDirection  && mImpl->mLayoutDirection != layoutDirection )
2040   {
2041     // Clear the update info. This info will be set the next time the text is updated.
2042     mImpl->mTextUpdateInfo.mClearAll = true;
2043     // Apply modifications to the model
2044     // Shape the text again is needed because characters like '()[]{}' have to be mirrored and the glyphs generated again.
2045     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2046                                                              GET_GLYPH_METRICS         |
2047                                                              SHAPE_TEXT                |
2048                                                              UPDATE_DIRECTION          |
2049                                                              LAYOUT                    |
2050                                                              BIDI_INFO                 |
2051                                                              REORDER );
2052     mImpl->mLayoutDirection = layoutDirection;
2053   }
2054
2055   // Make sure the model is up-to-date before layouting.
2056   ProcessModifyEvents();
2057   bool updated = mImpl->UpdateModel( mImpl->mOperationsPending );
2058
2059   // Layout the text.
2060   Size layoutSize;
2061   updated = DoRelayout( size,
2062                         mImpl->mOperationsPending,
2063                         layoutSize ) || updated;
2064
2065
2066   if( updated )
2067   {
2068     updateTextType = MODEL_UPDATED;
2069   }
2070
2071   // Do not re-do any operation until something changes.
2072   mImpl->mOperationsPending = NO_OPERATION;
2073   mImpl->mModel->mScrollPositionLast = mImpl->mModel->mScrollPosition;
2074
2075   // Whether the text control is editable
2076   const bool isEditable = NULL != mImpl->mEventData;
2077
2078   // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
2079   Vector2 offset;
2080   if( newSize && isEditable )
2081   {
2082     offset = mImpl->mModel->mScrollPosition;
2083   }
2084
2085   if( !isEditable || !IsMultiLineEnabled() )
2086   {
2087     // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
2088     CalculateVerticalOffset( size );
2089   }
2090
2091   if( isEditable )
2092   {
2093     if( newSize )
2094     {
2095       // If there is a new size, the scroll position needs to be clamped.
2096       mImpl->ClampHorizontalScroll( layoutSize );
2097
2098       // Update the decorator's positions is needed if there is a new size.
2099       mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mModel->mScrollPosition - offset );
2100     }
2101
2102     // Move the cursor, grab handle etc.
2103     if( mImpl->ProcessInputEvents() )
2104     {
2105       updateTextType = static_cast<UpdateTextType>( updateTextType | DECORATOR_UPDATED );
2106     }
2107   }
2108
2109   // Clear the update info. This info will be set the next time the text is updated.
2110   mImpl->mTextUpdateInfo.Clear();
2111   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
2112
2113   return updateTextType;
2114 }
2115
2116 void Controller::RequestRelayout()
2117 {
2118   mImpl->RequestRelayout();
2119 }
2120
2121 // public : Input style change signals.
2122
2123 bool Controller::IsInputStyleChangedSignalsQueueEmpty()
2124 {
2125   return ( NULL == mImpl->mEventData ) || ( 0u == mImpl->mEventData->mInputStyleChangedQueue.Count() );
2126 }
2127
2128 void Controller::ProcessInputStyleChangedSignals()
2129 {
2130   if( NULL == mImpl->mEventData )
2131   {
2132     // Nothing to do.
2133     return;
2134   }
2135
2136   for( Vector<InputStyle::Mask>::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(),
2137          endIt = mImpl->mEventData->mInputStyleChangedQueue.End();
2138        it != endIt;
2139        ++it )
2140   {
2141     const InputStyle::Mask mask = *it;
2142
2143     if( NULL != mImpl->mEditableControlInterface )
2144     {
2145       // Emit the input style changed signal.
2146       mImpl->mEditableControlInterface->InputStyleChanged( mask );
2147     }
2148   }
2149
2150   mImpl->mEventData->mInputStyleChangedQueue.Clear();
2151 }
2152
2153 // public : Text-input Event Queuing.
2154
2155 void Controller::KeyboardFocusGainEvent()
2156 {
2157   EventHandler::KeyboardFocusGainEvent(*this);
2158 }
2159
2160 void Controller::KeyboardFocusLostEvent()
2161 {
2162   EventHandler::KeyboardFocusLostEvent(*this);
2163 }
2164
2165 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
2166 {
2167   return EventHandler::KeyEvent(*this, keyEvent);
2168 }
2169
2170 void Controller::TapEvent( unsigned int tapCount, float x, float y )
2171 {
2172   EventHandler::TapEvent(*this, tapCount, x, y);
2173 }
2174
2175 void Controller::PanEvent( GestureState state, const Vector2& displacement )
2176 {
2177   EventHandler::PanEvent(*this, state, displacement);
2178 }
2179
2180 void Controller::LongPressEvent( GestureState state, float x, float y )
2181 {
2182   EventHandler::LongPressEvent(*this, state, x, y);
2183 }
2184
2185 void Controller::SelectEvent( float x, float y, SelectionType selectType )
2186 {
2187   EventHandler::SelectEvent(*this, x, y, selectType);
2188 }
2189
2190 void Controller::SetTextSelectionRange(const uint32_t *start, const uint32_t *end)
2191 {
2192   if( mImpl->mEventData )
2193   {
2194     mImpl->mEventData->mCheckScrollAmount = true;
2195     mImpl->mEventData->mIsLeftHandleSelected = true;
2196     mImpl->mEventData->mIsRightHandleSelected = true;
2197     mImpl->SetTextSelectionRange(start, end);
2198     mImpl->RequestRelayout();
2199     KeyboardFocusGainEvent();
2200   }
2201 }
2202
2203 Uint32Pair Controller::GetTextSelectionRange() const
2204 {
2205   return mImpl->GetTextSelectionRange();
2206 }
2207
2208 void Controller::SelectWholeText()
2209 {
2210   SelectEvent( 0.f, 0.f, SelectionType::ALL );
2211 }
2212
2213 void Controller::SelectNone()
2214 {
2215   SelectEvent( 0.f, 0.f, SelectionType::NONE );
2216 }
2217
2218 string Controller::GetSelectedText() const
2219 {
2220   string text;
2221   if( EventData::SELECTING == mImpl->mEventData->mState )
2222   {
2223     mImpl->RetrieveSelection( text, false );
2224   }
2225   return text;
2226 }
2227
2228 InputMethodContext::CallbackData Controller::OnInputMethodContextEvent( InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent )
2229 {
2230   return EventHandler::OnInputMethodContextEvent(*this, inputMethodContext, inputMethodContextEvent);
2231 }
2232
2233 void Controller::PasteClipboardItemEvent()
2234 {
2235   EventHandler::PasteClipboardItemEvent(*this);
2236 }
2237
2238 // protected : Inherit from Text::Decorator::ControllerInterface.
2239
2240 void Controller::GetTargetSize( Vector2& targetSize )
2241 {
2242   targetSize = mImpl->mModel->mVisualModel->mControlSize;
2243 }
2244
2245 void Controller::AddDecoration( Actor& actor, bool needsClipping )
2246 {
2247   if( NULL != mImpl->mEditableControlInterface )
2248   {
2249     mImpl->mEditableControlInterface->AddDecoration( actor, needsClipping );
2250   }
2251 }
2252
2253 bool Controller::IsEditable() const
2254 {
2255   return mImpl->IsEditable();
2256 }
2257
2258 void Controller::SetEditable( bool editable )
2259 {
2260   mImpl->SetEditable( editable );
2261   if(mImpl->mEventData && mImpl->mEventData->mDecorator)
2262   {
2263     mImpl->mEventData->mDecorator->SetEditable( editable );
2264   }
2265 }
2266
2267 void Controller::ScrollBy( Vector2 scroll )
2268 {
2269   if( mImpl->mEventData && (fabs(scroll.x) > Math::MACHINE_EPSILON_0 || fabs(scroll.y) > Math::MACHINE_EPSILON_0))
2270   {
2271       const Vector2& layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
2272       const Vector2 currentScroll = mImpl->mModel->mScrollPosition;
2273
2274       scroll.x = -scroll.x;
2275       scroll.y = -scroll.y;
2276
2277       if( fabs(scroll.x) > Math::MACHINE_EPSILON_0 )
2278       {
2279         mImpl->mModel->mScrollPosition.x += scroll.x;
2280         mImpl->ClampHorizontalScroll( layoutSize );
2281       }
2282
2283       if( fabs(scroll.y) > Math::MACHINE_EPSILON_0 )
2284       {
2285         mImpl->mModel->mScrollPosition.y += scroll.y;
2286         mImpl->ClampVerticalScroll( layoutSize );
2287       }
2288
2289       if (mImpl->mModel->mScrollPosition != currentScroll)
2290       {
2291         mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mModel->mScrollPosition - currentScroll );
2292         mImpl->RequestRelayout();
2293       }
2294   }
2295 }
2296
2297 float Controller::GetHorizontalScrollPosition()
2298 {
2299   if( mImpl->mEventData )
2300   {
2301     //scroll values are negative internally so we convert them to positive numbers
2302     return -mImpl->mModel->mScrollPosition.x;
2303   }
2304   return 0;
2305 }
2306
2307 float Controller::GetVerticalScrollPosition()
2308 {
2309   if( mImpl->mEventData )
2310   {
2311     //scroll values are negative internally so we convert them to positive numbers
2312     return -mImpl->mModel->mScrollPosition.y;
2313   }
2314   return 0;
2315 }
2316
2317 void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
2318 {
2319   EventHandler::DecorationEvent(*this, handleType, state, x, y);
2320 }
2321
2322 // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
2323
2324 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
2325 {
2326   EventHandler::TextPopupButtonTouched(*this, button);
2327 }
2328
2329 void Controller::DisplayTimeExpired()
2330 {
2331   mImpl->mEventData->mUpdateCursorPosition = true;
2332   // Apply modifications to the model
2333   mImpl->mOperationsPending = ALL_OPERATIONS;
2334
2335   mImpl->RequestRelayout();
2336 }
2337
2338 // private : Update.
2339
2340 void Controller::InsertText( const std::string& text, Controller::InsertType type )
2341 {
2342   bool removedPrevious = false;
2343   bool removedSelected = false;
2344   bool maxLengthReached = false;
2345
2346   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
2347
2348   if( NULL == mImpl->mEventData )
2349   {
2350     return;
2351   }
2352
2353   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
2354                  this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
2355                  mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2356
2357   // TODO: At the moment the underline runs are only for pre-edit.
2358   mImpl->mModel->mVisualModel->mUnderlineRuns.Clear();
2359
2360   // Remove the previous InputMethodContext pre-edit.
2361   if( mImpl->mEventData->mPreEditFlag && ( 0u != mImpl->mEventData->mPreEditLength ) )
2362   {
2363     removedPrevious = RemoveText( -static_cast<int>( mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition ),
2364                                   mImpl->mEventData->mPreEditLength,
2365                                   DONT_UPDATE_INPUT_STYLE );
2366
2367     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
2368     mImpl->mEventData->mPreEditLength = 0u;
2369   }
2370   else
2371   {
2372     // Remove the previous Selection.
2373     removedSelected = RemoveSelectedText();
2374
2375   }
2376
2377   Vector<Character> utf32Characters;
2378   Length characterCount = 0u;
2379
2380   if( !text.empty() )
2381   {
2382     //  Convert text into UTF-32
2383     utf32Characters.Resize( text.size() );
2384
2385     // This is a bit horrible but std::string returns a (signed) char*
2386     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
2387
2388     // Transform a text array encoded in utf8 into an array encoded in utf32.
2389     // It returns the actual number of characters.
2390     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
2391     utf32Characters.Resize( characterCount );
2392
2393     DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
2394     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
2395   }
2396
2397   if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
2398   {
2399     // The placeholder text is no longer needed
2400     if( mImpl->IsShowingPlaceholderText() )
2401     {
2402       ResetText();
2403     }
2404
2405     mImpl->ChangeState( EventData::EDITING );
2406
2407     // Handle the InputMethodContext (predicitive text) state changes
2408     if( COMMIT == type )
2409     {
2410       // InputMethodContext is no longer handling key-events
2411       mImpl->ClearPreEditFlag();
2412     }
2413     else // PRE_EDIT
2414     {
2415       if( !mImpl->mEventData->mPreEditFlag )
2416       {
2417         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state\n" );
2418
2419         // Record the start of the pre-edit text
2420         mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
2421       }
2422
2423       mImpl->mEventData->mPreEditLength = utf32Characters.Count();
2424       mImpl->mEventData->mPreEditFlag = true;
2425
2426       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2427     }
2428
2429     const Length numberOfCharactersInModel = mImpl->mModel->mLogicalModel->mText.Count();
2430
2431     // Restrict new text to fit within Maximum characters setting.
2432     Length maxSizeOfNewText = std::min( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
2433     maxLengthReached = ( characterCount > maxSizeOfNewText );
2434
2435     // The cursor position.
2436     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2437
2438     // Update the text's style.
2439
2440     // Updates the text style runs by adding characters.
2441     mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText );
2442
2443     // Get the character index from the cursor index.
2444     const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u;
2445
2446     // Retrieve the text's style for the given index.
2447     InputStyle style;
2448     mImpl->RetrieveDefaultInputStyle( style );
2449     mImpl->mModel->mLogicalModel->RetrieveStyle( styleIndex, style );
2450
2451     // Whether to add a new text color run.
2452     const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor ) && !mImpl->mEventData->mInputStyle.isDefaultColor;
2453
2454     // Whether to add a new font run.
2455     const bool addFontNameRun = ( style.familyName != mImpl->mEventData->mInputStyle.familyName ) && mImpl->mEventData->mInputStyle.isFamilyDefined;
2456     const bool addFontWeightRun = ( style.weight != mImpl->mEventData->mInputStyle.weight ) && mImpl->mEventData->mInputStyle.isWeightDefined;
2457     const bool addFontWidthRun = ( style.width != mImpl->mEventData->mInputStyle.width ) && mImpl->mEventData->mInputStyle.isWidthDefined;
2458     const bool addFontSlantRun = ( style.slant != mImpl->mEventData->mInputStyle.slant ) && mImpl->mEventData->mInputStyle.isSlantDefined;
2459     const bool addFontSizeRun = ( style.size != mImpl->mEventData->mInputStyle.size ) && mImpl->mEventData->mInputStyle.isSizeDefined ;
2460
2461     // Add style runs.
2462     if( addColorRun )
2463     {
2464       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
2465       mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
2466
2467       ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
2468       colorRun.color = mImpl->mEventData->mInputStyle.textColor;
2469       colorRun.characterRun.characterIndex = cursorIndex;
2470       colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2471     }
2472
2473     if( addFontNameRun   ||
2474         addFontWeightRun ||
2475         addFontWidthRun  ||
2476         addFontSlantRun  ||
2477         addFontSizeRun )
2478     {
2479       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Count();
2480       mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
2481
2482       FontDescriptionRun& fontDescriptionRun = *( mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
2483
2484       if( addFontNameRun )
2485       {
2486         fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
2487         fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
2488         memcpy( fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength );
2489         fontDescriptionRun.familyDefined = true;
2490
2491         // The memory allocated for the font family name is freed when the font description is removed from the logical model.
2492       }
2493
2494       if( addFontWeightRun )
2495       {
2496         fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
2497         fontDescriptionRun.weightDefined = true;
2498       }
2499
2500       if( addFontWidthRun )
2501       {
2502         fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
2503         fontDescriptionRun.widthDefined = true;
2504       }
2505
2506       if( addFontSlantRun )
2507       {
2508         fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
2509         fontDescriptionRun.slantDefined = true;
2510       }
2511
2512       if( addFontSizeRun )
2513       {
2514         fontDescriptionRun.size = static_cast<PointSize26Dot6>( mImpl->mEventData->mInputStyle.size * 64.f );
2515         fontDescriptionRun.sizeDefined = true;
2516       }
2517
2518       fontDescriptionRun.characterRun.characterIndex = cursorIndex;
2519       fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2520     }
2521
2522     // Insert at current cursor position.
2523     Vector<Character>& modifyText = mImpl->mModel->mLogicalModel->mText;
2524
2525     auto pos = modifyText.End();
2526     if( cursorIndex < numberOfCharactersInModel )
2527     {
2528       pos = modifyText.Begin() + cursorIndex;
2529     }
2530     unsigned int realPos = pos - modifyText.Begin();
2531     modifyText.Insert( pos, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
2532
2533     if( NULL != mImpl->mEditableControlInterface )
2534     {
2535       mImpl->mEditableControlInterface->TextInserted( realPos, maxSizeOfNewText, text );
2536     }
2537
2538     // Mark the first paragraph to be updated.
2539     if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
2540     {
2541       mImpl->mTextUpdateInfo.mCharacterIndex = 0;
2542       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2543       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = numberOfCharactersInModel + maxSizeOfNewText;
2544       mImpl->mTextUpdateInfo.mClearAll = true;
2545     }
2546     else
2547     {
2548       mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
2549       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
2550     }
2551
2552     // Update the cursor index.
2553     cursorIndex += maxSizeOfNewText;
2554
2555     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Inserted %d characters, new size %d new cursor %d\n", maxSizeOfNewText, mImpl->mModel->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition );
2556   }
2557
2558   if( ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) &&
2559       mImpl->IsPlaceholderAvailable() )
2560   {
2561     // Show place-holder if empty after removing the pre-edit text
2562     ShowPlaceholderText();
2563     mImpl->mEventData->mUpdateCursorPosition = true;
2564     mImpl->ClearPreEditFlag();
2565   }
2566   else if( removedPrevious ||
2567            removedSelected ||
2568            ( 0 != utf32Characters.Count() ) )
2569   {
2570     // Queue an inserted event
2571     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
2572
2573     mImpl->mEventData->mUpdateCursorPosition = true;
2574     if( removedSelected )
2575     {
2576       mImpl->mEventData->mScrollAfterDelete = true;
2577     }
2578     else
2579     {
2580       mImpl->mEventData->mScrollAfterUpdatePosition = true;
2581     }
2582   }
2583
2584   if( maxLengthReached )
2585   {
2586     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mModel->mLogicalModel->mText.Count() );
2587
2588     mImpl->ResetInputMethodContext();
2589
2590     if( NULL != mImpl->mEditableControlInterface )
2591     {
2592       // Do this last since it provides callbacks into application code
2593       mImpl->mEditableControlInterface->MaxLengthReached();
2594     }
2595   }
2596 }
2597
2598 void Controller::PasteText( const std::string& stringToPaste )
2599 {
2600   InsertText( stringToPaste, Text::Controller::COMMIT );
2601   mImpl->ChangeState( EventData::EDITING );
2602   mImpl->RequestRelayout();
2603
2604   if( NULL != mImpl->mEditableControlInterface )
2605   {
2606     // Do this last since it provides callbacks into application code
2607     mImpl->mEditableControlInterface->TextChanged();
2608   }
2609 }
2610
2611 bool Controller::RemoveText( int cursorOffset,
2612                              int numberOfCharacters,
2613                              UpdateInputStyleType type )
2614 {
2615   bool removed = false;
2616
2617   if( NULL == mImpl->mEventData )
2618   {
2619     return removed;
2620   }
2621
2622   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n",
2623                  this, mImpl->mModel->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters );
2624
2625   if( !mImpl->IsShowingPlaceholderText() )
2626   {
2627     // Delete at current cursor position
2628     Vector<Character>& currentText = mImpl->mModel->mLogicalModel->mText;
2629     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2630
2631     CharacterIndex cursorIndex = 0;
2632
2633     // Validate the cursor position & number of characters
2634     if( ( static_cast< int >( mImpl->mEventData->mPrimaryCursorPosition ) + cursorOffset ) >= 0 )
2635     {
2636       cursorIndex = mImpl->mEventData->mPrimaryCursorPosition + cursorOffset;
2637     }
2638
2639     if( ( cursorIndex + numberOfCharacters ) > currentText.Count() )
2640     {
2641       numberOfCharacters = currentText.Count() - cursorIndex;
2642     }
2643
2644     if( mImpl->mEventData->mPreEditFlag || // If the preedit flag is enabled, it means two (or more) of them came together i.e. when two keys have been pressed at the same time.
2645         ( ( cursorIndex + numberOfCharacters ) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) )
2646     {
2647       // Mark the paragraphs to be updated.
2648       if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
2649       {
2650         mImpl->mTextUpdateInfo.mCharacterIndex = 0;
2651         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2652         mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters;
2653         mImpl->mTextUpdateInfo.mClearAll = true;
2654       }
2655       else
2656       {
2657         mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
2658         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
2659       }
2660
2661       // Update the input style and remove the text's style before removing the text.
2662
2663       if( UPDATE_INPUT_STYLE == type )
2664       {
2665         // Keep a copy of the current input style.
2666         InputStyle currentInputStyle;
2667         currentInputStyle.Copy( mImpl->mEventData->mInputStyle );
2668
2669         // Set first the default input style.
2670         mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle );
2671
2672         // Update the input style.
2673         mImpl->mModel->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle );
2674
2675         // Compare if the input style has changed.
2676         const bool hasInputStyleChanged = !currentInputStyle.Equal( mImpl->mEventData->mInputStyle );
2677
2678         if( hasInputStyleChanged )
2679         {
2680           const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mImpl->mEventData->mInputStyle );
2681           // Queue the input style changed signal.
2682           mImpl->mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
2683         }
2684       }
2685
2686       // If the number of current text and the number of characters to be deleted are same,
2687       // it means all texts should be removed and all Preedit variables should be initialized.
2688       if( ( currentText.Count() - numberOfCharacters == 0 ) && ( cursorIndex == 0 ) )
2689       {
2690         mImpl->ClearPreEditFlag();
2691         mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0;
2692       }
2693
2694       // Updates the text style runs by removing characters. Runs with no characters are removed.
2695       mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters );
2696
2697       // Remove the characters.
2698       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
2699       Vector<Character>::Iterator last  = first + numberOfCharacters;
2700
2701       if( NULL != mImpl->mEditableControlInterface )
2702       {
2703         std::string utf8;
2704         Utf32ToUtf8( first, numberOfCharacters, utf8 );
2705         mImpl->mEditableControlInterface->TextDeleted( cursorIndex, numberOfCharacters, utf8 );
2706       }
2707
2708       currentText.Erase( first, last );
2709
2710       // Cursor position retreat
2711       oldCursorIndex = cursorIndex;
2712
2713       mImpl->mEventData->mScrollAfterDelete = true;
2714
2715       if( EventData::INACTIVE == mImpl->mEventData->mState )
2716       {
2717         mImpl->ChangeState( EventData::EDITING );
2718       }
2719
2720       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters );
2721       removed = true;
2722     }
2723   }
2724
2725   return removed;
2726 }
2727
2728 bool Controller::RemoveSelectedText()
2729 {
2730   bool textRemoved( false );
2731
2732   if( EventData::SELECTING == mImpl->mEventData->mState )
2733   {
2734     std::string removedString;
2735     mImpl->RetrieveSelection( removedString, true );
2736
2737     if( !removedString.empty() )
2738     {
2739       textRemoved = true;
2740       mImpl->ChangeState( EventData::EDITING );
2741     }
2742   }
2743
2744   return textRemoved;
2745 }
2746
2747 // private : Relayout.
2748
2749 bool Controller::DoRelayout( const Size& size,
2750                              OperationsMask operationsRequired,
2751                              Size& layoutSize )
2752 {
2753   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height );
2754   bool viewUpdated( false );
2755
2756   // Calculate the operations to be done.
2757   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
2758
2759   const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
2760   const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
2761
2762   // Get the current layout size.
2763   layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
2764
2765   if( NO_OPERATION != ( LAYOUT & operations ) )
2766   {
2767     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
2768
2769     // Some vectors with data needed to layout and reorder may be void
2770     // after the first time the text has been laid out.
2771     // Fill the vectors again.
2772
2773     // Calculate the number of glyphs to layout.
2774     const Vector<GlyphIndex>& charactersToGlyph = mImpl->mModel->mVisualModel->mCharactersToGlyph;
2775     const Vector<Length>& glyphsPerCharacter = mImpl->mModel->mVisualModel->mGlyphsPerCharacter;
2776     const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
2777     const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
2778
2779     const CharacterIndex lastIndex = startIndex + ( ( requestedNumberOfCharacters > 0u ) ? requestedNumberOfCharacters - 1u : 0u );
2780     const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
2781
2782     // Make sure the index is not out of bound
2783     if ( charactersToGlyph.Count() != glyphsPerCharacter.Count() ||
2784          requestedNumberOfCharacters > charactersToGlyph.Count() ||
2785          ( lastIndex > charactersToGlyph.Count() && charactersToGlyph.Count() > 0u ) )
2786     {
2787       std::string currentText;
2788       GetText( currentText );
2789
2790       DALI_LOG_ERROR( "Controller::DoRelayout: Attempting to access invalid buffer\n" );
2791       DALI_LOG_ERROR( "Current text is: %s\n", currentText.c_str() );
2792       DALI_LOG_ERROR( "startIndex: %u, lastIndex: %u, requestedNumberOfCharacters: %u, charactersToGlyph.Count = %lu, glyphsPerCharacter.Count = %lu\n", startIndex, lastIndex, requestedNumberOfCharacters, charactersToGlyph.Count(), glyphsPerCharacter.Count());
2793
2794       return false;
2795     }
2796
2797     const Length numberOfGlyphs = ( requestedNumberOfCharacters > 0u ) ? *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - startGlyphIndex : 0u;
2798     const Length totalNumberOfGlyphs = mImpl->mModel->mVisualModel->mGlyphs.Count();
2799
2800     if( 0u == totalNumberOfGlyphs )
2801     {
2802       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
2803       {
2804         mImpl->mModel->mVisualModel->SetLayoutSize( Size::ZERO );
2805       }
2806
2807       // Nothing else to do if there is no glyphs.
2808       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n" );
2809       return true;
2810     }
2811
2812     // Set the layout parameters.
2813     Layout::Parameters layoutParameters( size,
2814                                          mImpl->mModel);
2815
2816     // Resize the vector of positions to have the same size than the vector of glyphs.
2817     Vector<Vector2>& glyphPositions = mImpl->mModel->mVisualModel->mGlyphPositions;
2818     glyphPositions.Resize( totalNumberOfGlyphs );
2819
2820     // Whether the last character is a new paragraph character.
2821     const Character* const textBuffer = mImpl->mModel->mLogicalModel->mText.Begin();
2822     mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph =  TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mModel->mLogicalModel->mText.Count() - 1u ) ) );
2823     layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
2824
2825     // The initial glyph and the number of glyphs to layout.
2826     layoutParameters.startGlyphIndex = startGlyphIndex;
2827     layoutParameters.numberOfGlyphs = numberOfGlyphs;
2828     layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex;
2829     layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
2830
2831     // Update the ellipsis
2832     bool elideTextEnabled = mImpl->mModel->mElideEnabled;
2833
2834     if( NULL != mImpl->mEventData )
2835     {
2836       if( mImpl->mEventData->mPlaceholderEllipsisFlag && mImpl->IsShowingPlaceholderText() )
2837       {
2838         elideTextEnabled = mImpl->mEventData->mIsPlaceholderElideEnabled;
2839       }
2840       else if( EventData::INACTIVE != mImpl->mEventData->mState )
2841       {
2842         // Disable ellipsis when editing
2843         elideTextEnabled = false;
2844       }
2845
2846       // Reset the scroll position in inactive state
2847       if( elideTextEnabled && ( mImpl->mEventData->mState == EventData::INACTIVE ) )
2848       {
2849         ResetScrollPosition();
2850       }
2851     }
2852
2853     // Update the visual model.
2854     bool isAutoScrollEnabled = mImpl->mIsAutoScrollEnabled;
2855     Size newLayoutSize;
2856     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
2857                                                    newLayoutSize,
2858                                                    elideTextEnabled,
2859                                                    isAutoScrollEnabled );
2860     mImpl->mIsAutoScrollEnabled = isAutoScrollEnabled;
2861
2862     viewUpdated = viewUpdated || ( newLayoutSize != layoutSize );
2863
2864     if( viewUpdated )
2865     {
2866       layoutSize = newLayoutSize;
2867
2868       if( NO_OPERATION != ( UPDATE_DIRECTION & operations ) )
2869       {
2870         mImpl->mIsTextDirectionRTL = false;
2871       }
2872
2873       if ( ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) ) && !mImpl->mModel->mVisualModel->mLines.Empty() )
2874       {
2875         mImpl->mIsTextDirectionRTL = mImpl->mModel->mVisualModel->mLines[0u].direction;
2876       }
2877
2878       // Sets the layout size.
2879       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
2880       {
2881         mImpl->mModel->mVisualModel->SetLayoutSize( layoutSize );
2882       }
2883     } // view updated
2884   }
2885
2886   if( NO_OPERATION != ( ALIGN & operations ) )
2887   {
2888     // The laid-out lines.
2889     Vector<LineRun>& lines = mImpl->mModel->mVisualModel->mLines;
2890
2891     CharacterIndex alignStartIndex = startIndex;
2892     Length alignRequestedNumberOfCharacters = requestedNumberOfCharacters;
2893
2894     // the whole text needs to be full aligned.
2895     // If you do not do a full aligned, only the last line of the multiline input is aligned.
2896     if(  mImpl->mEventData && mImpl->mEventData->mUpdateAlignment )
2897     {
2898       alignStartIndex = 0u;
2899       alignRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
2900       mImpl->mEventData->mUpdateAlignment = false;
2901     }
2902
2903     // Need to align with the control's size as the text may contain lines
2904     // starting either with left to right text or right to left.
2905     mImpl->mLayoutEngine.Align( size,
2906                                 alignStartIndex,
2907                                 alignRequestedNumberOfCharacters,
2908                                 mImpl->mModel->mHorizontalAlignment,
2909                                 lines,
2910                                 mImpl->mModel->mAlignmentOffset,
2911                                 mImpl->mLayoutDirection,
2912                                 mImpl->mModel->mMatchSystemLanguageDirection );
2913
2914     viewUpdated = true;
2915   }
2916 #if defined(DEBUG_ENABLED)
2917   std::string currentText;
2918   GetText( currentText );
2919   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mIsTextDirectionRTL[%s] [%s]\n", this, (mImpl->mIsTextDirectionRTL)?"true":"false",  currentText.c_str() );
2920 #endif
2921   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
2922   return viewUpdated;
2923 }
2924
2925 void Controller::CalculateVerticalOffset( const Size& controlSize )
2926 {
2927   Size layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
2928
2929   if( fabsf( layoutSize.height ) < Math::MACHINE_EPSILON_1000 )
2930   {
2931     // Get the line height of the default font.
2932     layoutSize.height = mImpl->GetDefaultFontLineHeight();
2933   }
2934
2935   switch( mImpl->mModel->mVerticalAlignment )
2936   {
2937     case VerticalAlignment::TOP:
2938     {
2939       mImpl->mModel->mScrollPosition.y = 0.f;
2940       break;
2941     }
2942     case VerticalAlignment::CENTER:
2943     {
2944       mImpl->mModel->mScrollPosition.y = floorf( 0.5f * ( controlSize.height - layoutSize.height ) ); // try to avoid pixel alignment.
2945       break;
2946     }
2947     case VerticalAlignment::BOTTOM:
2948     {
2949       mImpl->mModel->mScrollPosition.y = controlSize.height - layoutSize.height;
2950       break;
2951     }
2952   }
2953 }
2954
2955 // private : Events.
2956
2957 void Controller::ProcessModifyEvents()
2958 {
2959   EventHandler::ProcessModifyEvents(*this);
2960 }
2961
2962 void Controller::TextReplacedEvent()
2963 {
2964   EventHandler::TextReplacedEvent(*this);
2965 }
2966
2967 void Controller::TextInsertedEvent()
2968 {
2969   EventHandler::TextInsertedEvent(*this);
2970 }
2971
2972 void Controller::TextDeletedEvent()
2973 {
2974   EventHandler::TextDeletedEvent(*this);
2975 }
2976
2977 bool Controller::DeleteEvent( int keyCode )
2978 {
2979   return EventHandler::DeleteEvent(*this, keyCode);
2980 }
2981
2982 // private : Helpers.
2983
2984 void Controller::ResetText()
2985 {
2986   // Reset buffers.
2987   mImpl->mModel->mLogicalModel->mText.Clear();
2988
2989   // Reset the embedded images buffer.
2990   mImpl->mModel->mLogicalModel->ClearEmbeddedImages();
2991
2992   // We have cleared everything including the placeholder-text
2993   mImpl->PlaceholderCleared();
2994
2995   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2996   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2997   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
2998
2999   // Clear any previous text.
3000   mImpl->mTextUpdateInfo.mClearAll = true;
3001
3002   // The natural size needs to be re-calculated.
3003   mImpl->mRecalculateNaturalSize = true;
3004
3005   // The text direction needs to be updated.
3006   mImpl->mUpdateTextDirection = true;
3007
3008   // Apply modifications to the model
3009   mImpl->mOperationsPending = ALL_OPERATIONS;
3010 }
3011
3012 void Controller::ShowPlaceholderText()
3013 {
3014   if( mImpl->IsPlaceholderAvailable() )
3015   {
3016     DALI_ASSERT_DEBUG( mImpl->mEventData && "No placeholder text available" );
3017
3018     if( NULL == mImpl->mEventData )
3019     {
3020       return;
3021     }
3022
3023     mImpl->mEventData->mIsShowingPlaceholderText = true;
3024
3025     // Disable handles when showing place-holder text
3026     mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
3027     mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
3028     mImpl->mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
3029
3030     const char* text( NULL );
3031     size_t size( 0 );
3032
3033     // TODO - Switch Placeholder text when changing state
3034     if( ( EventData::INACTIVE != mImpl->mEventData->mState ) &&
3035         ( 0u != mImpl->mEventData->mPlaceholderTextActive.c_str() ) )
3036     {
3037       text = mImpl->mEventData->mPlaceholderTextActive.c_str();
3038       size = mImpl->mEventData->mPlaceholderTextActive.size();
3039     }
3040     else
3041     {
3042       text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
3043       size = mImpl->mEventData->mPlaceholderTextInactive.size();
3044     }
3045
3046     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3047     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3048
3049     // Reset model for showing placeholder.
3050     mImpl->mModel->mLogicalModel->mText.Clear();
3051     mImpl->mModel->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor );
3052
3053     // Convert text into UTF-32
3054     Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
3055     utf32Characters.Resize( size );
3056
3057     // This is a bit horrible but std::string returns a (signed) char*
3058     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text );
3059
3060     // Transform a text array encoded in utf8 into an array encoded in utf32.
3061     // It returns the actual number of characters.
3062     const Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() );
3063     utf32Characters.Resize( characterCount );
3064
3065     // The characters to be added.
3066     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount;
3067
3068     // Reset the cursor position
3069     mImpl->mEventData->mPrimaryCursorPosition = 0;
3070
3071     // The natural size needs to be re-calculated.
3072     mImpl->mRecalculateNaturalSize = true;
3073
3074     // The text direction needs to be updated.
3075     mImpl->mUpdateTextDirection = true;
3076
3077     // Apply modifications to the model
3078     mImpl->mOperationsPending = ALL_OPERATIONS;
3079
3080     // Update the rest of the model during size negotiation
3081     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
3082   }
3083 }
3084
3085 void Controller::ClearFontData()
3086 {
3087   if( mImpl->mFontDefaults )
3088   {
3089     mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
3090   }
3091
3092   // Set flags to update the model.
3093   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3094   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3095   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
3096
3097   mImpl->mTextUpdateInfo.mClearAll = true;
3098   mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
3099   mImpl->mRecalculateNaturalSize = true;
3100
3101   mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
3102                                                            VALIDATE_FONTS            |
3103                                                            SHAPE_TEXT                |
3104                                                            BIDI_INFO                 |
3105                                                            GET_GLYPH_METRICS         |
3106                                                            LAYOUT                    |
3107                                                            UPDATE_LAYOUT_SIZE        |
3108                                                            REORDER                   |
3109                                                            ALIGN );
3110 }
3111
3112 void Controller::ClearStyleData()
3113 {
3114   mImpl->mModel->mLogicalModel->mColorRuns.Clear();
3115   mImpl->mModel->mLogicalModel->ClearFontDescriptionRuns();
3116 }
3117
3118 void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
3119 {
3120   // Reset the cursor position
3121   if( NULL != mImpl->mEventData )
3122   {
3123     mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
3124
3125     // Update the cursor if it's in editing mode.
3126     if( EventData::IsEditingState( mImpl->mEventData->mState )  )
3127     {
3128       mImpl->mEventData->mUpdateCursorPosition = true;
3129     }
3130   }
3131 }
3132
3133 CharacterIndex Controller::GetCursorPosition()
3134 {
3135   if( !mImpl->mEventData )
3136     return 0;
3137
3138   return mImpl->mEventData->mPrimaryCursorPosition;
3139 }
3140
3141 void Controller::ResetScrollPosition()
3142 {
3143   if( NULL != mImpl->mEventData )
3144   {
3145     // Reset the scroll position.
3146     mImpl->mModel->mScrollPosition = Vector2::ZERO;
3147     mImpl->mEventData->mScrollAfterUpdatePosition = true;
3148   }
3149 }
3150
3151 void Controller::SetControlInterface( ControlInterface* controlInterface )
3152 {
3153   mImpl->mControlInterface = controlInterface;
3154 }
3155
3156 bool Controller::ShouldClearFocusOnEscape() const
3157 {
3158   return mImpl->mShouldClearFocusOnEscape;
3159 }
3160
3161 Actor Controller::CreateBackgroundActor()
3162 {
3163   return mImpl->CreateBackgroundActor();
3164 }
3165
3166 // private : Private contructors & copy operator.
3167
3168 Controller::Controller()
3169 : Controller(nullptr, nullptr, nullptr)
3170 {
3171 }
3172
3173 Controller::Controller( ControlInterface* controlInterface )
3174 :Controller( controlInterface, nullptr, nullptr)
3175 {
3176 }
3177
3178 Controller::Controller( ControlInterface* controlInterface,
3179                         EditableControlInterface* editableControlInterface,
3180                         SelectableControlInterface* selectableControlInterface )
3181 : mImpl(new Controller::Impl(controlInterface, editableControlInterface, selectableControlInterface))
3182 {
3183 }
3184
3185 // The copy constructor and operator are left unimplemented.
3186
3187 // protected : Destructor.
3188
3189 Controller::~Controller()
3190 {
3191   delete mImpl;
3192 }
3193
3194 } // namespace Text
3195
3196 } // namespace Toolkit
3197
3198 } // namespace Dali