Merge "Add Placeholder Ellipsis in TextField" into devel/master
[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( Layout::HorizontalAlignment 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 Layout::HorizontalAlignment Controller::GetHorizontalAlignment() const
374 {
375   return mImpl->mModel->mHorizontalAlignment;
376 }
377
378 void Controller::SetVerticalAlignment( Layout::VerticalAlignment 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 Layout::VerticalAlignment 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::IsFontStyleSetByString()
1754 {
1755   return mImpl->mFontStyleSetByString;
1756 }
1757
1758 void Controller::FontStyleSetByString( bool setByString )
1759 {
1760   mImpl->mFontStyleSetByString = setByString;
1761 }
1762
1763 // public : Queries & retrieves.
1764
1765 Layout::Engine& Controller::GetLayoutEngine()
1766 {
1767   return mImpl->mLayoutEngine;
1768 }
1769
1770 View& Controller::GetView()
1771 {
1772   return mImpl->mView;
1773 }
1774
1775 Vector3 Controller::GetNaturalSize()
1776 {
1777   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n" );
1778   Vector3 naturalSize;
1779
1780   // Make sure the model is up-to-date before layouting
1781   ProcessModifyEvents();
1782
1783   if( mImpl->mRecalculateNaturalSize )
1784   {
1785     // Operations that can be done only once until the text changes.
1786     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1787                                                                            GET_SCRIPTS       |
1788                                                                            VALIDATE_FONTS    |
1789                                                                            GET_LINE_BREAKS   |
1790                                                                            GET_WORD_BREAKS   |
1791                                                                            BIDI_INFO         |
1792                                                                            SHAPE_TEXT        |
1793                                                                            GET_GLYPH_METRICS );
1794
1795     // Set the update info to relayout the whole text.
1796     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1797     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1798
1799     // Make sure the model is up-to-date before layouting
1800     mImpl->UpdateModel( onlyOnceOperations );
1801
1802     // Layout the text for the new width.
1803     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT | REORDER );
1804
1805     // Store the actual control's size to restore later.
1806     const Size actualControlSize = mImpl->mModel->mVisualModel->mControlSize;
1807
1808     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
1809                 static_cast<OperationsMask>( onlyOnceOperations |
1810                                              LAYOUT | REORDER ),
1811                 naturalSize.GetVectorXY() );
1812
1813     // Do not do again the only once operations.
1814     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1815
1816     // Do the size related operations again.
1817     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1818                                                                         ALIGN  |
1819                                                                         REORDER );
1820     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1821
1822     // Stores the natural size to avoid recalculate it again
1823     // unless the text/style changes.
1824     mImpl->mModel->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
1825
1826     mImpl->mRecalculateNaturalSize = false;
1827
1828     // Clear the update info. This info will be set the next time the text is updated.
1829     mImpl->mTextUpdateInfo.Clear();
1830
1831     // Restore the actual control's size.
1832     mImpl->mModel->mVisualModel->mControlSize = actualControlSize;
1833
1834     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1835   }
1836   else
1837   {
1838     naturalSize = mImpl->mModel->mVisualModel->GetNaturalSize();
1839
1840     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1841   }
1842
1843   naturalSize.x = ConvertToEven( naturalSize.x );
1844   naturalSize.y = ConvertToEven( naturalSize.y );
1845
1846   return naturalSize;
1847 }
1848
1849 float Controller::GetHeightForWidth( float width )
1850 {
1851   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width );
1852   // Make sure the model is up-to-date before layouting
1853   ProcessModifyEvents();
1854
1855   Size layoutSize;
1856   if( fabsf( width - mImpl->mModel->mVisualModel->mControlSize.width ) > Math::MACHINE_EPSILON_1000 ||
1857                                                          mImpl->mTextUpdateInfo.mFullRelayoutNeeded ||
1858                                                          mImpl->mTextUpdateInfo.mClearAll            )
1859   {
1860     // Operations that can be done only once until the text changes.
1861     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1862                                                                            GET_SCRIPTS       |
1863                                                                            VALIDATE_FONTS    |
1864                                                                            GET_LINE_BREAKS   |
1865                                                                            GET_WORD_BREAKS   |
1866                                                                            BIDI_INFO         |
1867                                                                            SHAPE_TEXT        |
1868                                                                            GET_GLYPH_METRICS );
1869
1870     // Set the update info to relayout the whole text.
1871     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1872     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1873
1874     // Make sure the model is up-to-date before layouting
1875     mImpl->UpdateModel( onlyOnceOperations );
1876
1877
1878     // Layout the text for the new width.
1879     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
1880
1881     // Store the actual control's width.
1882     const float actualControlWidth = mImpl->mModel->mVisualModel->mControlSize.width;
1883
1884     DoRelayout( Size( width, MAX_FLOAT ),
1885                 static_cast<OperationsMask>( onlyOnceOperations |
1886                                              LAYOUT ),
1887                 layoutSize );
1888
1889     // Do not do again the only once operations.
1890     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1891
1892     // Do the size related operations again.
1893     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1894                                                                         ALIGN  |
1895                                                                         REORDER );
1896
1897     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1898
1899     // Clear the update info. This info will be set the next time the text is updated.
1900     mImpl->mTextUpdateInfo.Clear();
1901
1902     // Restore the actual control's width.
1903     mImpl->mModel->mVisualModel->mControlSize.width = actualControlWidth;
1904
1905     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height );
1906   }
1907   else
1908   {
1909     layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
1910     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height );
1911   }
1912
1913   return layoutSize.height;
1914 }
1915
1916 int Controller::GetLineCount( float width )
1917 {
1918   GetHeightForWidth( width );
1919   int numberofLines = mImpl->mModel->GetNumberOfLines();
1920   return numberofLines;
1921 }
1922
1923 const ModelInterface* const Controller::GetTextModel() const
1924 {
1925   return mImpl->mModel.Get();
1926 }
1927
1928 float Controller::GetScrollAmountByUserInput()
1929 {
1930   float scrollAmount = 0.0f;
1931
1932   if (NULL != mImpl->mEventData && mImpl->mEventData->mCheckScrollAmount)
1933   {
1934     scrollAmount = mImpl->mModel->mScrollPosition.y -  mImpl->mModel->mScrollPositionLast.y;
1935     mImpl->mEventData->mCheckScrollAmount = false;
1936   }
1937   return scrollAmount;
1938 }
1939
1940 bool Controller::GetTextScrollInfo( float& scrollPosition, float& controlHeight, float& layoutHeight )
1941 {
1942   const Vector2& layout = mImpl->mModel->mVisualModel->GetLayoutSize();
1943   bool isScrolled;
1944
1945   controlHeight = mImpl->mModel->mVisualModel->mControlSize.height;
1946   layoutHeight = layout.height;
1947   scrollPosition = mImpl->mModel->mScrollPosition.y;
1948   isScrolled = !Equals( mImpl->mModel->mScrollPosition.y, mImpl->mModel->mScrollPositionLast.y, Math::MACHINE_EPSILON_1 );
1949   return isScrolled;
1950 }
1951
1952 void Controller::SetHiddenInputOption(const Property::Map& options )
1953 {
1954   if( NULL == mImpl->mHiddenInput )
1955   {
1956     mImpl->mHiddenInput = new HiddenText( this );
1957   }
1958   mImpl->mHiddenInput->SetProperties(options);
1959 }
1960
1961 void Controller::GetHiddenInputOption(Property::Map& options )
1962 {
1963   if( NULL != mImpl->mHiddenInput )
1964   {
1965     mImpl->mHiddenInput->GetProperties(options);
1966   }
1967 }
1968
1969 void Controller::SetPlaceholderProperty( const Property::Map& map )
1970 {
1971   const Property::Map::SizeType count = map.Count();
1972
1973   for( Property::Map::SizeType position = 0; position < count; ++position )
1974   {
1975     KeyValuePair keyValue = map.GetKeyValue( position );
1976     Property::Key& key = keyValue.first;
1977     Property::Value& value = keyValue.second;
1978
1979     if( key == PLACEHOLDER_TEXT )
1980     {
1981       std::string text = "";
1982       value.Get( text );
1983       SetPlaceholderText( Controller::PLACEHOLDER_TYPE_INACTIVE, text );
1984     }
1985     else if( key == PLACEHOLDER_TEXT_FOCUSED )
1986     {
1987       std::string text = "";
1988       value.Get( text );
1989       SetPlaceholderText( Controller::PLACEHOLDER_TYPE_ACTIVE, text );
1990     }
1991     else if( key == PLACEHOLDER_COLOR )
1992     {
1993       Vector4 textColor;
1994       value.Get( textColor );
1995       if( GetPlaceholderTextColor() != textColor )
1996       {
1997         SetPlaceholderTextColor( textColor );
1998       }
1999     }
2000     else if( key == PLACEHOLDER_FONT_FAMILY )
2001     {
2002       std::string fontFamily = "";
2003       value.Get( fontFamily );
2004       SetPlaceholderFontFamily( fontFamily );
2005     }
2006     else if( key == PLACEHOLDER_FONT_STYLE )
2007     {
2008       SetFontStyleProperty( this, value, Text::FontStyle::PLACEHOLDER );
2009     }
2010     else if( key == PLACEHOLDER_POINT_SIZE )
2011     {
2012       float pointSize;
2013       value.Get( pointSize );
2014       if( !Equals( GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE ), pointSize ) )
2015       {
2016         SetPlaceholderTextFontSize( pointSize, Text::Controller::POINT_SIZE );
2017       }
2018     }
2019     else if( key == PLACEHOLDER_PIXEL_SIZE )
2020     {
2021       float pixelSize;
2022       value.Get( pixelSize );
2023       if( !Equals( GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE ), pixelSize ) )
2024       {
2025         SetPlaceholderTextFontSize( pixelSize, Text::Controller::PIXEL_SIZE );
2026       }
2027     }
2028     else if( key == PLACEHOLDER_ELLIPSIS )
2029     {
2030       bool ellipsis;
2031       value.Get( ellipsis );
2032       SetPlaceholderTextElideEnabled( ellipsis );
2033     }
2034   }
2035 }
2036
2037 void Controller::GetPlaceholderProperty( Property::Map& map )
2038 {
2039   if( NULL != mImpl->mEventData )
2040   {
2041     if( !mImpl->mEventData->mPlaceholderTextActive.empty() )
2042     {
2043       map[ PLACEHOLDER_TEXT_FOCUSED ] = mImpl->mEventData->mPlaceholderTextActive;
2044     }
2045     if( !mImpl->mEventData->mPlaceholderTextInactive.empty() )
2046     {
2047       map[ PLACEHOLDER_TEXT ] = mImpl->mEventData->mPlaceholderTextInactive;
2048     }
2049
2050     map[ PLACEHOLDER_COLOR ] = mImpl->mEventData->mPlaceholderTextColor;
2051     map[ PLACEHOLDER_FONT_FAMILY ] = GetPlaceholderFontFamily();
2052
2053     Property::Value fontStyleMapGet;
2054     GetFontStyleProperty( this, fontStyleMapGet, Text::FontStyle::PLACEHOLDER );
2055     map[ PLACEHOLDER_FONT_STYLE ] = fontStyleMapGet;
2056
2057     // Choose font size : POINT_SIZE or PIXEL_SIZE
2058     if( !mImpl->mEventData->mIsPlaceholderPixelSize )
2059     {
2060       map[ PLACEHOLDER_POINT_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE );
2061     }
2062     else
2063     {
2064       map[ PLACEHOLDER_PIXEL_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE );
2065     }
2066
2067     if( mImpl->mEventData->mPlaceholderEllipsisFlag )
2068     {
2069       map[ PLACEHOLDER_ELLIPSIS ] = IsPlaceholderTextElideEnabled();
2070     }
2071   }
2072 }
2073
2074 // public : Relayout.
2075
2076 Controller::UpdateTextType Controller::Relayout( const Size& size )
2077 {
2078   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, mImpl->mIsAutoScrollEnabled ?"true":"false"  );
2079
2080   UpdateTextType updateTextType = NONE_UPDATED;
2081
2082   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
2083   {
2084     if( 0u != mImpl->mModel->mVisualModel->mGlyphPositions.Count() )
2085     {
2086       mImpl->mModel->mVisualModel->mGlyphPositions.Clear();
2087       updateTextType = MODEL_UPDATED;
2088     }
2089
2090     // Clear the update info. This info will be set the next time the text is updated.
2091     mImpl->mTextUpdateInfo.Clear();
2092
2093     // Not worth to relayout if width or height is equal to zero.
2094     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
2095
2096     return updateTextType;
2097   }
2098
2099   // Whether a new size has been set.
2100   const bool newSize = ( size != mImpl->mModel->mVisualModel->mControlSize );
2101
2102   if( newSize )
2103   {
2104     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mModel->mVisualModel->mControlSize.width, mImpl->mModel->mVisualModel->mControlSize.height );
2105
2106     // Layout operations that need to be done if the size changes.
2107     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2108                                                              LAYOUT                    |
2109                                                              ALIGN                     |
2110                                                              UPDATE_LAYOUT_SIZE        |
2111                                                              REORDER );
2112     // Set the update info to relayout the whole text.
2113     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2114     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2115
2116     // Store the size used to layout the text.
2117     mImpl->mModel->mVisualModel->mControlSize = size;
2118   }
2119
2120   // Whether there are modify events.
2121   if( 0u != mImpl->mModifyEvents.Count() )
2122   {
2123     // Style operations that need to be done if the text is modified.
2124     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2125                                                              COLOR );
2126   }
2127
2128   // Set the update info to elide the text.
2129   if( mImpl->mModel->mElideEnabled ||
2130       ( ( NULL != mImpl->mEventData ) && mImpl->mEventData->mIsPlaceholderElideEnabled ) )
2131   {
2132     // Update Text layout for applying elided
2133     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2134                                                              ALIGN                     |
2135                                                              LAYOUT                    |
2136                                                              UPDATE_LAYOUT_SIZE        |
2137                                                              REORDER );
2138     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2139     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2140   }
2141
2142   // Make sure the model is up-to-date before layouting.
2143   ProcessModifyEvents();
2144   bool updated = mImpl->UpdateModel( mImpl->mOperationsPending );
2145
2146   // Layout the text.
2147   Size layoutSize;
2148   updated = DoRelayout( size,
2149                         mImpl->mOperationsPending,
2150                         layoutSize ) || updated;
2151
2152   if( updated )
2153   {
2154     updateTextType = MODEL_UPDATED;
2155   }
2156
2157   // Do not re-do any operation until something changes.
2158   mImpl->mOperationsPending = NO_OPERATION;
2159   mImpl->mModel->mScrollPositionLast = mImpl->mModel->mScrollPosition;
2160
2161   // Whether the text control is editable
2162   const bool isEditable = NULL != mImpl->mEventData;
2163
2164   // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
2165   Vector2 offset;
2166   if( newSize && isEditable )
2167   {
2168     offset = mImpl->mModel->mScrollPosition;
2169   }
2170
2171   if( !isEditable || !IsMultiLineEnabled() )
2172   {
2173     // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
2174     CalculateVerticalOffset( size );
2175   }
2176
2177   if( isEditable )
2178   {
2179     if( newSize )
2180     {
2181       // If there is a new size, the scroll position needs to be clamped.
2182       mImpl->ClampHorizontalScroll( layoutSize );
2183
2184       // Update the decorator's positions is needed if there is a new size.
2185       mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mModel->mScrollPosition - offset );
2186     }
2187
2188     // Move the cursor, grab handle etc.
2189     if( mImpl->ProcessInputEvents() )
2190     {
2191       updateTextType = static_cast<UpdateTextType>( updateTextType | DECORATOR_UPDATED );
2192     }
2193   }
2194
2195   // Clear the update info. This info will be set the next time the text is updated.
2196   mImpl->mTextUpdateInfo.Clear();
2197   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
2198
2199   return updateTextType;
2200 }
2201
2202 void Controller::RequestRelayout()
2203 {
2204   mImpl->RequestRelayout();
2205 }
2206
2207 // public : Input style change signals.
2208
2209 bool Controller::IsInputStyleChangedSignalsQueueEmpty()
2210 {
2211   return ( NULL == mImpl->mEventData ) || ( 0u == mImpl->mEventData->mInputStyleChangedQueue.Count() );
2212 }
2213
2214 void Controller::ProcessInputStyleChangedSignals()
2215 {
2216   if( NULL == mImpl->mEventData )
2217   {
2218     // Nothing to do.
2219     return;
2220   }
2221
2222   for( Vector<InputStyle::Mask>::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(),
2223          endIt = mImpl->mEventData->mInputStyleChangedQueue.End();
2224        it != endIt;
2225        ++it )
2226   {
2227     const InputStyle::Mask mask = *it;
2228
2229     if( NULL != mImpl->mEditableControlInterface )
2230     {
2231       // Emit the input style changed signal.
2232       mImpl->mEditableControlInterface->InputStyleChanged( mask );
2233     }
2234   }
2235
2236   mImpl->mEventData->mInputStyleChangedQueue.Clear();
2237 }
2238
2239 // public : Text-input Event Queuing.
2240
2241 void Controller::KeyboardFocusGainEvent()
2242 {
2243   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
2244
2245   if( NULL != mImpl->mEventData )
2246   {
2247     if( ( EventData::INACTIVE == mImpl->mEventData->mState ) ||
2248         ( EventData::INTERRUPTED == mImpl->mEventData->mState ) )
2249     {
2250       mImpl->ChangeState( EventData::EDITING );
2251       mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
2252       mImpl->mEventData->mUpdateInputStyle = true;
2253     }
2254     mImpl->NotifyImfMultiLineStatus();
2255     if( mImpl->IsShowingPlaceholderText() )
2256     {
2257       // Show alternative placeholder-text when editing
2258       ShowPlaceholderText();
2259     }
2260
2261     mImpl->RequestRelayout();
2262   }
2263 }
2264
2265 void Controller::KeyboardFocusLostEvent()
2266 {
2267   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
2268
2269   if( NULL != mImpl->mEventData )
2270   {
2271     if( EventData::INTERRUPTED != mImpl->mEventData->mState )
2272     {
2273       mImpl->ChangeState( EventData::INACTIVE );
2274
2275       if( !mImpl->IsShowingRealText() )
2276       {
2277         // Revert to regular placeholder-text when not editing
2278         ShowPlaceholderText();
2279       }
2280     }
2281   }
2282   mImpl->RequestRelayout();
2283 }
2284
2285 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
2286 {
2287   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
2288
2289   bool textChanged = false;
2290   bool relayoutNeeded = false;
2291
2292   if( ( NULL != mImpl->mEventData ) &&
2293       ( keyEvent.state == KeyEvent::Down ) )
2294   {
2295     int keyCode = keyEvent.keyCode;
2296     const std::string& keyString = keyEvent.keyPressed;
2297
2298     const bool isNullKey = ( 0 == keyCode ) && ( keyString.empty() );
2299
2300     // Pre-process to separate modifying events from non-modifying input events.
2301     if( isNullKey )
2302     {
2303       // In some platforms arrive key events with no key code.
2304       // Do nothing.
2305       return false;
2306     }
2307     else if( Dali::DALI_KEY_ESCAPE == keyCode || Dali::DALI_KEY_BACK == keyCode )
2308     {
2309       // Do nothing
2310       return false;
2311     }
2312     else if( ( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ) ||
2313              ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode ) ||
2314              ( Dali::DALI_KEY_CURSOR_UP    == keyCode ) ||
2315              ( Dali::DALI_KEY_CURSOR_DOWN  == keyCode ) )
2316     {
2317       // If don't have any text, do nothing.
2318       if( !mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters )
2319       {
2320         return false;
2321       }
2322
2323       uint32_t cursorPosition = mImpl->mEventData->mPrimaryCursorPosition;
2324       uint32_t numberOfCharacters = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2325       uint32_t cursorLine = mImpl->mModel->mVisualModel->GetLineOfCharacter( cursorPosition );
2326       uint32_t numberOfLines = mImpl->mModel->GetNumberOfLines();
2327
2328       // Logic to determine whether this text control will lose focus or not.
2329       if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode && 0 == cursorPosition ) ||
2330           ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition) ||
2331           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && cursorLine == numberOfLines -1 ) ||
2332           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && numberOfCharacters == cursorPosition && cursorLine -1 == numberOfLines -1 ) ||
2333           ( Dali::DALI_KEY_CURSOR_UP == keyCode && cursorLine == 0 ) ||
2334           ( Dali::DALI_KEY_CURSOR_UP == keyCode && numberOfCharacters == cursorPosition && cursorLine == 1 ) )
2335       {
2336         return false;
2337       }
2338
2339       mImpl->mEventData->mCheckScrollAmount = true;
2340       Event event( Event::CURSOR_KEY_EVENT );
2341       event.p1.mInt = keyCode;
2342       mImpl->mEventData->mEventQueue.push_back( event );
2343
2344       // Will request for relayout.
2345       relayoutNeeded = true;
2346     }
2347     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
2348     {
2349       textChanged = BackspaceKeyEvent();
2350
2351       // Will request for relayout.
2352       relayoutNeeded = true;
2353     }
2354     else if( IsKey( keyEvent, Dali::DALI_KEY_POWER ) ||
2355              IsKey( keyEvent, Dali::DALI_KEY_MENU ) ||
2356              IsKey( keyEvent, Dali::DALI_KEY_HOME ) )
2357     {
2358       // Power key/Menu/Home key behaviour does not allow edit mode to resume.
2359       mImpl->ChangeState( EventData::INACTIVE );
2360
2361       // Will request for relayout.
2362       relayoutNeeded = true;
2363
2364       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
2365     }
2366     else if( Dali::DALI_KEY_SHIFT_LEFT == keyCode )
2367     {
2368       // DALI_KEY_SHIFT_LEFT is the key code for the Left Shift. It's sent (by the imf?) when the predictive text is enabled
2369       // and a character is typed after the type of a upper case latin character.
2370
2371       // Do nothing.
2372       return false;
2373     }
2374     else if( ( Dali::DALI_KEY_VOLUME_UP == keyCode ) || ( Dali::DALI_KEY_VOLUME_DOWN == keyCode ) )
2375     {
2376       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
2377       // Do nothing.
2378       return false;
2379     }
2380     else
2381     {
2382       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() );
2383
2384       // IMF manager is no longer handling key-events
2385       mImpl->ClearPreEditFlag();
2386
2387       InsertText( keyString, COMMIT );
2388       textChanged = true;
2389
2390       // Will request for relayout.
2391       relayoutNeeded = true;
2392     }
2393
2394     if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
2395          ( mImpl->mEventData->mState != EventData::INACTIVE ) &&
2396          ( !isNullKey ) &&
2397          ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) &&
2398          ( Dali::DALI_KEY_VOLUME_UP != keyCode ) &&
2399          ( Dali::DALI_KEY_VOLUME_DOWN != keyCode ) )
2400     {
2401       // Should not change the state if the key is the shift send by the imf manager.
2402       // Otherwise, when the state is SELECTING the text controller can't send the right
2403       // surrounding info to the imf.
2404       mImpl->ChangeState( EventData::EDITING );
2405
2406       // Will request for relayout.
2407       relayoutNeeded = true;
2408     }
2409
2410     if( relayoutNeeded )
2411     {
2412       mImpl->RequestRelayout();
2413     }
2414   }
2415
2416   if( textChanged &&
2417       ( NULL != mImpl->mEditableControlInterface ) )
2418   {
2419     // Do this last since it provides callbacks into application code
2420     mImpl->mEditableControlInterface->TextChanged();
2421   }
2422
2423   return true;
2424 }
2425
2426 void Controller::TapEvent( unsigned int tapCount, float x, float y )
2427 {
2428   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
2429
2430   if( NULL != mImpl->mEventData )
2431   {
2432     DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState );
2433     EventData::State state( mImpl->mEventData->mState );
2434     bool relayoutNeeded( false );   // to avoid unnecessary relayouts when tapping an empty text-field
2435
2436     if( mImpl->IsClipboardVisible() )
2437     {
2438       if( EventData::INACTIVE == state || EventData::EDITING == state)
2439       {
2440         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2441       }
2442       relayoutNeeded = true;
2443     }
2444     else if( 1u == tapCount )
2445     {
2446       if( EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state )
2447       {
2448         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );  // If Popup shown hide it here so can be shown again if required.
2449       }
2450
2451       if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != state ) )
2452       {
2453         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2454         relayoutNeeded = true;
2455       }
2456       else
2457       {
2458         if( mImpl->IsShowingPlaceholderText() && !mImpl->IsFocusedPlaceholderAvailable() )
2459         {
2460           // Hide placeholder text
2461           ResetText();
2462         }
2463
2464         if( EventData::INACTIVE == state )
2465         {
2466           mImpl->ChangeState( EventData::EDITING );
2467         }
2468         else if( !mImpl->IsClipboardEmpty() )
2469         {
2470           mImpl->ChangeState( EventData::EDITING_WITH_POPUP );
2471         }
2472         relayoutNeeded = true;
2473       }
2474     }
2475     else if( 2u == tapCount )
2476     {
2477       if( mImpl->mEventData->mSelectionEnabled &&
2478           mImpl->IsShowingRealText() )
2479       {
2480         relayoutNeeded = true;
2481         mImpl->mEventData->mIsLeftHandleSelected = true;
2482         mImpl->mEventData->mIsRightHandleSelected = true;
2483       }
2484     }
2485
2486     // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
2487     if( relayoutNeeded )
2488     {
2489       Event event( Event::TAP_EVENT );
2490       event.p1.mUint = tapCount;
2491       event.p2.mFloat = x;
2492       event.p3.mFloat = y;
2493       mImpl->mEventData->mEventQueue.push_back( event );
2494
2495       mImpl->RequestRelayout();
2496     }
2497   }
2498
2499   // Reset keyboard as tap event has occurred.
2500   mImpl->ResetImfManager();
2501 }
2502
2503 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
2504 {
2505   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
2506
2507   if( NULL != mImpl->mEventData )
2508   {
2509     Event event( Event::PAN_EVENT );
2510     event.p1.mInt = state;
2511     event.p2.mFloat = displacement.x;
2512     event.p3.mFloat = displacement.y;
2513     mImpl->mEventData->mEventQueue.push_back( event );
2514
2515     mImpl->RequestRelayout();
2516   }
2517 }
2518
2519 void Controller::LongPressEvent( Gesture::State state, float x, float y  )
2520 {
2521   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" );
2522
2523   if( ( state == Gesture::Started ) &&
2524       ( NULL != mImpl->mEventData ) )
2525   {
2526     // The 1st long-press on inactive text-field is treated as tap
2527     if( EventData::INACTIVE == mImpl->mEventData->mState )
2528     {
2529       mImpl->ChangeState( EventData::EDITING );
2530
2531       Event event( Event::TAP_EVENT );
2532       event.p1.mUint = 1;
2533       event.p2.mFloat = x;
2534       event.p3.mFloat = y;
2535       mImpl->mEventData->mEventQueue.push_back( event );
2536
2537       mImpl->RequestRelayout();
2538     }
2539     else if( !mImpl->IsShowingRealText() )
2540     {
2541       Event event( Event::LONG_PRESS_EVENT );
2542       event.p1.mInt = state;
2543       event.p2.mFloat = x;
2544       event.p3.mFloat = y;
2545       mImpl->mEventData->mEventQueue.push_back( event );
2546       mImpl->RequestRelayout();
2547     }
2548     else if( !mImpl->IsClipboardVisible() )
2549     {
2550       // Reset the imf manager to commit the pre-edit before selecting the text.
2551       mImpl->ResetImfManager();
2552
2553       Event event( Event::LONG_PRESS_EVENT );
2554       event.p1.mInt = state;
2555       event.p2.mFloat = x;
2556       event.p3.mFloat = y;
2557       mImpl->mEventData->mEventQueue.push_back( event );
2558       mImpl->RequestRelayout();
2559
2560       mImpl->mEventData->mIsLeftHandleSelected = true;
2561       mImpl->mEventData->mIsRightHandleSelected = true;
2562     }
2563   }
2564 }
2565
2566 ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
2567 {
2568   // Whether the text needs to be relaid-out.
2569   bool requestRelayout = false;
2570
2571   // Whether to retrieve the text and cursor position to be sent to the IMF manager.
2572   bool retrieveText = false;
2573   bool retrieveCursor = false;
2574
2575   switch( imfEvent.eventName )
2576   {
2577     case ImfManager::COMMIT:
2578     {
2579       InsertText( imfEvent.predictiveString, Text::Controller::COMMIT );
2580       requestRelayout = true;
2581       retrieveCursor = true;
2582       break;
2583     }
2584     case ImfManager::PREEDIT:
2585     {
2586       InsertText( imfEvent.predictiveString, Text::Controller::PRE_EDIT );
2587       requestRelayout = true;
2588       retrieveCursor = true;
2589       break;
2590     }
2591     case ImfManager::DELETESURROUNDING:
2592     {
2593       const bool textDeleted = RemoveText( imfEvent.cursorOffset,
2594                                            imfEvent.numberOfChars,
2595                                            DONT_UPDATE_INPUT_STYLE );
2596
2597       if( textDeleted )
2598       {
2599         if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
2600             !mImpl->IsPlaceholderAvailable() )
2601         {
2602           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2603         }
2604         else
2605         {
2606           ShowPlaceholderText();
2607         }
2608         mImpl->mEventData->mUpdateCursorPosition = true;
2609         mImpl->mEventData->mScrollAfterDelete = true;
2610
2611         requestRelayout = true;
2612       }
2613       break;
2614     }
2615     case ImfManager::GETSURROUNDING:
2616     {
2617       retrieveText = true;
2618       retrieveCursor = true;
2619       break;
2620     }
2621     case ImfManager::PRIVATECOMMAND:
2622     {
2623       // PRIVATECOMMAND event is just for getting the private command message
2624       retrieveText = true;
2625       retrieveCursor = true;
2626       break;
2627     }
2628     case ImfManager::VOID:
2629     {
2630       // do nothing
2631       break;
2632     }
2633   } // end switch
2634
2635   if( requestRelayout )
2636   {
2637     mImpl->mOperationsPending = ALL_OPERATIONS;
2638     mImpl->RequestRelayout();
2639   }
2640
2641   std::string text;
2642   CharacterIndex cursorPosition = 0u;
2643   Length numberOfWhiteSpaces = 0u;
2644
2645   if( retrieveCursor )
2646   {
2647     numberOfWhiteSpaces = mImpl->GetNumberOfWhiteSpaces( 0u );
2648
2649     cursorPosition = mImpl->GetLogicalCursorPosition();
2650
2651     if( cursorPosition < numberOfWhiteSpaces )
2652     {
2653       cursorPosition = 0u;
2654     }
2655     else
2656     {
2657       cursorPosition -= numberOfWhiteSpaces;
2658     }
2659   }
2660
2661   if( retrieveText )
2662   {
2663     mImpl->GetText( numberOfWhiteSpaces, text );
2664   }
2665
2666   ImfManager::ImfCallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false );
2667
2668   if( requestRelayout &&
2669       ( NULL != mImpl->mEditableControlInterface ) )
2670   {
2671     // Do this last since it provides callbacks into application code
2672     mImpl->mEditableControlInterface->TextChanged();
2673   }
2674
2675   return callbackData;
2676 }
2677
2678 void Controller::PasteClipboardItemEvent()
2679 {
2680   // Retrieve the clipboard contents first
2681   ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
2682   std::string stringToPaste( notifier.GetContent() );
2683
2684   // Commit the current pre-edit text; the contents of the clipboard should be appended
2685   mImpl->ResetImfManager();
2686
2687   // Temporary disable hiding clipboard
2688   mImpl->SetClipboardHideEnable( false );
2689
2690   // Paste
2691   PasteText( stringToPaste );
2692
2693   mImpl->SetClipboardHideEnable( true );
2694 }
2695
2696 // protected : Inherit from Text::Decorator::ControllerInterface.
2697
2698 void Controller::GetTargetSize( Vector2& targetSize )
2699 {
2700   targetSize = mImpl->mModel->mVisualModel->mControlSize;
2701 }
2702
2703 void Controller::AddDecoration( Actor& actor, bool needsClipping )
2704 {
2705   if( NULL != mImpl->mEditableControlInterface )
2706   {
2707     mImpl->mEditableControlInterface->AddDecoration( actor, needsClipping );
2708   }
2709 }
2710
2711 void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
2712 {
2713   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
2714
2715   if( NULL != mImpl->mEventData )
2716   {
2717     switch( handleType )
2718     {
2719       case GRAB_HANDLE:
2720       {
2721         Event event( Event::GRAB_HANDLE_EVENT );
2722         event.p1.mUint  = state;
2723         event.p2.mFloat = x;
2724         event.p3.mFloat = y;
2725
2726         mImpl->mEventData->mEventQueue.push_back( event );
2727         break;
2728       }
2729       case LEFT_SELECTION_HANDLE:
2730       {
2731         Event event( Event::LEFT_SELECTION_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 RIGHT_SELECTION_HANDLE:
2740       {
2741         Event event( Event::RIGHT_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 LEFT_SELECTION_HANDLE_MARKER:
2750       case RIGHT_SELECTION_HANDLE_MARKER:
2751       {
2752         // Markers do not move the handles.
2753         break;
2754       }
2755       case HANDLE_TYPE_COUNT:
2756       {
2757         DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
2758       }
2759     }
2760
2761     mImpl->RequestRelayout();
2762   }
2763 }
2764
2765 // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
2766
2767 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
2768 {
2769   if( NULL == mImpl->mEventData )
2770   {
2771     return;
2772   }
2773
2774   switch( button )
2775   {
2776     case Toolkit::TextSelectionPopup::CUT:
2777     {
2778       mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
2779       mImpl->mOperationsPending = ALL_OPERATIONS;
2780
2781       if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
2782           !mImpl->IsPlaceholderAvailable() )
2783       {
2784         mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2785       }
2786       else
2787       {
2788         ShowPlaceholderText();
2789       }
2790
2791       mImpl->mEventData->mUpdateCursorPosition = true;
2792       mImpl->mEventData->mScrollAfterDelete = true;
2793
2794       mImpl->RequestRelayout();
2795
2796       if( NULL != mImpl->mEditableControlInterface )
2797       {
2798         mImpl->mEditableControlInterface->TextChanged();
2799       }
2800       break;
2801     }
2802     case Toolkit::TextSelectionPopup::COPY:
2803     {
2804       mImpl->SendSelectionToClipboard( false ); // Text not modified
2805
2806       mImpl->mEventData->mUpdateCursorPosition = true;
2807
2808       mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup
2809       break;
2810     }
2811     case Toolkit::TextSelectionPopup::PASTE:
2812     {
2813       mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item
2814       break;
2815     }
2816     case Toolkit::TextSelectionPopup::SELECT:
2817     {
2818       const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
2819
2820       if( mImpl->mEventData->mSelectionEnabled )
2821       {
2822         // Creates a SELECT event.
2823         SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false );
2824       }
2825       break;
2826     }
2827     case Toolkit::TextSelectionPopup::SELECT_ALL:
2828     {
2829       // Creates a SELECT_ALL event
2830       SelectEvent( 0.f, 0.f, true );
2831       break;
2832     }
2833     case Toolkit::TextSelectionPopup::CLIPBOARD:
2834     {
2835       mImpl->ShowClipboard();
2836       break;
2837     }
2838     case Toolkit::TextSelectionPopup::NONE:
2839     {
2840       // Nothing to do.
2841       break;
2842     }
2843   }
2844 }
2845
2846 void Controller::DisplayTimeExpired()
2847 {
2848   mImpl->mEventData->mUpdateCursorPosition = true;
2849   // Apply modifications to the model
2850   mImpl->mOperationsPending = ALL_OPERATIONS;
2851
2852   mImpl->RequestRelayout();
2853 }
2854
2855 // private : Update.
2856
2857 void Controller::InsertText( const std::string& text, Controller::InsertType type )
2858 {
2859   bool removedPrevious = false;
2860   bool removedSelected = false;
2861   bool maxLengthReached = false;
2862
2863   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
2864
2865   if( NULL == mImpl->mEventData )
2866   {
2867     return;
2868   }
2869
2870   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
2871                  this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
2872                  mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2873
2874   // TODO: At the moment the underline runs are only for pre-edit.
2875   mImpl->mModel->mVisualModel->mUnderlineRuns.Clear();
2876
2877   // Remove the previous IMF pre-edit.
2878   if( mImpl->mEventData->mPreEditFlag && ( 0u != mImpl->mEventData->mPreEditLength ) )
2879   {
2880     removedPrevious = RemoveText( -static_cast<int>( mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition ),
2881                                   mImpl->mEventData->mPreEditLength,
2882                                   DONT_UPDATE_INPUT_STYLE );
2883
2884     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
2885     mImpl->mEventData->mPreEditLength = 0u;
2886   }
2887   else
2888   {
2889     // Remove the previous Selection.
2890     removedSelected = RemoveSelectedText();
2891
2892   }
2893
2894   Vector<Character> utf32Characters;
2895   Length characterCount = 0u;
2896
2897   if( !text.empty() )
2898   {
2899     //  Convert text into UTF-32
2900     utf32Characters.Resize( text.size() );
2901
2902     // This is a bit horrible but std::string returns a (signed) char*
2903     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
2904
2905     // Transform a text array encoded in utf8 into an array encoded in utf32.
2906     // It returns the actual number of characters.
2907     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
2908     utf32Characters.Resize( characterCount );
2909
2910     DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
2911     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
2912   }
2913
2914   if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
2915   {
2916     // The placeholder text is no longer needed
2917     if( mImpl->IsShowingPlaceholderText() )
2918     {
2919       ResetText();
2920     }
2921
2922     mImpl->ChangeState( EventData::EDITING );
2923
2924     // Handle the IMF (predicitive text) state changes
2925     if( COMMIT == type )
2926     {
2927       // IMF manager is no longer handling key-events
2928       mImpl->ClearPreEditFlag();
2929     }
2930     else // PRE_EDIT
2931     {
2932       if( !mImpl->mEventData->mPreEditFlag )
2933       {
2934         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state\n" );
2935
2936         // Record the start of the pre-edit text
2937         mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
2938       }
2939
2940       mImpl->mEventData->mPreEditLength = utf32Characters.Count();
2941       mImpl->mEventData->mPreEditFlag = true;
2942
2943       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2944     }
2945
2946     const Length numberOfCharactersInModel = mImpl->mModel->mLogicalModel->mText.Count();
2947
2948     // Restrict new text to fit within Maximum characters setting.
2949     Length maxSizeOfNewText = std::min( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
2950     maxLengthReached = ( characterCount > maxSizeOfNewText );
2951
2952     // The cursor position.
2953     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2954
2955     // Update the text's style.
2956
2957     // Updates the text style runs by adding characters.
2958     mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText );
2959
2960     // Get the character index from the cursor index.
2961     const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u;
2962
2963     // Retrieve the text's style for the given index.
2964     InputStyle style;
2965     mImpl->RetrieveDefaultInputStyle( style );
2966     mImpl->mModel->mLogicalModel->RetrieveStyle( styleIndex, style );
2967
2968     // Whether to add a new text color run.
2969     const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor );
2970
2971     // Whether to add a new font run.
2972     const bool addFontNameRun = style.familyName != mImpl->mEventData->mInputStyle.familyName;
2973     const bool addFontWeightRun = style.weight != mImpl->mEventData->mInputStyle.weight;
2974     const bool addFontWidthRun = style.width != mImpl->mEventData->mInputStyle.width;
2975     const bool addFontSlantRun = style.slant != mImpl->mEventData->mInputStyle.slant;
2976     const bool addFontSizeRun = style.size != mImpl->mEventData->mInputStyle.size;
2977
2978     // Add style runs.
2979     if( addColorRun )
2980     {
2981       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
2982       mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
2983
2984       ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
2985       colorRun.color = mImpl->mEventData->mInputStyle.textColor;
2986       colorRun.characterRun.characterIndex = cursorIndex;
2987       colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2988     }
2989
2990     if( addFontNameRun   ||
2991         addFontWeightRun ||
2992         addFontWidthRun  ||
2993         addFontSlantRun  ||
2994         addFontSizeRun )
2995     {
2996       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Count();
2997       mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
2998
2999       FontDescriptionRun& fontDescriptionRun = *( mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
3000
3001       if( addFontNameRun )
3002       {
3003         fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
3004         fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
3005         memcpy( fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength );
3006         fontDescriptionRun.familyDefined = true;
3007
3008         // The memory allocated for the font family name is freed when the font description is removed from the logical model.
3009       }
3010
3011       if( addFontWeightRun )
3012       {
3013         fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
3014         fontDescriptionRun.weightDefined = true;
3015       }
3016
3017       if( addFontWidthRun )
3018       {
3019         fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
3020         fontDescriptionRun.widthDefined = true;
3021       }
3022
3023       if( addFontSlantRun )
3024       {
3025         fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
3026         fontDescriptionRun.slantDefined = true;
3027       }
3028
3029       if( addFontSizeRun )
3030       {
3031         fontDescriptionRun.size = static_cast<PointSize26Dot6>( mImpl->mEventData->mInputStyle.size * 64.f );
3032         fontDescriptionRun.sizeDefined = true;
3033       }
3034
3035       fontDescriptionRun.characterRun.characterIndex = cursorIndex;
3036       fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
3037     }
3038
3039     // Insert at current cursor position.
3040     Vector<Character>& modifyText = mImpl->mModel->mLogicalModel->mText;
3041
3042     if( cursorIndex < numberOfCharactersInModel )
3043     {
3044       modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3045     }
3046     else
3047     {
3048       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3049     }
3050
3051     // Mark the first paragraph to be updated.
3052     if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
3053     {
3054       mImpl->mTextUpdateInfo.mCharacterIndex = 0;
3055       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3056       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = numberOfCharactersInModel + maxSizeOfNewText;
3057       mImpl->mTextUpdateInfo.mClearAll = true;
3058     }
3059     else
3060     {
3061       mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
3062       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
3063     }
3064
3065     // Update the cursor index.
3066     cursorIndex += maxSizeOfNewText;
3067
3068     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 );
3069   }
3070
3071   if( ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) &&
3072       mImpl->IsPlaceholderAvailable() )
3073   {
3074     // Show place-holder if empty after removing the pre-edit text
3075     ShowPlaceholderText();
3076     mImpl->mEventData->mUpdateCursorPosition = true;
3077     mImpl->ClearPreEditFlag();
3078   }
3079   else if( removedPrevious ||
3080            removedSelected ||
3081            ( 0 != utf32Characters.Count() ) )
3082   {
3083     // Queue an inserted event
3084     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
3085
3086     mImpl->mEventData->mUpdateCursorPosition = true;
3087     if( removedSelected )
3088     {
3089       mImpl->mEventData->mScrollAfterDelete = true;
3090     }
3091     else
3092     {
3093       mImpl->mEventData->mScrollAfterUpdatePosition = true;
3094     }
3095   }
3096
3097   if( maxLengthReached )
3098   {
3099     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mModel->mLogicalModel->mText.Count() );
3100
3101     mImpl->ResetImfManager();
3102
3103     if( NULL != mImpl->mEditableControlInterface )
3104     {
3105       // Do this last since it provides callbacks into application code
3106       mImpl->mEditableControlInterface->MaxLengthReached();
3107     }
3108   }
3109 }
3110
3111 void Controller::PasteText( const std::string& stringToPaste )
3112 {
3113   InsertText( stringToPaste, Text::Controller::COMMIT );
3114   mImpl->ChangeState( EventData::EDITING );
3115   mImpl->RequestRelayout();
3116
3117   if( NULL != mImpl->mEditableControlInterface )
3118   {
3119     // Do this last since it provides callbacks into application code
3120     mImpl->mEditableControlInterface->TextChanged();
3121   }
3122 }
3123
3124 bool Controller::RemoveText( int cursorOffset,
3125                              int numberOfCharacters,
3126                              UpdateInputStyleType type )
3127 {
3128   bool removed = false;
3129
3130   if( NULL == mImpl->mEventData )
3131   {
3132     return removed;
3133   }
3134
3135   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n",
3136                  this, mImpl->mModel->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters );
3137
3138   if( !mImpl->IsShowingPlaceholderText() )
3139   {
3140     // Delete at current cursor position
3141     Vector<Character>& currentText = mImpl->mModel->mLogicalModel->mText;
3142     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
3143
3144     CharacterIndex cursorIndex = 0;
3145
3146     // Validate the cursor position & number of characters
3147     if( ( static_cast< int >( mImpl->mEventData->mPrimaryCursorPosition ) + cursorOffset ) >= 0 )
3148     {
3149       cursorIndex = mImpl->mEventData->mPrimaryCursorPosition + cursorOffset;
3150     }
3151
3152     if( ( cursorIndex + numberOfCharacters ) > currentText.Count() )
3153     {
3154       numberOfCharacters = currentText.Count() - cursorIndex;
3155     }
3156
3157     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.
3158         ( ( cursorIndex + numberOfCharacters ) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) )
3159     {
3160       // Mark the paragraphs to be updated.
3161       if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
3162       {
3163         mImpl->mTextUpdateInfo.mCharacterIndex = 0;
3164         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3165         mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters;
3166         mImpl->mTextUpdateInfo.mClearAll = true;
3167       }
3168       else
3169       {
3170         mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
3171         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
3172       }
3173
3174       // Update the input style and remove the text's style before removing the text.
3175
3176       if( UPDATE_INPUT_STYLE == type )
3177       {
3178         // Keep a copy of the current input style.
3179         InputStyle currentInputStyle;
3180         currentInputStyle.Copy( mImpl->mEventData->mInputStyle );
3181
3182         // Set first the default input style.
3183         mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle );
3184
3185         // Update the input style.
3186         mImpl->mModel->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle );
3187
3188         // Compare if the input style has changed.
3189         const bool hasInputStyleChanged = !currentInputStyle.Equal( mImpl->mEventData->mInputStyle );
3190
3191         if( hasInputStyleChanged )
3192         {
3193           const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mImpl->mEventData->mInputStyle );
3194           // Queue the input style changed signal.
3195           mImpl->mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
3196         }
3197       }
3198
3199       // Updates the text style runs by removing characters. Runs with no characters are removed.
3200       mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters );
3201
3202       // Remove the characters.
3203       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
3204       Vector<Character>::Iterator last  = first + numberOfCharacters;
3205
3206       currentText.Erase( first, last );
3207
3208       // Cursor position retreat
3209       oldCursorIndex = cursorIndex;
3210
3211       mImpl->mEventData->mScrollAfterDelete = true;
3212
3213       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters );
3214       removed = true;
3215     }
3216   }
3217
3218   return removed;
3219 }
3220
3221 bool Controller::RemoveSelectedText()
3222 {
3223   bool textRemoved( false );
3224
3225   if( EventData::SELECTING == mImpl->mEventData->mState )
3226   {
3227     std::string removedString;
3228     mImpl->RetrieveSelection( removedString, true );
3229
3230     if( !removedString.empty() )
3231     {
3232       textRemoved = true;
3233       mImpl->ChangeState( EventData::EDITING );
3234     }
3235   }
3236
3237   return textRemoved;
3238 }
3239
3240 // private : Relayout.
3241
3242 bool Controller::DoRelayout( const Size& size,
3243                              OperationsMask operationsRequired,
3244                              Size& layoutSize )
3245 {
3246   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height );
3247   bool viewUpdated( false );
3248
3249   // Calculate the operations to be done.
3250   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
3251
3252   const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
3253   const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
3254
3255   // Get the current layout size.
3256   layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
3257
3258   if( NO_OPERATION != ( LAYOUT & operations ) )
3259   {
3260     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
3261
3262     // Some vectors with data needed to layout and reorder may be void
3263     // after the first time the text has been laid out.
3264     // Fill the vectors again.
3265
3266     // Calculate the number of glyphs to layout.
3267     const Vector<GlyphIndex>& charactersToGlyph = mImpl->mModel->mVisualModel->mCharactersToGlyph;
3268     const Vector<Length>& glyphsPerCharacter = mImpl->mModel->mVisualModel->mGlyphsPerCharacter;
3269     const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
3270     const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
3271
3272     const CharacterIndex lastIndex = startIndex + ( ( requestedNumberOfCharacters > 0u ) ? requestedNumberOfCharacters - 1u : 0u );
3273     const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
3274     const Length numberOfGlyphs = ( requestedNumberOfCharacters > 0u ) ? *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - startGlyphIndex : 0u;
3275     const Length totalNumberOfGlyphs = mImpl->mModel->mVisualModel->mGlyphs.Count();
3276
3277     if( 0u == totalNumberOfGlyphs )
3278     {
3279       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
3280       {
3281         mImpl->mModel->mVisualModel->SetLayoutSize( Size::ZERO );
3282       }
3283
3284       // Nothing else to do if there is no glyphs.
3285       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n" );
3286       return true;
3287     }
3288
3289     const Vector<LineBreakInfo>& lineBreakInfo = mImpl->mModel->mLogicalModel->mLineBreakInfo;
3290     const Vector<WordBreakInfo>& wordBreakInfo = mImpl->mModel->mLogicalModel->mWordBreakInfo;
3291     const Vector<CharacterDirection>& characterDirection = mImpl->mModel->mLogicalModel->mCharacterDirections;
3292     const Vector<GlyphInfo>& glyphs = mImpl->mModel->mVisualModel->mGlyphs;
3293     const Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mModel->mVisualModel->mGlyphsToCharacters;
3294     const Vector<Length>& charactersPerGlyph = mImpl->mModel->mVisualModel->mCharactersPerGlyph;
3295     const Character* const textBuffer = mImpl->mModel->mLogicalModel->mText.Begin();
3296
3297     // Set the layout parameters.
3298     Layout::Parameters layoutParameters( size,
3299                                          textBuffer,
3300                                          lineBreakInfo.Begin(),
3301                                          wordBreakInfo.Begin(),
3302                                          ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
3303                                          glyphs.Begin(),
3304                                          glyphsToCharactersMap.Begin(),
3305                                          charactersPerGlyph.Begin(),
3306                                          charactersToGlyphBuffer,
3307                                          glyphsPerCharacterBuffer,
3308                                          totalNumberOfGlyphs,
3309                                          mImpl->mModel->mHorizontalAlignment,
3310                                          mImpl->mModel->mLineWrapMode );
3311
3312     // Resize the vector of positions to have the same size than the vector of glyphs.
3313     Vector<Vector2>& glyphPositions = mImpl->mModel->mVisualModel->mGlyphPositions;
3314     glyphPositions.Resize( totalNumberOfGlyphs );
3315
3316     // Whether the last character is a new paragraph character.
3317     mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph =  TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mModel->mLogicalModel->mText.Count() - 1u ) ) );
3318     layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
3319
3320     // The initial glyph and the number of glyphs to layout.
3321     layoutParameters.startGlyphIndex = startGlyphIndex;
3322     layoutParameters.numberOfGlyphs = numberOfGlyphs;
3323     layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex;
3324     layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
3325
3326     // Update the ellipsis
3327     bool elideTextEnabled = mImpl->mModel->mElideEnabled;
3328
3329     if( NULL != mImpl->mEventData )
3330     {
3331       if( mImpl->mEventData->mPlaceholderEllipsisFlag && mImpl->IsShowingPlaceholderText() )
3332       {
3333         elideTextEnabled = mImpl->mEventData->mIsPlaceholderElideEnabled;
3334       }
3335       else if( EventData::INACTIVE != mImpl->mEventData->mState )
3336       {
3337         // Disable ellipsis when editing
3338         elideTextEnabled = false;
3339       }
3340
3341       // Reset the scroll position in inactive state
3342       if( elideTextEnabled && ( mImpl->mEventData->mState == EventData::INACTIVE ) )
3343       {
3344         ResetScrollPosition();
3345       }
3346     }
3347
3348     // Update the visual model.
3349     Size newLayoutSize;
3350     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
3351                                                    glyphPositions,
3352                                                    mImpl->mModel->mVisualModel->mLines,
3353                                                    newLayoutSize,
3354                                                    elideTextEnabled );
3355
3356     viewUpdated = viewUpdated || ( newLayoutSize != layoutSize );
3357
3358     if( viewUpdated )
3359     {
3360       layoutSize = newLayoutSize;
3361
3362       if( NO_OPERATION != ( UPDATE_DIRECTION & operations ) )
3363       {
3364         mImpl->mAutoScrollDirectionRTL = false;
3365       }
3366
3367       // Reorder the lines
3368       if( NO_OPERATION != ( REORDER & operations ) )
3369       {
3370         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mModel->mLogicalModel->mBidirectionalParagraphInfo;
3371         Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = mImpl->mModel->mLogicalModel->mBidirectionalLineInfo;
3372
3373         // Check first if there are paragraphs with bidirectional info.
3374         if( 0u != bidirectionalInfo.Count() )
3375         {
3376           // Get the lines
3377           const Length numberOfLines = mImpl->mModel->mVisualModel->mLines.Count();
3378
3379           // Reorder the lines.
3380           bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
3381           ReorderLines( bidirectionalInfo,
3382                         startIndex,
3383                         requestedNumberOfCharacters,
3384                         mImpl->mModel->mVisualModel->mLines,
3385                         bidirectionalLineInfo );
3386
3387           // Set the bidirectional info per line into the layout parameters.
3388           layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
3389           layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
3390
3391           // Re-layout the text. Reorder those lines with right to left characters.
3392           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
3393                                                          startIndex,
3394                                                          requestedNumberOfCharacters,
3395                                                          glyphPositions );
3396
3397           if ( ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) ) && ( numberOfLines > 0 ) )
3398           {
3399             const LineRun* const firstline = mImpl->mModel->mVisualModel->mLines.Begin();
3400             if ( firstline )
3401             {
3402               mImpl->mAutoScrollDirectionRTL = firstline->direction;
3403             }
3404           }
3405         }
3406       } // REORDER
3407
3408       // Sets the layout size.
3409       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
3410       {
3411         mImpl->mModel->mVisualModel->SetLayoutSize( layoutSize );
3412       }
3413     } // view updated
3414   }
3415
3416   if( NO_OPERATION != ( ALIGN & operations ) )
3417   {
3418     // The laid-out lines.
3419     Vector<LineRun>& lines = mImpl->mModel->mVisualModel->mLines;
3420
3421     // Need to align with the control's size as the text may contain lines
3422     // starting either with left to right text or right to left.
3423     mImpl->mLayoutEngine.Align( size,
3424                                 startIndex,
3425                                 requestedNumberOfCharacters,
3426                                 mImpl->mModel->mHorizontalAlignment,
3427                                 lines,
3428                                 mImpl->mModel->mAlignmentOffset );
3429
3430     viewUpdated = true;
3431   }
3432 #if defined(DEBUG_ENABLED)
3433   std::string currentText;
3434   GetText( currentText );
3435   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mAutoScrollDirectionRTL[%s] [%s]\n", this, (mImpl->mAutoScrollDirectionRTL)?"true":"false",  currentText.c_str() );
3436 #endif
3437   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
3438   return viewUpdated;
3439 }
3440
3441 void Controller::CalculateVerticalOffset( const Size& controlSize )
3442 {
3443   Size layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
3444
3445   if( fabsf( layoutSize.height ) < Math::MACHINE_EPSILON_1000 )
3446   {
3447     // Get the line height of the default font.
3448     layoutSize.height = mImpl->GetDefaultFontLineHeight();
3449   }
3450
3451   switch( mImpl->mModel->mVerticalAlignment )
3452   {
3453     case Layout::VERTICAL_ALIGN_TOP:
3454     {
3455       mImpl->mModel->mScrollPosition.y = 0.f;
3456       break;
3457     }
3458     case Layout::VERTICAL_ALIGN_CENTER:
3459     {
3460       mImpl->mModel->mScrollPosition.y = floorf( 0.5f * ( controlSize.height - layoutSize.height ) ); // try to avoid pixel alignment.
3461       break;
3462     }
3463     case Layout::VERTICAL_ALIGN_BOTTOM:
3464     {
3465       mImpl->mModel->mScrollPosition.y = controlSize.height - layoutSize.height;
3466       break;
3467     }
3468   }
3469 }
3470
3471 // private : Events.
3472
3473 void Controller::ProcessModifyEvents()
3474 {
3475   Vector<ModifyEvent>& events = mImpl->mModifyEvents;
3476
3477   if( 0u == events.Count() )
3478   {
3479     // Nothing to do.
3480     return;
3481   }
3482
3483   for( Vector<ModifyEvent>::ConstIterator it = events.Begin(),
3484          endIt = events.End();
3485        it != endIt;
3486        ++it )
3487   {
3488     const ModifyEvent& event = *it;
3489
3490     if( ModifyEvent::TEXT_REPLACED == event.type )
3491     {
3492       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
3493       DALI_ASSERT_DEBUG( it == events.Begin() && "Unexpected TEXT_REPLACED event" );
3494
3495       TextReplacedEvent();
3496     }
3497     else if( ModifyEvent::TEXT_INSERTED == event.type )
3498     {
3499       TextInsertedEvent();
3500     }
3501     else if( ModifyEvent::TEXT_DELETED == event.type )
3502     {
3503       // Placeholder-text cannot be deleted
3504       if( !mImpl->IsShowingPlaceholderText() )
3505       {
3506         TextDeletedEvent();
3507       }
3508     }
3509   }
3510
3511   if( NULL != mImpl->mEventData )
3512   {
3513     // When the text is being modified, delay cursor blinking
3514     mImpl->mEventData->mDecorator->DelayCursorBlink();
3515   }
3516
3517   // Discard temporary text
3518   events.Clear();
3519 }
3520
3521 void Controller::TextReplacedEvent()
3522 {
3523   // The natural size needs to be re-calculated.
3524   mImpl->mRecalculateNaturalSize = true;
3525
3526   // Apply modifications to the model
3527   mImpl->mOperationsPending = ALL_OPERATIONS;
3528 }
3529
3530 void Controller::TextInsertedEvent()
3531 {
3532   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" );
3533
3534   if( NULL == mImpl->mEventData )
3535   {
3536     return;
3537   }
3538
3539   mImpl->mEventData->mCheckScrollAmount = true;
3540
3541   // The natural size needs to be re-calculated.
3542   mImpl->mRecalculateNaturalSize = true;
3543
3544   // Apply modifications to the model; TODO - Optimize this
3545   mImpl->mOperationsPending = ALL_OPERATIONS;
3546 }
3547
3548 void Controller::TextDeletedEvent()
3549 {
3550   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" );
3551
3552   if( NULL == mImpl->mEventData )
3553   {
3554     return;
3555   }
3556
3557   mImpl->mEventData->mCheckScrollAmount = true;
3558
3559   // The natural size needs to be re-calculated.
3560   mImpl->mRecalculateNaturalSize = true;
3561
3562   // Apply modifications to the model; TODO - Optimize this
3563   mImpl->mOperationsPending = ALL_OPERATIONS;
3564 }
3565
3566 void Controller::SelectEvent( float x, float y, bool selectAll )
3567 {
3568   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" );
3569
3570   if( NULL != mImpl->mEventData )
3571   {
3572     if( selectAll )
3573     {
3574       Event event( Event::SELECT_ALL );
3575       mImpl->mEventData->mEventQueue.push_back( event );
3576     }
3577     else
3578     {
3579       Event event( Event::SELECT );
3580       event.p2.mFloat = x;
3581       event.p3.mFloat = y;
3582       mImpl->mEventData->mEventQueue.push_back( event );
3583     }
3584
3585     mImpl->mEventData->mCheckScrollAmount = true;
3586     mImpl->mEventData->mIsLeftHandleSelected = true;
3587     mImpl->mEventData->mIsRightHandleSelected = true;
3588     mImpl->RequestRelayout();
3589   }
3590 }
3591
3592 bool Controller::BackspaceKeyEvent()
3593 {
3594   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p DALI_KEY_BACKSPACE\n", this );
3595
3596   bool removed = false;
3597
3598   if( NULL == mImpl->mEventData )
3599   {
3600     return removed;
3601   }
3602
3603   // IMF manager is no longer handling key-events
3604   mImpl->ClearPreEditFlag();
3605
3606   if( EventData::SELECTING == mImpl->mEventData->mState )
3607   {
3608     removed = RemoveSelectedText();
3609   }
3610   else if( mImpl->mEventData->mPrimaryCursorPosition > 0 )
3611   {
3612     // Remove the character before the current cursor position
3613     removed = RemoveText( -1,
3614                           1,
3615                           UPDATE_INPUT_STYLE );
3616   }
3617
3618   if( removed )
3619   {
3620     if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
3621         !mImpl->IsPlaceholderAvailable() )
3622     {
3623       mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
3624     }
3625     else
3626     {
3627       ShowPlaceholderText();
3628     }
3629     mImpl->mEventData->mUpdateCursorPosition = true;
3630     mImpl->mEventData->mScrollAfterDelete = true;
3631   }
3632
3633   return removed;
3634 }
3635
3636 // private : Helpers.
3637
3638 void Controller::ResetText()
3639 {
3640   // Reset buffers.
3641   mImpl->mModel->mLogicalModel->mText.Clear();
3642
3643   // We have cleared everything including the placeholder-text
3644   mImpl->PlaceholderCleared();
3645
3646   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3647   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3648   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
3649
3650   // Clear any previous text.
3651   mImpl->mTextUpdateInfo.mClearAll = true;
3652
3653   // The natural size needs to be re-calculated.
3654   mImpl->mRecalculateNaturalSize = true;
3655
3656   // Apply modifications to the model
3657   mImpl->mOperationsPending = ALL_OPERATIONS;
3658 }
3659
3660 void Controller::ShowPlaceholderText()
3661 {
3662   if( mImpl->IsPlaceholderAvailable() )
3663   {
3664     DALI_ASSERT_DEBUG( mImpl->mEventData && "No placeholder text available" );
3665
3666     if( NULL == mImpl->mEventData )
3667     {
3668       return;
3669     }
3670
3671     mImpl->mEventData->mIsShowingPlaceholderText = true;
3672
3673     // Disable handles when showing place-holder text
3674     mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
3675     mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
3676     mImpl->mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
3677
3678     const char* text( NULL );
3679     size_t size( 0 );
3680
3681     // TODO - Switch Placeholder text when changing state
3682     if( ( EventData::INACTIVE != mImpl->mEventData->mState ) &&
3683         ( 0u != mImpl->mEventData->mPlaceholderTextActive.c_str() ) )
3684     {
3685       text = mImpl->mEventData->mPlaceholderTextActive.c_str();
3686       size = mImpl->mEventData->mPlaceholderTextActive.size();
3687     }
3688     else
3689     {
3690       text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
3691       size = mImpl->mEventData->mPlaceholderTextInactive.size();
3692     }
3693
3694     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3695     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3696
3697     // Reset model for showing placeholder.
3698     mImpl->mModel->mLogicalModel->mText.Clear();
3699     mImpl->mModel->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor );
3700
3701     // Convert text into UTF-32
3702     Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
3703     utf32Characters.Resize( size );
3704
3705     // This is a bit horrible but std::string returns a (signed) char*
3706     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text );
3707
3708     // Transform a text array encoded in utf8 into an array encoded in utf32.
3709     // It returns the actual number of characters.
3710     const Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() );
3711     utf32Characters.Resize( characterCount );
3712
3713     // The characters to be added.
3714     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount;
3715
3716     // Reset the cursor position
3717     mImpl->mEventData->mPrimaryCursorPosition = 0;
3718
3719     // The natural size needs to be re-calculated.
3720     mImpl->mRecalculateNaturalSize = true;
3721
3722     // Apply modifications to the model
3723     mImpl->mOperationsPending = ALL_OPERATIONS;
3724
3725     // Update the rest of the model during size negotiation
3726     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
3727   }
3728 }
3729
3730 void Controller::ClearFontData()
3731 {
3732   if( mImpl->mFontDefaults )
3733   {
3734     mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
3735   }
3736
3737   // Set flags to update the model.
3738   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3739   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3740   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
3741
3742   mImpl->mTextUpdateInfo.mClearAll = true;
3743   mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
3744   mImpl->mRecalculateNaturalSize = true;
3745
3746   mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
3747                                                            VALIDATE_FONTS            |
3748                                                            SHAPE_TEXT                |
3749                                                            GET_GLYPH_METRICS         |
3750                                                            LAYOUT                    |
3751                                                            UPDATE_LAYOUT_SIZE        |
3752                                                            REORDER                   |
3753                                                            ALIGN );
3754 }
3755
3756 void Controller::ClearStyleData()
3757 {
3758   mImpl->mModel->mLogicalModel->mColorRuns.Clear();
3759   mImpl->mModel->mLogicalModel->ClearFontDescriptionRuns();
3760 }
3761
3762 void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
3763 {
3764   // Reset the cursor position
3765   if( NULL != mImpl->mEventData )
3766   {
3767     mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
3768
3769     // Update the cursor if it's in editing mode.
3770     if( EventData::IsEditingState( mImpl->mEventData->mState )  )
3771     {
3772       mImpl->mEventData->mUpdateCursorPosition = true;
3773     }
3774   }
3775 }
3776
3777 void Controller::ResetScrollPosition()
3778 {
3779   if( NULL != mImpl->mEventData )
3780   {
3781     // Reset the scroll position.
3782     mImpl->mModel->mScrollPosition = Vector2::ZERO;
3783     mImpl->mEventData->mScrollAfterUpdatePosition = true;
3784   }
3785 }
3786
3787 void Controller::SetControlInterface( ControlInterface* controlInterface )
3788 {
3789   mImpl->mControlInterface = controlInterface;
3790 }
3791
3792 bool Controller::ShouldClearFocusOnEscape() const
3793 {
3794   return mImpl->mShouldClearFocusOnEscape;
3795 }
3796
3797 // private : Private contructors & copy operator.
3798
3799 Controller::Controller()
3800 : mImpl( NULL )
3801 {
3802   mImpl = new Controller::Impl( NULL, NULL );
3803 }
3804
3805 Controller::Controller( ControlInterface* controlInterface )
3806 {
3807   mImpl = new Controller::Impl( controlInterface, NULL );
3808 }
3809
3810 Controller::Controller( ControlInterface* controlInterface,
3811                         EditableControlInterface* editableControlInterface )
3812 {
3813   mImpl = new Controller::Impl( controlInterface,
3814                                 editableControlInterface );
3815 }
3816
3817 // The copy constructor and operator are left unimplemented.
3818
3819 // protected : Destructor.
3820
3821 Controller::~Controller()
3822 {
3823   delete mImpl;
3824 }
3825
3826 } // namespace Text
3827
3828 } // namespace Toolkit
3829
3830 } // namespace Dali