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