Merge "Fixed issue where only the last line was aligned in the case of a multiline...
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller.cpp
1 /*
2  * Copyright (c) 2019 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/public-api/adaptor-framework/key.h>
26 #include <dali/integration-api/debug.h>
27 #include <dali/devel-api/adaptor-framework/clipboard-event-notifier.h>
28 #include <dali/devel-api/text-abstraction/font-client.h>
29 #include <dali/devel-api/adaptor-framework/key-devel.h>
30
31 // INTERNAL INCLUDES
32 #include <dali-toolkit/public-api/controls/text-controls/placeholder-properties.h>
33 #include <dali-toolkit/internal/text/bidirectional-support.h>
34 #include <dali-toolkit/internal/text/character-set-conversion.h>
35 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
36 #include <dali-toolkit/internal/text/markup-processor.h>
37 #include <dali-toolkit/internal/text/multi-language-support.h>
38 #include <dali-toolkit/internal/text/text-controller-impl.h>
39 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
40 #include <dali-toolkit/internal/text/text-font-style.h>
41
42 namespace
43 {
44
45 #if defined(DEBUG_ENABLED)
46   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
47 #endif
48
49 const float MAX_FLOAT = std::numeric_limits<float>::max();
50
51 const std::string EMPTY_STRING("");
52
53 const std::string KEY_C_NAME = "c";
54 const std::string KEY_V_NAME = "v";
55 const std::string KEY_X_NAME = "x";
56
57 const char * const PLACEHOLDER_TEXT = "text";
58 const char * const PLACEHOLDER_TEXT_FOCUSED = "textFocused";
59 const char * const PLACEHOLDER_COLOR = "color";
60 const char * const PLACEHOLDER_FONT_FAMILY = "fontFamily";
61 const char * const PLACEHOLDER_FONT_STYLE = "fontStyle";
62 const char * const PLACEHOLDER_POINT_SIZE = "pointSize";
63 const char * const PLACEHOLDER_PIXEL_SIZE = "pixelSize";
64 const char * const PLACEHOLDER_ELLIPSIS = "ellipsis";
65 const unsigned int MAX_TEXT_LENGTH = 1024u * 32u;
66
67 float ConvertToEven( float value )
68 {
69   int intValue(static_cast<int>( value ));
70   return static_cast<float>( intValue + ( intValue & 1 ) );
71 }
72
73 int ConvertPixelToPint( float pixel )
74 {
75   unsigned int horizontalDpi = 0u;
76   unsigned int verticalDpi = 0u;
77   Dali::TextAbstraction::FontClient fontClient = Dali::TextAbstraction::FontClient::Get();
78   fontClient.GetDpi( horizontalDpi, verticalDpi );
79
80   return ( pixel * 72.f ) / static_cast< float >( horizontalDpi );
81 }
82
83
84 } // namespace
85
86 namespace Dali
87 {
88
89 namespace Toolkit
90 {
91
92 namespace Text
93 {
94
95 /**
96  * @brief Adds a new font description run for the selected text.
97  *
98  * The new font parameters are added after the call to this method.
99  *
100  * @param[in] eventData The event data pointer.
101  * @param[in] logicalModel The logical model where to add the new font description run.
102  * @param[out] startOfSelectedText Index to the first selected character.
103  * @param[out] lengthOfSelectedText Number of selected characters.
104  */
105 FontDescriptionRun& UpdateSelectionFontStyleRun( EventData* eventData,
106                                                  LogicalModelPtr logicalModel,
107                                                  CharacterIndex& startOfSelectedText,
108                                                  Length& lengthOfSelectedText )
109 {
110   const bool handlesCrossed = eventData->mLeftSelectionPosition > eventData->mRightSelectionPosition;
111
112   // Get start and end position of selection
113   startOfSelectedText = handlesCrossed ? eventData->mRightSelectionPosition : eventData->mLeftSelectionPosition;
114   lengthOfSelectedText = ( handlesCrossed ? eventData->mLeftSelectionPosition : eventData->mRightSelectionPosition ) - startOfSelectedText;
115
116   // Add the font run.
117   const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count();
118   logicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
119
120   FontDescriptionRun& fontDescriptionRun = *( logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
121
122   fontDescriptionRun.characterRun.characterIndex = startOfSelectedText;
123   fontDescriptionRun.characterRun.numberOfCharacters = lengthOfSelectedText;
124
125   // Recalculate the selection highlight as the metrics may have changed.
126   eventData->mUpdateLeftSelectionPosition = true;
127   eventData->mUpdateRightSelectionPosition = true;
128   eventData->mUpdateHighlightBox = true;
129
130   return fontDescriptionRun;
131 }
132
133 // public : Constructor.
134
135 ControllerPtr Controller::New()
136 {
137   return ControllerPtr( new Controller() );
138 }
139
140 ControllerPtr Controller::New( ControlInterface* controlInterface )
141 {
142   return ControllerPtr( new Controller( controlInterface ) );
143 }
144
145 ControllerPtr Controller::New( ControlInterface* controlInterface,
146                                EditableControlInterface* editableControlInterface )
147 {
148   return ControllerPtr( new Controller( controlInterface,
149                                         editableControlInterface ) );
150 }
151
152 // public : Configure the text controller.
153
154 void Controller::EnableTextInput( DecoratorPtr decorator, InputMethodContext& inputMethodContext )
155 {
156   if( !decorator )
157   {
158     delete mImpl->mEventData;
159     mImpl->mEventData = NULL;
160
161     // Nothing else to do.
162     return;
163   }
164
165   if( NULL == mImpl->mEventData )
166   {
167     mImpl->mEventData = new EventData( decorator, inputMethodContext );
168   }
169 }
170
171 void Controller::SetGlyphType( TextAbstraction::GlyphType glyphType )
172 {
173   // Metrics for bitmap & vector based glyphs are different
174   mImpl->mMetrics->SetGlyphType( glyphType );
175
176   // Clear the font-specific data
177   ClearFontData();
178
179   mImpl->RequestRelayout();
180 }
181
182 void Controller::SetMarkupProcessorEnabled( bool enable )
183 {
184   if( enable != mImpl->mMarkupProcessorEnabled )
185   {
186     //If Text was already set, call the SetText again for enabling or disabling markup
187     mImpl->mMarkupProcessorEnabled = enable;
188     std::string text;
189     GetText( text );
190     SetText( text );
191   }
192 }
193
194 bool Controller::IsMarkupProcessorEnabled() const
195 {
196   return mImpl->mMarkupProcessorEnabled;
197 }
198
199 void Controller::SetAutoScrollEnabled( bool enable )
200 {
201   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 );
202
203   if( mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX )
204   {
205     if( enable )
206     {
207       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n" );
208       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
209                                                                LAYOUT                    |
210                                                                ALIGN                     |
211                                                                UPDATE_LAYOUT_SIZE        |
212                                                                UPDATE_DIRECTION          |
213                                                                REORDER );
214
215     }
216     else
217     {
218       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n");
219       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
220                                                                LAYOUT                    |
221                                                                ALIGN                     |
222                                                                UPDATE_LAYOUT_SIZE        |
223                                                                REORDER );
224     }
225
226     mImpl->mIsAutoScrollEnabled = enable;
227     mImpl->RequestRelayout();
228   }
229   else
230   {
231     DALI_LOG_WARNING( "Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored\n" );
232     mImpl->mIsAutoScrollEnabled = false;
233   }
234 }
235
236 bool Controller::IsAutoScrollEnabled() const
237 {
238   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::IsAutoScrollEnabled[%s]\n", mImpl->mIsAutoScrollEnabled?"true":"false" );
239
240   return mImpl->mIsAutoScrollEnabled;
241 }
242
243 CharacterDirection Controller::GetAutoScrollDirection() const
244 {
245   return mImpl->mIsTextDirectionRTL;
246 }
247
248 float Controller::GetAutoScrollLineAlignment() const
249 {
250   float offset = 0.f;
251
252   if( mImpl->mModel->mVisualModel &&
253       ( 0u != mImpl->mModel->mVisualModel->mLines.Count() ) )
254   {
255     offset = ( *mImpl->mModel->mVisualModel->mLines.Begin() ).alignmentOffset;
256   }
257
258   return offset;
259 }
260
261 void Controller::SetHorizontalScrollEnabled( bool enable )
262 {
263   if( ( NULL != mImpl->mEventData ) &&
264       mImpl->mEventData->mDecorator )
265   {
266     mImpl->mEventData->mDecorator->SetHorizontalScrollEnabled( enable );
267   }
268 }
269 bool Controller::IsHorizontalScrollEnabled() const
270 {
271   if( ( NULL != mImpl->mEventData ) &&
272       mImpl->mEventData->mDecorator )
273   {
274     return mImpl->mEventData->mDecorator->IsHorizontalScrollEnabled();
275   }
276
277   return false;
278 }
279
280 void Controller::SetVerticalScrollEnabled( bool enable )
281 {
282   if( ( NULL != mImpl->mEventData ) &&
283       mImpl->mEventData->mDecorator )
284   {
285     if( mImpl->mEventData->mDecorator )
286     {
287       mImpl->mEventData->mDecorator->SetVerticalScrollEnabled( enable );
288     }
289   }
290 }
291
292 bool Controller::IsVerticalScrollEnabled() const
293 {
294   if( ( NULL != mImpl->mEventData ) &&
295       mImpl->mEventData->mDecorator )
296   {
297     return mImpl->mEventData->mDecorator->IsVerticalScrollEnabled();
298   }
299
300   return false;
301 }
302
303 void Controller::SetSmoothHandlePanEnabled( bool enable )
304 {
305   if( ( NULL != mImpl->mEventData ) &&
306       mImpl->mEventData->mDecorator )
307   {
308     mImpl->mEventData->mDecorator->SetSmoothHandlePanEnabled( enable );
309   }
310 }
311
312 bool Controller::IsSmoothHandlePanEnabled() const
313 {
314   if( ( NULL != mImpl->mEventData ) &&
315       mImpl->mEventData->mDecorator )
316   {
317     return mImpl->mEventData->mDecorator->IsSmoothHandlePanEnabled();
318   }
319
320   return false;
321 }
322
323 void Controller::SetMaximumNumberOfCharacters( Length maxCharacters )
324 {
325   mImpl->mMaximumNumberOfCharacters = std::min( maxCharacters, MAX_TEXT_LENGTH );
326 }
327
328 int Controller::GetMaximumNumberOfCharacters()
329 {
330   return mImpl->mMaximumNumberOfCharacters;
331 }
332
333 void Controller::SetEnableCursorBlink( bool enable )
334 {
335   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" );
336
337   if( NULL != mImpl->mEventData )
338   {
339     mImpl->mEventData->mCursorBlinkEnabled = enable;
340
341     if( !enable &&
342         mImpl->mEventData->mDecorator )
343     {
344       mImpl->mEventData->mDecorator->StopCursorBlink();
345     }
346   }
347 }
348
349 bool Controller::GetEnableCursorBlink() const
350 {
351   if( NULL != mImpl->mEventData )
352   {
353     return mImpl->mEventData->mCursorBlinkEnabled;
354   }
355
356   return false;
357 }
358
359 void Controller::SetMultiLineEnabled( bool enable )
360 {
361   const Layout::Engine::Type layout = enable ? Layout::Engine::MULTI_LINE_BOX : Layout::Engine::SINGLE_LINE_BOX;
362
363   if( layout != mImpl->mLayoutEngine.GetLayout() )
364   {
365     // Set the layout type.
366     mImpl->mLayoutEngine.SetLayout( layout );
367
368     // Set the flags to redo the layout operations
369     const OperationsMask layoutOperations =  static_cast<OperationsMask>( LAYOUT             |
370                                                                           UPDATE_LAYOUT_SIZE |
371                                                                           ALIGN              |
372                                                                           REORDER );
373
374     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
375     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | layoutOperations );
376
377     // Need to recalculate natural size
378     mImpl->mRecalculateNaturalSize = true;
379
380     mImpl->RequestRelayout();
381   }
382 }
383
384 bool Controller::IsMultiLineEnabled() const
385 {
386   return Layout::Engine::MULTI_LINE_BOX == mImpl->mLayoutEngine.GetLayout();
387 }
388
389 void Controller::SetHorizontalAlignment( Text::HorizontalAlignment::Type alignment )
390 {
391   if( alignment != mImpl->mModel->mHorizontalAlignment )
392   {
393     // Set the alignment.
394     mImpl->mModel->mHorizontalAlignment = alignment;
395
396     // Set the flag to redo the alignment operation.
397     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
398
399     if( mImpl->mEventData )
400     {
401       mImpl->mEventData->mUpdateAlignment = true;
402     }
403
404     mImpl->RequestRelayout();
405   }
406 }
407
408 Text::HorizontalAlignment::Type Controller::GetHorizontalAlignment() const
409 {
410   return mImpl->mModel->mHorizontalAlignment;
411 }
412
413 void Controller::SetVerticalAlignment( VerticalAlignment::Type alignment )
414 {
415   if( alignment != mImpl->mModel->mVerticalAlignment )
416   {
417     // Set the alignment.
418     mImpl->mModel->mVerticalAlignment = alignment;
419
420     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
421
422     mImpl->RequestRelayout();
423   }
424 }
425
426 VerticalAlignment::Type Controller::GetVerticalAlignment() const
427 {
428   return mImpl->mModel->mVerticalAlignment;
429 }
430
431 bool Controller::IsIgnoreSpacesAfterText() const
432 {
433   return mImpl->mModel->mIgnoreSpacesAfterText;
434 }
435
436 void Controller::SetIgnoreSpacesAfterText( bool ignore )
437 {
438   mImpl->mModel->mIgnoreSpacesAfterText = ignore;
439 }
440
441 bool Controller::IsMatchSystemLanguageDirection() const
442 {
443   return mImpl->mModel->mMatchSystemLanguageDirection;
444 }
445
446 void Controller::SetMatchSystemLanguageDirection( bool match )
447 {
448   mImpl->mModel->mMatchSystemLanguageDirection = match;
449 }
450
451 void Controller::SetLayoutDirection( Dali::LayoutDirection::Type layoutDirection )
452 {
453   mImpl->mLayoutDirection = layoutDirection;
454 }
455
456 bool Controller::IsShowingRealText() const
457 {
458   return mImpl->IsShowingRealText();
459 }
460
461
462 void Controller::SetLineWrapMode( Text::LineWrap::Mode lineWrapMode )
463 {
464   if( lineWrapMode != mImpl->mModel->mLineWrapMode )
465   {
466     // Set the text wrap mode.
467     mImpl->mModel->mLineWrapMode = lineWrapMode;
468
469
470     // Update Text layout for applying wrap mode
471     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
472                                                              ALIGN                     |
473                                                              LAYOUT                    |
474                                                              UPDATE_LAYOUT_SIZE        |
475                                                              REORDER                   );
476     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
477     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
478     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
479
480     // Request relayout
481     mImpl->RequestRelayout();
482   }
483 }
484
485 Text::LineWrap::Mode Controller::GetLineWrapMode() const
486 {
487   return mImpl->mModel->mLineWrapMode;
488 }
489
490 void Controller::SetTextElideEnabled( bool enabled )
491 {
492   mImpl->mModel->mElideEnabled = enabled;
493 }
494
495 bool Controller::IsTextElideEnabled() const
496 {
497   return mImpl->mModel->mElideEnabled;
498 }
499
500 void Controller::SetTextFitEnabled(bool enabled)
501 {
502   mImpl->mTextFitEnabled = enabled;
503 }
504
505 bool Controller::IsTextFitEnabled() const
506 {
507   return mImpl->mTextFitEnabled;
508 }
509
510 void Controller::SetTextFitMinSize( float minSize, FontSizeType type )
511 {
512   switch( type )
513   {
514     case POINT_SIZE:
515     {
516       mImpl->mTextFitMinSize = minSize;
517       break;
518     }
519     case PIXEL_SIZE:
520     {
521       mImpl->mTextFitMinSize = ConvertPixelToPint( minSize );
522       break;
523     }
524   }
525 }
526
527 float Controller::GetTextFitMinSize() const
528 {
529   return mImpl->mTextFitMinSize;
530 }
531
532 void Controller::SetTextFitMaxSize( float maxSize, FontSizeType type )
533 {
534   switch( type )
535   {
536     case POINT_SIZE:
537     {
538       mImpl->mTextFitMaxSize = maxSize;
539       break;
540     }
541     case PIXEL_SIZE:
542     {
543       mImpl->mTextFitMaxSize = ConvertPixelToPint( maxSize );
544       break;
545     }
546   }
547 }
548
549 float Controller::GetTextFitMaxSize() const
550 {
551   return mImpl->mTextFitMaxSize;
552 }
553
554 void Controller::SetTextFitStepSize( float step, FontSizeType type )
555 {
556   switch( type )
557   {
558     case POINT_SIZE:
559     {
560       mImpl->mTextFitStepSize = step;
561       break;
562     }
563     case PIXEL_SIZE:
564     {
565       mImpl->mTextFitStepSize = ConvertPixelToPint( step );
566       break;
567     }
568   }
569 }
570
571 float Controller::GetTextFitStepSize() const
572 {
573   return mImpl->mTextFitStepSize;
574 }
575
576 void Controller::SetTextFitContentSize(Vector2 size)
577 {
578   mImpl->mTextFitContentSize = size;
579 }
580
581 Vector2 Controller::GetTextFitContentSize() const
582 {
583   return mImpl->mTextFitContentSize;
584 }
585
586 void Controller::SetPlaceholderTextElideEnabled( bool enabled )
587 {
588   mImpl->mEventData->mIsPlaceholderElideEnabled = enabled;
589   mImpl->mEventData->mPlaceholderEllipsisFlag = true;
590
591   // Update placeholder if there is no text
592   if( mImpl->IsShowingPlaceholderText() ||
593       ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) )
594   {
595     ShowPlaceholderText();
596   }
597 }
598
599 bool Controller::IsPlaceholderTextElideEnabled() const
600 {
601   return mImpl->mEventData->mIsPlaceholderElideEnabled;
602 }
603
604 void Controller::SetSelectionEnabled( bool enabled )
605 {
606   mImpl->mEventData->mSelectionEnabled = enabled;
607 }
608
609 bool Controller::IsSelectionEnabled() const
610 {
611   return mImpl->mEventData->mSelectionEnabled;
612 }
613
614 void Controller::SetShiftSelectionEnabled( bool enabled )
615 {
616   mImpl->mEventData->mShiftSelectionFlag = enabled;
617 }
618
619 bool Controller::IsShiftSelectionEnabled() const
620 {
621   return mImpl->mEventData->mShiftSelectionFlag;
622 }
623
624 void Controller::SetGrabHandleEnabled( bool enabled )
625 {
626   mImpl->mEventData->mGrabHandleEnabled = enabled;
627 }
628
629 bool Controller::IsGrabHandleEnabled() const
630 {
631   return mImpl->mEventData->mGrabHandleEnabled;
632 }
633
634 void Controller::SetGrabHandlePopupEnabled(bool enabled)
635 {
636   mImpl->mEventData->mGrabHandlePopupEnabled = enabled;
637 }
638
639 bool Controller::IsGrabHandlePopupEnabled() const
640 {
641   return mImpl->mEventData->mGrabHandlePopupEnabled;
642 }
643
644 // public : Update
645
646 void Controller::SetText( const std::string& text )
647 {
648   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText\n" );
649
650   // Reset keyboard as text changed
651   mImpl->ResetInputMethodContext();
652
653   // Remove the previously set text and style.
654   ResetText();
655
656   // Remove the style.
657   ClearStyleData();
658
659   CharacterIndex lastCursorIndex = 0u;
660
661   if( NULL != mImpl->mEventData )
662   {
663     // If popup shown then hide it by switching to Editing state
664     if( ( EventData::SELECTING == mImpl->mEventData->mState )          ||
665         ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
666         ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) ||
667         ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) )
668     {
669       mImpl->ChangeState( EventData::EDITING );
670     }
671   }
672
673   if( !text.empty() )
674   {
675     mImpl->mModel->mVisualModel->SetTextColor( mImpl->mTextColor );
676
677     MarkupProcessData markupProcessData( mImpl->mModel->mLogicalModel->mColorRuns,
678                                          mImpl->mModel->mLogicalModel->mFontDescriptionRuns,
679                                          mImpl->mModel->mLogicalModel->mEmbeddedItems );
680
681     Length textSize = 0u;
682     const uint8_t* utf8 = NULL;
683     if( mImpl->mMarkupProcessorEnabled )
684     {
685       ProcessMarkupString( text, markupProcessData );
686       textSize = markupProcessData.markupProcessedText.size();
687
688       // This is a bit horrible but std::string returns a (signed) char*
689       utf8 = reinterpret_cast<const uint8_t*>( markupProcessData.markupProcessedText.c_str() );
690     }
691     else
692     {
693       textSize = text.size();
694
695       // This is a bit horrible but std::string returns a (signed) char*
696       utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
697     }
698
699     // Limit the text size. If the text size is too large, crash or deadlock will occur.
700     if( textSize > MAX_TEXT_LENGTH )
701     {
702       DALI_LOG_WARNING( "The text size is too large(%d), limit the length to 32,768u\n", textSize );
703       textSize = MAX_TEXT_LENGTH;
704     }
705
706     //  Convert text into UTF-32
707     Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
708     utf32Characters.Resize( textSize );
709
710     // Transform a text array encoded in utf8 into an array encoded in utf32.
711     // It returns the actual number of characters.
712     Length characterCount = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() );
713     utf32Characters.Resize( characterCount );
714
715     DALI_ASSERT_DEBUG( textSize >= characterCount && "Invalid UTF32 conversion length" );
716     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, textSize, mImpl->mModel->mLogicalModel->mText.Count() );
717
718     // The characters to be added.
719     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
720
721     // To reset the cursor position
722     lastCursorIndex = characterCount;
723
724     // Update the rest of the model during size negotiation
725     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
726
727     // The natural size needs to be re-calculated.
728     mImpl->mRecalculateNaturalSize = true;
729
730     // The text direction needs to be updated.
731     mImpl->mUpdateTextDirection = true;
732
733     // Apply modifications to the model
734     mImpl->mOperationsPending = ALL_OPERATIONS;
735   }
736   else
737   {
738     ShowPlaceholderText();
739   }
740
741   // Resets the cursor position.
742   ResetCursorPosition( lastCursorIndex );
743
744   // Scrolls the text to make the cursor visible.
745   ResetScrollPosition();
746
747   mImpl->RequestRelayout();
748
749   if( NULL != mImpl->mEventData )
750   {
751     // Cancel previously queued events
752     mImpl->mEventData->mEventQueue.clear();
753   }
754
755   // Do this last since it provides callbacks into application code.
756   if( NULL != mImpl->mEditableControlInterface )
757   {
758     mImpl->mEditableControlInterface->TextChanged();
759   }
760 }
761
762 void Controller::GetText( std::string& text ) const
763 {
764   if( !mImpl->IsShowingPlaceholderText() )
765   {
766     // Retrieves the text string.
767     mImpl->GetText( 0u, text );
768   }
769   else
770   {
771     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this );
772   }
773 }
774
775 void Controller::SetPlaceholderText( PlaceholderType type, const std::string& text )
776 {
777   if( NULL != mImpl->mEventData )
778   {
779     if( PLACEHOLDER_TYPE_INACTIVE == type )
780     {
781       mImpl->mEventData->mPlaceholderTextInactive = text;
782     }
783     else
784     {
785       mImpl->mEventData->mPlaceholderTextActive = text;
786     }
787
788     // Update placeholder if there is no text
789     if( mImpl->IsShowingPlaceholderText() ||
790         ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) )
791     {
792       ShowPlaceholderText();
793     }
794   }
795 }
796
797 void Controller::GetPlaceholderText( PlaceholderType type, std::string& text ) const
798 {
799   if( NULL != mImpl->mEventData )
800   {
801     if( PLACEHOLDER_TYPE_INACTIVE == type )
802     {
803       text = mImpl->mEventData->mPlaceholderTextInactive;
804     }
805     else
806     {
807       text = mImpl->mEventData->mPlaceholderTextActive;
808     }
809   }
810 }
811
812 void Controller::UpdateAfterFontChange( const std::string& newDefaultFont )
813 {
814   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange\n");
815
816   if( !mImpl->mFontDefaults->familyDefined ) // If user defined font then should not update when system font changes
817   {
818     DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str() );
819     mImpl->mFontDefaults->mFontDescription.family = newDefaultFont;
820
821     ClearFontData();
822
823     mImpl->RequestRelayout();
824   }
825 }
826
827 // public : Default style & Input style
828
829 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
830 {
831   if( NULL == mImpl->mFontDefaults )
832   {
833     mImpl->mFontDefaults = new FontDefaults();
834   }
835
836   mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
837   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str());
838   mImpl->mFontDefaults->familyDefined = !defaultFontFamily.empty();
839
840   // Clear the font-specific data
841   ClearFontData();
842
843   mImpl->RequestRelayout();
844 }
845
846 const std::string& Controller::GetDefaultFontFamily() const
847 {
848   if( NULL != mImpl->mFontDefaults )
849   {
850     return mImpl->mFontDefaults->mFontDescription.family;
851   }
852
853   return EMPTY_STRING;
854 }
855
856 void Controller::SetPlaceholderFontFamily( const std::string& placeholderTextFontFamily )
857 {
858   if( NULL != mImpl->mEventData )
859   {
860     if( NULL == mImpl->mEventData->mPlaceholderFont )
861     {
862       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
863     }
864
865     mImpl->mEventData->mPlaceholderFont->mFontDescription.family = placeholderTextFontFamily;
866     DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetPlaceholderFontFamily %s\n", placeholderTextFontFamily.c_str());
867     mImpl->mEventData->mPlaceholderFont->familyDefined = !placeholderTextFontFamily.empty();
868
869     mImpl->RequestRelayout();
870   }
871 }
872
873 const std::string& Controller::GetPlaceholderFontFamily() const
874 {
875   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
876   {
877     return mImpl->mEventData->mPlaceholderFont->mFontDescription.family;
878   }
879
880   return EMPTY_STRING;
881 }
882
883 void Controller::SetDefaultFontWeight( FontWeight weight )
884 {
885   if( NULL == mImpl->mFontDefaults )
886   {
887     mImpl->mFontDefaults = new FontDefaults();
888   }
889
890   mImpl->mFontDefaults->mFontDescription.weight = weight;
891   mImpl->mFontDefaults->weightDefined = true;
892
893   // Clear the font-specific data
894   ClearFontData();
895
896   mImpl->RequestRelayout();
897 }
898
899 bool Controller::IsDefaultFontWeightDefined() const
900 {
901   if( NULL != mImpl->mFontDefaults )
902   {
903     return mImpl->mFontDefaults->weightDefined;
904   }
905
906   return false;
907 }
908
909 FontWeight Controller::GetDefaultFontWeight() const
910 {
911   if( NULL != mImpl->mFontDefaults )
912   {
913     return mImpl->mFontDefaults->mFontDescription.weight;
914   }
915
916   return TextAbstraction::FontWeight::NORMAL;
917 }
918
919 void Controller::SetPlaceholderTextFontWeight( FontWeight weight )
920 {
921   if( NULL != mImpl->mEventData )
922   {
923     if( NULL == mImpl->mEventData->mPlaceholderFont )
924     {
925       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
926     }
927
928     mImpl->mEventData->mPlaceholderFont->mFontDescription.weight = weight;
929     mImpl->mEventData->mPlaceholderFont->weightDefined = true;
930
931     mImpl->RequestRelayout();
932   }
933 }
934
935 bool Controller::IsPlaceholderTextFontWeightDefined() const
936 {
937   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
938   {
939     return mImpl->mEventData->mPlaceholderFont->weightDefined;
940   }
941   return false;
942 }
943
944 FontWeight Controller::GetPlaceholderTextFontWeight() const
945 {
946   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
947   {
948     return mImpl->mEventData->mPlaceholderFont->mFontDescription.weight;
949   }
950
951   return TextAbstraction::FontWeight::NORMAL;
952 }
953
954 void Controller::SetDefaultFontWidth( FontWidth width )
955 {
956   if( NULL == mImpl->mFontDefaults )
957   {
958     mImpl->mFontDefaults = new FontDefaults();
959   }
960
961   mImpl->mFontDefaults->mFontDescription.width = width;
962   mImpl->mFontDefaults->widthDefined = true;
963
964   // Clear the font-specific data
965   ClearFontData();
966
967   mImpl->RequestRelayout();
968 }
969
970 bool Controller::IsDefaultFontWidthDefined() const
971 {
972   if( NULL != mImpl->mFontDefaults )
973   {
974     return mImpl->mFontDefaults->widthDefined;
975   }
976
977   return false;
978 }
979
980 FontWidth Controller::GetDefaultFontWidth() const
981 {
982   if( NULL != mImpl->mFontDefaults )
983   {
984     return mImpl->mFontDefaults->mFontDescription.width;
985   }
986
987   return TextAbstraction::FontWidth::NORMAL;
988 }
989
990 void Controller::SetPlaceholderTextFontWidth( FontWidth width )
991 {
992   if( NULL != mImpl->mEventData )
993   {
994     if( NULL == mImpl->mEventData->mPlaceholderFont )
995     {
996       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
997     }
998
999     mImpl->mEventData->mPlaceholderFont->mFontDescription.width = width;
1000     mImpl->mEventData->mPlaceholderFont->widthDefined = true;
1001
1002     mImpl->RequestRelayout();
1003   }
1004 }
1005
1006 bool Controller::IsPlaceholderTextFontWidthDefined() const
1007 {
1008   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
1009   {
1010     return mImpl->mEventData->mPlaceholderFont->widthDefined;
1011   }
1012   return false;
1013 }
1014
1015 FontWidth Controller::GetPlaceholderTextFontWidth() const
1016 {
1017   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
1018   {
1019     return mImpl->mEventData->mPlaceholderFont->mFontDescription.width;
1020   }
1021
1022   return TextAbstraction::FontWidth::NORMAL;
1023 }
1024
1025 void Controller::SetDefaultFontSlant( FontSlant slant )
1026 {
1027   if( NULL == mImpl->mFontDefaults )
1028   {
1029     mImpl->mFontDefaults = new FontDefaults();
1030   }
1031
1032   mImpl->mFontDefaults->mFontDescription.slant = slant;
1033   mImpl->mFontDefaults->slantDefined = true;
1034
1035   // Clear the font-specific data
1036   ClearFontData();
1037
1038   mImpl->RequestRelayout();
1039 }
1040
1041 bool Controller::IsDefaultFontSlantDefined() const
1042 {
1043   if( NULL != mImpl->mFontDefaults )
1044   {
1045     return mImpl->mFontDefaults->slantDefined;
1046   }
1047   return false;
1048 }
1049
1050 FontSlant Controller::GetDefaultFontSlant() const
1051 {
1052   if( NULL != mImpl->mFontDefaults )
1053   {
1054     return mImpl->mFontDefaults->mFontDescription.slant;
1055   }
1056
1057   return TextAbstraction::FontSlant::NORMAL;
1058 }
1059
1060 void Controller::SetPlaceholderTextFontSlant( FontSlant slant )
1061 {
1062   if( NULL != mImpl->mEventData )
1063   {
1064     if( NULL == mImpl->mEventData->mPlaceholderFont )
1065     {
1066       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
1067     }
1068
1069     mImpl->mEventData->mPlaceholderFont->mFontDescription.slant = slant;
1070     mImpl->mEventData->mPlaceholderFont->slantDefined = true;
1071
1072     mImpl->RequestRelayout();
1073   }
1074 }
1075
1076 bool Controller::IsPlaceholderTextFontSlantDefined() const
1077 {
1078   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
1079   {
1080     return mImpl->mEventData->mPlaceholderFont->slantDefined;
1081   }
1082   return false;
1083 }
1084
1085 FontSlant Controller::GetPlaceholderTextFontSlant() const
1086 {
1087   if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
1088   {
1089     return mImpl->mEventData->mPlaceholderFont->mFontDescription.slant;
1090   }
1091
1092   return TextAbstraction::FontSlant::NORMAL;
1093 }
1094
1095 void Controller::SetDefaultFontSize( float fontSize, FontSizeType type )
1096 {
1097   if( NULL == mImpl->mFontDefaults )
1098   {
1099     mImpl->mFontDefaults = new FontDefaults();
1100   }
1101
1102   switch( type )
1103   {
1104     case POINT_SIZE:
1105     {
1106       mImpl->mFontDefaults->mDefaultPointSize = fontSize;
1107       mImpl->mFontDefaults->sizeDefined = true;
1108       break;
1109     }
1110     case PIXEL_SIZE:
1111     {
1112       // Point size = Pixel size * 72.f / DPI
1113       unsigned int horizontalDpi = 0u;
1114       unsigned int verticalDpi = 0u;
1115       TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
1116       fontClient.GetDpi( horizontalDpi, verticalDpi );
1117
1118       mImpl->mFontDefaults->mDefaultPointSize = ( fontSize * 72.f ) / static_cast< float >( horizontalDpi );
1119       mImpl->mFontDefaults->sizeDefined = true;
1120       break;
1121     }
1122   }
1123
1124   // Clear the font-specific data
1125   ClearFontData();
1126
1127   mImpl->RequestRelayout();
1128 }
1129
1130 float Controller::GetDefaultFontSize( FontSizeType type ) const
1131 {
1132   float value = 0.0f;
1133   if( NULL != mImpl->mFontDefaults )
1134   {
1135     switch( type )
1136     {
1137       case POINT_SIZE:
1138       {
1139         value = mImpl->mFontDefaults->mDefaultPointSize;
1140         break;
1141       }
1142       case PIXEL_SIZE:
1143       {
1144         // Pixel size = Point size * DPI / 72.f
1145         unsigned int horizontalDpi = 0u;
1146         unsigned int verticalDpi = 0u;
1147         TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
1148         fontClient.GetDpi( horizontalDpi, verticalDpi );
1149
1150         value = mImpl->mFontDefaults->mDefaultPointSize * static_cast< float >( horizontalDpi ) / 72.f;
1151         break;
1152       }
1153     }
1154     return value;
1155   }
1156
1157   return value;
1158 }
1159
1160 void Controller::SetPlaceholderTextFontSize( float fontSize, FontSizeType type )
1161 {
1162   if( NULL != mImpl->mEventData )
1163   {
1164     if( NULL == mImpl->mEventData->mPlaceholderFont )
1165     {
1166       mImpl->mEventData->mPlaceholderFont = new FontDefaults();
1167     }
1168
1169     switch( type )
1170     {
1171       case POINT_SIZE:
1172       {
1173         mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = fontSize;
1174         mImpl->mEventData->mPlaceholderFont->sizeDefined = true;
1175         mImpl->mEventData->mIsPlaceholderPixelSize = false; // Font size flag
1176         break;
1177       }
1178       case PIXEL_SIZE:
1179       {
1180         // Point size = Pixel size * 72.f / DPI
1181         unsigned int horizontalDpi = 0u;
1182         unsigned int verticalDpi = 0u;
1183         TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
1184         fontClient.GetDpi( horizontalDpi, verticalDpi );
1185
1186         mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = ( fontSize * 72.f ) / static_cast< float >( horizontalDpi );
1187         mImpl->mEventData->mPlaceholderFont->sizeDefined = true;
1188         mImpl->mEventData->mIsPlaceholderPixelSize = true; // Font size flag
1189         break;
1190       }
1191     }
1192
1193     mImpl->RequestRelayout();
1194   }
1195 }
1196
1197 float Controller::GetPlaceholderTextFontSize( FontSizeType type ) const
1198 {
1199   float value = 0.0f;
1200   if( NULL != mImpl->mEventData )
1201   {
1202     switch( type )
1203     {
1204       case POINT_SIZE:
1205       {
1206         if( NULL != mImpl->mEventData->mPlaceholderFont )
1207         {
1208           value = mImpl->mEventData->mPlaceholderFont->mDefaultPointSize;
1209         }
1210         else
1211         {
1212           // If the placeholder text font size is not set, then return the default font size.
1213           value = GetDefaultFontSize( POINT_SIZE );
1214         }
1215         break;
1216       }
1217       case PIXEL_SIZE:
1218       {
1219         if( NULL != mImpl->mEventData->mPlaceholderFont )
1220         {
1221           // Pixel size = Point size * DPI / 72.f
1222           unsigned int horizontalDpi = 0u;
1223           unsigned int verticalDpi = 0u;
1224           TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
1225           fontClient.GetDpi( horizontalDpi, verticalDpi );
1226
1227           value = mImpl->mEventData->mPlaceholderFont->mDefaultPointSize * static_cast< float >( horizontalDpi ) / 72.f;
1228         }
1229         else
1230         {
1231           // If the placeholder text font size is not set, then return the default font size.
1232           value = GetDefaultFontSize( PIXEL_SIZE );
1233         }
1234         break;
1235       }
1236     }
1237     return value;
1238   }
1239
1240   return value;
1241 }
1242
1243 void Controller::SetDefaultColor( const Vector4& color )
1244 {
1245   mImpl->mTextColor = color;
1246
1247   if( !mImpl->IsShowingPlaceholderText() )
1248   {
1249     mImpl->mModel->mVisualModel->SetTextColor( color );
1250
1251     mImpl->mModel->mLogicalModel->mColorRuns.Clear();
1252
1253     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
1254
1255     mImpl->RequestRelayout();
1256   }
1257 }
1258
1259 const Vector4& Controller::GetDefaultColor() const
1260 {
1261   return mImpl->mTextColor;
1262 }
1263
1264 void Controller::SetPlaceholderTextColor( const Vector4& textColor )
1265 {
1266   if( NULL != mImpl->mEventData )
1267   {
1268     mImpl->mEventData->mPlaceholderTextColor = textColor;
1269   }
1270
1271   if( mImpl->IsShowingPlaceholderText() )
1272   {
1273     mImpl->mModel->mVisualModel->SetTextColor( textColor );
1274     mImpl->RequestRelayout();
1275   }
1276 }
1277
1278 const Vector4& Controller::GetPlaceholderTextColor() const
1279 {
1280   if( NULL != mImpl->mEventData )
1281   {
1282     return mImpl->mEventData->mPlaceholderTextColor;
1283   }
1284
1285   return Color::BLACK;
1286 }
1287
1288 void Controller::SetShadowOffset( const Vector2& shadowOffset )
1289 {
1290   mImpl->mModel->mVisualModel->SetShadowOffset( shadowOffset );
1291
1292   mImpl->RequestRelayout();
1293 }
1294
1295 const Vector2& Controller::GetShadowOffset() const
1296 {
1297   return mImpl->mModel->mVisualModel->GetShadowOffset();
1298 }
1299
1300 void Controller::SetShadowColor( const Vector4& shadowColor )
1301 {
1302   mImpl->mModel->mVisualModel->SetShadowColor( shadowColor );
1303
1304   mImpl->RequestRelayout();
1305 }
1306
1307 const Vector4& Controller::GetShadowColor() const
1308 {
1309   return mImpl->mModel->mVisualModel->GetShadowColor();
1310 }
1311
1312 void Controller::SetShadowBlurRadius( const float& shadowBlurRadius )
1313 {
1314   if ( fabsf( GetShadowBlurRadius() - shadowBlurRadius ) > Math::MACHINE_EPSILON_1 )
1315   {
1316     mImpl->mModel->mVisualModel->SetShadowBlurRadius( shadowBlurRadius );
1317
1318     mImpl->RequestRelayout();
1319   }
1320 }
1321
1322 const float& Controller::GetShadowBlurRadius() const
1323 {
1324   return mImpl->mModel->mVisualModel->GetShadowBlurRadius();
1325 }
1326
1327 void Controller::SetUnderlineColor( const Vector4& color )
1328 {
1329   mImpl->mModel->mVisualModel->SetUnderlineColor( color );
1330
1331   mImpl->RequestRelayout();
1332 }
1333
1334 const Vector4& Controller::GetUnderlineColor() const
1335 {
1336   return mImpl->mModel->mVisualModel->GetUnderlineColor();
1337 }
1338
1339 void Controller::SetUnderlineEnabled( bool enabled )
1340 {
1341   mImpl->mModel->mVisualModel->SetUnderlineEnabled( enabled );
1342
1343   mImpl->RequestRelayout();
1344 }
1345
1346 bool Controller::IsUnderlineEnabled() const
1347 {
1348   return mImpl->mModel->mVisualModel->IsUnderlineEnabled();
1349 }
1350
1351 void Controller::SetUnderlineHeight( float height )
1352 {
1353   mImpl->mModel->mVisualModel->SetUnderlineHeight( height );
1354
1355   mImpl->RequestRelayout();
1356 }
1357
1358 float Controller::GetUnderlineHeight() const
1359 {
1360   return mImpl->mModel->mVisualModel->GetUnderlineHeight();
1361 }
1362
1363 void Controller::SetOutlineColor( const Vector4& color )
1364 {
1365   mImpl->mModel->mVisualModel->SetOutlineColor( color );
1366
1367   mImpl->RequestRelayout();
1368 }
1369
1370 const Vector4& Controller::GetOutlineColor() const
1371 {
1372   return mImpl->mModel->mVisualModel->GetOutlineColor();
1373 }
1374
1375 void Controller::SetOutlineWidth( uint16_t width )
1376 {
1377   mImpl->mModel->mVisualModel->SetOutlineWidth( width );
1378
1379   mImpl->RequestRelayout();
1380 }
1381
1382 uint16_t Controller::GetOutlineWidth() const
1383 {
1384   return mImpl->mModel->mVisualModel->GetOutlineWidth();
1385 }
1386
1387 void Controller::SetBackgroundColor( const Vector4& color )
1388 {
1389   mImpl->mModel->mVisualModel->SetBackgroundColor( color );
1390
1391   mImpl->RequestRelayout();
1392 }
1393
1394 const Vector4& Controller::GetBackgroundColor() const
1395 {
1396   return mImpl->mModel->mVisualModel->GetBackgroundColor();
1397 }
1398
1399 void Controller::SetBackgroundEnabled( bool enabled )
1400 {
1401   mImpl->mModel->mVisualModel->SetBackgroundEnabled( enabled );
1402
1403   mImpl->RequestRelayout();
1404 }
1405
1406 bool Controller::IsBackgroundEnabled() const
1407 {
1408   return mImpl->mModel->mVisualModel->IsBackgroundEnabled();
1409 }
1410
1411 void Controller::SetDefaultEmbossProperties( const std::string& embossProperties )
1412 {
1413   if( NULL == mImpl->mEmbossDefaults )
1414   {
1415     mImpl->mEmbossDefaults = new EmbossDefaults();
1416   }
1417
1418   mImpl->mEmbossDefaults->properties = embossProperties;
1419 }
1420
1421 const std::string& Controller::GetDefaultEmbossProperties() const
1422 {
1423   if( NULL != mImpl->mEmbossDefaults )
1424   {
1425     return mImpl->mEmbossDefaults->properties;
1426   }
1427
1428   return EMPTY_STRING;
1429 }
1430
1431 void Controller::SetDefaultOutlineProperties( const std::string& outlineProperties )
1432 {
1433   if( NULL == mImpl->mOutlineDefaults )
1434   {
1435     mImpl->mOutlineDefaults = new OutlineDefaults();
1436   }
1437
1438   mImpl->mOutlineDefaults->properties = outlineProperties;
1439 }
1440
1441 const std::string& Controller::GetDefaultOutlineProperties() const
1442 {
1443   if( NULL != mImpl->mOutlineDefaults )
1444   {
1445     return mImpl->mOutlineDefaults->properties;
1446   }
1447
1448   return EMPTY_STRING;
1449 }
1450
1451 bool Controller::SetDefaultLineSpacing( float lineSpacing )
1452 {
1453   if( std::fabs( lineSpacing - mImpl->mLayoutEngine.GetDefaultLineSpacing() ) > Math::MACHINE_EPSILON_1000 )
1454   {
1455     mImpl->mLayoutEngine.SetDefaultLineSpacing(lineSpacing);
1456     mImpl->mRecalculateNaturalSize = true;
1457     return true;
1458   }
1459   return false;
1460 }
1461
1462 float Controller::GetDefaultLineSpacing() const
1463 {
1464   return mImpl->mLayoutEngine.GetDefaultLineSpacing();
1465 }
1466
1467 void Controller::SetInputColor( const Vector4& color )
1468 {
1469   if( NULL != mImpl->mEventData )
1470   {
1471     mImpl->mEventData->mInputStyle.textColor = color;
1472     mImpl->mEventData->mInputStyle.isDefaultColor = false;
1473
1474     if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState )
1475     {
1476       const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition;
1477
1478       // Get start and end position of selection
1479       const CharacterIndex startOfSelectedText = handlesCrossed ? mImpl->mEventData->mRightSelectionPosition : mImpl->mEventData->mLeftSelectionPosition;
1480       const Length lengthOfSelectedText = ( handlesCrossed ? mImpl->mEventData->mLeftSelectionPosition : mImpl->mEventData->mRightSelectionPosition ) - startOfSelectedText;
1481
1482       // Add the color run.
1483       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
1484       mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
1485
1486       ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
1487       colorRun.color = color;
1488       colorRun.characterRun.characterIndex = startOfSelectedText;
1489       colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
1490
1491       // Request to relayout.
1492       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
1493       mImpl->RequestRelayout();
1494
1495       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1496       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1497       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1498     }
1499   }
1500 }
1501
1502 const Vector4& Controller::GetInputColor() const
1503 {
1504   if( NULL != mImpl->mEventData )
1505   {
1506     return mImpl->mEventData->mInputStyle.textColor;
1507   }
1508
1509   // Return the default text's color if there is no EventData.
1510   return mImpl->mTextColor;
1511
1512 }
1513
1514 void Controller::SetInputFontFamily( const std::string& fontFamily )
1515 {
1516   if( NULL != mImpl->mEventData )
1517   {
1518     mImpl->mEventData->mInputStyle.familyName = fontFamily;
1519     mImpl->mEventData->mInputStyle.isFamilyDefined = true;
1520
1521     if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState )
1522     {
1523       CharacterIndex startOfSelectedText = 0u;
1524       Length lengthOfSelectedText = 0u;
1525       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1526                                                                             mImpl->mModel->mLogicalModel,
1527                                                                             startOfSelectedText,
1528                                                                             lengthOfSelectedText );
1529
1530       fontDescriptionRun.familyLength = fontFamily.size();
1531       fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
1532       memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength );
1533       fontDescriptionRun.familyDefined = true;
1534
1535       // The memory allocated for the font family name is freed when the font description is removed from the logical model.
1536
1537       // Request to relayout.
1538       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1539                                                                VALIDATE_FONTS            |
1540                                                                SHAPE_TEXT                |
1541                                                                GET_GLYPH_METRICS         |
1542                                                                LAYOUT                    |
1543                                                                UPDATE_LAYOUT_SIZE        |
1544                                                                REORDER                   |
1545                                                                ALIGN );
1546       mImpl->mRecalculateNaturalSize = true;
1547       mImpl->RequestRelayout();
1548
1549       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1550       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1551       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1552
1553       // As the font changes, recalculate the handle positions is needed.
1554       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1555       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1556       mImpl->mEventData->mUpdateHighlightBox = true;
1557       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1558     }
1559   }
1560 }
1561
1562 const std::string& Controller::GetInputFontFamily() const
1563 {
1564   if( NULL != mImpl->mEventData )
1565   {
1566     return mImpl->mEventData->mInputStyle.familyName;
1567   }
1568
1569   // Return the default font's family if there is no EventData.
1570   return GetDefaultFontFamily();
1571 }
1572
1573 void Controller::SetInputFontWeight( FontWeight weight )
1574 {
1575   if( NULL != mImpl->mEventData )
1576   {
1577     mImpl->mEventData->mInputStyle.weight = weight;
1578     mImpl->mEventData->mInputStyle.isWeightDefined = true;
1579
1580     if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState )
1581     {
1582       CharacterIndex startOfSelectedText = 0u;
1583       Length lengthOfSelectedText = 0u;
1584       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1585                                                                             mImpl->mModel->mLogicalModel,
1586                                                                             startOfSelectedText,
1587                                                                             lengthOfSelectedText );
1588
1589       fontDescriptionRun.weight = weight;
1590       fontDescriptionRun.weightDefined = true;
1591
1592       // Request to relayout.
1593       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1594                                                                VALIDATE_FONTS            |
1595                                                                SHAPE_TEXT                |
1596                                                                GET_GLYPH_METRICS         |
1597                                                                LAYOUT                    |
1598                                                                UPDATE_LAYOUT_SIZE        |
1599                                                                REORDER                   |
1600                                                                ALIGN );
1601       mImpl->mRecalculateNaturalSize = true;
1602       mImpl->RequestRelayout();
1603
1604       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1605       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1606       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1607
1608       // As the font might change, recalculate the handle positions is needed.
1609       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1610       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1611       mImpl->mEventData->mUpdateHighlightBox = true;
1612       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1613     }
1614   }
1615 }
1616
1617 bool Controller::IsInputFontWeightDefined() const
1618 {
1619   bool defined = false;
1620
1621   if( NULL != mImpl->mEventData )
1622   {
1623     defined = mImpl->mEventData->mInputStyle.isWeightDefined;
1624   }
1625
1626   return defined;
1627 }
1628
1629 FontWeight Controller::GetInputFontWeight() const
1630 {
1631   if( NULL != mImpl->mEventData )
1632   {
1633     return mImpl->mEventData->mInputStyle.weight;
1634   }
1635
1636   return GetDefaultFontWeight();
1637 }
1638
1639 void Controller::SetInputFontWidth( FontWidth width )
1640 {
1641   if( NULL != mImpl->mEventData )
1642   {
1643     mImpl->mEventData->mInputStyle.width = width;
1644     mImpl->mEventData->mInputStyle.isWidthDefined = true;
1645
1646     if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState )
1647     {
1648       CharacterIndex startOfSelectedText = 0u;
1649       Length lengthOfSelectedText = 0u;
1650       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1651                                                                             mImpl->mModel->mLogicalModel,
1652                                                                             startOfSelectedText,
1653                                                                             lengthOfSelectedText );
1654
1655       fontDescriptionRun.width = width;
1656       fontDescriptionRun.widthDefined = true;
1657
1658       // Request to relayout.
1659       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1660                                                                VALIDATE_FONTS            |
1661                                                                SHAPE_TEXT                |
1662                                                                GET_GLYPH_METRICS         |
1663                                                                LAYOUT                    |
1664                                                                UPDATE_LAYOUT_SIZE        |
1665                                                                REORDER                   |
1666                                                                ALIGN );
1667       mImpl->mRecalculateNaturalSize = true;
1668       mImpl->RequestRelayout();
1669
1670       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1671       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1672       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1673
1674       // As the font might change, recalculate the handle positions is needed.
1675       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1676       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1677       mImpl->mEventData->mUpdateHighlightBox = true;
1678       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1679     }
1680   }
1681 }
1682
1683 bool Controller::IsInputFontWidthDefined() const
1684 {
1685   bool defined = false;
1686
1687   if( NULL != mImpl->mEventData )
1688   {
1689     defined = mImpl->mEventData->mInputStyle.isWidthDefined;
1690   }
1691
1692   return defined;
1693 }
1694
1695 FontWidth Controller::GetInputFontWidth() const
1696 {
1697   if( NULL != mImpl->mEventData )
1698   {
1699     return mImpl->mEventData->mInputStyle.width;
1700   }
1701
1702   return GetDefaultFontWidth();
1703 }
1704
1705 void Controller::SetInputFontSlant( FontSlant slant )
1706 {
1707   if( NULL != mImpl->mEventData )
1708   {
1709     mImpl->mEventData->mInputStyle.slant = slant;
1710     mImpl->mEventData->mInputStyle.isSlantDefined = true;
1711
1712     if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState )
1713     {
1714       CharacterIndex startOfSelectedText = 0u;
1715       Length lengthOfSelectedText = 0u;
1716       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1717                                                                             mImpl->mModel->mLogicalModel,
1718                                                                             startOfSelectedText,
1719                                                                             lengthOfSelectedText );
1720
1721       fontDescriptionRun.slant = slant;
1722       fontDescriptionRun.slantDefined = true;
1723
1724       // Request to relayout.
1725       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1726                                                                VALIDATE_FONTS            |
1727                                                                SHAPE_TEXT                |
1728                                                                GET_GLYPH_METRICS         |
1729                                                                LAYOUT                    |
1730                                                                UPDATE_LAYOUT_SIZE        |
1731                                                                REORDER                   |
1732                                                                ALIGN );
1733       mImpl->mRecalculateNaturalSize = true;
1734       mImpl->RequestRelayout();
1735
1736       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1737       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1738       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1739
1740       // As the font might change, recalculate the handle positions is needed.
1741       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1742       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1743       mImpl->mEventData->mUpdateHighlightBox = true;
1744       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1745     }
1746   }
1747 }
1748
1749 bool Controller::IsInputFontSlantDefined() const
1750 {
1751   bool defined = false;
1752
1753   if( NULL != mImpl->mEventData )
1754   {
1755     defined = mImpl->mEventData->mInputStyle.isSlantDefined;
1756   }
1757
1758   return defined;
1759 }
1760
1761 FontSlant Controller::GetInputFontSlant() const
1762 {
1763   if( NULL != mImpl->mEventData )
1764   {
1765     return mImpl->mEventData->mInputStyle.slant;
1766   }
1767
1768   return GetDefaultFontSlant();
1769 }
1770
1771 void Controller::SetInputFontPointSize( float size )
1772 {
1773   if( NULL != mImpl->mEventData )
1774   {
1775     mImpl->mEventData->mInputStyle.size = size;
1776     mImpl->mEventData->mInputStyle.isSizeDefined = true;
1777
1778     if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState )
1779     {
1780       CharacterIndex startOfSelectedText = 0u;
1781       Length lengthOfSelectedText = 0u;
1782       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1783                                                                             mImpl->mModel->mLogicalModel,
1784                                                                             startOfSelectedText,
1785                                                                             lengthOfSelectedText );
1786
1787       fontDescriptionRun.size = static_cast<PointSize26Dot6>( size * 64.f );
1788       fontDescriptionRun.sizeDefined = true;
1789
1790       // Request to relayout.
1791       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1792                                                                VALIDATE_FONTS            |
1793                                                                SHAPE_TEXT                |
1794                                                                GET_GLYPH_METRICS         |
1795                                                                LAYOUT                    |
1796                                                                UPDATE_LAYOUT_SIZE        |
1797                                                                REORDER                   |
1798                                                                ALIGN );
1799       mImpl->mRecalculateNaturalSize = true;
1800       mImpl->RequestRelayout();
1801
1802       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1803       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1804       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1805
1806       // As the font might change, recalculate the handle positions is needed.
1807       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1808       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1809       mImpl->mEventData->mUpdateHighlightBox = true;
1810       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1811     }
1812   }
1813 }
1814
1815 float Controller::GetInputFontPointSize() const
1816 {
1817   if( NULL != mImpl->mEventData )
1818   {
1819     return mImpl->mEventData->mInputStyle.size;
1820   }
1821
1822   // Return the default font's point size if there is no EventData.
1823   return GetDefaultFontSize( Text::Controller::POINT_SIZE );
1824 }
1825
1826 void Controller::SetInputLineSpacing( float lineSpacing )
1827 {
1828   if( NULL != mImpl->mEventData )
1829   {
1830     mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing;
1831     mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
1832   }
1833 }
1834
1835 float Controller::GetInputLineSpacing() const
1836 {
1837   if( NULL != mImpl->mEventData )
1838   {
1839     return mImpl->mEventData->mInputStyle.lineSpacing;
1840   }
1841
1842   return 0.f;
1843 }
1844
1845 void Controller::SetInputShadowProperties( const std::string& shadowProperties )
1846 {
1847   if( NULL != mImpl->mEventData )
1848   {
1849     mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
1850   }
1851 }
1852
1853 const std::string& Controller::GetInputShadowProperties() const
1854 {
1855   if( NULL != mImpl->mEventData )
1856   {
1857     return mImpl->mEventData->mInputStyle.shadowProperties;
1858   }
1859
1860   return EMPTY_STRING;
1861 }
1862
1863 void Controller::SetInputUnderlineProperties( const std::string& underlineProperties )
1864 {
1865   if( NULL != mImpl->mEventData )
1866   {
1867     mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
1868   }
1869 }
1870
1871 const std::string& Controller::GetInputUnderlineProperties() const
1872 {
1873   if( NULL != mImpl->mEventData )
1874   {
1875     return mImpl->mEventData->mInputStyle.underlineProperties;
1876   }
1877
1878   return EMPTY_STRING;
1879 }
1880
1881 void Controller::SetInputEmbossProperties( const std::string& embossProperties )
1882 {
1883   if( NULL != mImpl->mEventData )
1884   {
1885     mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
1886   }
1887 }
1888
1889 const std::string& Controller::GetInputEmbossProperties() const
1890 {
1891   if( NULL != mImpl->mEventData )
1892   {
1893     return mImpl->mEventData->mInputStyle.embossProperties;
1894   }
1895
1896   return GetDefaultEmbossProperties();
1897 }
1898
1899 void Controller::SetInputOutlineProperties( const std::string& outlineProperties )
1900 {
1901   if( NULL != mImpl->mEventData )
1902   {
1903     mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
1904   }
1905 }
1906
1907 const std::string& Controller::GetInputOutlineProperties() const
1908 {
1909   if( NULL != mImpl->mEventData )
1910   {
1911     return mImpl->mEventData->mInputStyle.outlineProperties;
1912   }
1913
1914   return GetDefaultOutlineProperties();
1915 }
1916
1917 void Controller::SetInputModePassword( bool passwordInput )
1918 {
1919   if( NULL != mImpl->mEventData )
1920   {
1921     mImpl->mEventData->mPasswordInput = passwordInput;
1922   }
1923 }
1924
1925 bool Controller::IsInputModePassword()
1926 {
1927   if( NULL != mImpl->mEventData )
1928   {
1929     return mImpl->mEventData->mPasswordInput;
1930   }
1931   return false;
1932 }
1933
1934 void Controller::SetNoTextDoubleTapAction( NoTextTap::Action action )
1935 {
1936   if( NULL != mImpl->mEventData )
1937   {
1938     mImpl->mEventData->mDoubleTapAction = action;
1939   }
1940 }
1941
1942 Controller::NoTextTap::Action Controller::GetNoTextDoubleTapAction() const
1943 {
1944   NoTextTap::Action action = NoTextTap::NO_ACTION;
1945
1946   if( NULL != mImpl->mEventData )
1947   {
1948     action = mImpl->mEventData->mDoubleTapAction;
1949   }
1950
1951   return action;
1952 }
1953
1954 void Controller::SetNoTextLongPressAction( NoTextTap::Action action )
1955 {
1956   if( NULL != mImpl->mEventData )
1957   {
1958     mImpl->mEventData->mLongPressAction = action;
1959   }
1960 }
1961
1962 Controller::NoTextTap::Action Controller::GetNoTextLongPressAction() const
1963 {
1964   NoTextTap::Action action = NoTextTap::NO_ACTION;
1965
1966   if( NULL != mImpl->mEventData )
1967   {
1968     action = mImpl->mEventData->mLongPressAction;
1969   }
1970
1971   return action;
1972 }
1973
1974 bool Controller::IsUnderlineSetByString()
1975 {
1976   return mImpl->mUnderlineSetByString;
1977 }
1978
1979 void Controller::UnderlineSetByString( bool setByString )
1980 {
1981   mImpl->mUnderlineSetByString = setByString;
1982 }
1983
1984 bool Controller::IsShadowSetByString()
1985 {
1986   return mImpl->mShadowSetByString;
1987 }
1988
1989 void Controller::ShadowSetByString( bool setByString )
1990 {
1991   mImpl->mShadowSetByString = setByString;
1992 }
1993
1994 bool Controller::IsOutlineSetByString()
1995 {
1996   return mImpl->mOutlineSetByString;
1997 }
1998
1999 void Controller::OutlineSetByString( bool setByString )
2000 {
2001   mImpl->mOutlineSetByString = setByString;
2002 }
2003
2004 bool Controller::IsFontStyleSetByString()
2005 {
2006   return mImpl->mFontStyleSetByString;
2007 }
2008
2009 void Controller::FontStyleSetByString( bool setByString )
2010 {
2011   mImpl->mFontStyleSetByString = setByString;
2012 }
2013
2014 // public : Queries & retrieves.
2015
2016 Layout::Engine& Controller::GetLayoutEngine()
2017 {
2018   return mImpl->mLayoutEngine;
2019 }
2020
2021 View& Controller::GetView()
2022 {
2023   return mImpl->mView;
2024 }
2025
2026 Vector3 Controller::GetNaturalSize()
2027 {
2028   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n" );
2029   Vector3 naturalSize;
2030
2031   // Make sure the model is up-to-date before layouting
2032   ProcessModifyEvents();
2033
2034   if( mImpl->mRecalculateNaturalSize )
2035   {
2036     // Operations that can be done only once until the text changes.
2037     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
2038                                                                            GET_SCRIPTS       |
2039                                                                            VALIDATE_FONTS    |
2040                                                                            GET_LINE_BREAKS   |
2041                                                                            GET_WORD_BREAKS   |
2042                                                                            BIDI_INFO         |
2043                                                                            SHAPE_TEXT        |
2044                                                                            GET_GLYPH_METRICS );
2045
2046     // Set the update info to relayout the whole text.
2047     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
2048     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
2049
2050     // Make sure the model is up-to-date before layouting
2051     mImpl->UpdateModel( onlyOnceOperations );
2052
2053     // Layout the text for the new width.
2054     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT | REORDER );
2055
2056     // Store the actual control's size to restore later.
2057     const Size actualControlSize = mImpl->mModel->mVisualModel->mControlSize;
2058
2059     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
2060                 static_cast<OperationsMask>( onlyOnceOperations |
2061                                              LAYOUT | REORDER ),
2062                 naturalSize.GetVectorXY() );
2063
2064     // Do not do again the only once operations.
2065     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
2066
2067     // Do the size related operations again.
2068     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
2069                                                                         ALIGN  |
2070                                                                         REORDER );
2071     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
2072
2073     // Stores the natural size to avoid recalculate it again
2074     // unless the text/style changes.
2075     mImpl->mModel->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
2076
2077     mImpl->mRecalculateNaturalSize = false;
2078
2079     // Clear the update info. This info will be set the next time the text is updated.
2080     mImpl->mTextUpdateInfo.Clear();
2081     mImpl->mTextUpdateInfo.mClearAll = true;
2082
2083     // Restore the actual control's size.
2084     mImpl->mModel->mVisualModel->mControlSize = actualControlSize;
2085
2086     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
2087   }
2088   else
2089   {
2090     naturalSize = mImpl->mModel->mVisualModel->GetNaturalSize();
2091
2092     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
2093   }
2094
2095   naturalSize.x = ConvertToEven( naturalSize.x );
2096   naturalSize.y = ConvertToEven( naturalSize.y );
2097
2098   return naturalSize;
2099 }
2100
2101 bool Controller::CheckForTextFit( float pointSize, Size& layoutSize )
2102 {
2103   Size textSize;
2104   mImpl->mFontDefaults->mFitPointSize = pointSize;
2105   mImpl->mFontDefaults->sizeDefined = true;
2106   ClearFontData();
2107
2108   // Operations that can be done only once until the text changes.
2109   const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
2110                                                                               GET_SCRIPTS |
2111                                                                            VALIDATE_FONTS |
2112                                                                           GET_LINE_BREAKS |
2113                                                                           GET_WORD_BREAKS |
2114                                                                                 BIDI_INFO |
2115                                                                                 SHAPE_TEXT|
2116                                                                          GET_GLYPH_METRICS );
2117
2118   mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
2119   mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
2120
2121   // Make sure the model is up-to-date before layouting
2122   mImpl->UpdateModel( onlyOnceOperations );
2123
2124   DoRelayout( Size( layoutSize.width, MAX_FLOAT ),
2125               static_cast<OperationsMask>( onlyOnceOperations | LAYOUT),
2126               textSize);
2127
2128   // Clear the update info. This info will be set the next time the text is updated.
2129   mImpl->mTextUpdateInfo.Clear();
2130   mImpl->mTextUpdateInfo.mClearAll = true;
2131
2132   if( textSize.width > layoutSize.width || textSize.height > layoutSize.height )
2133   {
2134     return false;
2135   }
2136   return true;
2137 }
2138
2139 void Controller::FitPointSizeforLayout( Size layoutSize )
2140 {
2141   const OperationsMask operations  = mImpl->mOperationsPending;
2142   if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
2143   {
2144     bool actualellipsis = mImpl->mModel->mElideEnabled;
2145     float minPointSize = mImpl->mTextFitMinSize;
2146     float maxPointSize = mImpl->mTextFitMaxSize;
2147     float pointInterval = mImpl->mTextFitStepSize;
2148
2149     mImpl->mModel->mElideEnabled = false;
2150     Vector<float> pointSizeArray;
2151
2152     // check zero value
2153     if( pointInterval < 1.f )
2154     {
2155       mImpl->mTextFitStepSize = pointInterval = 1.0f;
2156     }
2157
2158     pointSizeArray.Reserve( static_cast< unsigned int >( ceil( ( maxPointSize - minPointSize ) / pointInterval ) ) );
2159
2160     for( float i = minPointSize; i < maxPointSize; i += pointInterval )
2161     {
2162       pointSizeArray.PushBack( i );
2163     }
2164
2165     pointSizeArray.PushBack( maxPointSize );
2166
2167     int bestSizeIndex = 0;
2168     int min = bestSizeIndex + 1;
2169     int max = pointSizeArray.Size() - 1;
2170     while( min <= max )
2171     {
2172       int destI = ( min + max ) / 2;
2173
2174       if( CheckForTextFit( pointSizeArray[destI], layoutSize ) )
2175       {
2176         bestSizeIndex = min;
2177         min = destI + 1;
2178       }
2179       else
2180       {
2181         max = destI - 1;
2182         bestSizeIndex = max;
2183       }
2184     }
2185
2186     mImpl->mModel->mElideEnabled = actualellipsis;
2187     mImpl->mFontDefaults->mFitPointSize = pointSizeArray[bestSizeIndex];
2188     mImpl->mFontDefaults->sizeDefined = true;
2189     ClearFontData();
2190   }
2191 }
2192
2193 float Controller::GetHeightForWidth( float width )
2194 {
2195   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width );
2196   // Make sure the model is up-to-date before layouting
2197   ProcessModifyEvents();
2198
2199   Size layoutSize;
2200   if( fabsf( width - mImpl->mModel->mVisualModel->mControlSize.width ) > Math::MACHINE_EPSILON_1000 ||
2201                                                          mImpl->mTextUpdateInfo.mFullRelayoutNeeded ||
2202                                                          mImpl->mTextUpdateInfo.mClearAll            )
2203   {
2204     // Operations that can be done only once until the text changes.
2205     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
2206                                                                            GET_SCRIPTS       |
2207                                                                            VALIDATE_FONTS    |
2208                                                                            GET_LINE_BREAKS   |
2209                                                                            GET_WORD_BREAKS   |
2210                                                                            BIDI_INFO         |
2211                                                                            SHAPE_TEXT        |
2212                                                                            GET_GLYPH_METRICS );
2213
2214     // Set the update info to relayout the whole text.
2215     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
2216     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
2217
2218     // Make sure the model is up-to-date before layouting
2219     mImpl->UpdateModel( onlyOnceOperations );
2220
2221
2222     // Layout the text for the new width.
2223     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
2224
2225     // Store the actual control's width.
2226     const float actualControlWidth = mImpl->mModel->mVisualModel->mControlSize.width;
2227
2228     DoRelayout( Size( width, MAX_FLOAT ),
2229                 static_cast<OperationsMask>( onlyOnceOperations |
2230                                              LAYOUT ),
2231                 layoutSize );
2232
2233     // Do not do again the only once operations.
2234     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
2235
2236     // Do the size related operations again.
2237     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
2238                                                                         ALIGN  |
2239                                                                         REORDER );
2240
2241     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
2242
2243     // Clear the update info. This info will be set the next time the text is updated.
2244     mImpl->mTextUpdateInfo.Clear();
2245     mImpl->mTextUpdateInfo.mClearAll = true;
2246
2247     // Restore the actual control's width.
2248     mImpl->mModel->mVisualModel->mControlSize.width = actualControlWidth;
2249
2250     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height );
2251   }
2252   else
2253   {
2254     layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
2255     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height );
2256   }
2257
2258   return layoutSize.height;
2259 }
2260
2261 int Controller::GetLineCount( float width )
2262 {
2263   GetHeightForWidth( width );
2264   int numberofLines = mImpl->mModel->GetNumberOfLines();
2265   return numberofLines;
2266 }
2267
2268 const ModelInterface* const Controller::GetTextModel() const
2269 {
2270   return mImpl->mModel.Get();
2271 }
2272
2273 float Controller::GetScrollAmountByUserInput()
2274 {
2275   float scrollAmount = 0.0f;
2276
2277   if (NULL != mImpl->mEventData && mImpl->mEventData->mCheckScrollAmount)
2278   {
2279     scrollAmount = mImpl->mModel->mScrollPosition.y -  mImpl->mModel->mScrollPositionLast.y;
2280     mImpl->mEventData->mCheckScrollAmount = false;
2281   }
2282   return scrollAmount;
2283 }
2284
2285 bool Controller::GetTextScrollInfo( float& scrollPosition, float& controlHeight, float& layoutHeight )
2286 {
2287   const Vector2& layout = mImpl->mModel->mVisualModel->GetLayoutSize();
2288   bool isScrolled;
2289
2290   controlHeight = mImpl->mModel->mVisualModel->mControlSize.height;
2291   layoutHeight = layout.height;
2292   scrollPosition = mImpl->mModel->mScrollPosition.y;
2293   isScrolled = !Equals( mImpl->mModel->mScrollPosition.y, mImpl->mModel->mScrollPositionLast.y, Math::MACHINE_EPSILON_1 );
2294   return isScrolled;
2295 }
2296
2297 void Controller::SetHiddenInputOption(const Property::Map& options )
2298 {
2299   if( NULL == mImpl->mHiddenInput )
2300   {
2301     mImpl->mHiddenInput = new HiddenText( this );
2302   }
2303   mImpl->mHiddenInput->SetProperties(options);
2304 }
2305
2306 void Controller::GetHiddenInputOption(Property::Map& options )
2307 {
2308   if( NULL != mImpl->mHiddenInput )
2309   {
2310     mImpl->mHiddenInput->GetProperties(options);
2311   }
2312 }
2313
2314 void Controller::SetPlaceholderProperty( const Property::Map& map )
2315 {
2316   const Property::Map::SizeType count = map.Count();
2317
2318   for( Property::Map::SizeType position = 0; position < count; ++position )
2319   {
2320     KeyValuePair keyValue = map.GetKeyValue( position );
2321     Property::Key& key = keyValue.first;
2322     Property::Value& value = keyValue.second;
2323
2324     if( key == Toolkit::Text::PlaceHolder::Property::TEXT  || key == PLACEHOLDER_TEXT )
2325     {
2326       std::string text = "";
2327       value.Get( text );
2328       SetPlaceholderText( Controller::PLACEHOLDER_TYPE_INACTIVE, text );
2329     }
2330     else if( key == Toolkit::Text::PlaceHolder::Property::TEXT_FOCUSED || key == PLACEHOLDER_TEXT_FOCUSED )
2331     {
2332       std::string text = "";
2333       value.Get( text );
2334       SetPlaceholderText( Controller::PLACEHOLDER_TYPE_ACTIVE, text );
2335     }
2336     else if( key == Toolkit::Text::PlaceHolder::Property::COLOR || key == PLACEHOLDER_COLOR )
2337     {
2338       Vector4 textColor;
2339       value.Get( textColor );
2340       if( GetPlaceholderTextColor() != textColor )
2341       {
2342         SetPlaceholderTextColor( textColor );
2343       }
2344     }
2345     else if( key == Toolkit::Text::PlaceHolder::Property::FONT_FAMILY || key == PLACEHOLDER_FONT_FAMILY )
2346     {
2347       std::string fontFamily = "";
2348       value.Get( fontFamily );
2349       SetPlaceholderFontFamily( fontFamily );
2350     }
2351     else if( key == Toolkit::Text::PlaceHolder::Property::FONT_STYLE || key == PLACEHOLDER_FONT_STYLE )
2352     {
2353       SetFontStyleProperty( this, value, Text::FontStyle::PLACEHOLDER );
2354     }
2355     else if( key == Toolkit::Text::PlaceHolder::Property::POINT_SIZE || key == PLACEHOLDER_POINT_SIZE )
2356     {
2357       float pointSize;
2358       value.Get( pointSize );
2359       if( !Equals( GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE ), pointSize ) )
2360       {
2361         SetPlaceholderTextFontSize( pointSize, Text::Controller::POINT_SIZE );
2362       }
2363     }
2364     else if( key == Toolkit::Text::PlaceHolder::Property::PIXEL_SIZE || key == PLACEHOLDER_PIXEL_SIZE )
2365     {
2366       float pixelSize;
2367       value.Get( pixelSize );
2368       if( !Equals( GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE ), pixelSize ) )
2369       {
2370         SetPlaceholderTextFontSize( pixelSize, Text::Controller::PIXEL_SIZE );
2371       }
2372     }
2373     else if( key == Toolkit::Text::PlaceHolder::Property::ELLIPSIS || key == PLACEHOLDER_ELLIPSIS )
2374     {
2375       bool ellipsis;
2376       value.Get( ellipsis );
2377       SetPlaceholderTextElideEnabled( ellipsis );
2378     }
2379   }
2380 }
2381
2382 void Controller::GetPlaceholderProperty( Property::Map& map )
2383 {
2384   if( NULL != mImpl->mEventData )
2385   {
2386     if( !mImpl->mEventData->mPlaceholderTextActive.empty() )
2387     {
2388       map[ Text::PlaceHolder::Property::TEXT_FOCUSED ] = mImpl->mEventData->mPlaceholderTextActive;
2389     }
2390     if( !mImpl->mEventData->mPlaceholderTextInactive.empty() )
2391     {
2392       map[ Text::PlaceHolder::Property::TEXT ] = mImpl->mEventData->mPlaceholderTextInactive;
2393     }
2394
2395     map[ Text::PlaceHolder::Property::COLOR ] = mImpl->mEventData->mPlaceholderTextColor;
2396     map[ Text::PlaceHolder::Property::FONT_FAMILY ] = GetPlaceholderFontFamily();
2397
2398     Property::Value fontStyleMapGet;
2399     GetFontStyleProperty( this, fontStyleMapGet, Text::FontStyle::PLACEHOLDER );
2400     map[ Text::PlaceHolder::Property::FONT_STYLE ] = fontStyleMapGet;
2401
2402     // Choose font size : POINT_SIZE or PIXEL_SIZE
2403     if( !mImpl->mEventData->mIsPlaceholderPixelSize )
2404     {
2405       map[ Text::PlaceHolder::Property::POINT_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE );
2406     }
2407     else
2408     {
2409       map[ Text::PlaceHolder::Property::PIXEL_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE );
2410     }
2411
2412     if( mImpl->mEventData->mPlaceholderEllipsisFlag )
2413     {
2414       map[ Text::PlaceHolder::Property::ELLIPSIS ] = IsPlaceholderTextElideEnabled();
2415     }
2416   }
2417 }
2418
2419 Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection()
2420 {
2421   // Make sure the model is up-to-date before layouting
2422   ProcessModifyEvents();
2423
2424   if ( mImpl->mUpdateTextDirection )
2425   {
2426     // Operations that can be done only once until the text changes.
2427     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
2428                                                                            GET_SCRIPTS       |
2429                                                                            VALIDATE_FONTS    |
2430                                                                            GET_LINE_BREAKS   |
2431                                                                            GET_WORD_BREAKS   |
2432                                                                            BIDI_INFO         |
2433                                                                            SHAPE_TEXT        |
2434                                                                            GET_GLYPH_METRICS );
2435
2436     // Set the update info to relayout the whole text.
2437     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
2438     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
2439
2440     // Make sure the model is up-to-date before layouting
2441     mImpl->UpdateModel( onlyOnceOperations );
2442
2443     Vector3 naturalSize;
2444     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
2445                 static_cast<OperationsMask>( onlyOnceOperations |
2446                                              LAYOUT | REORDER | UPDATE_DIRECTION ),
2447                 naturalSize.GetVectorXY() );
2448
2449     // Do not do again the only once operations.
2450     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
2451
2452     // Clear the update info. This info will be set the next time the text is updated.
2453     mImpl->mTextUpdateInfo.Clear();
2454
2455     mImpl->mUpdateTextDirection = false;
2456   }
2457
2458   return mImpl->mIsTextDirectionRTL ? Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT : Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
2459 }
2460
2461 Toolkit::DevelText::VerticalLineAlignment::Type Controller::GetVerticalLineAlignment() const
2462 {
2463   return mImpl->mModel->GetVerticalLineAlignment();
2464 }
2465
2466 void Controller::SetVerticalLineAlignment( Toolkit::DevelText::VerticalLineAlignment::Type alignment )
2467 {
2468   mImpl->mModel->mVerticalLineAlignment = alignment;
2469 }
2470
2471 // public : Relayout.
2472
2473 Controller::UpdateTextType Controller::Relayout( const Size& size, Dali::LayoutDirection::Type layoutDirection )
2474 {
2475   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, mImpl->mIsAutoScrollEnabled ?"true":"false"  );
2476
2477   UpdateTextType updateTextType = NONE_UPDATED;
2478
2479   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
2480   {
2481     if( 0u != mImpl->mModel->mVisualModel->mGlyphPositions.Count() )
2482     {
2483       mImpl->mModel->mVisualModel->mGlyphPositions.Clear();
2484       updateTextType = MODEL_UPDATED;
2485     }
2486
2487     // Clear the update info. This info will be set the next time the text is updated.
2488     mImpl->mTextUpdateInfo.Clear();
2489
2490     // Not worth to relayout if width or height is equal to zero.
2491     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
2492
2493     return updateTextType;
2494   }
2495
2496   // Whether a new size has been set.
2497   const bool newSize = ( size != mImpl->mModel->mVisualModel->mControlSize );
2498
2499   if( newSize )
2500   {
2501     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mModel->mVisualModel->mControlSize.width, mImpl->mModel->mVisualModel->mControlSize.height );
2502
2503     if( ( 0 == mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd ) &&
2504         ( 0 == mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) &&
2505         ( ( mImpl->mModel->mVisualModel->mControlSize.width < Math::MACHINE_EPSILON_1000 ) || ( mImpl->mModel->mVisualModel->mControlSize.height < Math::MACHINE_EPSILON_1000 ) ) )
2506     {
2507       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
2508     }
2509
2510     // Layout operations that need to be done if the size changes.
2511     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2512                                                              LAYOUT                    |
2513                                                              ALIGN                     |
2514                                                              UPDATE_LAYOUT_SIZE        |
2515                                                              REORDER );
2516     // Set the update info to relayout the whole text.
2517     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2518     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2519
2520     // Store the size used to layout the text.
2521     mImpl->mModel->mVisualModel->mControlSize = size;
2522   }
2523
2524   // Whether there are modify events.
2525   if( 0u != mImpl->mModifyEvents.Count() )
2526   {
2527     // Style operations that need to be done if the text is modified.
2528     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2529                                                              COLOR );
2530   }
2531
2532   // Set the update info to elide the text.
2533   if( mImpl->mModel->mElideEnabled ||
2534       ( ( NULL != mImpl->mEventData ) && mImpl->mEventData->mIsPlaceholderElideEnabled ) )
2535   {
2536     // Update Text layout for applying elided
2537     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2538                                                              ALIGN                     |
2539                                                              LAYOUT                    |
2540                                                              UPDATE_LAYOUT_SIZE        |
2541                                                              REORDER );
2542     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2543     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2544   }
2545
2546   if( mImpl->mModel->mMatchSystemLanguageDirection  && mImpl->mLayoutDirection != layoutDirection )
2547   {
2548     // Clear the update info. This info will be set the next time the text is updated.
2549     mImpl->mTextUpdateInfo.mClearAll = true;
2550     // Apply modifications to the model
2551     // Shape the text again is needed because characters like '()[]{}' have to be mirrored and the glyphs generated again.
2552     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2553                                                              GET_GLYPH_METRICS         |
2554                                                              SHAPE_TEXT                |
2555                                                              UPDATE_DIRECTION          |
2556                                                              LAYOUT                    |
2557                                                              BIDI_INFO                 |
2558                                                              REORDER );
2559     mImpl->mLayoutDirection = layoutDirection;
2560   }
2561
2562   // Make sure the model is up-to-date before layouting.
2563   ProcessModifyEvents();
2564   bool updated = mImpl->UpdateModel( mImpl->mOperationsPending );
2565
2566   // Layout the text.
2567   Size layoutSize;
2568   updated = DoRelayout( size,
2569                         mImpl->mOperationsPending,
2570                         layoutSize ) || updated;
2571
2572
2573   if( updated )
2574   {
2575     updateTextType = MODEL_UPDATED;
2576   }
2577
2578   // Do not re-do any operation until something changes.
2579   mImpl->mOperationsPending = NO_OPERATION;
2580   mImpl->mModel->mScrollPositionLast = mImpl->mModel->mScrollPosition;
2581
2582   // Whether the text control is editable
2583   const bool isEditable = NULL != mImpl->mEventData;
2584
2585   // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
2586   Vector2 offset;
2587   if( newSize && isEditable )
2588   {
2589     offset = mImpl->mModel->mScrollPosition;
2590   }
2591
2592   if( !isEditable || !IsMultiLineEnabled() )
2593   {
2594     // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
2595     CalculateVerticalOffset( size );
2596   }
2597
2598   if( isEditable )
2599   {
2600     if( newSize )
2601     {
2602       // If there is a new size, the scroll position needs to be clamped.
2603       mImpl->ClampHorizontalScroll( layoutSize );
2604
2605       // Update the decorator's positions is needed if there is a new size.
2606       mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mModel->mScrollPosition - offset );
2607     }
2608
2609     // Move the cursor, grab handle etc.
2610     if( mImpl->ProcessInputEvents() )
2611     {
2612       updateTextType = static_cast<UpdateTextType>( updateTextType | DECORATOR_UPDATED );
2613     }
2614   }
2615
2616   // Clear the update info. This info will be set the next time the text is updated.
2617   mImpl->mTextUpdateInfo.Clear();
2618   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
2619
2620   return updateTextType;
2621 }
2622
2623 void Controller::RequestRelayout()
2624 {
2625   mImpl->RequestRelayout();
2626 }
2627
2628 // public : Input style change signals.
2629
2630 bool Controller::IsInputStyleChangedSignalsQueueEmpty()
2631 {
2632   return ( NULL == mImpl->mEventData ) || ( 0u == mImpl->mEventData->mInputStyleChangedQueue.Count() );
2633 }
2634
2635 void Controller::ProcessInputStyleChangedSignals()
2636 {
2637   if( NULL == mImpl->mEventData )
2638   {
2639     // Nothing to do.
2640     return;
2641   }
2642
2643   for( Vector<InputStyle::Mask>::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(),
2644          endIt = mImpl->mEventData->mInputStyleChangedQueue.End();
2645        it != endIt;
2646        ++it )
2647   {
2648     const InputStyle::Mask mask = *it;
2649
2650     if( NULL != mImpl->mEditableControlInterface )
2651     {
2652       // Emit the input style changed signal.
2653       mImpl->mEditableControlInterface->InputStyleChanged( mask );
2654     }
2655   }
2656
2657   mImpl->mEventData->mInputStyleChangedQueue.Clear();
2658 }
2659
2660 // public : Text-input Event Queuing.
2661
2662 void Controller::KeyboardFocusGainEvent()
2663 {
2664   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
2665
2666   if( NULL != mImpl->mEventData )
2667   {
2668     if( ( EventData::INACTIVE == mImpl->mEventData->mState ) ||
2669         ( EventData::INTERRUPTED == mImpl->mEventData->mState ) )
2670     {
2671       mImpl->ChangeState( EventData::EDITING );
2672       mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
2673       mImpl->mEventData->mUpdateInputStyle = true;
2674       mImpl->mEventData->mScrollAfterUpdatePosition = true;
2675     }
2676     mImpl->NotifyInputMethodContextMultiLineStatus();
2677     if( mImpl->IsShowingPlaceholderText() )
2678     {
2679       // Show alternative placeholder-text when editing
2680       ShowPlaceholderText();
2681     }
2682
2683     mImpl->RequestRelayout();
2684   }
2685 }
2686
2687 void Controller::KeyboardFocusLostEvent()
2688 {
2689   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
2690
2691   if( NULL != mImpl->mEventData )
2692   {
2693     if( EventData::INTERRUPTED != mImpl->mEventData->mState )
2694     {
2695       mImpl->ChangeState( EventData::INACTIVE );
2696
2697       if( !mImpl->IsShowingRealText() )
2698       {
2699         // Revert to regular placeholder-text when not editing
2700         ShowPlaceholderText();
2701       }
2702     }
2703   }
2704   mImpl->RequestRelayout();
2705 }
2706
2707 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
2708 {
2709   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
2710
2711   bool textChanged = false;
2712   bool relayoutNeeded = false;
2713
2714   if( ( NULL != mImpl->mEventData ) &&
2715       ( keyEvent.state == KeyEvent::Down ) )
2716   {
2717     int keyCode = keyEvent.keyCode;
2718     const std::string& keyString = keyEvent.keyPressed;
2719     const std::string keyName = keyEvent.keyPressedName;
2720
2721     const bool isNullKey = ( 0 == keyCode ) && ( keyString.empty() );
2722
2723     // Pre-process to separate modifying events from non-modifying input events.
2724     if( isNullKey )
2725     {
2726       // In some platforms arrive key events with no key code.
2727       // Do nothing.
2728       return false;
2729     }
2730     else if( Dali::DALI_KEY_ESCAPE == keyCode || Dali::DALI_KEY_BACK == keyCode  || Dali::DALI_KEY_SEARCH == keyCode )
2731     {
2732       // Do nothing
2733       return false;
2734     }
2735     else if( ( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ) ||
2736              ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode ) ||
2737              ( Dali::DALI_KEY_CURSOR_UP    == keyCode ) ||
2738              ( Dali::DALI_KEY_CURSOR_DOWN  == keyCode ) )
2739     {
2740       // If don't have any text, do nothing.
2741       if( !mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters )
2742       {
2743         return false;
2744       }
2745
2746       uint32_t cursorPosition = mImpl->mEventData->mPrimaryCursorPosition;
2747       uint32_t numberOfCharacters = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2748       uint32_t cursorLine = mImpl->mModel->mVisualModel->GetLineOfCharacter( cursorPosition );
2749       uint32_t numberOfLines = mImpl->mModel->GetNumberOfLines();
2750
2751       // Logic to determine whether this text control will lose focus or not.
2752       if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode && 0 == cursorPosition && !keyEvent.IsShiftModifier() ) ||
2753           ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition && !keyEvent.IsShiftModifier() ) ||
2754           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && cursorLine == numberOfLines -1 ) ||
2755           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && numberOfCharacters == cursorPosition && cursorLine -1 == numberOfLines -1 ) ||
2756           ( Dali::DALI_KEY_CURSOR_UP == keyCode && cursorLine == 0 ) ||
2757           ( Dali::DALI_KEY_CURSOR_UP == keyCode && numberOfCharacters == cursorPosition && cursorLine == 1 ) )
2758       {
2759         // Release the active highlight.
2760         if( mImpl->mEventData->mState == EventData::SELECTING )
2761         {
2762           mImpl->ChangeState( EventData::EDITING );
2763
2764           // Update selection position.
2765           mImpl->mEventData->mLeftSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
2766           mImpl->mEventData->mRightSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
2767           mImpl->mEventData->mUpdateCursorPosition = true;
2768           mImpl->RequestRelayout();
2769         }
2770         return false;
2771       }
2772
2773       mImpl->mEventData->mCheckScrollAmount = true;
2774       Event event( Event::CURSOR_KEY_EVENT );
2775       event.p1.mInt = keyCode;
2776       event.p2.mBool = keyEvent.IsShiftModifier();
2777       mImpl->mEventData->mEventQueue.push_back( event );
2778
2779       // Will request for relayout.
2780       relayoutNeeded = true;
2781     }
2782     else if ( Dali::DevelKey::DALI_KEY_CONTROL_LEFT == keyCode || Dali::DevelKey::DALI_KEY_CONTROL_RIGHT == keyCode )
2783     {
2784       // Left or Right Control key event is received before Ctrl-C/V/X key event is received
2785       // If not handle it here, any selected text will be deleted
2786
2787       // Do nothing
2788       return false;
2789     }
2790     else if ( keyEvent.IsCtrlModifier() )
2791     {
2792       bool consumed = false;
2793       if (keyName == KEY_C_NAME)
2794       {
2795         // Ctrl-C to copy the selected text
2796         TextPopupButtonTouched( Toolkit::TextSelectionPopup::COPY );
2797         consumed = true;
2798       }
2799       else if (keyName == KEY_V_NAME)
2800       {
2801         // Ctrl-V to paste the copied text
2802         TextPopupButtonTouched( Toolkit::TextSelectionPopup::PASTE );
2803         consumed = true;
2804       }
2805       else if (keyName == KEY_X_NAME)
2806       {
2807         // Ctrl-X to cut the selected text
2808         TextPopupButtonTouched( Toolkit::TextSelectionPopup::CUT );
2809         consumed = true;
2810       }
2811       return consumed;
2812     }
2813     else if( ( Dali::DALI_KEY_BACKSPACE == keyCode ) ||
2814              ( Dali::DevelKey::DALI_KEY_DELETE == keyCode ) )
2815     {
2816       textChanged = DeleteEvent( keyCode );
2817
2818       // Will request for relayout.
2819       relayoutNeeded = true;
2820     }
2821     else if( IsKey( keyEvent, Dali::DALI_KEY_POWER ) ||
2822              IsKey( keyEvent, Dali::DALI_KEY_MENU ) ||
2823              IsKey( keyEvent, Dali::DALI_KEY_HOME ) )
2824     {
2825       // Power key/Menu/Home key behaviour does not allow edit mode to resume.
2826       mImpl->ChangeState( EventData::INACTIVE );
2827
2828       // Will request for relayout.
2829       relayoutNeeded = true;
2830
2831       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
2832     }
2833     else if( ( Dali::DALI_KEY_SHIFT_LEFT == keyCode ) || ( Dali::DALI_KEY_SHIFT_RIGHT == keyCode ) )
2834     {
2835       // DALI_KEY_SHIFT_LEFT or DALI_KEY_SHIFT_RIGHT is the key code for Shift. It's sent (by the InputMethodContext?) when the predictive text is enabled
2836       // and a character is typed after the type of a upper case latin character.
2837
2838       // Do nothing.
2839       return false;
2840     }
2841     else if( ( Dali::DALI_KEY_VOLUME_UP == keyCode ) || ( Dali::DALI_KEY_VOLUME_DOWN == keyCode ) )
2842     {
2843       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
2844       // Do nothing.
2845       return false;
2846     }
2847     else
2848     {
2849       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() );
2850
2851       if( !keyString.empty() )
2852       {
2853         // InputMethodContext is no longer handling key-events
2854         mImpl->ClearPreEditFlag();
2855
2856         InsertText( keyString, COMMIT );
2857
2858         textChanged = true;
2859
2860         // Will request for relayout.
2861         relayoutNeeded = true;
2862       }
2863
2864     }
2865
2866     if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
2867          ( mImpl->mEventData->mState != EventData::INACTIVE ) &&
2868          ( !isNullKey ) &&
2869          ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) &&
2870          ( Dali::DALI_KEY_SHIFT_RIGHT != keyCode ) &&
2871          ( Dali::DALI_KEY_VOLUME_UP != keyCode ) &&
2872          ( Dali::DALI_KEY_VOLUME_DOWN != keyCode ) )
2873     {
2874       // Should not change the state if the key is the shift send by the InputMethodContext.
2875       // Otherwise, when the state is SELECTING the text controller can't send the right
2876       // surrounding info to the InputMethodContext.
2877       mImpl->ChangeState( EventData::EDITING );
2878
2879       // Will request for relayout.
2880       relayoutNeeded = true;
2881     }
2882
2883     if( relayoutNeeded )
2884     {
2885       mImpl->RequestRelayout();
2886     }
2887   }
2888
2889   if( textChanged &&
2890       ( NULL != mImpl->mEditableControlInterface ) )
2891   {
2892     // Do this last since it provides callbacks into application code
2893     mImpl->mEditableControlInterface->TextChanged();
2894   }
2895
2896   return true;
2897 }
2898
2899 void Controller::TapEvent( unsigned int tapCount, float x, float y )
2900 {
2901   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
2902
2903   if( NULL != mImpl->mEventData )
2904   {
2905     DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState );
2906     EventData::State state( mImpl->mEventData->mState );
2907     bool relayoutNeeded( false );   // to avoid unnecessary relayouts when tapping an empty text-field
2908
2909     if( mImpl->IsClipboardVisible() )
2910     {
2911       if( EventData::INACTIVE == state || EventData::EDITING == state)
2912       {
2913         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2914       }
2915       relayoutNeeded = true;
2916     }
2917     else if( 1u == tapCount )
2918     {
2919       if( EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state )
2920       {
2921         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );  // If Popup shown hide it here so can be shown again if required.
2922       }
2923
2924       if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != state ) )
2925       {
2926         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2927         relayoutNeeded = true;
2928       }
2929       else
2930       {
2931         if( mImpl->IsShowingPlaceholderText() && !mImpl->IsFocusedPlaceholderAvailable() )
2932         {
2933           // Hide placeholder text
2934           ResetText();
2935         }
2936
2937         if( EventData::INACTIVE == state )
2938         {
2939           mImpl->ChangeState( EventData::EDITING );
2940         }
2941         else if( !mImpl->IsClipboardEmpty() )
2942         {
2943           mImpl->ChangeState( EventData::EDITING_WITH_POPUP );
2944         }
2945         relayoutNeeded = true;
2946       }
2947     }
2948     else if( 2u == tapCount )
2949     {
2950       if( mImpl->mEventData->mSelectionEnabled &&
2951           mImpl->IsShowingRealText() )
2952       {
2953         relayoutNeeded = true;
2954         mImpl->mEventData->mIsLeftHandleSelected = true;
2955         mImpl->mEventData->mIsRightHandleSelected = true;
2956       }
2957     }
2958
2959     // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
2960     if( relayoutNeeded )
2961     {
2962       Event event( Event::TAP_EVENT );
2963       event.p1.mUint = tapCount;
2964       event.p2.mFloat = x;
2965       event.p3.mFloat = y;
2966       mImpl->mEventData->mEventQueue.push_back( event );
2967
2968       mImpl->RequestRelayout();
2969     }
2970   }
2971
2972   // Reset keyboard as tap event has occurred.
2973   mImpl->ResetInputMethodContext();
2974 }
2975
2976 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
2977 {
2978   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
2979
2980   if( NULL != mImpl->mEventData )
2981   {
2982     Event event( Event::PAN_EVENT );
2983     event.p1.mInt = state;
2984     event.p2.mFloat = displacement.x;
2985     event.p3.mFloat = displacement.y;
2986     mImpl->mEventData->mEventQueue.push_back( event );
2987
2988     mImpl->RequestRelayout();
2989   }
2990 }
2991
2992 void Controller::LongPressEvent( Gesture::State state, float x, float y  )
2993 {
2994   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" );
2995
2996   if( ( state == Gesture::Started ) &&
2997       ( NULL != mImpl->mEventData ) )
2998   {
2999     // The 1st long-press on inactive text-field is treated as tap
3000     if( EventData::INACTIVE == mImpl->mEventData->mState )
3001     {
3002       mImpl->ChangeState( EventData::EDITING );
3003
3004       Event event( Event::TAP_EVENT );
3005       event.p1.mUint = 1;
3006       event.p2.mFloat = x;
3007       event.p3.mFloat = y;
3008       mImpl->mEventData->mEventQueue.push_back( event );
3009
3010       mImpl->RequestRelayout();
3011     }
3012     else if( !mImpl->IsShowingRealText() )
3013     {
3014       Event event( Event::LONG_PRESS_EVENT );
3015       event.p1.mInt = state;
3016       event.p2.mFloat = x;
3017       event.p3.mFloat = y;
3018       mImpl->mEventData->mEventQueue.push_back( event );
3019       mImpl->RequestRelayout();
3020     }
3021     else if( !mImpl->IsClipboardVisible() )
3022     {
3023       // Reset the InputMethodContext to commit the pre-edit before selecting the text.
3024       mImpl->ResetInputMethodContext();
3025
3026       Event event( Event::LONG_PRESS_EVENT );
3027       event.p1.mInt = state;
3028       event.p2.mFloat = x;
3029       event.p3.mFloat = y;
3030       mImpl->mEventData->mEventQueue.push_back( event );
3031       mImpl->RequestRelayout();
3032
3033       mImpl->mEventData->mIsLeftHandleSelected = true;
3034       mImpl->mEventData->mIsRightHandleSelected = true;
3035     }
3036   }
3037 }
3038
3039 void Controller::SelectEvent( float x, float y, bool selectAll )
3040 {
3041   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" );
3042
3043   if( NULL != mImpl->mEventData )
3044   {
3045     if( selectAll )
3046     {
3047       Event event( Event::SELECT_ALL );
3048       mImpl->mEventData->mEventQueue.push_back( event );
3049     }
3050     else
3051     {
3052       Event event( Event::SELECT );
3053       event.p2.mFloat = x;
3054       event.p3.mFloat = y;
3055       mImpl->mEventData->mEventQueue.push_back( event );
3056     }
3057
3058     mImpl->mEventData->mCheckScrollAmount = true;
3059     mImpl->mEventData->mIsLeftHandleSelected = true;
3060     mImpl->mEventData->mIsRightHandleSelected = true;
3061     mImpl->RequestRelayout();
3062   }
3063 }
3064
3065 InputMethodContext::CallbackData Controller::OnInputMethodContextEvent( InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent )
3066 {
3067   // Whether the text needs to be relaid-out.
3068   bool requestRelayout = false;
3069
3070   // Whether to retrieve the text and cursor position to be sent to the InputMethodContext.
3071   bool retrieveText = false;
3072   bool retrieveCursor = false;
3073
3074   switch( inputMethodContextEvent.eventName )
3075   {
3076     case InputMethodContext::COMMIT:
3077     {
3078       InsertText( inputMethodContextEvent.predictiveString, Text::Controller::COMMIT );
3079       requestRelayout = true;
3080       retrieveCursor = true;
3081       break;
3082     }
3083     case InputMethodContext::PRE_EDIT:
3084     {
3085       InsertText( inputMethodContextEvent.predictiveString, Text::Controller::PRE_EDIT );
3086       requestRelayout = true;
3087       retrieveCursor = true;
3088       break;
3089     }
3090     case InputMethodContext::DELETE_SURROUNDING:
3091     {
3092       const bool textDeleted = RemoveText( inputMethodContextEvent.cursorOffset,
3093                                            inputMethodContextEvent.numberOfChars,
3094                                            DONT_UPDATE_INPUT_STYLE );
3095
3096       if( textDeleted )
3097       {
3098         if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
3099             !mImpl->IsPlaceholderAvailable() )
3100         {
3101           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
3102         }
3103         else
3104         {
3105           ShowPlaceholderText();
3106         }
3107         mImpl->mEventData->mUpdateCursorPosition = true;
3108         mImpl->mEventData->mScrollAfterDelete = true;
3109
3110         requestRelayout = true;
3111       }
3112       break;
3113     }
3114     case InputMethodContext::GET_SURROUNDING:
3115     {
3116       retrieveText = true;
3117       retrieveCursor = true;
3118       break;
3119     }
3120     case InputMethodContext::PRIVATE_COMMAND:
3121     {
3122       // PRIVATECOMMAND event is just for getting the private command message
3123       retrieveText = true;
3124       retrieveCursor = true;
3125       break;
3126     }
3127     case InputMethodContext::VOID:
3128     {
3129       // do nothing
3130       break;
3131     }
3132   } // end switch
3133
3134   if( requestRelayout )
3135   {
3136     mImpl->mOperationsPending = ALL_OPERATIONS;
3137     mImpl->RequestRelayout();
3138   }
3139
3140   std::string text;
3141   CharacterIndex cursorPosition = 0u;
3142   Length numberOfWhiteSpaces = 0u;
3143
3144   if( retrieveCursor )
3145   {
3146     numberOfWhiteSpaces = mImpl->GetNumberOfWhiteSpaces( 0u );
3147
3148     cursorPosition = mImpl->GetLogicalCursorPosition();
3149
3150     if( cursorPosition < numberOfWhiteSpaces )
3151     {
3152       cursorPosition = 0u;
3153     }
3154     else
3155     {
3156       cursorPosition -= numberOfWhiteSpaces;
3157     }
3158   }
3159
3160   if( retrieveText )
3161   {
3162     if( !mImpl->IsShowingPlaceholderText() )
3163     {
3164       // Retrieves the normal text string.
3165       mImpl->GetText( numberOfWhiteSpaces, text );
3166     }
3167     else
3168     {
3169       // When the current text is Placeholder Text, the surrounding text should be empty string.
3170       // It means DALi should send empty string ("") to IME.
3171       text = "";
3172     }
3173   }
3174
3175   InputMethodContext::CallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false );
3176
3177   if( requestRelayout &&
3178       ( NULL != mImpl->mEditableControlInterface ) )
3179   {
3180     // Do this last since it provides callbacks into application code
3181     mImpl->mEditableControlInterface->TextChanged();
3182   }
3183
3184   return callbackData;
3185 }
3186
3187 void Controller::PasteClipboardItemEvent()
3188 {
3189   // Retrieve the clipboard contents first
3190   ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
3191   std::string stringToPaste( notifier.GetContent() );
3192
3193   // Commit the current pre-edit text; the contents of the clipboard should be appended
3194   mImpl->ResetInputMethodContext();
3195
3196   // Temporary disable hiding clipboard
3197   mImpl->SetClipboardHideEnable( false );
3198
3199   // Paste
3200   PasteText( stringToPaste );
3201
3202   mImpl->SetClipboardHideEnable( true );
3203 }
3204
3205 // protected : Inherit from Text::Decorator::ControllerInterface.
3206
3207 void Controller::GetTargetSize( Vector2& targetSize )
3208 {
3209   targetSize = mImpl->mModel->mVisualModel->mControlSize;
3210 }
3211
3212 void Controller::AddDecoration( Actor& actor, bool needsClipping )
3213 {
3214   if( NULL != mImpl->mEditableControlInterface )
3215   {
3216     mImpl->mEditableControlInterface->AddDecoration( actor, needsClipping );
3217   }
3218 }
3219
3220 void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
3221 {
3222   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
3223
3224   if( NULL != mImpl->mEventData )
3225   {
3226     switch( handleType )
3227     {
3228       case GRAB_HANDLE:
3229       {
3230         Event event( Event::GRAB_HANDLE_EVENT );
3231         event.p1.mUint  = state;
3232         event.p2.mFloat = x;
3233         event.p3.mFloat = y;
3234
3235         mImpl->mEventData->mEventQueue.push_back( event );
3236         break;
3237       }
3238       case LEFT_SELECTION_HANDLE:
3239       {
3240         Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
3241         event.p1.mUint  = state;
3242         event.p2.mFloat = x;
3243         event.p3.mFloat = y;
3244
3245         mImpl->mEventData->mEventQueue.push_back( event );
3246         break;
3247       }
3248       case RIGHT_SELECTION_HANDLE:
3249       {
3250         Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
3251         event.p1.mUint  = state;
3252         event.p2.mFloat = x;
3253         event.p3.mFloat = y;
3254
3255         mImpl->mEventData->mEventQueue.push_back( event );
3256         break;
3257       }
3258       case LEFT_SELECTION_HANDLE_MARKER:
3259       case RIGHT_SELECTION_HANDLE_MARKER:
3260       {
3261         // Markers do not move the handles.
3262         break;
3263       }
3264       case HANDLE_TYPE_COUNT:
3265       {
3266         DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
3267       }
3268     }
3269
3270     mImpl->RequestRelayout();
3271   }
3272 }
3273
3274 // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
3275
3276 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
3277 {
3278   if( NULL == mImpl->mEventData )
3279   {
3280     return;
3281   }
3282
3283   switch( button )
3284   {
3285     case Toolkit::TextSelectionPopup::CUT:
3286     {
3287       mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
3288       mImpl->mOperationsPending = ALL_OPERATIONS;
3289
3290       if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
3291           !mImpl->IsPlaceholderAvailable() )
3292       {
3293         mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
3294       }
3295       else
3296       {
3297         ShowPlaceholderText();
3298       }
3299
3300       mImpl->mEventData->mUpdateCursorPosition = true;
3301       mImpl->mEventData->mScrollAfterDelete = true;
3302
3303       mImpl->RequestRelayout();
3304
3305       if( NULL != mImpl->mEditableControlInterface )
3306       {
3307         mImpl->mEditableControlInterface->TextChanged();
3308       }
3309       break;
3310     }
3311     case Toolkit::TextSelectionPopup::COPY:
3312     {
3313       mImpl->SendSelectionToClipboard( false ); // Text not modified
3314
3315       mImpl->mEventData->mUpdateCursorPosition = true;
3316
3317       mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup
3318       break;
3319     }
3320     case Toolkit::TextSelectionPopup::PASTE:
3321     {
3322       mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item
3323       break;
3324     }
3325     case Toolkit::TextSelectionPopup::SELECT:
3326     {
3327       const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
3328
3329       if( mImpl->mEventData->mSelectionEnabled )
3330       {
3331         // Creates a SELECT event.
3332         SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false );
3333       }
3334       break;
3335     }
3336     case Toolkit::TextSelectionPopup::SELECT_ALL:
3337     {
3338       // Creates a SELECT_ALL event
3339       SelectEvent( 0.f, 0.f, true );
3340       break;
3341     }
3342     case Toolkit::TextSelectionPopup::CLIPBOARD:
3343     {
3344       mImpl->ShowClipboard();
3345       break;
3346     }
3347     case Toolkit::TextSelectionPopup::NONE:
3348     {
3349       // Nothing to do.
3350       break;
3351     }
3352   }
3353 }
3354
3355 void Controller::DisplayTimeExpired()
3356 {
3357   mImpl->mEventData->mUpdateCursorPosition = true;
3358   // Apply modifications to the model
3359   mImpl->mOperationsPending = ALL_OPERATIONS;
3360
3361   mImpl->RequestRelayout();
3362 }
3363
3364 // private : Update.
3365
3366 void Controller::InsertText( const std::string& text, Controller::InsertType type )
3367 {
3368   bool removedPrevious = false;
3369   bool removedSelected = false;
3370   bool maxLengthReached = false;
3371
3372   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
3373
3374   if( NULL == mImpl->mEventData )
3375   {
3376     return;
3377   }
3378
3379   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
3380                  this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
3381                  mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
3382
3383   // TODO: At the moment the underline runs are only for pre-edit.
3384   mImpl->mModel->mVisualModel->mUnderlineRuns.Clear();
3385
3386   // Remove the previous InputMethodContext pre-edit.
3387   if( mImpl->mEventData->mPreEditFlag && ( 0u != mImpl->mEventData->mPreEditLength ) )
3388   {
3389     removedPrevious = RemoveText( -static_cast<int>( mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition ),
3390                                   mImpl->mEventData->mPreEditLength,
3391                                   DONT_UPDATE_INPUT_STYLE );
3392
3393     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
3394     mImpl->mEventData->mPreEditLength = 0u;
3395   }
3396   else
3397   {
3398     // Remove the previous Selection.
3399     removedSelected = RemoveSelectedText();
3400
3401   }
3402
3403   Vector<Character> utf32Characters;
3404   Length characterCount = 0u;
3405
3406   if( !text.empty() )
3407   {
3408     //  Convert text into UTF-32
3409     utf32Characters.Resize( text.size() );
3410
3411     // This is a bit horrible but std::string returns a (signed) char*
3412     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
3413
3414     // Transform a text array encoded in utf8 into an array encoded in utf32.
3415     // It returns the actual number of characters.
3416     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
3417     utf32Characters.Resize( characterCount );
3418
3419     DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
3420     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
3421   }
3422
3423   if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
3424   {
3425     // The placeholder text is no longer needed
3426     if( mImpl->IsShowingPlaceholderText() )
3427     {
3428       ResetText();
3429     }
3430
3431     mImpl->ChangeState( EventData::EDITING );
3432
3433     // Handle the InputMethodContext (predicitive text) state changes
3434     if( COMMIT == type )
3435     {
3436       // InputMethodContext is no longer handling key-events
3437       mImpl->ClearPreEditFlag();
3438     }
3439     else // PRE_EDIT
3440     {
3441       if( !mImpl->mEventData->mPreEditFlag )
3442       {
3443         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state\n" );
3444
3445         // Record the start of the pre-edit text
3446         mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
3447       }
3448
3449       mImpl->mEventData->mPreEditLength = utf32Characters.Count();
3450       mImpl->mEventData->mPreEditFlag = true;
3451
3452       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
3453     }
3454
3455     const Length numberOfCharactersInModel = mImpl->mModel->mLogicalModel->mText.Count();
3456
3457     // Restrict new text to fit within Maximum characters setting.
3458     Length maxSizeOfNewText = std::min( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
3459     maxLengthReached = ( characterCount > maxSizeOfNewText );
3460
3461     // The cursor position.
3462     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
3463
3464     // Update the text's style.
3465
3466     // Updates the text style runs by adding characters.
3467     mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText );
3468
3469     // Get the character index from the cursor index.
3470     const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u;
3471
3472     // Retrieve the text's style for the given index.
3473     InputStyle style;
3474     mImpl->RetrieveDefaultInputStyle( style );
3475     mImpl->mModel->mLogicalModel->RetrieveStyle( styleIndex, style );
3476
3477     // Whether to add a new text color run.
3478     const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor ) && !mImpl->mEventData->mInputStyle.isDefaultColor;
3479
3480     // Whether to add a new font run.
3481     const bool addFontNameRun = ( style.familyName != mImpl->mEventData->mInputStyle.familyName ) && mImpl->mEventData->mInputStyle.isFamilyDefined;
3482     const bool addFontWeightRun = ( style.weight != mImpl->mEventData->mInputStyle.weight ) && mImpl->mEventData->mInputStyle.isWeightDefined;
3483     const bool addFontWidthRun = ( style.width != mImpl->mEventData->mInputStyle.width ) && mImpl->mEventData->mInputStyle.isWidthDefined;
3484     const bool addFontSlantRun = ( style.slant != mImpl->mEventData->mInputStyle.slant ) && mImpl->mEventData->mInputStyle.isSlantDefined;
3485     const bool addFontSizeRun = ( style.size != mImpl->mEventData->mInputStyle.size ) && mImpl->mEventData->mInputStyle.isSizeDefined ;
3486
3487     // Add style runs.
3488     if( addColorRun )
3489     {
3490       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
3491       mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
3492
3493       ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
3494       colorRun.color = mImpl->mEventData->mInputStyle.textColor;
3495       colorRun.characterRun.characterIndex = cursorIndex;
3496       colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
3497     }
3498
3499     if( addFontNameRun   ||
3500         addFontWeightRun ||
3501         addFontWidthRun  ||
3502         addFontSlantRun  ||
3503         addFontSizeRun )
3504     {
3505       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Count();
3506       mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
3507
3508       FontDescriptionRun& fontDescriptionRun = *( mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
3509
3510       if( addFontNameRun )
3511       {
3512         fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
3513         fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
3514         memcpy( fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength );
3515         fontDescriptionRun.familyDefined = true;
3516
3517         // The memory allocated for the font family name is freed when the font description is removed from the logical model.
3518       }
3519
3520       if( addFontWeightRun )
3521       {
3522         fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
3523         fontDescriptionRun.weightDefined = true;
3524       }
3525
3526       if( addFontWidthRun )
3527       {
3528         fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
3529         fontDescriptionRun.widthDefined = true;
3530       }
3531
3532       if( addFontSlantRun )
3533       {
3534         fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
3535         fontDescriptionRun.slantDefined = true;
3536       }
3537
3538       if( addFontSizeRun )
3539       {
3540         fontDescriptionRun.size = static_cast<PointSize26Dot6>( mImpl->mEventData->mInputStyle.size * 64.f );
3541         fontDescriptionRun.sizeDefined = true;
3542       }
3543
3544       fontDescriptionRun.characterRun.characterIndex = cursorIndex;
3545       fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
3546     }
3547
3548     // Insert at current cursor position.
3549     Vector<Character>& modifyText = mImpl->mModel->mLogicalModel->mText;
3550
3551     if( cursorIndex < numberOfCharactersInModel )
3552     {
3553       modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3554     }
3555     else
3556     {
3557       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3558     }
3559
3560     // Mark the first paragraph to be updated.
3561     if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
3562     {
3563       mImpl->mTextUpdateInfo.mCharacterIndex = 0;
3564       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3565       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = numberOfCharactersInModel + maxSizeOfNewText;
3566       mImpl->mTextUpdateInfo.mClearAll = true;
3567     }
3568     else
3569     {
3570       mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
3571       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
3572     }
3573
3574     // Update the cursor index.
3575     cursorIndex += maxSizeOfNewText;
3576
3577     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 );
3578   }
3579
3580   if( ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) &&
3581       mImpl->IsPlaceholderAvailable() )
3582   {
3583     // Show place-holder if empty after removing the pre-edit text
3584     ShowPlaceholderText();
3585     mImpl->mEventData->mUpdateCursorPosition = true;
3586     mImpl->ClearPreEditFlag();
3587   }
3588   else if( removedPrevious ||
3589            removedSelected ||
3590            ( 0 != utf32Characters.Count() ) )
3591   {
3592     // Queue an inserted event
3593     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
3594
3595     mImpl->mEventData->mUpdateCursorPosition = true;
3596     if( removedSelected )
3597     {
3598       mImpl->mEventData->mScrollAfterDelete = true;
3599     }
3600     else
3601     {
3602       mImpl->mEventData->mScrollAfterUpdatePosition = true;
3603     }
3604   }
3605
3606   if( maxLengthReached )
3607   {
3608     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mModel->mLogicalModel->mText.Count() );
3609
3610     mImpl->ResetInputMethodContext();
3611
3612     if( NULL != mImpl->mEditableControlInterface )
3613     {
3614       // Do this last since it provides callbacks into application code
3615       mImpl->mEditableControlInterface->MaxLengthReached();
3616     }
3617   }
3618 }
3619
3620 void Controller::PasteText( const std::string& stringToPaste )
3621 {
3622   InsertText( stringToPaste, Text::Controller::COMMIT );
3623   mImpl->ChangeState( EventData::EDITING );
3624   mImpl->RequestRelayout();
3625
3626   if( NULL != mImpl->mEditableControlInterface )
3627   {
3628     // Do this last since it provides callbacks into application code
3629     mImpl->mEditableControlInterface->TextChanged();
3630   }
3631 }
3632
3633 bool Controller::RemoveText( int cursorOffset,
3634                              int numberOfCharacters,
3635                              UpdateInputStyleType type )
3636 {
3637   bool removed = false;
3638
3639   if( NULL == mImpl->mEventData )
3640   {
3641     return removed;
3642   }
3643
3644   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n",
3645                  this, mImpl->mModel->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters );
3646
3647   if( !mImpl->IsShowingPlaceholderText() )
3648   {
3649     // Delete at current cursor position
3650     Vector<Character>& currentText = mImpl->mModel->mLogicalModel->mText;
3651     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
3652
3653     CharacterIndex cursorIndex = 0;
3654
3655     // Validate the cursor position & number of characters
3656     if( ( static_cast< int >( mImpl->mEventData->mPrimaryCursorPosition ) + cursorOffset ) >= 0 )
3657     {
3658       cursorIndex = mImpl->mEventData->mPrimaryCursorPosition + cursorOffset;
3659     }
3660
3661     if( ( cursorIndex + numberOfCharacters ) > currentText.Count() )
3662     {
3663       numberOfCharacters = currentText.Count() - cursorIndex;
3664     }
3665
3666     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.
3667         ( ( cursorIndex + numberOfCharacters ) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) )
3668     {
3669       // Mark the paragraphs to be updated.
3670       if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
3671       {
3672         mImpl->mTextUpdateInfo.mCharacterIndex = 0;
3673         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3674         mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters;
3675         mImpl->mTextUpdateInfo.mClearAll = true;
3676       }
3677       else
3678       {
3679         mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
3680         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
3681       }
3682
3683       // Update the input style and remove the text's style before removing the text.
3684
3685       if( UPDATE_INPUT_STYLE == type )
3686       {
3687         // Keep a copy of the current input style.
3688         InputStyle currentInputStyle;
3689         currentInputStyle.Copy( mImpl->mEventData->mInputStyle );
3690
3691         // Set first the default input style.
3692         mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle );
3693
3694         // Update the input style.
3695         mImpl->mModel->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle );
3696
3697         // Compare if the input style has changed.
3698         const bool hasInputStyleChanged = !currentInputStyle.Equal( mImpl->mEventData->mInputStyle );
3699
3700         if( hasInputStyleChanged )
3701         {
3702           const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mImpl->mEventData->mInputStyle );
3703           // Queue the input style changed signal.
3704           mImpl->mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
3705         }
3706       }
3707
3708       // Updates the text style runs by removing characters. Runs with no characters are removed.
3709       mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters );
3710
3711       // Remove the characters.
3712       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
3713       Vector<Character>::Iterator last  = first + numberOfCharacters;
3714
3715       currentText.Erase( first, last );
3716
3717       // Cursor position retreat
3718       oldCursorIndex = cursorIndex;
3719
3720       mImpl->mEventData->mScrollAfterDelete = true;
3721
3722       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters );
3723       removed = true;
3724     }
3725   }
3726
3727   return removed;
3728 }
3729
3730 bool Controller::RemoveSelectedText()
3731 {
3732   bool textRemoved( false );
3733
3734   if( EventData::SELECTING == mImpl->mEventData->mState )
3735   {
3736     std::string removedString;
3737     mImpl->RetrieveSelection( removedString, true );
3738
3739     if( !removedString.empty() )
3740     {
3741       textRemoved = true;
3742       mImpl->ChangeState( EventData::EDITING );
3743     }
3744   }
3745
3746   return textRemoved;
3747 }
3748
3749 // private : Relayout.
3750
3751 bool Controller::DoRelayout( const Size& size,
3752                              OperationsMask operationsRequired,
3753                              Size& layoutSize )
3754 {
3755   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height );
3756   bool viewUpdated( false );
3757
3758   // Calculate the operations to be done.
3759   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
3760
3761   const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
3762   const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
3763
3764   // Get the current layout size.
3765   layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
3766
3767   if( NO_OPERATION != ( LAYOUT & operations ) )
3768   {
3769     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
3770
3771     // Some vectors with data needed to layout and reorder may be void
3772     // after the first time the text has been laid out.
3773     // Fill the vectors again.
3774
3775     // Calculate the number of glyphs to layout.
3776     const Vector<GlyphIndex>& charactersToGlyph = mImpl->mModel->mVisualModel->mCharactersToGlyph;
3777     const Vector<Length>& glyphsPerCharacter = mImpl->mModel->mVisualModel->mGlyphsPerCharacter;
3778     const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
3779     const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
3780
3781     const CharacterIndex lastIndex = startIndex + ( ( requestedNumberOfCharacters > 0u ) ? requestedNumberOfCharacters - 1u : 0u );
3782     const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
3783
3784     // Make sure the index is not out of bound
3785     if ( charactersToGlyph.Count() != glyphsPerCharacter.Count() ||
3786          requestedNumberOfCharacters > charactersToGlyph.Count() ||
3787          ( lastIndex > charactersToGlyph.Count() && charactersToGlyph.Count() > 0u ) )
3788     {
3789       std::string currentText;
3790       GetText( currentText );
3791
3792       DALI_LOG_ERROR( "Controller::DoRelayout: Attempting to access invalid buffer\n" );
3793       DALI_LOG_ERROR( "Current text is: %s\n", currentText.c_str() );
3794       DALI_LOG_ERROR( "startIndex: %u, lastIndex: %u, requestedNumberOfCharacters: %u, charactersToGlyph.Count = %lu, glyphsPerCharacter.Count = %lu\n", startIndex, lastIndex, requestedNumberOfCharacters, charactersToGlyph.Count(), glyphsPerCharacter.Count());
3795
3796       return false;
3797     }
3798
3799     const Length numberOfGlyphs = ( requestedNumberOfCharacters > 0u ) ? *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - startGlyphIndex : 0u;
3800     const Length totalNumberOfGlyphs = mImpl->mModel->mVisualModel->mGlyphs.Count();
3801
3802     if( 0u == totalNumberOfGlyphs )
3803     {
3804       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
3805       {
3806         mImpl->mModel->mVisualModel->SetLayoutSize( Size::ZERO );
3807       }
3808
3809       // Nothing else to do if there is no glyphs.
3810       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n" );
3811       return true;
3812     }
3813
3814     const Vector<LineBreakInfo>& lineBreakInfo = mImpl->mModel->mLogicalModel->mLineBreakInfo;
3815     const Vector<WordBreakInfo>& wordBreakInfo = mImpl->mModel->mLogicalModel->mWordBreakInfo;
3816     const Vector<CharacterDirection>& characterDirection = mImpl->mModel->mLogicalModel->mCharacterDirections;
3817     const Vector<GlyphInfo>& glyphs = mImpl->mModel->mVisualModel->mGlyphs;
3818     const Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mModel->mVisualModel->mGlyphsToCharacters;
3819     const Vector<Length>& charactersPerGlyph = mImpl->mModel->mVisualModel->mCharactersPerGlyph;
3820     const Character* const textBuffer = mImpl->mModel->mLogicalModel->mText.Begin();
3821     const float outlineWidth = static_cast<float>( mImpl->mModel->GetOutlineWidth() );
3822
3823     // Set the layout parameters.
3824     Layout::Parameters layoutParameters( size,
3825                                          textBuffer,
3826                                          lineBreakInfo.Begin(),
3827                                          wordBreakInfo.Begin(),
3828                                          ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
3829                                          glyphs.Begin(),
3830                                          glyphsToCharactersMap.Begin(),
3831                                          charactersPerGlyph.Begin(),
3832                                          charactersToGlyphBuffer,
3833                                          glyphsPerCharacterBuffer,
3834                                          totalNumberOfGlyphs,
3835                                          mImpl->mModel->mHorizontalAlignment,
3836                                          mImpl->mModel->mLineWrapMode,
3837                                          outlineWidth,
3838                                          mImpl->mModel->mIgnoreSpacesAfterText,
3839                                          mImpl->mModel->mMatchSystemLanguageDirection );
3840
3841     // Resize the vector of positions to have the same size than the vector of glyphs.
3842     Vector<Vector2>& glyphPositions = mImpl->mModel->mVisualModel->mGlyphPositions;
3843     glyphPositions.Resize( totalNumberOfGlyphs );
3844
3845     // Whether the last character is a new paragraph character.
3846     mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph =  TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mModel->mLogicalModel->mText.Count() - 1u ) ) );
3847     layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
3848
3849     // The initial glyph and the number of glyphs to layout.
3850     layoutParameters.startGlyphIndex = startGlyphIndex;
3851     layoutParameters.numberOfGlyphs = numberOfGlyphs;
3852     layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex;
3853     layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
3854
3855     // Update the ellipsis
3856     bool elideTextEnabled = mImpl->mModel->mElideEnabled;
3857
3858     if( NULL != mImpl->mEventData )
3859     {
3860       if( mImpl->mEventData->mPlaceholderEllipsisFlag && mImpl->IsShowingPlaceholderText() )
3861       {
3862         elideTextEnabled = mImpl->mEventData->mIsPlaceholderElideEnabled;
3863       }
3864       else if( EventData::INACTIVE != mImpl->mEventData->mState )
3865       {
3866         // Disable ellipsis when editing
3867         elideTextEnabled = false;
3868       }
3869
3870       // Reset the scroll position in inactive state
3871       if( elideTextEnabled && ( mImpl->mEventData->mState == EventData::INACTIVE ) )
3872       {
3873         ResetScrollPosition();
3874       }
3875     }
3876
3877     // Update the visual model.
3878     bool isAutoScrollEnabled = mImpl->mIsAutoScrollEnabled;
3879     Size newLayoutSize;
3880     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
3881                                                    glyphPositions,
3882                                                    mImpl->mModel->mVisualModel->mLines,
3883                                                    newLayoutSize,
3884                                                    elideTextEnabled,
3885                                                    isAutoScrollEnabled );
3886     mImpl->mIsAutoScrollEnabled = isAutoScrollEnabled;
3887
3888     viewUpdated = viewUpdated || ( newLayoutSize != layoutSize );
3889
3890     if( viewUpdated )
3891     {
3892       layoutSize = newLayoutSize;
3893
3894       if( NO_OPERATION != ( UPDATE_DIRECTION & operations ) )
3895       {
3896         mImpl->mIsTextDirectionRTL = false;
3897       }
3898
3899       // Reorder the lines
3900       if( NO_OPERATION != ( REORDER & operations ) )
3901       {
3902         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mModel->mLogicalModel->mBidirectionalParagraphInfo;
3903         Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = mImpl->mModel->mLogicalModel->mBidirectionalLineInfo;
3904
3905         // Check first if there are paragraphs with bidirectional info.
3906         if( 0u != bidirectionalInfo.Count() )
3907         {
3908           // Get the lines
3909           const Length numberOfLines = mImpl->mModel->mVisualModel->mLines.Count();
3910
3911           // Reorder the lines.
3912           bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
3913           ReorderLines( bidirectionalInfo,
3914                         startIndex,
3915                         requestedNumberOfCharacters,
3916                         mImpl->mModel->mVisualModel->mLines,
3917                         bidirectionalLineInfo );
3918
3919           // Set the bidirectional info per line into the layout parameters.
3920           layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
3921           layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
3922
3923           // Re-layout the text. Reorder those lines with right to left characters.
3924           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
3925                                                          startIndex,
3926                                                          requestedNumberOfCharacters,
3927                                                          glyphPositions );
3928
3929           if ( ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) ) && ( numberOfLines > 0 ) )
3930           {
3931             const LineRun* const firstline = mImpl->mModel->mVisualModel->mLines.Begin();
3932             if ( firstline )
3933             {
3934               mImpl->mIsTextDirectionRTL = firstline->direction;
3935             }
3936           }
3937         }
3938       } // REORDER
3939
3940       // Sets the layout size.
3941       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
3942       {
3943         mImpl->mModel->mVisualModel->SetLayoutSize( layoutSize );
3944       }
3945     } // view updated
3946   }
3947
3948   if( NO_OPERATION != ( ALIGN & operations ) )
3949   {
3950     // The laid-out lines.
3951     Vector<LineRun>& lines = mImpl->mModel->mVisualModel->mLines;
3952
3953     CharacterIndex alignStartIndex = startIndex;
3954     Length alignRequestedNumberOfCharacters = requestedNumberOfCharacters;
3955
3956     // the whole text needs to be full aligned.
3957     // If you do not do a full aligned, only the last line of the multiline input is aligned.
3958     if(  mImpl->mEventData && mImpl->mEventData->mUpdateAlignment )
3959     {
3960       alignStartIndex = 0u;
3961       alignRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
3962       mImpl->mEventData->mUpdateAlignment = false;
3963     }
3964
3965     // Need to align with the control's size as the text may contain lines
3966     // starting either with left to right text or right to left.
3967     mImpl->mLayoutEngine.Align( size,
3968                                 alignStartIndex,
3969                                 alignRequestedNumberOfCharacters,
3970                                 mImpl->mModel->mHorizontalAlignment,
3971                                 lines,
3972                                 mImpl->mModel->mAlignmentOffset,
3973                                 mImpl->mLayoutDirection,
3974                                 mImpl->mModel->mMatchSystemLanguageDirection );
3975
3976     viewUpdated = true;
3977   }
3978 #if defined(DEBUG_ENABLED)
3979   std::string currentText;
3980   GetText( currentText );
3981   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mIsTextDirectionRTL[%s] [%s]\n", this, (mImpl->mIsTextDirectionRTL)?"true":"false",  currentText.c_str() );
3982 #endif
3983   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
3984   return viewUpdated;
3985 }
3986
3987 void Controller::CalculateVerticalOffset( const Size& controlSize )
3988 {
3989   Size layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
3990
3991   if( fabsf( layoutSize.height ) < Math::MACHINE_EPSILON_1000 )
3992   {
3993     // Get the line height of the default font.
3994     layoutSize.height = mImpl->GetDefaultFontLineHeight();
3995   }
3996
3997   switch( mImpl->mModel->mVerticalAlignment )
3998   {
3999     case VerticalAlignment::TOP:
4000     {
4001       mImpl->mModel->mScrollPosition.y = 0.f;
4002       break;
4003     }
4004     case VerticalAlignment::CENTER:
4005     {
4006       mImpl->mModel->mScrollPosition.y = floorf( 0.5f * ( controlSize.height - layoutSize.height ) ); // try to avoid pixel alignment.
4007       break;
4008     }
4009     case VerticalAlignment::BOTTOM:
4010     {
4011       mImpl->mModel->mScrollPosition.y = controlSize.height - layoutSize.height;
4012       break;
4013     }
4014   }
4015 }
4016
4017 // private : Events.
4018
4019 void Controller::ProcessModifyEvents()
4020 {
4021   Vector<ModifyEvent>& events = mImpl->mModifyEvents;
4022
4023   if( 0u == events.Count() )
4024   {
4025     // Nothing to do.
4026     return;
4027   }
4028
4029   for( Vector<ModifyEvent>::ConstIterator it = events.Begin(),
4030          endIt = events.End();
4031        it != endIt;
4032        ++it )
4033   {
4034     const ModifyEvent& event = *it;
4035
4036     if( ModifyEvent::TEXT_REPLACED == event.type )
4037     {
4038       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
4039       DALI_ASSERT_DEBUG( it == events.Begin() && "Unexpected TEXT_REPLACED event" );
4040
4041       TextReplacedEvent();
4042     }
4043     else if( ModifyEvent::TEXT_INSERTED == event.type )
4044     {
4045       TextInsertedEvent();
4046     }
4047     else if( ModifyEvent::TEXT_DELETED == event.type )
4048     {
4049       // Placeholder-text cannot be deleted
4050       if( !mImpl->IsShowingPlaceholderText() )
4051       {
4052         TextDeletedEvent();
4053       }
4054     }
4055   }
4056
4057   if( NULL != mImpl->mEventData )
4058   {
4059     // When the text is being modified, delay cursor blinking
4060     mImpl->mEventData->mDecorator->DelayCursorBlink();
4061
4062     // Update selection position after modifying the text
4063     mImpl->mEventData->mLeftSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
4064     mImpl->mEventData->mRightSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
4065   }
4066
4067   // Discard temporary text
4068   events.Clear();
4069 }
4070
4071 void Controller::TextReplacedEvent()
4072 {
4073   // The natural size needs to be re-calculated.
4074   mImpl->mRecalculateNaturalSize = true;
4075
4076   // The text direction needs to be updated.
4077   mImpl->mUpdateTextDirection = true;
4078
4079   // Apply modifications to the model
4080   mImpl->mOperationsPending = ALL_OPERATIONS;
4081 }
4082
4083 void Controller::TextInsertedEvent()
4084 {
4085   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" );
4086
4087   if( NULL == mImpl->mEventData )
4088   {
4089     return;
4090   }
4091
4092   mImpl->mEventData->mCheckScrollAmount = true;
4093
4094   // The natural size needs to be re-calculated.
4095   mImpl->mRecalculateNaturalSize = true;
4096
4097   // The text direction needs to be updated.
4098   mImpl->mUpdateTextDirection = true;
4099
4100   // Apply modifications to the model; TODO - Optimize this
4101   mImpl->mOperationsPending = ALL_OPERATIONS;
4102 }
4103
4104 void Controller::TextDeletedEvent()
4105 {
4106   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" );
4107
4108   if( NULL == mImpl->mEventData )
4109   {
4110     return;
4111   }
4112
4113   mImpl->mEventData->mCheckScrollAmount = true;
4114
4115   // The natural size needs to be re-calculated.
4116   mImpl->mRecalculateNaturalSize = true;
4117
4118   // The text direction needs to be updated.
4119   mImpl->mUpdateTextDirection = true;
4120
4121   // Apply modifications to the model; TODO - Optimize this
4122   mImpl->mOperationsPending = ALL_OPERATIONS;
4123 }
4124
4125 bool Controller::DeleteEvent( int keyCode )
4126 {
4127   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p KeyCode : %d \n", this, keyCode );
4128
4129   bool removed = false;
4130
4131   if( NULL == mImpl->mEventData )
4132   {
4133     return removed;
4134   }
4135
4136   // InputMethodContext is no longer handling key-events
4137   mImpl->ClearPreEditFlag();
4138
4139   if( EventData::SELECTING == mImpl->mEventData->mState )
4140   {
4141     removed = RemoveSelectedText();
4142   }
4143   else if( ( mImpl->mEventData->mPrimaryCursorPosition > 0 ) && ( keyCode == Dali::DALI_KEY_BACKSPACE) )
4144   {
4145     // Remove the character before the current cursor position
4146     removed = RemoveText( -1,
4147                           1,
4148                           UPDATE_INPUT_STYLE );
4149   }
4150   else if( keyCode == Dali::DevelKey::DALI_KEY_DELETE )
4151   {
4152     // Remove the character after the current cursor position
4153     removed = RemoveText( 0,
4154                           1,
4155                           UPDATE_INPUT_STYLE );
4156   }
4157
4158   if( removed )
4159   {
4160     if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
4161         !mImpl->IsPlaceholderAvailable() )
4162     {
4163       mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
4164     }
4165     else
4166     {
4167       ShowPlaceholderText();
4168     }
4169     mImpl->mEventData->mUpdateCursorPosition = true;
4170     mImpl->mEventData->mScrollAfterDelete = true;
4171   }
4172
4173   return removed;
4174 }
4175
4176 // private : Helpers.
4177
4178 void Controller::ResetText()
4179 {
4180   // Reset buffers.
4181   mImpl->mModel->mLogicalModel->mText.Clear();
4182
4183   // Reset the embedded images buffer.
4184   mImpl->mModel->mLogicalModel->ClearEmbeddedImages();
4185
4186   // We have cleared everything including the placeholder-text
4187   mImpl->PlaceholderCleared();
4188
4189   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
4190   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
4191   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
4192
4193   // Clear any previous text.
4194   mImpl->mTextUpdateInfo.mClearAll = true;
4195
4196   // The natural size needs to be re-calculated.
4197   mImpl->mRecalculateNaturalSize = true;
4198
4199   // The text direction needs to be updated.
4200   mImpl->mUpdateTextDirection = true;
4201
4202   // Apply modifications to the model
4203   mImpl->mOperationsPending = ALL_OPERATIONS;
4204 }
4205
4206 void Controller::ShowPlaceholderText()
4207 {
4208   if( mImpl->IsPlaceholderAvailable() )
4209   {
4210     DALI_ASSERT_DEBUG( mImpl->mEventData && "No placeholder text available" );
4211
4212     if( NULL == mImpl->mEventData )
4213     {
4214       return;
4215     }
4216
4217     mImpl->mEventData->mIsShowingPlaceholderText = true;
4218
4219     // Disable handles when showing place-holder text
4220     mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
4221     mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
4222     mImpl->mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
4223
4224     const char* text( NULL );
4225     size_t size( 0 );
4226
4227     // TODO - Switch Placeholder text when changing state
4228     if( ( EventData::INACTIVE != mImpl->mEventData->mState ) &&
4229         ( 0u != mImpl->mEventData->mPlaceholderTextActive.c_str() ) )
4230     {
4231       text = mImpl->mEventData->mPlaceholderTextActive.c_str();
4232       size = mImpl->mEventData->mPlaceholderTextActive.size();
4233     }
4234     else
4235     {
4236       text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
4237       size = mImpl->mEventData->mPlaceholderTextInactive.size();
4238     }
4239
4240     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
4241     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
4242
4243     // Reset model for showing placeholder.
4244     mImpl->mModel->mLogicalModel->mText.Clear();
4245     mImpl->mModel->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor );
4246
4247     // Convert text into UTF-32
4248     Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
4249     utf32Characters.Resize( size );
4250
4251     // This is a bit horrible but std::string returns a (signed) char*
4252     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text );
4253
4254     // Transform a text array encoded in utf8 into an array encoded in utf32.
4255     // It returns the actual number of characters.
4256     const Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() );
4257     utf32Characters.Resize( characterCount );
4258
4259     // The characters to be added.
4260     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount;
4261
4262     // Reset the cursor position
4263     mImpl->mEventData->mPrimaryCursorPosition = 0;
4264
4265     // The natural size needs to be re-calculated.
4266     mImpl->mRecalculateNaturalSize = true;
4267
4268     // The text direction needs to be updated.
4269     mImpl->mUpdateTextDirection = true;
4270
4271     // Apply modifications to the model
4272     mImpl->mOperationsPending = ALL_OPERATIONS;
4273
4274     // Update the rest of the model during size negotiation
4275     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
4276   }
4277 }
4278
4279 void Controller::ClearFontData()
4280 {
4281   if( mImpl->mFontDefaults )
4282   {
4283     mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
4284   }
4285
4286   // Set flags to update the model.
4287   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
4288   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
4289   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
4290
4291   mImpl->mTextUpdateInfo.mClearAll = true;
4292   mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
4293   mImpl->mRecalculateNaturalSize = true;
4294
4295   mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
4296                                                            VALIDATE_FONTS            |
4297                                                            SHAPE_TEXT                |
4298                                                            BIDI_INFO                 |
4299                                                            GET_GLYPH_METRICS         |
4300                                                            LAYOUT                    |
4301                                                            UPDATE_LAYOUT_SIZE        |
4302                                                            REORDER                   |
4303                                                            ALIGN );
4304 }
4305
4306 void Controller::ClearStyleData()
4307 {
4308   mImpl->mModel->mLogicalModel->mColorRuns.Clear();
4309   mImpl->mModel->mLogicalModel->ClearFontDescriptionRuns();
4310 }
4311
4312 void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
4313 {
4314   // Reset the cursor position
4315   if( NULL != mImpl->mEventData )
4316   {
4317     mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
4318
4319     // Update the cursor if it's in editing mode.
4320     if( EventData::IsEditingState( mImpl->mEventData->mState )  )
4321     {
4322       mImpl->mEventData->mUpdateCursorPosition = true;
4323     }
4324   }
4325 }
4326
4327 void Controller::ResetScrollPosition()
4328 {
4329   if( NULL != mImpl->mEventData )
4330   {
4331     // Reset the scroll position.
4332     mImpl->mModel->mScrollPosition = Vector2::ZERO;
4333     mImpl->mEventData->mScrollAfterUpdatePosition = true;
4334   }
4335 }
4336
4337 void Controller::SetControlInterface( ControlInterface* controlInterface )
4338 {
4339   mImpl->mControlInterface = controlInterface;
4340 }
4341
4342 bool Controller::ShouldClearFocusOnEscape() const
4343 {
4344   return mImpl->mShouldClearFocusOnEscape;
4345 }
4346
4347 // private : Private contructors & copy operator.
4348
4349 Controller::Controller()
4350 : mImpl( NULL )
4351 {
4352   mImpl = new Controller::Impl( NULL, NULL );
4353 }
4354
4355 Controller::Controller( ControlInterface* controlInterface )
4356 {
4357   mImpl = new Controller::Impl( controlInterface, NULL );
4358 }
4359
4360 Controller::Controller( ControlInterface* controlInterface,
4361                         EditableControlInterface* editableControlInterface )
4362 {
4363   mImpl = new Controller::Impl( controlInterface,
4364                                 editableControlInterface );
4365 }
4366
4367 // The copy constructor and operator are left unimplemented.
4368
4369 // protected : Destructor.
4370
4371 Controller::~Controller()
4372 {
4373   delete mImpl;
4374 }
4375
4376 } // namespace Text
4377
4378 } // namespace Toolkit
4379
4380 } // namespace Dali