Merge "Add ENABLE_SHIFT_SELECTION property" 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 void Controller::SetDefaultLineSpacing( float lineSpacing )
1248 {
1249   //TODO finish implementation
1250   mImpl->mLayoutEngine.SetDefaultLineSpacing( lineSpacing );
1251 }
1252
1253 float Controller::GetDefaultLineSpacing() const
1254 {
1255   return mImpl->mLayoutEngine.GetDefaultLineSpacing();
1256 }
1257
1258 void Controller::SetInputColor( const Vector4& color )
1259 {
1260   if( NULL != mImpl->mEventData )
1261   {
1262     mImpl->mEventData->mInputStyle.textColor = color;
1263     mImpl->mEventData->mInputStyle.isDefaultColor = false;
1264
1265     if( EventData::SELECTING == mImpl->mEventData->mState )
1266     {
1267       const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition;
1268
1269       // Get start and end position of selection
1270       const CharacterIndex startOfSelectedText = handlesCrossed ? mImpl->mEventData->mRightSelectionPosition : mImpl->mEventData->mLeftSelectionPosition;
1271       const Length lengthOfSelectedText = ( handlesCrossed ? mImpl->mEventData->mLeftSelectionPosition : mImpl->mEventData->mRightSelectionPosition ) - startOfSelectedText;
1272
1273       // Add the color run.
1274       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
1275       mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
1276
1277       ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
1278       colorRun.color = color;
1279       colorRun.characterRun.characterIndex = startOfSelectedText;
1280       colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
1281
1282       // Request to relayout.
1283       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
1284       mImpl->RequestRelayout();
1285
1286       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1287       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1288       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1289     }
1290   }
1291 }
1292
1293 const Vector4& Controller::GetInputColor() const
1294 {
1295   if( NULL != mImpl->mEventData )
1296   {
1297     return mImpl->mEventData->mInputStyle.textColor;
1298   }
1299
1300   // Return the default text's color if there is no EventData.
1301   return mImpl->mTextColor;
1302
1303 }
1304
1305 void Controller::SetInputFontFamily( const std::string& fontFamily )
1306 {
1307   if( NULL != mImpl->mEventData )
1308   {
1309     mImpl->mEventData->mInputStyle.familyName = fontFamily;
1310     mImpl->mEventData->mInputStyle.isFamilyDefined = true;
1311
1312     if( EventData::SELECTING == mImpl->mEventData->mState )
1313     {
1314       CharacterIndex startOfSelectedText = 0u;
1315       Length lengthOfSelectedText = 0u;
1316       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1317                                                                             mImpl->mModel->mLogicalModel,
1318                                                                             startOfSelectedText,
1319                                                                             lengthOfSelectedText );
1320
1321       fontDescriptionRun.familyLength = fontFamily.size();
1322       fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
1323       memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength );
1324       fontDescriptionRun.familyDefined = true;
1325
1326       // The memory allocated for the font family name is freed when the font description is removed from the logical model.
1327
1328       // Request to relayout.
1329       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1330                                                                VALIDATE_FONTS            |
1331                                                                SHAPE_TEXT                |
1332                                                                GET_GLYPH_METRICS         |
1333                                                                LAYOUT                    |
1334                                                                UPDATE_LAYOUT_SIZE        |
1335                                                                REORDER                   |
1336                                                                ALIGN );
1337       mImpl->mRecalculateNaturalSize = true;
1338       mImpl->RequestRelayout();
1339
1340       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1341       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1342       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1343
1344       // As the font changes, recalculate the handle positions is needed.
1345       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1346       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1347       mImpl->mEventData->mUpdateHighlightBox = true;
1348       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1349     }
1350   }
1351 }
1352
1353 const std::string& Controller::GetInputFontFamily() const
1354 {
1355   if( NULL != mImpl->mEventData )
1356   {
1357     return mImpl->mEventData->mInputStyle.familyName;
1358   }
1359
1360   // Return the default font's family if there is no EventData.
1361   return GetDefaultFontFamily();
1362 }
1363
1364 void Controller::SetInputFontWeight( FontWeight weight )
1365 {
1366   if( NULL != mImpl->mEventData )
1367   {
1368     mImpl->mEventData->mInputStyle.weight = weight;
1369     mImpl->mEventData->mInputStyle.isWeightDefined = true;
1370
1371     if( EventData::SELECTING == mImpl->mEventData->mState )
1372     {
1373       CharacterIndex startOfSelectedText = 0u;
1374       Length lengthOfSelectedText = 0u;
1375       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1376                                                                             mImpl->mModel->mLogicalModel,
1377                                                                             startOfSelectedText,
1378                                                                             lengthOfSelectedText );
1379
1380       fontDescriptionRun.weight = weight;
1381       fontDescriptionRun.weightDefined = true;
1382
1383       // Request to relayout.
1384       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1385                                                                VALIDATE_FONTS            |
1386                                                                SHAPE_TEXT                |
1387                                                                GET_GLYPH_METRICS         |
1388                                                                LAYOUT                    |
1389                                                                UPDATE_LAYOUT_SIZE        |
1390                                                                REORDER                   |
1391                                                                ALIGN );
1392       mImpl->mRecalculateNaturalSize = true;
1393       mImpl->RequestRelayout();
1394
1395       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1396       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1397       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1398
1399       // As the font might change, recalculate the handle positions is needed.
1400       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1401       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1402       mImpl->mEventData->mUpdateHighlightBox = true;
1403       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1404     }
1405   }
1406 }
1407
1408 bool Controller::IsInputFontWeightDefined() const
1409 {
1410   bool defined = false;
1411
1412   if( NULL != mImpl->mEventData )
1413   {
1414     defined = mImpl->mEventData->mInputStyle.isWeightDefined;
1415   }
1416
1417   return defined;
1418 }
1419
1420 FontWeight Controller::GetInputFontWeight() const
1421 {
1422   if( NULL != mImpl->mEventData )
1423   {
1424     return mImpl->mEventData->mInputStyle.weight;
1425   }
1426
1427   return GetDefaultFontWeight();
1428 }
1429
1430 void Controller::SetInputFontWidth( FontWidth width )
1431 {
1432   if( NULL != mImpl->mEventData )
1433   {
1434     mImpl->mEventData->mInputStyle.width = width;
1435     mImpl->mEventData->mInputStyle.isWidthDefined = true;
1436
1437     if( EventData::SELECTING == mImpl->mEventData->mState )
1438     {
1439       CharacterIndex startOfSelectedText = 0u;
1440       Length lengthOfSelectedText = 0u;
1441       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1442                                                                             mImpl->mModel->mLogicalModel,
1443                                                                             startOfSelectedText,
1444                                                                             lengthOfSelectedText );
1445
1446       fontDescriptionRun.width = width;
1447       fontDescriptionRun.widthDefined = true;
1448
1449       // Request to relayout.
1450       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1451                                                                VALIDATE_FONTS            |
1452                                                                SHAPE_TEXT                |
1453                                                                GET_GLYPH_METRICS         |
1454                                                                LAYOUT                    |
1455                                                                UPDATE_LAYOUT_SIZE        |
1456                                                                REORDER                   |
1457                                                                ALIGN );
1458       mImpl->mRecalculateNaturalSize = true;
1459       mImpl->RequestRelayout();
1460
1461       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1462       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1463       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1464
1465       // As the font might change, recalculate the handle positions is needed.
1466       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1467       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1468       mImpl->mEventData->mUpdateHighlightBox = true;
1469       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1470     }
1471   }
1472 }
1473
1474 bool Controller::IsInputFontWidthDefined() const
1475 {
1476   bool defined = false;
1477
1478   if( NULL != mImpl->mEventData )
1479   {
1480     defined = mImpl->mEventData->mInputStyle.isWidthDefined;
1481   }
1482
1483   return defined;
1484 }
1485
1486 FontWidth Controller::GetInputFontWidth() const
1487 {
1488   if( NULL != mImpl->mEventData )
1489   {
1490     return mImpl->mEventData->mInputStyle.width;
1491   }
1492
1493   return GetDefaultFontWidth();
1494 }
1495
1496 void Controller::SetInputFontSlant( FontSlant slant )
1497 {
1498   if( NULL != mImpl->mEventData )
1499   {
1500     mImpl->mEventData->mInputStyle.slant = slant;
1501     mImpl->mEventData->mInputStyle.isSlantDefined = true;
1502
1503     if( EventData::SELECTING == mImpl->mEventData->mState )
1504     {
1505       CharacterIndex startOfSelectedText = 0u;
1506       Length lengthOfSelectedText = 0u;
1507       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1508                                                                             mImpl->mModel->mLogicalModel,
1509                                                                             startOfSelectedText,
1510                                                                             lengthOfSelectedText );
1511
1512       fontDescriptionRun.slant = slant;
1513       fontDescriptionRun.slantDefined = true;
1514
1515       // Request to relayout.
1516       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1517                                                                VALIDATE_FONTS            |
1518                                                                SHAPE_TEXT                |
1519                                                                GET_GLYPH_METRICS         |
1520                                                                LAYOUT                    |
1521                                                                UPDATE_LAYOUT_SIZE        |
1522                                                                REORDER                   |
1523                                                                ALIGN );
1524       mImpl->mRecalculateNaturalSize = true;
1525       mImpl->RequestRelayout();
1526
1527       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1528       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1529       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1530
1531       // As the font might change, recalculate the handle positions is needed.
1532       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1533       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1534       mImpl->mEventData->mUpdateHighlightBox = true;
1535       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1536     }
1537   }
1538 }
1539
1540 bool Controller::IsInputFontSlantDefined() const
1541 {
1542   bool defined = false;
1543
1544   if( NULL != mImpl->mEventData )
1545   {
1546     defined = mImpl->mEventData->mInputStyle.isSlantDefined;
1547   }
1548
1549   return defined;
1550 }
1551
1552 FontSlant Controller::GetInputFontSlant() const
1553 {
1554   if( NULL != mImpl->mEventData )
1555   {
1556     return mImpl->mEventData->mInputStyle.slant;
1557   }
1558
1559   return GetDefaultFontSlant();
1560 }
1561
1562 void Controller::SetInputFontPointSize( float size )
1563 {
1564   if( NULL != mImpl->mEventData )
1565   {
1566     mImpl->mEventData->mInputStyle.size = size;
1567     mImpl->mEventData->mInputStyle.isSizeDefined = true;
1568
1569     if( EventData::SELECTING == mImpl->mEventData->mState )
1570     {
1571       CharacterIndex startOfSelectedText = 0u;
1572       Length lengthOfSelectedText = 0u;
1573       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
1574                                                                             mImpl->mModel->mLogicalModel,
1575                                                                             startOfSelectedText,
1576                                                                             lengthOfSelectedText );
1577
1578       fontDescriptionRun.size = static_cast<PointSize26Dot6>( size * 64.f );
1579       fontDescriptionRun.sizeDefined = true;
1580
1581       // Request to relayout.
1582       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
1583                                                                VALIDATE_FONTS            |
1584                                                                SHAPE_TEXT                |
1585                                                                GET_GLYPH_METRICS         |
1586                                                                LAYOUT                    |
1587                                                                UPDATE_LAYOUT_SIZE        |
1588                                                                REORDER                   |
1589                                                                ALIGN );
1590       mImpl->mRecalculateNaturalSize = true;
1591       mImpl->RequestRelayout();
1592
1593       mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1594       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1595       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1596
1597       // As the font might change, recalculate the handle positions is needed.
1598       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
1599       mImpl->mEventData->mUpdateRightSelectionPosition = true;
1600       mImpl->mEventData->mUpdateHighlightBox = true;
1601       mImpl->mEventData->mScrollAfterUpdatePosition = true;
1602     }
1603   }
1604 }
1605
1606 float Controller::GetInputFontPointSize() const
1607 {
1608   if( NULL != mImpl->mEventData )
1609   {
1610     return mImpl->mEventData->mInputStyle.size;
1611   }
1612
1613   // Return the default font's point size if there is no EventData.
1614   return GetDefaultFontSize( Text::Controller::POINT_SIZE );
1615 }
1616
1617 void Controller::SetInputLineSpacing( float lineSpacing )
1618 {
1619   if( NULL != mImpl->mEventData )
1620   {
1621     mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing;
1622     mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
1623   }
1624 }
1625
1626 float Controller::GetInputLineSpacing() const
1627 {
1628   if( NULL != mImpl->mEventData )
1629   {
1630     return mImpl->mEventData->mInputStyle.lineSpacing;
1631   }
1632
1633   return 0.f;
1634 }
1635
1636 void Controller::SetInputShadowProperties( const std::string& shadowProperties )
1637 {
1638   if( NULL != mImpl->mEventData )
1639   {
1640     mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
1641   }
1642 }
1643
1644 const std::string& Controller::GetInputShadowProperties() const
1645 {
1646   if( NULL != mImpl->mEventData )
1647   {
1648     return mImpl->mEventData->mInputStyle.shadowProperties;
1649   }
1650
1651   return EMPTY_STRING;
1652 }
1653
1654 void Controller::SetInputUnderlineProperties( const std::string& underlineProperties )
1655 {
1656   if( NULL != mImpl->mEventData )
1657   {
1658     mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
1659   }
1660 }
1661
1662 const std::string& Controller::GetInputUnderlineProperties() const
1663 {
1664   if( NULL != mImpl->mEventData )
1665   {
1666     return mImpl->mEventData->mInputStyle.underlineProperties;
1667   }
1668
1669   return EMPTY_STRING;
1670 }
1671
1672 void Controller::SetInputEmbossProperties( const std::string& embossProperties )
1673 {
1674   if( NULL != mImpl->mEventData )
1675   {
1676     mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
1677   }
1678 }
1679
1680 const std::string& Controller::GetInputEmbossProperties() const
1681 {
1682   if( NULL != mImpl->mEventData )
1683   {
1684     return mImpl->mEventData->mInputStyle.embossProperties;
1685   }
1686
1687   return GetDefaultEmbossProperties();
1688 }
1689
1690 void Controller::SetInputOutlineProperties( const std::string& outlineProperties )
1691 {
1692   if( NULL != mImpl->mEventData )
1693   {
1694     mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
1695   }
1696 }
1697
1698 const std::string& Controller::GetInputOutlineProperties() const
1699 {
1700   if( NULL != mImpl->mEventData )
1701   {
1702     return mImpl->mEventData->mInputStyle.outlineProperties;
1703   }
1704
1705   return GetDefaultOutlineProperties();
1706 }
1707
1708 void Controller::SetInputModePassword( bool passwordInput )
1709 {
1710   if( NULL != mImpl->mEventData )
1711   {
1712     mImpl->mEventData->mPasswordInput = passwordInput;
1713   }
1714 }
1715
1716 bool Controller::IsInputModePassword()
1717 {
1718   if( NULL != mImpl->mEventData )
1719   {
1720     return mImpl->mEventData->mPasswordInput;
1721   }
1722   return false;
1723 }
1724
1725 void Controller::SetNoTextDoubleTapAction( NoTextTap::Action action )
1726 {
1727   if( NULL != mImpl->mEventData )
1728   {
1729     mImpl->mEventData->mDoubleTapAction = action;
1730   }
1731 }
1732
1733 Controller::NoTextTap::Action Controller::GetNoTextDoubleTapAction() const
1734 {
1735   NoTextTap::Action action = NoTextTap::NO_ACTION;
1736
1737   if( NULL != mImpl->mEventData )
1738   {
1739     action = mImpl->mEventData->mDoubleTapAction;
1740   }
1741
1742   return action;
1743 }
1744
1745 void Controller::SetNoTextLongPressAction( NoTextTap::Action action )
1746 {
1747   if( NULL != mImpl->mEventData )
1748   {
1749     mImpl->mEventData->mLongPressAction = action;
1750   }
1751 }
1752
1753 Controller::NoTextTap::Action Controller::GetNoTextLongPressAction() const
1754 {
1755   NoTextTap::Action action = NoTextTap::NO_ACTION;
1756
1757   if( NULL != mImpl->mEventData )
1758   {
1759     action = mImpl->mEventData->mLongPressAction;
1760   }
1761
1762   return action;
1763 }
1764
1765 bool Controller::IsUnderlineSetByString()
1766 {
1767   return mImpl->mUnderlineSetByString;
1768 }
1769
1770 void Controller::UnderlineSetByString( bool setByString )
1771 {
1772   mImpl->mUnderlineSetByString = setByString;
1773 }
1774
1775 bool Controller::IsShadowSetByString()
1776 {
1777   return mImpl->mShadowSetByString;
1778 }
1779
1780 void Controller::ShadowSetByString( bool setByString )
1781 {
1782   mImpl->mShadowSetByString = setByString;
1783 }
1784
1785 bool Controller::IsOutlineSetByString()
1786 {
1787   return mImpl->mOutlineSetByString;
1788 }
1789
1790 void Controller::OutlineSetByString( bool setByString )
1791 {
1792   mImpl->mOutlineSetByString = setByString;
1793 }
1794
1795 bool Controller::IsFontStyleSetByString()
1796 {
1797   return mImpl->mFontStyleSetByString;
1798 }
1799
1800 void Controller::FontStyleSetByString( bool setByString )
1801 {
1802   mImpl->mFontStyleSetByString = setByString;
1803 }
1804
1805 // public : Queries & retrieves.
1806
1807 Layout::Engine& Controller::GetLayoutEngine()
1808 {
1809   return mImpl->mLayoutEngine;
1810 }
1811
1812 View& Controller::GetView()
1813 {
1814   return mImpl->mView;
1815 }
1816
1817 Vector3 Controller::GetNaturalSize()
1818 {
1819   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n" );
1820   Vector3 naturalSize;
1821
1822   // Make sure the model is up-to-date before layouting
1823   ProcessModifyEvents();
1824
1825   if( mImpl->mRecalculateNaturalSize )
1826   {
1827     // Operations that can be done only once until the text changes.
1828     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1829                                                                            GET_SCRIPTS       |
1830                                                                            VALIDATE_FONTS    |
1831                                                                            GET_LINE_BREAKS   |
1832                                                                            GET_WORD_BREAKS   |
1833                                                                            BIDI_INFO         |
1834                                                                            SHAPE_TEXT        |
1835                                                                            GET_GLYPH_METRICS );
1836
1837     // Set the update info to relayout the whole text.
1838     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1839     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1840
1841     // Make sure the model is up-to-date before layouting
1842     mImpl->UpdateModel( onlyOnceOperations );
1843
1844     // Layout the text for the new width.
1845     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT | REORDER );
1846
1847     // Store the actual control's size to restore later.
1848     const Size actualControlSize = mImpl->mModel->mVisualModel->mControlSize;
1849
1850     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
1851                 static_cast<OperationsMask>( onlyOnceOperations |
1852                                              LAYOUT | REORDER ),
1853                 naturalSize.GetVectorXY() );
1854
1855     // Do not do again the only once operations.
1856     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1857
1858     // Do the size related operations again.
1859     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1860                                                                         ALIGN  |
1861                                                                         REORDER );
1862     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1863
1864     // Stores the natural size to avoid recalculate it again
1865     // unless the text/style changes.
1866     mImpl->mModel->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
1867
1868     mImpl->mRecalculateNaturalSize = false;
1869
1870     // Clear the update info. This info will be set the next time the text is updated.
1871     mImpl->mTextUpdateInfo.Clear();
1872
1873     // Restore the actual control's size.
1874     mImpl->mModel->mVisualModel->mControlSize = actualControlSize;
1875
1876     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1877   }
1878   else
1879   {
1880     naturalSize = mImpl->mModel->mVisualModel->GetNaturalSize();
1881
1882     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
1883   }
1884
1885   naturalSize.x = ConvertToEven( naturalSize.x );
1886   naturalSize.y = ConvertToEven( naturalSize.y );
1887
1888   return naturalSize;
1889 }
1890
1891 float Controller::GetHeightForWidth( float width )
1892 {
1893   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width );
1894   // Make sure the model is up-to-date before layouting
1895   ProcessModifyEvents();
1896
1897   Size layoutSize;
1898   if( fabsf( width - mImpl->mModel->mVisualModel->mControlSize.width ) > Math::MACHINE_EPSILON_1000 ||
1899                                                          mImpl->mTextUpdateInfo.mFullRelayoutNeeded ||
1900                                                          mImpl->mTextUpdateInfo.mClearAll            )
1901   {
1902     // Operations that can be done only once until the text changes.
1903     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
1904                                                                            GET_SCRIPTS       |
1905                                                                            VALIDATE_FONTS    |
1906                                                                            GET_LINE_BREAKS   |
1907                                                                            GET_WORD_BREAKS   |
1908                                                                            BIDI_INFO         |
1909                                                                            SHAPE_TEXT        |
1910                                                                            GET_GLYPH_METRICS );
1911
1912     // Set the update info to relayout the whole text.
1913     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1914     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1915
1916     // Make sure the model is up-to-date before layouting
1917     mImpl->UpdateModel( onlyOnceOperations );
1918
1919
1920     // Layout the text for the new width.
1921     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
1922
1923     // Store the actual control's width.
1924     const float actualControlWidth = mImpl->mModel->mVisualModel->mControlSize.width;
1925
1926     DoRelayout( Size( width, MAX_FLOAT ),
1927                 static_cast<OperationsMask>( onlyOnceOperations |
1928                                              LAYOUT ),
1929                 layoutSize );
1930
1931     // Do not do again the only once operations.
1932     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
1933
1934     // Do the size related operations again.
1935     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
1936                                                                         ALIGN  |
1937                                                                         REORDER );
1938
1939     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
1940
1941     // Clear the update info. This info will be set the next time the text is updated.
1942     mImpl->mTextUpdateInfo.Clear();
1943
1944     // Restore the actual control's width.
1945     mImpl->mModel->mVisualModel->mControlSize.width = actualControlWidth;
1946
1947     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height );
1948   }
1949   else
1950   {
1951     layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
1952     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height );
1953   }
1954
1955   return layoutSize.height;
1956 }
1957
1958 int Controller::GetLineCount( float width )
1959 {
1960   GetHeightForWidth( width );
1961   int numberofLines = mImpl->mModel->GetNumberOfLines();
1962   return numberofLines;
1963 }
1964
1965 const ModelInterface* const Controller::GetTextModel() const
1966 {
1967   return mImpl->mModel.Get();
1968 }
1969
1970 float Controller::GetScrollAmountByUserInput()
1971 {
1972   float scrollAmount = 0.0f;
1973
1974   if (NULL != mImpl->mEventData && mImpl->mEventData->mCheckScrollAmount)
1975   {
1976     scrollAmount = mImpl->mModel->mScrollPosition.y -  mImpl->mModel->mScrollPositionLast.y;
1977     mImpl->mEventData->mCheckScrollAmount = false;
1978   }
1979   return scrollAmount;
1980 }
1981
1982 bool Controller::GetTextScrollInfo( float& scrollPosition, float& controlHeight, float& layoutHeight )
1983 {
1984   const Vector2& layout = mImpl->mModel->mVisualModel->GetLayoutSize();
1985   bool isScrolled;
1986
1987   controlHeight = mImpl->mModel->mVisualModel->mControlSize.height;
1988   layoutHeight = layout.height;
1989   scrollPosition = mImpl->mModel->mScrollPosition.y;
1990   isScrolled = !Equals( mImpl->mModel->mScrollPosition.y, mImpl->mModel->mScrollPositionLast.y, Math::MACHINE_EPSILON_1 );
1991   return isScrolled;
1992 }
1993
1994 void Controller::SetHiddenInputOption(const Property::Map& options )
1995 {
1996   if( NULL == mImpl->mHiddenInput )
1997   {
1998     mImpl->mHiddenInput = new HiddenText( this );
1999   }
2000   mImpl->mHiddenInput->SetProperties(options);
2001 }
2002
2003 void Controller::GetHiddenInputOption(Property::Map& options )
2004 {
2005   if( NULL != mImpl->mHiddenInput )
2006   {
2007     mImpl->mHiddenInput->GetProperties(options);
2008   }
2009 }
2010
2011 void Controller::SetPlaceholderProperty( const Property::Map& map )
2012 {
2013   const Property::Map::SizeType count = map.Count();
2014
2015   for( Property::Map::SizeType position = 0; position < count; ++position )
2016   {
2017     KeyValuePair keyValue = map.GetKeyValue( position );
2018     Property::Key& key = keyValue.first;
2019     Property::Value& value = keyValue.second;
2020
2021     if( key == Toolkit::Text::PlaceHolder::Property::TEXT  || key == PLACEHOLDER_TEXT )
2022     {
2023       std::string text = "";
2024       value.Get( text );
2025       SetPlaceholderText( Controller::PLACEHOLDER_TYPE_INACTIVE, text );
2026     }
2027     else if( key == Toolkit::Text::PlaceHolder::Property::TEXT_FOCUSED || key == PLACEHOLDER_TEXT_FOCUSED )
2028     {
2029       std::string text = "";
2030       value.Get( text );
2031       SetPlaceholderText( Controller::PLACEHOLDER_TYPE_ACTIVE, text );
2032     }
2033     else if( key == Toolkit::Text::PlaceHolder::Property::COLOR || key == PLACEHOLDER_COLOR )
2034     {
2035       Vector4 textColor;
2036       value.Get( textColor );
2037       if( GetPlaceholderTextColor() != textColor )
2038       {
2039         SetPlaceholderTextColor( textColor );
2040       }
2041     }
2042     else if( key == Toolkit::Text::PlaceHolder::Property::FONT_FAMILY || key == PLACEHOLDER_FONT_FAMILY )
2043     {
2044       std::string fontFamily = "";
2045       value.Get( fontFamily );
2046       SetPlaceholderFontFamily( fontFamily );
2047     }
2048     else if( key == Toolkit::Text::PlaceHolder::Property::FONT_STYLE || key == PLACEHOLDER_FONT_STYLE )
2049     {
2050       SetFontStyleProperty( this, value, Text::FontStyle::PLACEHOLDER );
2051     }
2052     else if( key == Toolkit::Text::PlaceHolder::Property::POINT_SIZE || key == PLACEHOLDER_POINT_SIZE )
2053     {
2054       float pointSize;
2055       value.Get( pointSize );
2056       if( !Equals( GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE ), pointSize ) )
2057       {
2058         SetPlaceholderTextFontSize( pointSize, Text::Controller::POINT_SIZE );
2059       }
2060     }
2061     else if( key == Toolkit::Text::PlaceHolder::Property::PIXEL_SIZE || key == PLACEHOLDER_PIXEL_SIZE )
2062     {
2063       float pixelSize;
2064       value.Get( pixelSize );
2065       if( !Equals( GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE ), pixelSize ) )
2066       {
2067         SetPlaceholderTextFontSize( pixelSize, Text::Controller::PIXEL_SIZE );
2068       }
2069     }
2070     else if( key == Toolkit::Text::PlaceHolder::Property::ELLIPSIS || key == PLACEHOLDER_ELLIPSIS )
2071     {
2072       bool ellipsis;
2073       value.Get( ellipsis );
2074       SetPlaceholderTextElideEnabled( ellipsis );
2075     }
2076   }
2077 }
2078
2079 void Controller::GetPlaceholderProperty( Property::Map& map )
2080 {
2081   if( NULL != mImpl->mEventData )
2082   {
2083     if( !mImpl->mEventData->mPlaceholderTextActive.empty() )
2084     {
2085       map[ Text::PlaceHolder::Property::TEXT_FOCUSED ] = mImpl->mEventData->mPlaceholderTextActive;
2086     }
2087     if( !mImpl->mEventData->mPlaceholderTextInactive.empty() )
2088     {
2089       map[ Text::PlaceHolder::Property::TEXT ] = mImpl->mEventData->mPlaceholderTextInactive;
2090     }
2091
2092     map[ Text::PlaceHolder::Property::COLOR ] = mImpl->mEventData->mPlaceholderTextColor;
2093     map[ Text::PlaceHolder::Property::FONT_FAMILY ] = GetPlaceholderFontFamily();
2094
2095     Property::Value fontStyleMapGet;
2096     GetFontStyleProperty( this, fontStyleMapGet, Text::FontStyle::PLACEHOLDER );
2097     map[ Text::PlaceHolder::Property::FONT_STYLE ] = fontStyleMapGet;
2098
2099     // Choose font size : POINT_SIZE or PIXEL_SIZE
2100     if( !mImpl->mEventData->mIsPlaceholderPixelSize )
2101     {
2102       map[ Text::PlaceHolder::Property::POINT_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE );
2103     }
2104     else
2105     {
2106       map[ Text::PlaceHolder::Property::PIXEL_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE );
2107     }
2108
2109     if( mImpl->mEventData->mPlaceholderEllipsisFlag )
2110     {
2111       map[ Text::PlaceHolder::Property::ELLIPSIS ] = IsPlaceholderTextElideEnabled();
2112     }
2113   }
2114 }
2115
2116 Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection()
2117 {
2118   if( ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) )
2119   {
2120     return Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
2121   }
2122
2123   const Character character = mImpl->mModel->mLogicalModel->mText[0];
2124   Script script = TextAbstraction::GetCharacterScript( character );
2125
2126   if( TextAbstraction::IsRightToLeftScript( script ) )
2127   {
2128     return Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT;
2129   }
2130
2131   return Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
2132 }
2133
2134 // public : Relayout.
2135
2136 Controller::UpdateTextType Controller::Relayout( const Size& size )
2137 {
2138   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, mImpl->mIsAutoScrollEnabled ?"true":"false"  );
2139
2140   UpdateTextType updateTextType = NONE_UPDATED;
2141
2142   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
2143   {
2144     if( 0u != mImpl->mModel->mVisualModel->mGlyphPositions.Count() )
2145     {
2146       mImpl->mModel->mVisualModel->mGlyphPositions.Clear();
2147       updateTextType = MODEL_UPDATED;
2148     }
2149
2150     // Clear the update info. This info will be set the next time the text is updated.
2151     mImpl->mTextUpdateInfo.Clear();
2152
2153     // Not worth to relayout if width or height is equal to zero.
2154     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
2155
2156     return updateTextType;
2157   }
2158
2159   // Whether a new size has been set.
2160   const bool newSize = ( size != mImpl->mModel->mVisualModel->mControlSize );
2161
2162   if( newSize )
2163   {
2164     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mModel->mVisualModel->mControlSize.width, mImpl->mModel->mVisualModel->mControlSize.height );
2165
2166     // Layout operations that need to be done if the size changes.
2167     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2168                                                              LAYOUT                    |
2169                                                              ALIGN                     |
2170                                                              UPDATE_LAYOUT_SIZE        |
2171                                                              REORDER );
2172     // Set the update info to relayout the whole text.
2173     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2174     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2175
2176     // Store the size used to layout the text.
2177     mImpl->mModel->mVisualModel->mControlSize = size;
2178   }
2179
2180   // Whether there are modify events.
2181   if( 0u != mImpl->mModifyEvents.Count() )
2182   {
2183     // Style operations that need to be done if the text is modified.
2184     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2185                                                              COLOR );
2186   }
2187
2188   // Set the update info to elide the text.
2189   if( mImpl->mModel->mElideEnabled ||
2190       ( ( NULL != mImpl->mEventData ) && mImpl->mEventData->mIsPlaceholderElideEnabled ) )
2191   {
2192     // Update Text layout for applying elided
2193     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2194                                                              ALIGN                     |
2195                                                              LAYOUT                    |
2196                                                              UPDATE_LAYOUT_SIZE        |
2197                                                              REORDER );
2198     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2199     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2200   }
2201
2202   // Make sure the model is up-to-date before layouting.
2203   ProcessModifyEvents();
2204   bool updated = mImpl->UpdateModel( mImpl->mOperationsPending );
2205
2206   // Layout the text.
2207   Size layoutSize;
2208   updated = DoRelayout( size,
2209                         mImpl->mOperationsPending,
2210                         layoutSize ) || updated;
2211
2212   if( updated )
2213   {
2214     updateTextType = MODEL_UPDATED;
2215   }
2216
2217   // Do not re-do any operation until something changes.
2218   mImpl->mOperationsPending = NO_OPERATION;
2219   mImpl->mModel->mScrollPositionLast = mImpl->mModel->mScrollPosition;
2220
2221   // Whether the text control is editable
2222   const bool isEditable = NULL != mImpl->mEventData;
2223
2224   // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
2225   Vector2 offset;
2226   if( newSize && isEditable )
2227   {
2228     offset = mImpl->mModel->mScrollPosition;
2229   }
2230
2231   if( !isEditable || !IsMultiLineEnabled() )
2232   {
2233     // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
2234     CalculateVerticalOffset( size );
2235   }
2236
2237   if( isEditable )
2238   {
2239     if( newSize )
2240     {
2241       // If there is a new size, the scroll position needs to be clamped.
2242       mImpl->ClampHorizontalScroll( layoutSize );
2243
2244       // Update the decorator's positions is needed if there is a new size.
2245       mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mModel->mScrollPosition - offset );
2246     }
2247
2248     // Move the cursor, grab handle etc.
2249     if( mImpl->ProcessInputEvents() )
2250     {
2251       updateTextType = static_cast<UpdateTextType>( updateTextType | DECORATOR_UPDATED );
2252     }
2253   }
2254
2255   // Clear the update info. This info will be set the next time the text is updated.
2256   mImpl->mTextUpdateInfo.Clear();
2257   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
2258
2259   return updateTextType;
2260 }
2261
2262 void Controller::RequestRelayout()
2263 {
2264   mImpl->RequestRelayout();
2265 }
2266
2267 // public : Input style change signals.
2268
2269 bool Controller::IsInputStyleChangedSignalsQueueEmpty()
2270 {
2271   return ( NULL == mImpl->mEventData ) || ( 0u == mImpl->mEventData->mInputStyleChangedQueue.Count() );
2272 }
2273
2274 void Controller::ProcessInputStyleChangedSignals()
2275 {
2276   if( NULL == mImpl->mEventData )
2277   {
2278     // Nothing to do.
2279     return;
2280   }
2281
2282   for( Vector<InputStyle::Mask>::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(),
2283          endIt = mImpl->mEventData->mInputStyleChangedQueue.End();
2284        it != endIt;
2285        ++it )
2286   {
2287     const InputStyle::Mask mask = *it;
2288
2289     if( NULL != mImpl->mEditableControlInterface )
2290     {
2291       // Emit the input style changed signal.
2292       mImpl->mEditableControlInterface->InputStyleChanged( mask );
2293     }
2294   }
2295
2296   mImpl->mEventData->mInputStyleChangedQueue.Clear();
2297 }
2298
2299 // public : Text-input Event Queuing.
2300
2301 void Controller::KeyboardFocusGainEvent()
2302 {
2303   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
2304
2305   if( NULL != mImpl->mEventData )
2306   {
2307     if( ( EventData::INACTIVE == mImpl->mEventData->mState ) ||
2308         ( EventData::INTERRUPTED == mImpl->mEventData->mState ) )
2309     {
2310       mImpl->ChangeState( EventData::EDITING );
2311       mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
2312       mImpl->mEventData->mUpdateInputStyle = true;
2313     }
2314     mImpl->NotifyImfMultiLineStatus();
2315     if( mImpl->IsShowingPlaceholderText() )
2316     {
2317       // Show alternative placeholder-text when editing
2318       ShowPlaceholderText();
2319     }
2320
2321     mImpl->RequestRelayout();
2322   }
2323 }
2324
2325 void Controller::KeyboardFocusLostEvent()
2326 {
2327   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
2328
2329   if( NULL != mImpl->mEventData )
2330   {
2331     if( EventData::INTERRUPTED != mImpl->mEventData->mState )
2332     {
2333       mImpl->ChangeState( EventData::INACTIVE );
2334
2335       if( !mImpl->IsShowingRealText() )
2336       {
2337         // Revert to regular placeholder-text when not editing
2338         ShowPlaceholderText();
2339       }
2340     }
2341   }
2342   mImpl->RequestRelayout();
2343 }
2344
2345 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
2346 {
2347   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
2348
2349   bool textChanged = false;
2350   bool relayoutNeeded = false;
2351
2352   if( ( NULL != mImpl->mEventData ) &&
2353       ( keyEvent.state == KeyEvent::Down ) )
2354   {
2355     int keyCode = keyEvent.keyCode;
2356     const std::string& keyString = keyEvent.keyPressed;
2357     const std::string keyName = keyEvent.keyPressedName;
2358
2359     const bool isNullKey = ( 0 == keyCode ) && ( keyString.empty() );
2360
2361     // Pre-process to separate modifying events from non-modifying input events.
2362     if( isNullKey )
2363     {
2364       // In some platforms arrive key events with no key code.
2365       // Do nothing.
2366       return false;
2367     }
2368     else if( Dali::DALI_KEY_ESCAPE == keyCode || Dali::DALI_KEY_BACK == keyCode  || Dali::DALI_KEY_SEARCH == keyCode )
2369     {
2370       // Do nothing
2371       return false;
2372     }
2373     else if( ( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ) ||
2374              ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode ) ||
2375              ( Dali::DALI_KEY_CURSOR_UP    == keyCode ) ||
2376              ( Dali::DALI_KEY_CURSOR_DOWN  == keyCode ) )
2377     {
2378       // If don't have any text, do nothing.
2379       if( !mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters )
2380       {
2381         return false;
2382       }
2383
2384       uint32_t cursorPosition = mImpl->mEventData->mPrimaryCursorPosition;
2385       uint32_t numberOfCharacters = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2386       uint32_t cursorLine = mImpl->mModel->mVisualModel->GetLineOfCharacter( cursorPosition );
2387       uint32_t numberOfLines = mImpl->mModel->GetNumberOfLines();
2388
2389       // Logic to determine whether this text control will lose focus or not.
2390       if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode && 0 == cursorPosition ) ||
2391           ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition) ||
2392           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && cursorLine == numberOfLines -1 ) ||
2393           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && numberOfCharacters == cursorPosition && cursorLine -1 == numberOfLines -1 ) ||
2394           ( Dali::DALI_KEY_CURSOR_UP == keyCode && cursorLine == 0 ) ||
2395           ( Dali::DALI_KEY_CURSOR_UP == keyCode && numberOfCharacters == cursorPosition && cursorLine == 1 ) )
2396       {
2397         return false;
2398       }
2399
2400       mImpl->mEventData->mCheckScrollAmount = true;
2401       Event event( Event::CURSOR_KEY_EVENT );
2402       event.p1.mInt = keyCode;
2403       event.p2.mBool = keyEvent.IsShiftModifier();
2404       mImpl->mEventData->mEventQueue.push_back( event );
2405
2406       // Will request for relayout.
2407       relayoutNeeded = true;
2408     }
2409     else if ( Dali::DevelKey::DALI_KEY_CONTROL_LEFT == keyCode || Dali::DevelKey::DALI_KEY_CONTROL_RIGHT == keyCode )
2410     {
2411       // Left or Right Control key event is received before Ctrl-C/V/X key event is received
2412       // If not handle it here, any selected text will be deleted
2413
2414       // Do nothing
2415       return false;
2416     }
2417     else if ( keyEvent.IsCtrlModifier() )
2418     {
2419       bool consumed = false;
2420       if (keyName == KEY_C_NAME)
2421       {
2422         // Ctrl-C to copy the selected text
2423         TextPopupButtonTouched( Toolkit::TextSelectionPopup::COPY );
2424         consumed = true;
2425       }
2426       else if (keyName == KEY_V_NAME)
2427       {
2428         // Ctrl-V to paste the copied text
2429         TextPopupButtonTouched( Toolkit::TextSelectionPopup::PASTE );
2430         consumed = true;
2431       }
2432       else if (keyName == KEY_X_NAME)
2433       {
2434         // Ctrl-X to cut the selected text
2435         TextPopupButtonTouched( Toolkit::TextSelectionPopup::CUT );
2436         consumed = true;
2437       }
2438       return consumed;
2439     }
2440     else if( ( Dali::DALI_KEY_BACKSPACE == keyCode ) ||
2441              ( Dali::DevelKey::DALI_KEY_DELETE == keyCode ) )
2442     {
2443       textChanged = DeleteEvent( keyCode );
2444
2445       // Will request for relayout.
2446       relayoutNeeded = true;
2447     }
2448     else if( IsKey( keyEvent, Dali::DALI_KEY_POWER ) ||
2449              IsKey( keyEvent, Dali::DALI_KEY_MENU ) ||
2450              IsKey( keyEvent, Dali::DALI_KEY_HOME ) )
2451     {
2452       // Power key/Menu/Home key behaviour does not allow edit mode to resume.
2453       mImpl->ChangeState( EventData::INACTIVE );
2454
2455       // Will request for relayout.
2456       relayoutNeeded = true;
2457
2458       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
2459     }
2460     else if( Dali::DALI_KEY_SHIFT_LEFT == keyCode )
2461     {
2462       // DALI_KEY_SHIFT_LEFT is the key code for the Left Shift. It's sent (by the imf?) when the predictive text is enabled
2463       // and a character is typed after the type of a upper case latin character.
2464
2465       // Do nothing.
2466       return false;
2467     }
2468     else if( ( Dali::DALI_KEY_VOLUME_UP == keyCode ) || ( Dali::DALI_KEY_VOLUME_DOWN == keyCode ) )
2469     {
2470       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
2471       // Do nothing.
2472       return false;
2473     }
2474     else
2475     {
2476       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() );
2477
2478       // IMF manager is no longer handling key-events
2479       mImpl->ClearPreEditFlag();
2480
2481       InsertText( keyString, COMMIT );
2482       textChanged = true;
2483
2484       // Will request for relayout.
2485       relayoutNeeded = true;
2486     }
2487
2488     if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
2489          ( mImpl->mEventData->mState != EventData::INACTIVE ) &&
2490          ( !isNullKey ) &&
2491          ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) &&
2492          ( Dali::DALI_KEY_VOLUME_UP != keyCode ) &&
2493          ( Dali::DALI_KEY_VOLUME_DOWN != keyCode ) )
2494     {
2495       // Should not change the state if the key is the shift send by the imf manager.
2496       // Otherwise, when the state is SELECTING the text controller can't send the right
2497       // surrounding info to the imf.
2498       mImpl->ChangeState( EventData::EDITING );
2499
2500       // Will request for relayout.
2501       relayoutNeeded = true;
2502     }
2503
2504     if( relayoutNeeded )
2505     {
2506       mImpl->RequestRelayout();
2507     }
2508   }
2509
2510   if( textChanged &&
2511       ( NULL != mImpl->mEditableControlInterface ) )
2512   {
2513     // Do this last since it provides callbacks into application code
2514     mImpl->mEditableControlInterface->TextChanged();
2515   }
2516
2517   return true;
2518 }
2519
2520 void Controller::TapEvent( unsigned int tapCount, float x, float y )
2521 {
2522   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
2523
2524   if( NULL != mImpl->mEventData )
2525   {
2526     DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState );
2527     EventData::State state( mImpl->mEventData->mState );
2528     bool relayoutNeeded( false );   // to avoid unnecessary relayouts when tapping an empty text-field
2529
2530     if( mImpl->IsClipboardVisible() )
2531     {
2532       if( EventData::INACTIVE == state || EventData::EDITING == state)
2533       {
2534         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2535       }
2536       relayoutNeeded = true;
2537     }
2538     else if( 1u == tapCount )
2539     {
2540       if( EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state )
2541       {
2542         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );  // If Popup shown hide it here so can be shown again if required.
2543       }
2544
2545       if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != state ) )
2546       {
2547         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2548         relayoutNeeded = true;
2549       }
2550       else
2551       {
2552         if( mImpl->IsShowingPlaceholderText() && !mImpl->IsFocusedPlaceholderAvailable() )
2553         {
2554           // Hide placeholder text
2555           ResetText();
2556         }
2557
2558         if( EventData::INACTIVE == state )
2559         {
2560           mImpl->ChangeState( EventData::EDITING );
2561         }
2562         else if( !mImpl->IsClipboardEmpty() )
2563         {
2564           mImpl->ChangeState( EventData::EDITING_WITH_POPUP );
2565         }
2566         relayoutNeeded = true;
2567       }
2568     }
2569     else if( 2u == tapCount )
2570     {
2571       if( mImpl->mEventData->mSelectionEnabled &&
2572           mImpl->IsShowingRealText() )
2573       {
2574         relayoutNeeded = true;
2575         mImpl->mEventData->mIsLeftHandleSelected = true;
2576         mImpl->mEventData->mIsRightHandleSelected = true;
2577       }
2578     }
2579
2580     // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
2581     if( relayoutNeeded )
2582     {
2583       Event event( Event::TAP_EVENT );
2584       event.p1.mUint = tapCount;
2585       event.p2.mFloat = x;
2586       event.p3.mFloat = y;
2587       mImpl->mEventData->mEventQueue.push_back( event );
2588
2589       mImpl->RequestRelayout();
2590     }
2591   }
2592
2593   // Reset keyboard as tap event has occurred.
2594   mImpl->ResetImfManager();
2595 }
2596
2597 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
2598 {
2599   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
2600
2601   if( NULL != mImpl->mEventData )
2602   {
2603     Event event( Event::PAN_EVENT );
2604     event.p1.mInt = state;
2605     event.p2.mFloat = displacement.x;
2606     event.p3.mFloat = displacement.y;
2607     mImpl->mEventData->mEventQueue.push_back( event );
2608
2609     mImpl->RequestRelayout();
2610   }
2611 }
2612
2613 void Controller::LongPressEvent( Gesture::State state, float x, float y  )
2614 {
2615   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" );
2616
2617   if( ( state == Gesture::Started ) &&
2618       ( NULL != mImpl->mEventData ) )
2619   {
2620     // The 1st long-press on inactive text-field is treated as tap
2621     if( EventData::INACTIVE == mImpl->mEventData->mState )
2622     {
2623       mImpl->ChangeState( EventData::EDITING );
2624
2625       Event event( Event::TAP_EVENT );
2626       event.p1.mUint = 1;
2627       event.p2.mFloat = x;
2628       event.p3.mFloat = y;
2629       mImpl->mEventData->mEventQueue.push_back( event );
2630
2631       mImpl->RequestRelayout();
2632     }
2633     else if( !mImpl->IsShowingRealText() )
2634     {
2635       Event event( Event::LONG_PRESS_EVENT );
2636       event.p1.mInt = state;
2637       event.p2.mFloat = x;
2638       event.p3.mFloat = y;
2639       mImpl->mEventData->mEventQueue.push_back( event );
2640       mImpl->RequestRelayout();
2641     }
2642     else if( !mImpl->IsClipboardVisible() )
2643     {
2644       // Reset the imf manager to commit the pre-edit before selecting the text.
2645       mImpl->ResetImfManager();
2646
2647       Event event( Event::LONG_PRESS_EVENT );
2648       event.p1.mInt = state;
2649       event.p2.mFloat = x;
2650       event.p3.mFloat = y;
2651       mImpl->mEventData->mEventQueue.push_back( event );
2652       mImpl->RequestRelayout();
2653
2654       mImpl->mEventData->mIsLeftHandleSelected = true;
2655       mImpl->mEventData->mIsRightHandleSelected = true;
2656     }
2657   }
2658 }
2659
2660 ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
2661 {
2662   // Whether the text needs to be relaid-out.
2663   bool requestRelayout = false;
2664
2665   // Whether to retrieve the text and cursor position to be sent to the IMF manager.
2666   bool retrieveText = false;
2667   bool retrieveCursor = false;
2668
2669   switch( imfEvent.eventName )
2670   {
2671     case ImfManager::COMMIT:
2672     {
2673       InsertText( imfEvent.predictiveString, Text::Controller::COMMIT );
2674       requestRelayout = true;
2675       retrieveCursor = true;
2676       break;
2677     }
2678     case ImfManager::PREEDIT:
2679     {
2680       InsertText( imfEvent.predictiveString, Text::Controller::PRE_EDIT );
2681       requestRelayout = true;
2682       retrieveCursor = true;
2683       break;
2684     }
2685     case ImfManager::DELETESURROUNDING:
2686     {
2687       const bool textDeleted = RemoveText( imfEvent.cursorOffset,
2688                                            imfEvent.numberOfChars,
2689                                            DONT_UPDATE_INPUT_STYLE );
2690
2691       if( textDeleted )
2692       {
2693         if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
2694             !mImpl->IsPlaceholderAvailable() )
2695         {
2696           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2697         }
2698         else
2699         {
2700           ShowPlaceholderText();
2701         }
2702         mImpl->mEventData->mUpdateCursorPosition = true;
2703         mImpl->mEventData->mScrollAfterDelete = true;
2704
2705         requestRelayout = true;
2706       }
2707       break;
2708     }
2709     case ImfManager::GETSURROUNDING:
2710     {
2711       retrieveText = true;
2712       retrieveCursor = true;
2713       break;
2714     }
2715     case ImfManager::PRIVATECOMMAND:
2716     {
2717       // PRIVATECOMMAND event is just for getting the private command message
2718       retrieveText = true;
2719       retrieveCursor = true;
2720       break;
2721     }
2722     case ImfManager::VOID:
2723     {
2724       // do nothing
2725       break;
2726     }
2727   } // end switch
2728
2729   if( requestRelayout )
2730   {
2731     mImpl->mOperationsPending = ALL_OPERATIONS;
2732     mImpl->RequestRelayout();
2733   }
2734
2735   std::string text;
2736   CharacterIndex cursorPosition = 0u;
2737   Length numberOfWhiteSpaces = 0u;
2738
2739   if( retrieveCursor )
2740   {
2741     numberOfWhiteSpaces = mImpl->GetNumberOfWhiteSpaces( 0u );
2742
2743     cursorPosition = mImpl->GetLogicalCursorPosition();
2744
2745     if( cursorPosition < numberOfWhiteSpaces )
2746     {
2747       cursorPosition = 0u;
2748     }
2749     else
2750     {
2751       cursorPosition -= numberOfWhiteSpaces;
2752     }
2753   }
2754
2755   if( retrieveText )
2756   {
2757     if( !mImpl->IsShowingPlaceholderText() )
2758     {
2759       // Retrieves the normal text string.
2760       mImpl->GetText( numberOfWhiteSpaces, text );
2761     }
2762     else
2763     {
2764       // When the current text is Placeholder Text, the surrounding text should be empty string.
2765       // It means DALi should send empty string ("") to IME.
2766       text = "";
2767     }
2768   }
2769
2770   ImfManager::ImfCallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false );
2771
2772   if( requestRelayout &&
2773       ( NULL != mImpl->mEditableControlInterface ) )
2774   {
2775     // Do this last since it provides callbacks into application code
2776     mImpl->mEditableControlInterface->TextChanged();
2777   }
2778
2779   return callbackData;
2780 }
2781
2782 void Controller::PasteClipboardItemEvent()
2783 {
2784   // Retrieve the clipboard contents first
2785   ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
2786   std::string stringToPaste( notifier.GetContent() );
2787
2788   // Commit the current pre-edit text; the contents of the clipboard should be appended
2789   mImpl->ResetImfManager();
2790
2791   // Temporary disable hiding clipboard
2792   mImpl->SetClipboardHideEnable( false );
2793
2794   // Paste
2795   PasteText( stringToPaste );
2796
2797   mImpl->SetClipboardHideEnable( true );
2798 }
2799
2800 // protected : Inherit from Text::Decorator::ControllerInterface.
2801
2802 void Controller::GetTargetSize( Vector2& targetSize )
2803 {
2804   targetSize = mImpl->mModel->mVisualModel->mControlSize;
2805 }
2806
2807 void Controller::AddDecoration( Actor& actor, bool needsClipping )
2808 {
2809   if( NULL != mImpl->mEditableControlInterface )
2810   {
2811     mImpl->mEditableControlInterface->AddDecoration( actor, needsClipping );
2812   }
2813 }
2814
2815 void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
2816 {
2817   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
2818
2819   if( NULL != mImpl->mEventData )
2820   {
2821     switch( handleType )
2822     {
2823       case GRAB_HANDLE:
2824       {
2825         Event event( Event::GRAB_HANDLE_EVENT );
2826         event.p1.mUint  = state;
2827         event.p2.mFloat = x;
2828         event.p3.mFloat = y;
2829
2830         mImpl->mEventData->mEventQueue.push_back( event );
2831         break;
2832       }
2833       case LEFT_SELECTION_HANDLE:
2834       {
2835         Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
2836         event.p1.mUint  = state;
2837         event.p2.mFloat = x;
2838         event.p3.mFloat = y;
2839
2840         mImpl->mEventData->mEventQueue.push_back( event );
2841         break;
2842       }
2843       case RIGHT_SELECTION_HANDLE:
2844       {
2845         Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
2846         event.p1.mUint  = state;
2847         event.p2.mFloat = x;
2848         event.p3.mFloat = y;
2849
2850         mImpl->mEventData->mEventQueue.push_back( event );
2851         break;
2852       }
2853       case LEFT_SELECTION_HANDLE_MARKER:
2854       case RIGHT_SELECTION_HANDLE_MARKER:
2855       {
2856         // Markers do not move the handles.
2857         break;
2858       }
2859       case HANDLE_TYPE_COUNT:
2860       {
2861         DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
2862       }
2863     }
2864
2865     mImpl->RequestRelayout();
2866   }
2867 }
2868
2869 // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
2870
2871 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
2872 {
2873   if( NULL == mImpl->mEventData )
2874   {
2875     return;
2876   }
2877
2878   switch( button )
2879   {
2880     case Toolkit::TextSelectionPopup::CUT:
2881     {
2882       mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
2883       mImpl->mOperationsPending = ALL_OPERATIONS;
2884
2885       if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
2886           !mImpl->IsPlaceholderAvailable() )
2887       {
2888         mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2889       }
2890       else
2891       {
2892         ShowPlaceholderText();
2893       }
2894
2895       mImpl->mEventData->mUpdateCursorPosition = true;
2896       mImpl->mEventData->mScrollAfterDelete = true;
2897
2898       mImpl->RequestRelayout();
2899
2900       if( NULL != mImpl->mEditableControlInterface )
2901       {
2902         mImpl->mEditableControlInterface->TextChanged();
2903       }
2904       break;
2905     }
2906     case Toolkit::TextSelectionPopup::COPY:
2907     {
2908       mImpl->SendSelectionToClipboard( false ); // Text not modified
2909
2910       mImpl->mEventData->mUpdateCursorPosition = true;
2911
2912       mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup
2913       break;
2914     }
2915     case Toolkit::TextSelectionPopup::PASTE:
2916     {
2917       mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item
2918       break;
2919     }
2920     case Toolkit::TextSelectionPopup::SELECT:
2921     {
2922       const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
2923
2924       if( mImpl->mEventData->mSelectionEnabled )
2925       {
2926         // Creates a SELECT event.
2927         SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false );
2928       }
2929       break;
2930     }
2931     case Toolkit::TextSelectionPopup::SELECT_ALL:
2932     {
2933       // Creates a SELECT_ALL event
2934       SelectEvent( 0.f, 0.f, true );
2935       break;
2936     }
2937     case Toolkit::TextSelectionPopup::CLIPBOARD:
2938     {
2939       mImpl->ShowClipboard();
2940       break;
2941     }
2942     case Toolkit::TextSelectionPopup::NONE:
2943     {
2944       // Nothing to do.
2945       break;
2946     }
2947   }
2948 }
2949
2950 void Controller::DisplayTimeExpired()
2951 {
2952   mImpl->mEventData->mUpdateCursorPosition = true;
2953   // Apply modifications to the model
2954   mImpl->mOperationsPending = ALL_OPERATIONS;
2955
2956   mImpl->RequestRelayout();
2957 }
2958
2959 // private : Update.
2960
2961 void Controller::InsertText( const std::string& text, Controller::InsertType type )
2962 {
2963   bool removedPrevious = false;
2964   bool removedSelected = false;
2965   bool maxLengthReached = false;
2966
2967   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
2968
2969   if( NULL == mImpl->mEventData )
2970   {
2971     return;
2972   }
2973
2974   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
2975                  this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
2976                  mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
2977
2978   // TODO: At the moment the underline runs are only for pre-edit.
2979   mImpl->mModel->mVisualModel->mUnderlineRuns.Clear();
2980
2981   // Remove the previous IMF pre-edit.
2982   if( mImpl->mEventData->mPreEditFlag && ( 0u != mImpl->mEventData->mPreEditLength ) )
2983   {
2984     removedPrevious = RemoveText( -static_cast<int>( mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition ),
2985                                   mImpl->mEventData->mPreEditLength,
2986                                   DONT_UPDATE_INPUT_STYLE );
2987
2988     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
2989     mImpl->mEventData->mPreEditLength = 0u;
2990   }
2991   else
2992   {
2993     // Remove the previous Selection.
2994     removedSelected = RemoveSelectedText();
2995
2996   }
2997
2998   Vector<Character> utf32Characters;
2999   Length characterCount = 0u;
3000
3001   if( !text.empty() )
3002   {
3003     //  Convert text into UTF-32
3004     utf32Characters.Resize( text.size() );
3005
3006     // This is a bit horrible but std::string returns a (signed) char*
3007     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
3008
3009     // Transform a text array encoded in utf8 into an array encoded in utf32.
3010     // It returns the actual number of characters.
3011     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
3012     utf32Characters.Resize( characterCount );
3013
3014     DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
3015     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
3016   }
3017
3018   if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
3019   {
3020     // The placeholder text is no longer needed
3021     if( mImpl->IsShowingPlaceholderText() )
3022     {
3023       ResetText();
3024     }
3025
3026     mImpl->ChangeState( EventData::EDITING );
3027
3028     // Handle the IMF (predicitive text) state changes
3029     if( COMMIT == type )
3030     {
3031       // IMF manager is no longer handling key-events
3032       mImpl->ClearPreEditFlag();
3033     }
3034     else // PRE_EDIT
3035     {
3036       if( !mImpl->mEventData->mPreEditFlag )
3037       {
3038         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state\n" );
3039
3040         // Record the start of the pre-edit text
3041         mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
3042       }
3043
3044       mImpl->mEventData->mPreEditLength = utf32Characters.Count();
3045       mImpl->mEventData->mPreEditFlag = true;
3046
3047       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
3048     }
3049
3050     const Length numberOfCharactersInModel = mImpl->mModel->mLogicalModel->mText.Count();
3051
3052     // Restrict new text to fit within Maximum characters setting.
3053     Length maxSizeOfNewText = std::min( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
3054     maxLengthReached = ( characterCount > maxSizeOfNewText );
3055
3056     // The cursor position.
3057     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
3058
3059     // Update the text's style.
3060
3061     // Updates the text style runs by adding characters.
3062     mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText );
3063
3064     // Get the character index from the cursor index.
3065     const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u;
3066
3067     // Retrieve the text's style for the given index.
3068     InputStyle style;
3069     mImpl->RetrieveDefaultInputStyle( style );
3070     mImpl->mModel->mLogicalModel->RetrieveStyle( styleIndex, style );
3071
3072     // Whether to add a new text color run.
3073     const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor );
3074
3075     // Whether to add a new font run.
3076     const bool addFontNameRun = style.familyName != mImpl->mEventData->mInputStyle.familyName;
3077     const bool addFontWeightRun = style.weight != mImpl->mEventData->mInputStyle.weight;
3078     const bool addFontWidthRun = style.width != mImpl->mEventData->mInputStyle.width;
3079     const bool addFontSlantRun = style.slant != mImpl->mEventData->mInputStyle.slant;
3080     const bool addFontSizeRun = style.size != mImpl->mEventData->mInputStyle.size;
3081
3082     // Add style runs.
3083     if( addColorRun )
3084     {
3085       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
3086       mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
3087
3088       ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
3089       colorRun.color = mImpl->mEventData->mInputStyle.textColor;
3090       colorRun.characterRun.characterIndex = cursorIndex;
3091       colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
3092     }
3093
3094     if( addFontNameRun   ||
3095         addFontWeightRun ||
3096         addFontWidthRun  ||
3097         addFontSlantRun  ||
3098         addFontSizeRun )
3099     {
3100       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Count();
3101       mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
3102
3103       FontDescriptionRun& fontDescriptionRun = *( mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
3104
3105       if( addFontNameRun )
3106       {
3107         fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
3108         fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
3109         memcpy( fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength );
3110         fontDescriptionRun.familyDefined = true;
3111
3112         // The memory allocated for the font family name is freed when the font description is removed from the logical model.
3113       }
3114
3115       if( addFontWeightRun )
3116       {
3117         fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
3118         fontDescriptionRun.weightDefined = true;
3119       }
3120
3121       if( addFontWidthRun )
3122       {
3123         fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
3124         fontDescriptionRun.widthDefined = true;
3125       }
3126
3127       if( addFontSlantRun )
3128       {
3129         fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
3130         fontDescriptionRun.slantDefined = true;
3131       }
3132
3133       if( addFontSizeRun )
3134       {
3135         fontDescriptionRun.size = static_cast<PointSize26Dot6>( mImpl->mEventData->mInputStyle.size * 64.f );
3136         fontDescriptionRun.sizeDefined = true;
3137       }
3138
3139       fontDescriptionRun.characterRun.characterIndex = cursorIndex;
3140       fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
3141     }
3142
3143     // Insert at current cursor position.
3144     Vector<Character>& modifyText = mImpl->mModel->mLogicalModel->mText;
3145
3146     if( cursorIndex < numberOfCharactersInModel )
3147     {
3148       modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3149     }
3150     else
3151     {
3152       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3153     }
3154
3155     // Mark the first paragraph to be updated.
3156     if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
3157     {
3158       mImpl->mTextUpdateInfo.mCharacterIndex = 0;
3159       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3160       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = numberOfCharactersInModel + maxSizeOfNewText;
3161       mImpl->mTextUpdateInfo.mClearAll = true;
3162     }
3163     else
3164     {
3165       mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
3166       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
3167     }
3168
3169     // Update the cursor index.
3170     cursorIndex += maxSizeOfNewText;
3171
3172     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 );
3173   }
3174
3175   if( ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) &&
3176       mImpl->IsPlaceholderAvailable() )
3177   {
3178     // Show place-holder if empty after removing the pre-edit text
3179     ShowPlaceholderText();
3180     mImpl->mEventData->mUpdateCursorPosition = true;
3181     mImpl->ClearPreEditFlag();
3182   }
3183   else if( removedPrevious ||
3184            removedSelected ||
3185            ( 0 != utf32Characters.Count() ) )
3186   {
3187     // Queue an inserted event
3188     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
3189
3190     mImpl->mEventData->mUpdateCursorPosition = true;
3191     if( removedSelected )
3192     {
3193       mImpl->mEventData->mScrollAfterDelete = true;
3194     }
3195     else
3196     {
3197       mImpl->mEventData->mScrollAfterUpdatePosition = true;
3198     }
3199   }
3200
3201   if( maxLengthReached )
3202   {
3203     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mModel->mLogicalModel->mText.Count() );
3204
3205     mImpl->ResetImfManager();
3206
3207     if( NULL != mImpl->mEditableControlInterface )
3208     {
3209       // Do this last since it provides callbacks into application code
3210       mImpl->mEditableControlInterface->MaxLengthReached();
3211     }
3212   }
3213 }
3214
3215 void Controller::PasteText( const std::string& stringToPaste )
3216 {
3217   InsertText( stringToPaste, Text::Controller::COMMIT );
3218   mImpl->ChangeState( EventData::EDITING );
3219   mImpl->RequestRelayout();
3220
3221   if( NULL != mImpl->mEditableControlInterface )
3222   {
3223     // Do this last since it provides callbacks into application code
3224     mImpl->mEditableControlInterface->TextChanged();
3225   }
3226 }
3227
3228 bool Controller::RemoveText( int cursorOffset,
3229                              int numberOfCharacters,
3230                              UpdateInputStyleType type )
3231 {
3232   bool removed = false;
3233
3234   if( NULL == mImpl->mEventData )
3235   {
3236     return removed;
3237   }
3238
3239   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n",
3240                  this, mImpl->mModel->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters );
3241
3242   if( !mImpl->IsShowingPlaceholderText() )
3243   {
3244     // Delete at current cursor position
3245     Vector<Character>& currentText = mImpl->mModel->mLogicalModel->mText;
3246     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
3247
3248     CharacterIndex cursorIndex = 0;
3249
3250     // Validate the cursor position & number of characters
3251     if( ( static_cast< int >( mImpl->mEventData->mPrimaryCursorPosition ) + cursorOffset ) >= 0 )
3252     {
3253       cursorIndex = mImpl->mEventData->mPrimaryCursorPosition + cursorOffset;
3254     }
3255
3256     if( ( cursorIndex + numberOfCharacters ) > currentText.Count() )
3257     {
3258       numberOfCharacters = currentText.Count() - cursorIndex;
3259     }
3260
3261     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.
3262         ( ( cursorIndex + numberOfCharacters ) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) )
3263     {
3264       // Mark the paragraphs to be updated.
3265       if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
3266       {
3267         mImpl->mTextUpdateInfo.mCharacterIndex = 0;
3268         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3269         mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters;
3270         mImpl->mTextUpdateInfo.mClearAll = true;
3271       }
3272       else
3273       {
3274         mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
3275         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
3276       }
3277
3278       // Update the input style and remove the text's style before removing the text.
3279
3280       if( UPDATE_INPUT_STYLE == type )
3281       {
3282         // Keep a copy of the current input style.
3283         InputStyle currentInputStyle;
3284         currentInputStyle.Copy( mImpl->mEventData->mInputStyle );
3285
3286         // Set first the default input style.
3287         mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle );
3288
3289         // Update the input style.
3290         mImpl->mModel->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle );
3291
3292         // Compare if the input style has changed.
3293         const bool hasInputStyleChanged = !currentInputStyle.Equal( mImpl->mEventData->mInputStyle );
3294
3295         if( hasInputStyleChanged )
3296         {
3297           const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mImpl->mEventData->mInputStyle );
3298           // Queue the input style changed signal.
3299           mImpl->mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
3300         }
3301       }
3302
3303       // Updates the text style runs by removing characters. Runs with no characters are removed.
3304       mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters );
3305
3306       // Remove the characters.
3307       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
3308       Vector<Character>::Iterator last  = first + numberOfCharacters;
3309
3310       currentText.Erase( first, last );
3311
3312       // Cursor position retreat
3313       oldCursorIndex = cursorIndex;
3314
3315       mImpl->mEventData->mScrollAfterDelete = true;
3316
3317       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters );
3318       removed = true;
3319     }
3320   }
3321
3322   return removed;
3323 }
3324
3325 bool Controller::RemoveSelectedText()
3326 {
3327   bool textRemoved( false );
3328
3329   if( EventData::SELECTING == mImpl->mEventData->mState )
3330   {
3331     std::string removedString;
3332     mImpl->RetrieveSelection( removedString, true );
3333
3334     if( !removedString.empty() )
3335     {
3336       textRemoved = true;
3337       mImpl->ChangeState( EventData::EDITING );
3338     }
3339   }
3340
3341   return textRemoved;
3342 }
3343
3344 // private : Relayout.
3345
3346 bool Controller::DoRelayout( const Size& size,
3347                              OperationsMask operationsRequired,
3348                              Size& layoutSize )
3349 {
3350   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height );
3351   bool viewUpdated( false );
3352
3353   // Calculate the operations to be done.
3354   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
3355
3356   const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
3357   const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
3358
3359   // Get the current layout size.
3360   layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
3361
3362   if( NO_OPERATION != ( LAYOUT & operations ) )
3363   {
3364     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
3365
3366     // Some vectors with data needed to layout and reorder may be void
3367     // after the first time the text has been laid out.
3368     // Fill the vectors again.
3369
3370     // Calculate the number of glyphs to layout.
3371     const Vector<GlyphIndex>& charactersToGlyph = mImpl->mModel->mVisualModel->mCharactersToGlyph;
3372     const Vector<Length>& glyphsPerCharacter = mImpl->mModel->mVisualModel->mGlyphsPerCharacter;
3373     const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
3374     const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
3375
3376     const CharacterIndex lastIndex = startIndex + ( ( requestedNumberOfCharacters > 0u ) ? requestedNumberOfCharacters - 1u : 0u );
3377     const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
3378     const Length numberOfGlyphs = ( requestedNumberOfCharacters > 0u ) ? *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - startGlyphIndex : 0u;
3379     const Length totalNumberOfGlyphs = mImpl->mModel->mVisualModel->mGlyphs.Count();
3380
3381     if( 0u == totalNumberOfGlyphs )
3382     {
3383       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
3384       {
3385         mImpl->mModel->mVisualModel->SetLayoutSize( Size::ZERO );
3386       }
3387
3388       // Nothing else to do if there is no glyphs.
3389       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n" );
3390       return true;
3391     }
3392
3393     const Vector<LineBreakInfo>& lineBreakInfo = mImpl->mModel->mLogicalModel->mLineBreakInfo;
3394     const Vector<WordBreakInfo>& wordBreakInfo = mImpl->mModel->mLogicalModel->mWordBreakInfo;
3395     const Vector<CharacterDirection>& characterDirection = mImpl->mModel->mLogicalModel->mCharacterDirections;
3396     const Vector<GlyphInfo>& glyphs = mImpl->mModel->mVisualModel->mGlyphs;
3397     const Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mModel->mVisualModel->mGlyphsToCharacters;
3398     const Vector<Length>& charactersPerGlyph = mImpl->mModel->mVisualModel->mCharactersPerGlyph;
3399     const Character* const textBuffer = mImpl->mModel->mLogicalModel->mText.Begin();
3400     const float outlineWidth = static_cast<float>( mImpl->mModel->GetOutlineWidth() );
3401
3402     // Set the layout parameters.
3403     Layout::Parameters layoutParameters( size,
3404                                          textBuffer,
3405                                          lineBreakInfo.Begin(),
3406                                          wordBreakInfo.Begin(),
3407                                          ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
3408                                          glyphs.Begin(),
3409                                          glyphsToCharactersMap.Begin(),
3410                                          charactersPerGlyph.Begin(),
3411                                          charactersToGlyphBuffer,
3412                                          glyphsPerCharacterBuffer,
3413                                          totalNumberOfGlyphs,
3414                                          mImpl->mModel->mHorizontalAlignment,
3415                                          mImpl->mModel->mLineWrapMode,
3416                                          outlineWidth );
3417
3418     // Resize the vector of positions to have the same size than the vector of glyphs.
3419     Vector<Vector2>& glyphPositions = mImpl->mModel->mVisualModel->mGlyphPositions;
3420     glyphPositions.Resize( totalNumberOfGlyphs );
3421
3422     // Whether the last character is a new paragraph character.
3423     mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph =  TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mModel->mLogicalModel->mText.Count() - 1u ) ) );
3424     layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
3425
3426     // The initial glyph and the number of glyphs to layout.
3427     layoutParameters.startGlyphIndex = startGlyphIndex;
3428     layoutParameters.numberOfGlyphs = numberOfGlyphs;
3429     layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex;
3430     layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
3431
3432     // Update the ellipsis
3433     bool elideTextEnabled = mImpl->mModel->mElideEnabled;
3434
3435     if( NULL != mImpl->mEventData )
3436     {
3437       if( mImpl->mEventData->mPlaceholderEllipsisFlag && mImpl->IsShowingPlaceholderText() )
3438       {
3439         elideTextEnabled = mImpl->mEventData->mIsPlaceholderElideEnabled;
3440       }
3441       else if( EventData::INACTIVE != mImpl->mEventData->mState )
3442       {
3443         // Disable ellipsis when editing
3444         elideTextEnabled = false;
3445       }
3446
3447       // Reset the scroll position in inactive state
3448       if( elideTextEnabled && ( mImpl->mEventData->mState == EventData::INACTIVE ) )
3449       {
3450         ResetScrollPosition();
3451       }
3452     }
3453
3454     // Update the visual model.
3455     Size newLayoutSize;
3456     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
3457                                                    glyphPositions,
3458                                                    mImpl->mModel->mVisualModel->mLines,
3459                                                    newLayoutSize,
3460                                                    elideTextEnabled );
3461
3462     viewUpdated = viewUpdated || ( newLayoutSize != layoutSize );
3463
3464     if( viewUpdated )
3465     {
3466       layoutSize = newLayoutSize;
3467
3468       if( NO_OPERATION != ( UPDATE_DIRECTION & operations ) )
3469       {
3470         mImpl->mAutoScrollDirectionRTL = false;
3471       }
3472
3473       // Reorder the lines
3474       if( NO_OPERATION != ( REORDER & operations ) )
3475       {
3476         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mModel->mLogicalModel->mBidirectionalParagraphInfo;
3477         Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = mImpl->mModel->mLogicalModel->mBidirectionalLineInfo;
3478
3479         // Check first if there are paragraphs with bidirectional info.
3480         if( 0u != bidirectionalInfo.Count() )
3481         {
3482           // Get the lines
3483           const Length numberOfLines = mImpl->mModel->mVisualModel->mLines.Count();
3484
3485           // Reorder the lines.
3486           bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
3487           ReorderLines( bidirectionalInfo,
3488                         startIndex,
3489                         requestedNumberOfCharacters,
3490                         mImpl->mModel->mVisualModel->mLines,
3491                         bidirectionalLineInfo );
3492
3493           // Set the bidirectional info per line into the layout parameters.
3494           layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
3495           layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
3496
3497           // Re-layout the text. Reorder those lines with right to left characters.
3498           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
3499                                                          startIndex,
3500                                                          requestedNumberOfCharacters,
3501                                                          glyphPositions );
3502
3503           if ( ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) ) && ( numberOfLines > 0 ) )
3504           {
3505             const LineRun* const firstline = mImpl->mModel->mVisualModel->mLines.Begin();
3506             if ( firstline )
3507             {
3508               mImpl->mAutoScrollDirectionRTL = firstline->direction;
3509             }
3510           }
3511         }
3512       } // REORDER
3513
3514       // Sets the layout size.
3515       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
3516       {
3517         mImpl->mModel->mVisualModel->SetLayoutSize( layoutSize );
3518       }
3519     } // view updated
3520   }
3521
3522   if( NO_OPERATION != ( ALIGN & operations ) )
3523   {
3524     // The laid-out lines.
3525     Vector<LineRun>& lines = mImpl->mModel->mVisualModel->mLines;
3526
3527     // Need to align with the control's size as the text may contain lines
3528     // starting either with left to right text or right to left.
3529     mImpl->mLayoutEngine.Align( size,
3530                                 startIndex,
3531                                 requestedNumberOfCharacters,
3532                                 mImpl->mModel->mHorizontalAlignment,
3533                                 lines,
3534                                 mImpl->mModel->mAlignmentOffset );
3535
3536     viewUpdated = true;
3537   }
3538 #if defined(DEBUG_ENABLED)
3539   std::string currentText;
3540   GetText( currentText );
3541   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mAutoScrollDirectionRTL[%s] [%s]\n", this, (mImpl->mAutoScrollDirectionRTL)?"true":"false",  currentText.c_str() );
3542 #endif
3543   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
3544   return viewUpdated;
3545 }
3546
3547 void Controller::CalculateVerticalOffset( const Size& controlSize )
3548 {
3549   Size layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
3550
3551   if( fabsf( layoutSize.height ) < Math::MACHINE_EPSILON_1000 )
3552   {
3553     // Get the line height of the default font.
3554     layoutSize.height = mImpl->GetDefaultFontLineHeight();
3555   }
3556
3557   switch( mImpl->mModel->mVerticalAlignment )
3558   {
3559     case VerticalAlignment::TOP:
3560     {
3561       mImpl->mModel->mScrollPosition.y = 0.f;
3562       break;
3563     }
3564     case VerticalAlignment::CENTER:
3565     {
3566       mImpl->mModel->mScrollPosition.y = floorf( 0.5f * ( controlSize.height - layoutSize.height ) ); // try to avoid pixel alignment.
3567       break;
3568     }
3569     case VerticalAlignment::BOTTOM:
3570     {
3571       mImpl->mModel->mScrollPosition.y = controlSize.height - layoutSize.height;
3572       break;
3573     }
3574   }
3575 }
3576
3577 // private : Events.
3578
3579 void Controller::ProcessModifyEvents()
3580 {
3581   Vector<ModifyEvent>& events = mImpl->mModifyEvents;
3582
3583   if( 0u == events.Count() )
3584   {
3585     // Nothing to do.
3586     return;
3587   }
3588
3589   for( Vector<ModifyEvent>::ConstIterator it = events.Begin(),
3590          endIt = events.End();
3591        it != endIt;
3592        ++it )
3593   {
3594     const ModifyEvent& event = *it;
3595
3596     if( ModifyEvent::TEXT_REPLACED == event.type )
3597     {
3598       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
3599       DALI_ASSERT_DEBUG( it == events.Begin() && "Unexpected TEXT_REPLACED event" );
3600
3601       TextReplacedEvent();
3602     }
3603     else if( ModifyEvent::TEXT_INSERTED == event.type )
3604     {
3605       TextInsertedEvent();
3606     }
3607     else if( ModifyEvent::TEXT_DELETED == event.type )
3608     {
3609       // Placeholder-text cannot be deleted
3610       if( !mImpl->IsShowingPlaceholderText() )
3611       {
3612         TextDeletedEvent();
3613       }
3614     }
3615   }
3616
3617   if( NULL != mImpl->mEventData )
3618   {
3619     // When the text is being modified, delay cursor blinking
3620     mImpl->mEventData->mDecorator->DelayCursorBlink();
3621
3622     // Update selection position after modifying the text
3623     mImpl->mEventData->mLeftSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
3624     mImpl->mEventData->mRightSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
3625   }
3626
3627   // Discard temporary text
3628   events.Clear();
3629 }
3630
3631 void Controller::TextReplacedEvent()
3632 {
3633   // The natural size needs to be re-calculated.
3634   mImpl->mRecalculateNaturalSize = true;
3635
3636   // Apply modifications to the model
3637   mImpl->mOperationsPending = ALL_OPERATIONS;
3638 }
3639
3640 void Controller::TextInsertedEvent()
3641 {
3642   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" );
3643
3644   if( NULL == mImpl->mEventData )
3645   {
3646     return;
3647   }
3648
3649   mImpl->mEventData->mCheckScrollAmount = true;
3650
3651   // The natural size needs to be re-calculated.
3652   mImpl->mRecalculateNaturalSize = true;
3653
3654   // Apply modifications to the model; TODO - Optimize this
3655   mImpl->mOperationsPending = ALL_OPERATIONS;
3656 }
3657
3658 void Controller::TextDeletedEvent()
3659 {
3660   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" );
3661
3662   if( NULL == mImpl->mEventData )
3663   {
3664     return;
3665   }
3666
3667   mImpl->mEventData->mCheckScrollAmount = true;
3668
3669   // The natural size needs to be re-calculated.
3670   mImpl->mRecalculateNaturalSize = true;
3671
3672   // Apply modifications to the model; TODO - Optimize this
3673   mImpl->mOperationsPending = ALL_OPERATIONS;
3674 }
3675
3676 void Controller::SelectEvent( float x, float y, bool selectAll )
3677 {
3678   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" );
3679
3680   if( NULL != mImpl->mEventData )
3681   {
3682     if( selectAll )
3683     {
3684       Event event( Event::SELECT_ALL );
3685       mImpl->mEventData->mEventQueue.push_back( event );
3686     }
3687     else
3688     {
3689       Event event( Event::SELECT );
3690       event.p2.mFloat = x;
3691       event.p3.mFloat = y;
3692       mImpl->mEventData->mEventQueue.push_back( event );
3693     }
3694
3695     mImpl->mEventData->mCheckScrollAmount = true;
3696     mImpl->mEventData->mIsLeftHandleSelected = true;
3697     mImpl->mEventData->mIsRightHandleSelected = true;
3698     mImpl->RequestRelayout();
3699   }
3700 }
3701
3702 bool Controller::DeleteEvent( int keyCode )
3703 {
3704   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p KeyCode : %d \n", this, keyCode );
3705
3706   bool removed = false;
3707
3708   if( NULL == mImpl->mEventData )
3709   {
3710     return removed;
3711   }
3712
3713   // IMF manager is no longer handling key-events
3714   mImpl->ClearPreEditFlag();
3715
3716   if( EventData::SELECTING == mImpl->mEventData->mState )
3717   {
3718     removed = RemoveSelectedText();
3719   }
3720   else if( ( mImpl->mEventData->mPrimaryCursorPosition > 0 ) && ( keyCode == Dali::DALI_KEY_BACKSPACE) )
3721   {
3722     // Remove the character before the current cursor position
3723     removed = RemoveText( -1,
3724                           1,
3725                           UPDATE_INPUT_STYLE );
3726   }
3727   else if( keyCode == Dali::DevelKey::DALI_KEY_DELETE )
3728   {
3729     // Remove the character after the current cursor position
3730     removed = RemoveText( 0,
3731                           1,
3732                           UPDATE_INPUT_STYLE );
3733   }
3734
3735   if( removed )
3736   {
3737     if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
3738         !mImpl->IsPlaceholderAvailable() )
3739     {
3740       mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
3741     }
3742     else
3743     {
3744       ShowPlaceholderText();
3745     }
3746     mImpl->mEventData->mUpdateCursorPosition = true;
3747     mImpl->mEventData->mScrollAfterDelete = true;
3748   }
3749
3750   return removed;
3751 }
3752
3753 // private : Helpers.
3754
3755 void Controller::ResetText()
3756 {
3757   // Reset buffers.
3758   mImpl->mModel->mLogicalModel->mText.Clear();
3759
3760   // We have cleared everything including the placeholder-text
3761   mImpl->PlaceholderCleared();
3762
3763   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3764   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3765   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
3766
3767   // Clear any previous text.
3768   mImpl->mTextUpdateInfo.mClearAll = true;
3769
3770   // The natural size needs to be re-calculated.
3771   mImpl->mRecalculateNaturalSize = true;
3772
3773   // Apply modifications to the model
3774   mImpl->mOperationsPending = ALL_OPERATIONS;
3775 }
3776
3777 void Controller::ShowPlaceholderText()
3778 {
3779   if( mImpl->IsPlaceholderAvailable() )
3780   {
3781     DALI_ASSERT_DEBUG( mImpl->mEventData && "No placeholder text available" );
3782
3783     if( NULL == mImpl->mEventData )
3784     {
3785       return;
3786     }
3787
3788     mImpl->mEventData->mIsShowingPlaceholderText = true;
3789
3790     // Disable handles when showing place-holder text
3791     mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
3792     mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
3793     mImpl->mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
3794
3795     const char* text( NULL );
3796     size_t size( 0 );
3797
3798     // TODO - Switch Placeholder text when changing state
3799     if( ( EventData::INACTIVE != mImpl->mEventData->mState ) &&
3800         ( 0u != mImpl->mEventData->mPlaceholderTextActive.c_str() ) )
3801     {
3802       text = mImpl->mEventData->mPlaceholderTextActive.c_str();
3803       size = mImpl->mEventData->mPlaceholderTextActive.size();
3804     }
3805     else
3806     {
3807       text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
3808       size = mImpl->mEventData->mPlaceholderTextInactive.size();
3809     }
3810
3811     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3812     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3813
3814     // Reset model for showing placeholder.
3815     mImpl->mModel->mLogicalModel->mText.Clear();
3816     mImpl->mModel->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor );
3817
3818     // Convert text into UTF-32
3819     Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
3820     utf32Characters.Resize( size );
3821
3822     // This is a bit horrible but std::string returns a (signed) char*
3823     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text );
3824
3825     // Transform a text array encoded in utf8 into an array encoded in utf32.
3826     // It returns the actual number of characters.
3827     const Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() );
3828     utf32Characters.Resize( characterCount );
3829
3830     // The characters to be added.
3831     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount;
3832
3833     // Reset the cursor position
3834     mImpl->mEventData->mPrimaryCursorPosition = 0;
3835
3836     // The natural size needs to be re-calculated.
3837     mImpl->mRecalculateNaturalSize = true;
3838
3839     // Apply modifications to the model
3840     mImpl->mOperationsPending = ALL_OPERATIONS;
3841
3842     // Update the rest of the model during size negotiation
3843     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
3844   }
3845 }
3846
3847 void Controller::ClearFontData()
3848 {
3849   if( mImpl->mFontDefaults )
3850   {
3851     mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
3852   }
3853
3854   // Set flags to update the model.
3855   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3856   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3857   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
3858
3859   mImpl->mTextUpdateInfo.mClearAll = true;
3860   mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
3861   mImpl->mRecalculateNaturalSize = true;
3862
3863   mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
3864                                                            VALIDATE_FONTS            |
3865                                                            SHAPE_TEXT                |
3866                                                            BIDI_INFO                 |
3867                                                            GET_GLYPH_METRICS         |
3868                                                            LAYOUT                    |
3869                                                            UPDATE_LAYOUT_SIZE        |
3870                                                            REORDER                   |
3871                                                            ALIGN );
3872 }
3873
3874 void Controller::ClearStyleData()
3875 {
3876   mImpl->mModel->mLogicalModel->mColorRuns.Clear();
3877   mImpl->mModel->mLogicalModel->ClearFontDescriptionRuns();
3878 }
3879
3880 void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
3881 {
3882   // Reset the cursor position
3883   if( NULL != mImpl->mEventData )
3884   {
3885     mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
3886
3887     // Update the cursor if it's in editing mode.
3888     if( EventData::IsEditingState( mImpl->mEventData->mState )  )
3889     {
3890       mImpl->mEventData->mUpdateCursorPosition = true;
3891     }
3892   }
3893 }
3894
3895 void Controller::ResetScrollPosition()
3896 {
3897   if( NULL != mImpl->mEventData )
3898   {
3899     // Reset the scroll position.
3900     mImpl->mModel->mScrollPosition = Vector2::ZERO;
3901     mImpl->mEventData->mScrollAfterUpdatePosition = true;
3902   }
3903 }
3904
3905 void Controller::SetControlInterface( ControlInterface* controlInterface )
3906 {
3907   mImpl->mControlInterface = controlInterface;
3908 }
3909
3910 bool Controller::ShouldClearFocusOnEscape() const
3911 {
3912   return mImpl->mShouldClearFocusOnEscape;
3913 }
3914
3915 // private : Private contructors & copy operator.
3916
3917 Controller::Controller()
3918 : mImpl( NULL )
3919 {
3920   mImpl = new Controller::Impl( NULL, NULL );
3921 }
3922
3923 Controller::Controller( ControlInterface* controlInterface )
3924 {
3925   mImpl = new Controller::Impl( controlInterface, NULL );
3926 }
3927
3928 Controller::Controller( ControlInterface* controlInterface,
3929                         EditableControlInterface* editableControlInterface )
3930 {
3931   mImpl = new Controller::Impl( controlInterface,
3932                                 editableControlInterface );
3933 }
3934
3935 // The copy constructor and operator are left unimplemented.
3936
3937 // protected : Destructor.
3938
3939 Controller::~Controller()
3940 {
3941   delete mImpl;
3942 }
3943
3944 } // namespace Text
3945
3946 } // namespace Toolkit
3947
3948 } // namespace Dali