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