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