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