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