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