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