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