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