[4.0] DALi version 1.2.88
[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>( GET_SCRIPTS       |
2144                                                                            VALIDATE_FONTS    |
2145                                                                            GET_LINE_BREAKS   |
2146                                                                            GET_WORD_BREAKS   |
2147                                                                            BIDI_INFO         |
2148                                                                            SHAPE_TEXT        |
2149                                                                            GET_GLYPH_METRICS );
2150
2151     // Set the update info to relayout the whole text.
2152     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
2153     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
2154
2155     // Make sure the model is up-to-date before layouting
2156     mImpl->UpdateModel( onlyOnceOperations );
2157
2158     Vector3 naturalSize;
2159     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
2160                 static_cast<OperationsMask>( onlyOnceOperations |
2161                                              LAYOUT | REORDER | UPDATE_DIRECTION ),
2162                 naturalSize.GetVectorXY() );
2163
2164     // Clear the update info. This info will be set the next time the text is updated.
2165     mImpl->mTextUpdateInfo.Clear();
2166
2167     mImpl->mUpdateTextDirection = false;
2168   }
2169
2170   return mImpl->mIsTextDirectionRTL ? Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT : Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
2171 }
2172
2173 Toolkit::DevelText::VerticalLineAlignment::Type Controller::GetVerticalLineAlignment() const
2174 {
2175   return mImpl->mModel->GetVerticalLineAlignment();
2176 }
2177
2178 void Controller::SetVerticalLineAlignment( Toolkit::DevelText::VerticalLineAlignment::Type alignment )
2179 {
2180   mImpl->mModel->mVerticalLineAlignment = alignment;
2181 }
2182
2183 // public : Relayout.
2184
2185 Controller::UpdateTextType Controller::Relayout( const Size& size )
2186 {
2187   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, mImpl->mIsAutoScrollEnabled ?"true":"false"  );
2188
2189   UpdateTextType updateTextType = NONE_UPDATED;
2190
2191   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
2192   {
2193     if( 0u != mImpl->mModel->mVisualModel->mGlyphPositions.Count() )
2194     {
2195       mImpl->mModel->mVisualModel->mGlyphPositions.Clear();
2196       updateTextType = MODEL_UPDATED;
2197     }
2198
2199     // Clear the update info. This info will be set the next time the text is updated.
2200     mImpl->mTextUpdateInfo.Clear();
2201
2202     // Not worth to relayout if width or height is equal to zero.
2203     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
2204
2205     return updateTextType;
2206   }
2207
2208   // Whether a new size has been set.
2209   const bool newSize = ( size != mImpl->mModel->mVisualModel->mControlSize );
2210
2211   if( newSize )
2212   {
2213     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mModel->mVisualModel->mControlSize.width, mImpl->mModel->mVisualModel->mControlSize.height );
2214
2215     if( ( 0 == mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd ) &&
2216         ( 0 == mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) &&
2217         ( ( mImpl->mModel->mVisualModel->mControlSize.width < Math::MACHINE_EPSILON_1000 ) || ( mImpl->mModel->mVisualModel->mControlSize.height < Math::MACHINE_EPSILON_1000 ) ) )
2218     {
2219       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
2220     }
2221
2222     // Layout operations that need to be done if the size changes.
2223     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2224                                                              LAYOUT                    |
2225                                                              ALIGN                     |
2226                                                              UPDATE_LAYOUT_SIZE        |
2227                                                              REORDER );
2228     // Set the update info to relayout the whole text.
2229     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2230     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2231
2232     // Store the size used to layout the text.
2233     mImpl->mModel->mVisualModel->mControlSize = size;
2234   }
2235
2236   // Whether there are modify events.
2237   if( 0u != mImpl->mModifyEvents.Count() )
2238   {
2239     // Style operations that need to be done if the text is modified.
2240     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2241                                                              COLOR );
2242   }
2243
2244   // Set the update info to elide the text.
2245   if( mImpl->mModel->mElideEnabled ||
2246       ( ( NULL != mImpl->mEventData ) && mImpl->mEventData->mIsPlaceholderElideEnabled ) )
2247   {
2248     // Update Text layout for applying elided
2249     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
2250                                                              ALIGN                     |
2251                                                              LAYOUT                    |
2252                                                              UPDATE_LAYOUT_SIZE        |
2253                                                              REORDER );
2254     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2255     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2256   }
2257
2258   // Make sure the model is up-to-date before layouting.
2259   ProcessModifyEvents();
2260   bool updated = mImpl->UpdateModel( mImpl->mOperationsPending );
2261
2262   // Layout the text.
2263   Size layoutSize;
2264   updated = DoRelayout( size,
2265                         mImpl->mOperationsPending,
2266                         layoutSize ) || updated;
2267
2268   if( updated )
2269   {
2270     updateTextType = MODEL_UPDATED;
2271   }
2272
2273   // Do not re-do any operation until something changes.
2274   mImpl->mOperationsPending = NO_OPERATION;
2275   mImpl->mModel->mScrollPositionLast = mImpl->mModel->mScrollPosition;
2276
2277   // Whether the text control is editable
2278   const bool isEditable = NULL != mImpl->mEventData;
2279
2280   // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
2281   Vector2 offset;
2282   if( newSize && isEditable )
2283   {
2284     offset = mImpl->mModel->mScrollPosition;
2285   }
2286
2287   if( !isEditable || !IsMultiLineEnabled() )
2288   {
2289     // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
2290     CalculateVerticalOffset( size );
2291   }
2292
2293   if( isEditable )
2294   {
2295     if( newSize )
2296     {
2297       // If there is a new size, the scroll position needs to be clamped.
2298       mImpl->ClampHorizontalScroll( layoutSize );
2299
2300       // Update the decorator's positions is needed if there is a new size.
2301       mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mModel->mScrollPosition - offset );
2302     }
2303
2304     // Move the cursor, grab handle etc.
2305     if( mImpl->ProcessInputEvents() )
2306     {
2307       updateTextType = static_cast<UpdateTextType>( updateTextType | DECORATOR_UPDATED );
2308     }
2309   }
2310
2311   // Clear the update info. This info will be set the next time the text is updated.
2312   mImpl->mTextUpdateInfo.Clear();
2313   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
2314
2315   return updateTextType;
2316 }
2317
2318 void Controller::RequestRelayout()
2319 {
2320   mImpl->RequestRelayout();
2321 }
2322
2323 // public : Input style change signals.
2324
2325 bool Controller::IsInputStyleChangedSignalsQueueEmpty()
2326 {
2327   return ( NULL == mImpl->mEventData ) || ( 0u == mImpl->mEventData->mInputStyleChangedQueue.Count() );
2328 }
2329
2330 void Controller::ProcessInputStyleChangedSignals()
2331 {
2332   if( NULL == mImpl->mEventData )
2333   {
2334     // Nothing to do.
2335     return;
2336   }
2337
2338   for( Vector<InputStyle::Mask>::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(),
2339          endIt = mImpl->mEventData->mInputStyleChangedQueue.End();
2340        it != endIt;
2341        ++it )
2342   {
2343     const InputStyle::Mask mask = *it;
2344
2345     if( NULL != mImpl->mEditableControlInterface )
2346     {
2347       // Emit the input style changed signal.
2348       mImpl->mEditableControlInterface->InputStyleChanged( mask );
2349     }
2350   }
2351
2352   mImpl->mEventData->mInputStyleChangedQueue.Clear();
2353 }
2354
2355 // public : Text-input Event Queuing.
2356
2357 void Controller::KeyboardFocusGainEvent()
2358 {
2359   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
2360
2361   if( NULL != mImpl->mEventData )
2362   {
2363     if( ( EventData::INACTIVE == mImpl->mEventData->mState ) ||
2364         ( EventData::INTERRUPTED == mImpl->mEventData->mState ) )
2365     {
2366       mImpl->ChangeState( EventData::EDITING );
2367       mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
2368       mImpl->mEventData->mUpdateInputStyle = true;
2369     }
2370     mImpl->NotifyImfMultiLineStatus();
2371     if( mImpl->IsShowingPlaceholderText() )
2372     {
2373       // Show alternative placeholder-text when editing
2374       ShowPlaceholderText();
2375     }
2376
2377     mImpl->RequestRelayout();
2378   }
2379 }
2380
2381 void Controller::KeyboardFocusLostEvent()
2382 {
2383   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
2384
2385   if( NULL != mImpl->mEventData )
2386   {
2387     if( EventData::INTERRUPTED != mImpl->mEventData->mState )
2388     {
2389       mImpl->ChangeState( EventData::INACTIVE );
2390
2391       if( !mImpl->IsShowingRealText() )
2392       {
2393         // Revert to regular placeholder-text when not editing
2394         ShowPlaceholderText();
2395       }
2396     }
2397   }
2398   mImpl->RequestRelayout();
2399 }
2400
2401 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
2402 {
2403   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
2404
2405   bool textChanged = false;
2406   bool relayoutNeeded = false;
2407
2408   if( ( NULL != mImpl->mEventData ) &&
2409       ( keyEvent.state == KeyEvent::Down ) )
2410   {
2411     int keyCode = keyEvent.keyCode;
2412     const std::string& keyString = keyEvent.keyPressed;
2413     const std::string keyName = keyEvent.keyPressedName;
2414
2415     const bool isNullKey = ( 0 == keyCode ) && ( keyString.empty() );
2416
2417     // Pre-process to separate modifying events from non-modifying input events.
2418     if( isNullKey )
2419     {
2420       // In some platforms arrive key events with no key code.
2421       // Do nothing.
2422       return false;
2423     }
2424     else if( Dali::DALI_KEY_ESCAPE == keyCode || Dali::DALI_KEY_BACK == keyCode  || Dali::DALI_KEY_SEARCH == keyCode )
2425     {
2426       // Do nothing
2427       return false;
2428     }
2429     else if( ( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ) ||
2430              ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode ) ||
2431              ( Dali::DALI_KEY_CURSOR_UP    == keyCode ) ||
2432              ( Dali::DALI_KEY_CURSOR_DOWN  == keyCode ) )
2433     {
2434       // If don't have any text, do nothing.
2435       if( !mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters )
2436       {
2437         return false;
2438       }
2439
2440       uint32_t cursorPosition = mImpl->mEventData->mPrimaryCursorPosition;
2441       uint32_t numberOfCharacters = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2442       uint32_t cursorLine = mImpl->mModel->mVisualModel->GetLineOfCharacter( cursorPosition );
2443       uint32_t numberOfLines = mImpl->mModel->GetNumberOfLines();
2444
2445       // Logic to determine whether this text control will lose focus or not.
2446       if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode && 0 == cursorPosition && !keyEvent.IsShiftModifier() ) ||
2447           ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition && !keyEvent.IsShiftModifier() ) ||
2448           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && cursorLine == numberOfLines -1 ) ||
2449           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && numberOfCharacters == cursorPosition && cursorLine -1 == numberOfLines -1 ) ||
2450           ( Dali::DALI_KEY_CURSOR_UP == keyCode && cursorLine == 0 ) ||
2451           ( Dali::DALI_KEY_CURSOR_UP == keyCode && numberOfCharacters == cursorPosition && cursorLine == 1 ) )
2452       {
2453         // Release the active highlight.
2454         if( mImpl->mEventData->mState == EventData::SELECTING )
2455         {
2456           mImpl->ChangeState( EventData::EDITING );
2457
2458           // Update selection position.
2459           mImpl->mEventData->mLeftSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
2460           mImpl->mEventData->mRightSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
2461           mImpl->mEventData->mUpdateCursorPosition = true;
2462           mImpl->RequestRelayout();
2463         }
2464         return false;
2465       }
2466
2467       mImpl->mEventData->mCheckScrollAmount = true;
2468       Event event( Event::CURSOR_KEY_EVENT );
2469       event.p1.mInt = keyCode;
2470       event.p2.mBool = keyEvent.IsShiftModifier();
2471       mImpl->mEventData->mEventQueue.push_back( event );
2472
2473       // Will request for relayout.
2474       relayoutNeeded = true;
2475     }
2476     else if ( Dali::DevelKey::DALI_KEY_CONTROL_LEFT == keyCode || Dali::DevelKey::DALI_KEY_CONTROL_RIGHT == keyCode )
2477     {
2478       // Left or Right Control key event is received before Ctrl-C/V/X key event is received
2479       // If not handle it here, any selected text will be deleted
2480
2481       // Do nothing
2482       return false;
2483     }
2484     else if ( keyEvent.IsCtrlModifier() )
2485     {
2486       bool consumed = false;
2487       if (keyName == KEY_C_NAME)
2488       {
2489         // Ctrl-C to copy the selected text
2490         TextPopupButtonTouched( Toolkit::TextSelectionPopup::COPY );
2491         consumed = true;
2492       }
2493       else if (keyName == KEY_V_NAME)
2494       {
2495         // Ctrl-V to paste the copied text
2496         TextPopupButtonTouched( Toolkit::TextSelectionPopup::PASTE );
2497         consumed = true;
2498       }
2499       else if (keyName == KEY_X_NAME)
2500       {
2501         // Ctrl-X to cut the selected text
2502         TextPopupButtonTouched( Toolkit::TextSelectionPopup::CUT );
2503         consumed = true;
2504       }
2505       return consumed;
2506     }
2507     else if( ( Dali::DALI_KEY_BACKSPACE == keyCode ) ||
2508              ( Dali::DevelKey::DALI_KEY_DELETE == keyCode ) )
2509     {
2510       textChanged = DeleteEvent( keyCode );
2511
2512       // Will request for relayout.
2513       relayoutNeeded = true;
2514     }
2515     else if( IsKey( keyEvent, Dali::DALI_KEY_POWER ) ||
2516              IsKey( keyEvent, Dali::DALI_KEY_MENU )  ||
2517              IsKey( keyEvent, static_cast<Dali::KEY>(Dali::DevelKey::DALI_KEY_SOURCE) ) ||
2518              IsKey( keyEvent, Dali::DALI_KEY_HOME ) )
2519     {
2520       // Power key/Menu/Home key behaviour does not allow edit mode to resume.
2521       mImpl->ChangeState( EventData::INACTIVE );
2522
2523       // Will request for relayout.
2524       relayoutNeeded = true;
2525
2526       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
2527     }
2528     else if( Dali::DALI_KEY_SHIFT_LEFT == keyCode )
2529     {
2530       // DALI_KEY_SHIFT_LEFT is the key code for the Left Shift. It's sent (by the imf?) when the predictive text is enabled
2531       // and a character is typed after the type of a upper case latin character.
2532
2533       // Do nothing.
2534       return false;
2535     }
2536     else if( ( Dali::DALI_KEY_VOLUME_UP == keyCode ) || ( Dali::DALI_KEY_VOLUME_DOWN == keyCode ) )
2537     {
2538       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
2539       // Do nothing.
2540       return false;
2541     }
2542     else
2543     {
2544       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() );
2545
2546       // IMF manager is no longer handling key-events
2547       mImpl->ClearPreEditFlag();
2548
2549       InsertText( keyString, COMMIT );
2550       textChanged = true;
2551
2552       // Will request for relayout.
2553       relayoutNeeded = true;
2554     }
2555
2556     if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
2557          ( mImpl->mEventData->mState != EventData::INACTIVE ) &&
2558          ( !isNullKey ) &&
2559          ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) &&
2560          ( Dali::DALI_KEY_VOLUME_UP != keyCode ) &&
2561          ( Dali::DALI_KEY_VOLUME_DOWN != keyCode ) )
2562     {
2563       // Should not change the state if the key is the shift send by the imf manager.
2564       // Otherwise, when the state is SELECTING the text controller can't send the right
2565       // surrounding info to the imf.
2566       mImpl->ChangeState( EventData::EDITING );
2567
2568       // Will request for relayout.
2569       relayoutNeeded = true;
2570     }
2571
2572     if( relayoutNeeded )
2573     {
2574       mImpl->RequestRelayout();
2575     }
2576   }
2577
2578   if( textChanged &&
2579       ( NULL != mImpl->mEditableControlInterface ) )
2580   {
2581     // Do this last since it provides callbacks into application code
2582     mImpl->mEditableControlInterface->TextChanged();
2583   }
2584
2585   return true;
2586 }
2587
2588 void Controller::TapEvent( unsigned int tapCount, float x, float y )
2589 {
2590   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
2591
2592   if( NULL != mImpl->mEventData )
2593   {
2594     DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState );
2595     EventData::State state( mImpl->mEventData->mState );
2596     bool relayoutNeeded( false );   // to avoid unnecessary relayouts when tapping an empty text-field
2597
2598     if( mImpl->IsClipboardVisible() )
2599     {
2600       if( EventData::INACTIVE == state || EventData::EDITING == state)
2601       {
2602         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2603       }
2604       relayoutNeeded = true;
2605     }
2606     else if( 1u == tapCount )
2607     {
2608       if( EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state )
2609       {
2610         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );  // If Popup shown hide it here so can be shown again if required.
2611       }
2612
2613       if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != state ) )
2614       {
2615         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
2616         relayoutNeeded = true;
2617       }
2618       else
2619       {
2620         if( mImpl->IsShowingPlaceholderText() && !mImpl->IsFocusedPlaceholderAvailable() )
2621         {
2622           // Hide placeholder text
2623           ResetText();
2624         }
2625
2626         if( EventData::INACTIVE == state )
2627         {
2628           mImpl->ChangeState( EventData::EDITING );
2629         }
2630         else if( !mImpl->IsClipboardEmpty() )
2631         {
2632           mImpl->ChangeState( EventData::EDITING_WITH_POPUP );
2633         }
2634         relayoutNeeded = true;
2635       }
2636     }
2637     else if( 2u == tapCount )
2638     {
2639       if( mImpl->mEventData->mSelectionEnabled &&
2640           mImpl->IsShowingRealText() )
2641       {
2642         relayoutNeeded = true;
2643         mImpl->mEventData->mIsLeftHandleSelected = true;
2644         mImpl->mEventData->mIsRightHandleSelected = true;
2645       }
2646     }
2647
2648     // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
2649     if( relayoutNeeded )
2650     {
2651       Event event( Event::TAP_EVENT );
2652       event.p1.mUint = tapCount;
2653       event.p2.mFloat = x;
2654       event.p3.mFloat = y;
2655       mImpl->mEventData->mEventQueue.push_back( event );
2656
2657       mImpl->RequestRelayout();
2658     }
2659   }
2660
2661   // Reset keyboard as tap event has occurred.
2662   mImpl->ResetImfManager();
2663 }
2664
2665 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
2666 {
2667   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
2668
2669   if( NULL != mImpl->mEventData )
2670   {
2671     Event event( Event::PAN_EVENT );
2672     event.p1.mInt = state;
2673     event.p2.mFloat = displacement.x;
2674     event.p3.mFloat = displacement.y;
2675     mImpl->mEventData->mEventQueue.push_back( event );
2676
2677     mImpl->RequestRelayout();
2678   }
2679 }
2680
2681 void Controller::LongPressEvent( Gesture::State state, float x, float y  )
2682 {
2683   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" );
2684
2685   if( ( state == Gesture::Started ) &&
2686       ( NULL != mImpl->mEventData ) )
2687   {
2688     // The 1st long-press on inactive text-field is treated as tap
2689     if( EventData::INACTIVE == mImpl->mEventData->mState )
2690     {
2691       mImpl->ChangeState( EventData::EDITING );
2692
2693       Event event( Event::TAP_EVENT );
2694       event.p1.mUint = 1;
2695       event.p2.mFloat = x;
2696       event.p3.mFloat = y;
2697       mImpl->mEventData->mEventQueue.push_back( event );
2698
2699       mImpl->RequestRelayout();
2700     }
2701     else if( !mImpl->IsShowingRealText() )
2702     {
2703       Event event( Event::LONG_PRESS_EVENT );
2704       event.p1.mInt = state;
2705       event.p2.mFloat = x;
2706       event.p3.mFloat = y;
2707       mImpl->mEventData->mEventQueue.push_back( event );
2708       mImpl->RequestRelayout();
2709     }
2710     else if( !mImpl->IsClipboardVisible() )
2711     {
2712       // Reset the imf manager to commit the pre-edit before selecting the text.
2713       mImpl->ResetImfManager();
2714
2715       Event event( Event::LONG_PRESS_EVENT );
2716       event.p1.mInt = state;
2717       event.p2.mFloat = x;
2718       event.p3.mFloat = y;
2719       mImpl->mEventData->mEventQueue.push_back( event );
2720       mImpl->RequestRelayout();
2721
2722       mImpl->mEventData->mIsLeftHandleSelected = true;
2723       mImpl->mEventData->mIsRightHandleSelected = true;
2724     }
2725   }
2726 }
2727
2728 ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
2729 {
2730   // Whether the text needs to be relaid-out.
2731   bool requestRelayout = false;
2732
2733   // Whether to retrieve the text and cursor position to be sent to the IMF manager.
2734   bool retrieveText = false;
2735   bool retrieveCursor = false;
2736
2737   switch( imfEvent.eventName )
2738   {
2739     case ImfManager::COMMIT:
2740     {
2741       InsertText( imfEvent.predictiveString, Text::Controller::COMMIT );
2742       requestRelayout = true;
2743       retrieveCursor = true;
2744       break;
2745     }
2746     case ImfManager::PREEDIT:
2747     {
2748       InsertText( imfEvent.predictiveString, Text::Controller::PRE_EDIT );
2749       requestRelayout = true;
2750       retrieveCursor = true;
2751       break;
2752     }
2753     case ImfManager::DELETESURROUNDING:
2754     {
2755       const bool textDeleted = RemoveText( imfEvent.cursorOffset,
2756                                            imfEvent.numberOfChars,
2757                                            DONT_UPDATE_INPUT_STYLE );
2758
2759       if( textDeleted )
2760       {
2761         if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
2762             !mImpl->IsPlaceholderAvailable() )
2763         {
2764           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2765         }
2766         else
2767         {
2768           ShowPlaceholderText();
2769         }
2770         mImpl->mEventData->mUpdateCursorPosition = true;
2771         mImpl->mEventData->mScrollAfterDelete = true;
2772
2773         requestRelayout = true;
2774       }
2775       break;
2776     }
2777     case ImfManager::GETSURROUNDING:
2778     {
2779       retrieveText = true;
2780       retrieveCursor = true;
2781       break;
2782     }
2783     case ImfManager::PRIVATECOMMAND:
2784     {
2785       // PRIVATECOMMAND event is just for getting the private command message
2786       retrieveText = true;
2787       retrieveCursor = true;
2788       break;
2789     }
2790     case ImfManager::VOID:
2791     {
2792       // do nothing
2793       break;
2794     }
2795   } // end switch
2796
2797   if( requestRelayout )
2798   {
2799     mImpl->mOperationsPending = ALL_OPERATIONS;
2800     mImpl->RequestRelayout();
2801   }
2802
2803   std::string text;
2804   CharacterIndex cursorPosition = 0u;
2805   Length numberOfWhiteSpaces = 0u;
2806
2807   if( retrieveCursor )
2808   {
2809     numberOfWhiteSpaces = mImpl->GetNumberOfWhiteSpaces( 0u );
2810
2811     cursorPosition = mImpl->GetLogicalCursorPosition();
2812
2813     if( cursorPosition < numberOfWhiteSpaces )
2814     {
2815       cursorPosition = 0u;
2816     }
2817     else
2818     {
2819       cursorPosition -= numberOfWhiteSpaces;
2820     }
2821   }
2822
2823   if( retrieveText )
2824   {
2825     if( !mImpl->IsShowingPlaceholderText() )
2826     {
2827       // Retrieves the normal text string.
2828       mImpl->GetText( numberOfWhiteSpaces, text );
2829     }
2830     else
2831     {
2832       // When the current text is Placeholder Text, the surrounding text should be empty string.
2833       // It means DALi should send empty string ("") to IME.
2834       text = "";
2835     }
2836   }
2837
2838   ImfManager::ImfCallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false );
2839
2840   if( requestRelayout &&
2841       ( NULL != mImpl->mEditableControlInterface ) )
2842   {
2843     // Do this last since it provides callbacks into application code
2844     mImpl->mEditableControlInterface->TextChanged();
2845   }
2846
2847   return callbackData;
2848 }
2849
2850 void Controller::PasteClipboardItemEvent()
2851 {
2852   // Retrieve the clipboard contents first
2853   ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
2854   std::string stringToPaste( notifier.GetContent() );
2855
2856   // Commit the current pre-edit text; the contents of the clipboard should be appended
2857   mImpl->ResetImfManager();
2858
2859   // Temporary disable hiding clipboard
2860   mImpl->SetClipboardHideEnable( false );
2861
2862   // Paste
2863   PasteText( stringToPaste );
2864
2865   mImpl->SetClipboardHideEnable( true );
2866 }
2867
2868 // protected : Inherit from Text::Decorator::ControllerInterface.
2869
2870 void Controller::GetTargetSize( Vector2& targetSize )
2871 {
2872   targetSize = mImpl->mModel->mVisualModel->mControlSize;
2873 }
2874
2875 void Controller::AddDecoration( Actor& actor, bool needsClipping )
2876 {
2877   if( NULL != mImpl->mEditableControlInterface )
2878   {
2879     mImpl->mEditableControlInterface->AddDecoration( actor, needsClipping );
2880   }
2881 }
2882
2883 void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
2884 {
2885   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
2886
2887   if( NULL != mImpl->mEventData )
2888   {
2889     switch( handleType )
2890     {
2891       case GRAB_HANDLE:
2892       {
2893         Event event( Event::GRAB_HANDLE_EVENT );
2894         event.p1.mUint  = state;
2895         event.p2.mFloat = x;
2896         event.p3.mFloat = y;
2897
2898         mImpl->mEventData->mEventQueue.push_back( event );
2899         break;
2900       }
2901       case LEFT_SELECTION_HANDLE:
2902       {
2903         Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
2904         event.p1.mUint  = state;
2905         event.p2.mFloat = x;
2906         event.p3.mFloat = y;
2907
2908         mImpl->mEventData->mEventQueue.push_back( event );
2909         break;
2910       }
2911       case RIGHT_SELECTION_HANDLE:
2912       {
2913         Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
2914         event.p1.mUint  = state;
2915         event.p2.mFloat = x;
2916         event.p3.mFloat = y;
2917
2918         mImpl->mEventData->mEventQueue.push_back( event );
2919         break;
2920       }
2921       case LEFT_SELECTION_HANDLE_MARKER:
2922       case RIGHT_SELECTION_HANDLE_MARKER:
2923       {
2924         // Markers do not move the handles.
2925         break;
2926       }
2927       case HANDLE_TYPE_COUNT:
2928       {
2929         DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
2930       }
2931     }
2932
2933     mImpl->RequestRelayout();
2934   }
2935 }
2936
2937 // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
2938
2939 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
2940 {
2941   if( NULL == mImpl->mEventData )
2942   {
2943     return;
2944   }
2945
2946   switch( button )
2947   {
2948     case Toolkit::TextSelectionPopup::CUT:
2949     {
2950       mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
2951       mImpl->mOperationsPending = ALL_OPERATIONS;
2952
2953       if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
2954           !mImpl->IsPlaceholderAvailable() )
2955       {
2956         mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
2957       }
2958       else
2959       {
2960         ShowPlaceholderText();
2961       }
2962
2963       mImpl->mEventData->mUpdateCursorPosition = true;
2964       mImpl->mEventData->mScrollAfterDelete = true;
2965
2966       mImpl->RequestRelayout();
2967
2968       if( NULL != mImpl->mEditableControlInterface )
2969       {
2970         mImpl->mEditableControlInterface->TextChanged();
2971       }
2972       break;
2973     }
2974     case Toolkit::TextSelectionPopup::COPY:
2975     {
2976       mImpl->SendSelectionToClipboard( false ); // Text not modified
2977
2978       mImpl->mEventData->mUpdateCursorPosition = true;
2979
2980       mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup
2981       break;
2982     }
2983     case Toolkit::TextSelectionPopup::PASTE:
2984     {
2985       mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item
2986       break;
2987     }
2988     case Toolkit::TextSelectionPopup::SELECT:
2989     {
2990       const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
2991
2992       if( mImpl->mEventData->mSelectionEnabled )
2993       {
2994         // Creates a SELECT event.
2995         SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false );
2996       }
2997       break;
2998     }
2999     case Toolkit::TextSelectionPopup::SELECT_ALL:
3000     {
3001       // Creates a SELECT_ALL event
3002       SelectEvent( 0.f, 0.f, true );
3003       break;
3004     }
3005     case Toolkit::TextSelectionPopup::CLIPBOARD:
3006     {
3007       mImpl->ShowClipboard();
3008       break;
3009     }
3010     case Toolkit::TextSelectionPopup::NONE:
3011     {
3012       // Nothing to do.
3013       break;
3014     }
3015   }
3016 }
3017
3018 void Controller::DisplayTimeExpired()
3019 {
3020   mImpl->mEventData->mUpdateCursorPosition = true;
3021   // Apply modifications to the model
3022   mImpl->mOperationsPending = ALL_OPERATIONS;
3023
3024   mImpl->RequestRelayout();
3025 }
3026
3027 // private : Update.
3028
3029 void Controller::InsertText( const std::string& text, Controller::InsertType type )
3030 {
3031   bool removedPrevious = false;
3032   bool removedSelected = false;
3033   bool maxLengthReached = false;
3034
3035   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
3036
3037   if( NULL == mImpl->mEventData )
3038   {
3039     return;
3040   }
3041
3042   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
3043                  this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
3044                  mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
3045
3046   // TODO: At the moment the underline runs are only for pre-edit.
3047   mImpl->mModel->mVisualModel->mUnderlineRuns.Clear();
3048
3049   // Remove the previous IMF pre-edit.
3050   if( mImpl->mEventData->mPreEditFlag && ( 0u != mImpl->mEventData->mPreEditLength ) )
3051   {
3052     removedPrevious = RemoveText( -static_cast<int>( mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition ),
3053                                   mImpl->mEventData->mPreEditLength,
3054                                   DONT_UPDATE_INPUT_STYLE );
3055
3056     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
3057     mImpl->mEventData->mPreEditLength = 0u;
3058   }
3059   else
3060   {
3061     // Remove the previous Selection.
3062     removedSelected = RemoveSelectedText();
3063
3064   }
3065
3066   Vector<Character> utf32Characters;
3067   Length characterCount = 0u;
3068
3069   if( !text.empty() )
3070   {
3071     //  Convert text into UTF-32
3072     utf32Characters.Resize( text.size() );
3073
3074     // This is a bit horrible but std::string returns a (signed) char*
3075     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
3076
3077     // Transform a text array encoded in utf8 into an array encoded in utf32.
3078     // It returns the actual number of characters.
3079     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
3080     utf32Characters.Resize( characterCount );
3081
3082     DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
3083     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
3084   }
3085
3086   if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
3087   {
3088     // The placeholder text is no longer needed
3089     if( mImpl->IsShowingPlaceholderText() )
3090     {
3091       ResetText();
3092     }
3093
3094     mImpl->ChangeState( EventData::EDITING );
3095
3096     // Handle the IMF (predicitive text) state changes
3097     if( COMMIT == type )
3098     {
3099       // IMF manager is no longer handling key-events
3100       mImpl->ClearPreEditFlag();
3101     }
3102     else // PRE_EDIT
3103     {
3104       if( !mImpl->mEventData->mPreEditFlag )
3105       {
3106         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state\n" );
3107
3108         // Record the start of the pre-edit text
3109         mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
3110       }
3111
3112       mImpl->mEventData->mPreEditLength = utf32Characters.Count();
3113       mImpl->mEventData->mPreEditFlag = true;
3114
3115       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
3116     }
3117
3118     const Length numberOfCharactersInModel = mImpl->mModel->mLogicalModel->mText.Count();
3119
3120     // Restrict new text to fit within Maximum characters setting.
3121     Length maxSizeOfNewText = std::min( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
3122     maxLengthReached = ( characterCount > maxSizeOfNewText );
3123
3124     // The cursor position.
3125     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
3126
3127     // Update the text's style.
3128
3129     // Updates the text style runs by adding characters.
3130     mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText );
3131
3132     // Get the character index from the cursor index.
3133     const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u;
3134
3135     // Retrieve the text's style for the given index.
3136     InputStyle style;
3137     mImpl->RetrieveDefaultInputStyle( style );
3138     mImpl->mModel->mLogicalModel->RetrieveStyle( styleIndex, style );
3139
3140     // Whether to add a new text color run.
3141     const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor );
3142
3143     // Whether to add a new font run.
3144     const bool addFontNameRun = style.familyName != mImpl->mEventData->mInputStyle.familyName;
3145     const bool addFontWeightRun = style.weight != mImpl->mEventData->mInputStyle.weight;
3146     const bool addFontWidthRun = style.width != mImpl->mEventData->mInputStyle.width;
3147     const bool addFontSlantRun = style.slant != mImpl->mEventData->mInputStyle.slant;
3148     const bool addFontSizeRun = style.size != mImpl->mEventData->mInputStyle.size;
3149
3150     // Add style runs.
3151     if( addColorRun )
3152     {
3153       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
3154       mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
3155
3156       ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
3157       colorRun.color = mImpl->mEventData->mInputStyle.textColor;
3158       colorRun.characterRun.characterIndex = cursorIndex;
3159       colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
3160     }
3161
3162     if( addFontNameRun   ||
3163         addFontWeightRun ||
3164         addFontWidthRun  ||
3165         addFontSlantRun  ||
3166         addFontSizeRun )
3167     {
3168       const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Count();
3169       mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
3170
3171       FontDescriptionRun& fontDescriptionRun = *( mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
3172
3173       if( addFontNameRun )
3174       {
3175         fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
3176         fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
3177         memcpy( fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength );
3178         fontDescriptionRun.familyDefined = true;
3179
3180         // The memory allocated for the font family name is freed when the font description is removed from the logical model.
3181       }
3182
3183       if( addFontWeightRun )
3184       {
3185         fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
3186         fontDescriptionRun.weightDefined = true;
3187       }
3188
3189       if( addFontWidthRun )
3190       {
3191         fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
3192         fontDescriptionRun.widthDefined = true;
3193       }
3194
3195       if( addFontSlantRun )
3196       {
3197         fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
3198         fontDescriptionRun.slantDefined = true;
3199       }
3200
3201       if( addFontSizeRun )
3202       {
3203         fontDescriptionRun.size = static_cast<PointSize26Dot6>( mImpl->mEventData->mInputStyle.size * 64.f );
3204         fontDescriptionRun.sizeDefined = true;
3205       }
3206
3207       fontDescriptionRun.characterRun.characterIndex = cursorIndex;
3208       fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
3209     }
3210
3211     // Insert at current cursor position.
3212     Vector<Character>& modifyText = mImpl->mModel->mLogicalModel->mText;
3213
3214     if( cursorIndex < numberOfCharactersInModel )
3215     {
3216       modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3217     }
3218     else
3219     {
3220       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
3221     }
3222
3223     // Mark the first paragraph to be updated.
3224     if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
3225     {
3226       mImpl->mTextUpdateInfo.mCharacterIndex = 0;
3227       mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3228       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = numberOfCharactersInModel + maxSizeOfNewText;
3229       mImpl->mTextUpdateInfo.mClearAll = true;
3230     }
3231     else
3232     {
3233       mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
3234       mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
3235     }
3236
3237     // Update the cursor index.
3238     cursorIndex += maxSizeOfNewText;
3239
3240     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 );
3241   }
3242
3243   if( ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) &&
3244       mImpl->IsPlaceholderAvailable() )
3245   {
3246     // Show place-holder if empty after removing the pre-edit text
3247     ShowPlaceholderText();
3248     mImpl->mEventData->mUpdateCursorPosition = true;
3249     mImpl->ClearPreEditFlag();
3250   }
3251   else if( removedPrevious ||
3252            removedSelected ||
3253            ( 0 != utf32Characters.Count() ) )
3254   {
3255     // Queue an inserted event
3256     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
3257
3258     mImpl->mEventData->mUpdateCursorPosition = true;
3259     if( removedSelected )
3260     {
3261       mImpl->mEventData->mScrollAfterDelete = true;
3262     }
3263     else
3264     {
3265       mImpl->mEventData->mScrollAfterUpdatePosition = true;
3266     }
3267   }
3268
3269   if( maxLengthReached )
3270   {
3271     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mModel->mLogicalModel->mText.Count() );
3272
3273     mImpl->ResetImfManager();
3274
3275     if( NULL != mImpl->mEditableControlInterface )
3276     {
3277       // Do this last since it provides callbacks into application code
3278       mImpl->mEditableControlInterface->MaxLengthReached();
3279     }
3280   }
3281 }
3282
3283 void Controller::PasteText( const std::string& stringToPaste )
3284 {
3285   InsertText( stringToPaste, Text::Controller::COMMIT );
3286   mImpl->ChangeState( EventData::EDITING );
3287   mImpl->RequestRelayout();
3288
3289   if( NULL != mImpl->mEditableControlInterface )
3290   {
3291     // Do this last since it provides callbacks into application code
3292     mImpl->mEditableControlInterface->TextChanged();
3293   }
3294 }
3295
3296 bool Controller::RemoveText( int cursorOffset,
3297                              int numberOfCharacters,
3298                              UpdateInputStyleType type )
3299 {
3300   bool removed = false;
3301
3302   // When the users press "Delete All" button, the IME sends numberOfCharacters as '200000' value which means the max number of characters.
3303   const bool deleteAll = ( numberOfCharacters >= MAX_NUMBER_OF_CHARACTERS );
3304
3305   if( NULL == mImpl->mEventData )
3306   {
3307     return removed;
3308   }
3309
3310   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n",
3311                  this, mImpl->mModel->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters );
3312
3313   if( !mImpl->IsShowingPlaceholderText() )
3314   {
3315     // Delete at current cursor position
3316     Vector<Character>& currentText = mImpl->mModel->mLogicalModel->mText;
3317     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
3318
3319     CharacterIndex cursorIndex = 0;
3320
3321     // Validate the cursor position & number of characters
3322     if( ( static_cast< int >( mImpl->mEventData->mPrimaryCursorPosition ) + cursorOffset ) >= 0 )
3323     {
3324       cursorIndex = mImpl->mEventData->mPrimaryCursorPosition + cursorOffset;
3325     }
3326
3327     if( ( cursorIndex + numberOfCharacters ) > currentText.Count() )
3328     {
3329       numberOfCharacters = currentText.Count() - cursorIndex;
3330     }
3331
3332     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.
3333         ( ( cursorIndex + numberOfCharacters ) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) || deleteAll /*'Delete All' button clicked*/ )
3334     {
3335       // Mark the paragraphs to be updated.
3336       if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
3337       {
3338         mImpl->mTextUpdateInfo.mCharacterIndex = 0;
3339         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3340         mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters;
3341         mImpl->mTextUpdateInfo.mClearAll = true;
3342       }
3343       else
3344       {
3345         mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
3346         mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
3347       }
3348
3349       // Update the input style and remove the text's style before removing the text.
3350
3351       if( UPDATE_INPUT_STYLE == type )
3352       {
3353         // Keep a copy of the current input style.
3354         InputStyle currentInputStyle;
3355         currentInputStyle.Copy( mImpl->mEventData->mInputStyle );
3356
3357         // Set first the default input style.
3358         mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle );
3359
3360         // Update the input style.
3361         mImpl->mModel->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle );
3362
3363         // Compare if the input style has changed.
3364         const bool hasInputStyleChanged = !currentInputStyle.Equal( mImpl->mEventData->mInputStyle );
3365
3366         if( hasInputStyleChanged )
3367         {
3368           const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mImpl->mEventData->mInputStyle );
3369           // Queue the input style changed signal.
3370           mImpl->mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
3371         }
3372       }
3373
3374       // Updates the text style runs by removing characters. Runs with no characters are removed.
3375       mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters );
3376
3377       // Remove the characters.
3378       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
3379       Vector<Character>::Iterator last  = first + numberOfCharacters;
3380
3381       currentText.Erase( first, last );
3382
3383       // Cursor position retreat
3384       oldCursorIndex = cursorIndex;
3385
3386       mImpl->mEventData->mScrollAfterDelete = true;
3387
3388       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters );
3389       removed = true;
3390     }
3391   }
3392
3393   return removed;
3394 }
3395
3396 bool Controller::RemoveSelectedText()
3397 {
3398   bool textRemoved( false );
3399
3400   if( EventData::SELECTING == mImpl->mEventData->mState )
3401   {
3402     std::string removedString;
3403     mImpl->RetrieveSelection( removedString, true );
3404
3405     if( !removedString.empty() )
3406     {
3407       textRemoved = true;
3408       mImpl->ChangeState( EventData::EDITING );
3409     }
3410   }
3411
3412   return textRemoved;
3413 }
3414
3415 // private : Relayout.
3416
3417 bool Controller::DoRelayout( const Size& size,
3418                              OperationsMask operationsRequired,
3419                              Size& layoutSize )
3420 {
3421   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height );
3422   bool viewUpdated( false );
3423
3424   // Calculate the operations to be done.
3425   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
3426
3427   const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
3428   const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
3429
3430   // Get the current layout size.
3431   layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
3432
3433   if( NO_OPERATION != ( LAYOUT & operations ) )
3434   {
3435     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
3436
3437     // Some vectors with data needed to layout and reorder may be void
3438     // after the first time the text has been laid out.
3439     // Fill the vectors again.
3440
3441     // Calculate the number of glyphs to layout.
3442     const Vector<GlyphIndex>& charactersToGlyph = mImpl->mModel->mVisualModel->mCharactersToGlyph;
3443     const Vector<Length>& glyphsPerCharacter = mImpl->mModel->mVisualModel->mGlyphsPerCharacter;
3444     const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
3445     const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
3446
3447     const CharacterIndex lastIndex = startIndex + ( ( requestedNumberOfCharacters > 0u ) ? requestedNumberOfCharacters - 1u : 0u );
3448     const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
3449
3450     // Make sure the index is not out of bound
3451     if ( charactersToGlyph.Count() != glyphsPerCharacter.Count() ||
3452          requestedNumberOfCharacters > charactersToGlyph.Count() ||
3453          ( lastIndex >= charactersToGlyph.Count() && charactersToGlyph.Count() > 0u ) )
3454     {
3455       std::string currentText;
3456       GetText( currentText );
3457
3458       DALI_LOG_ERROR( "Controller::DoRelayout: Attempting to access invalid buffer\n" );
3459       DALI_LOG_ERROR( "Current text is: %s\n", currentText.c_str() );
3460       DALI_LOG_ERROR( "startIndex: %u, lastIndex: %u, requestedNumberOfCharacters: %u, charactersToGlyph.Count = %lu, glyphsPerCharacter.Count = %lu\n", startIndex, lastIndex, requestedNumberOfCharacters, charactersToGlyph.Count(), glyphsPerCharacter.Count());
3461
3462       return false;
3463     }
3464
3465     const Length numberOfGlyphs = ( requestedNumberOfCharacters > 0u ) ? *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - startGlyphIndex : 0u;
3466     const Length totalNumberOfGlyphs = mImpl->mModel->mVisualModel->mGlyphs.Count();
3467
3468     if( 0u == totalNumberOfGlyphs )
3469     {
3470       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
3471       {
3472         mImpl->mModel->mVisualModel->SetLayoutSize( Size::ZERO );
3473       }
3474
3475       // Nothing else to do if there is no glyphs.
3476       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n" );
3477       return true;
3478     }
3479
3480     const Vector<LineBreakInfo>& lineBreakInfo = mImpl->mModel->mLogicalModel->mLineBreakInfo;
3481     const Vector<WordBreakInfo>& wordBreakInfo = mImpl->mModel->mLogicalModel->mWordBreakInfo;
3482     const Vector<CharacterDirection>& characterDirection = mImpl->mModel->mLogicalModel->mCharacterDirections;
3483     const Vector<GlyphInfo>& glyphs = mImpl->mModel->mVisualModel->mGlyphs;
3484     const Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mModel->mVisualModel->mGlyphsToCharacters;
3485     const Vector<Length>& charactersPerGlyph = mImpl->mModel->mVisualModel->mCharactersPerGlyph;
3486     const Character* const textBuffer = mImpl->mModel->mLogicalModel->mText.Begin();
3487     const float outlineWidth = static_cast<float>( mImpl->mModel->GetOutlineWidth() );
3488
3489     // Set the layout parameters.
3490     Layout::Parameters layoutParameters( size,
3491                                          textBuffer,
3492                                          lineBreakInfo.Begin(),
3493                                          wordBreakInfo.Begin(),
3494                                          ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
3495                                          glyphs.Begin(),
3496                                          glyphsToCharactersMap.Begin(),
3497                                          charactersPerGlyph.Begin(),
3498                                          charactersToGlyphBuffer,
3499                                          glyphsPerCharacterBuffer,
3500                                          totalNumberOfGlyphs,
3501                                          mImpl->mModel->mHorizontalAlignment,
3502                                          mImpl->mModel->mLineWrapMode,
3503                                          outlineWidth );
3504
3505     // Resize the vector of positions to have the same size than the vector of glyphs.
3506     Vector<Vector2>& glyphPositions = mImpl->mModel->mVisualModel->mGlyphPositions;
3507     glyphPositions.Resize( totalNumberOfGlyphs );
3508
3509     // Whether the last character is a new paragraph character.
3510     mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph =  TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mModel->mLogicalModel->mText.Count() - 1u ) ) );
3511     layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
3512
3513     // The initial glyph and the number of glyphs to layout.
3514     layoutParameters.startGlyphIndex = startGlyphIndex;
3515     layoutParameters.numberOfGlyphs = numberOfGlyphs;
3516     layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex;
3517     layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
3518
3519     // Update the ellipsis
3520     bool elideTextEnabled = mImpl->mModel->mElideEnabled;
3521
3522     if( NULL != mImpl->mEventData )
3523     {
3524       if( mImpl->mEventData->mPlaceholderEllipsisFlag && mImpl->IsShowingPlaceholderText() )
3525       {
3526         elideTextEnabled = mImpl->mEventData->mIsPlaceholderElideEnabled;
3527       }
3528       else if( EventData::INACTIVE != mImpl->mEventData->mState )
3529       {
3530         // Disable ellipsis when editing
3531         elideTextEnabled = false;
3532       }
3533
3534       // Reset the scroll position in inactive state
3535       if( elideTextEnabled && ( mImpl->mEventData->mState == EventData::INACTIVE ) )
3536       {
3537         ResetScrollPosition();
3538       }
3539     }
3540
3541     // Update the visual model.
3542     Size newLayoutSize;
3543     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
3544                                                    glyphPositions,
3545                                                    mImpl->mModel->mVisualModel->mLines,
3546                                                    newLayoutSize,
3547                                                    elideTextEnabled );
3548
3549     viewUpdated = viewUpdated || ( newLayoutSize != layoutSize );
3550
3551     if( viewUpdated )
3552     {
3553       layoutSize = newLayoutSize;
3554
3555       if( NO_OPERATION != ( UPDATE_DIRECTION & operations ) )
3556       {
3557         mImpl->mIsTextDirectionRTL = false;
3558       }
3559
3560       // Reorder the lines
3561       if( NO_OPERATION != ( REORDER & operations ) )
3562       {
3563         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mModel->mLogicalModel->mBidirectionalParagraphInfo;
3564         Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = mImpl->mModel->mLogicalModel->mBidirectionalLineInfo;
3565
3566         // Check first if there are paragraphs with bidirectional info.
3567         if( 0u != bidirectionalInfo.Count() )
3568         {
3569           // Get the lines
3570           const Length numberOfLines = mImpl->mModel->mVisualModel->mLines.Count();
3571
3572           // Reorder the lines.
3573           bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
3574           ReorderLines( bidirectionalInfo,
3575                         startIndex,
3576                         requestedNumberOfCharacters,
3577                         mImpl->mModel->mVisualModel->mLines,
3578                         bidirectionalLineInfo );
3579
3580           // Set the bidirectional info per line into the layout parameters.
3581           layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
3582           layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
3583
3584           // Re-layout the text. Reorder those lines with right to left characters.
3585           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
3586                                                          startIndex,
3587                                                          requestedNumberOfCharacters,
3588                                                          glyphPositions );
3589
3590           if ( ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) ) && ( numberOfLines > 0 ) )
3591           {
3592             const LineRun* const firstline = mImpl->mModel->mVisualModel->mLines.Begin();
3593             if ( firstline )
3594             {
3595               mImpl->mIsTextDirectionRTL = firstline->direction;
3596             }
3597           }
3598         }
3599       } // REORDER
3600
3601       // Sets the layout size.
3602       if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
3603       {
3604         mImpl->mModel->mVisualModel->SetLayoutSize( layoutSize );
3605       }
3606     } // view updated
3607   }
3608
3609   if( NO_OPERATION != ( ALIGN & operations ) )
3610   {
3611     // The laid-out lines.
3612     Vector<LineRun>& lines = mImpl->mModel->mVisualModel->mLines;
3613
3614     // Need to align with the control's size as the text may contain lines
3615     // starting either with left to right text or right to left.
3616     mImpl->mLayoutEngine.Align( size,
3617                                 startIndex,
3618                                 requestedNumberOfCharacters,
3619                                 mImpl->mModel->mHorizontalAlignment,
3620                                 lines,
3621                                 mImpl->mModel->mAlignmentOffset );
3622
3623     viewUpdated = true;
3624   }
3625 #if defined(DEBUG_ENABLED)
3626   std::string currentText;
3627   GetText( currentText );
3628   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mIsTextDirectionRTL[%s] [%s]\n", this, (mImpl->mIsTextDirectionRTL)?"true":"false",  currentText.c_str() );
3629 #endif
3630   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
3631   return viewUpdated;
3632 }
3633
3634 void Controller::CalculateVerticalOffset( const Size& controlSize )
3635 {
3636   Size layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
3637
3638   if( fabsf( layoutSize.height ) < Math::MACHINE_EPSILON_1000 )
3639   {
3640     // Get the line height of the default font.
3641     layoutSize.height = mImpl->GetDefaultFontLineHeight();
3642   }
3643
3644   switch( mImpl->mModel->mVerticalAlignment )
3645   {
3646     case VerticalAlignment::TOP:
3647     {
3648       mImpl->mModel->mScrollPosition.y = 0.f;
3649       break;
3650     }
3651     case VerticalAlignment::CENTER:
3652     {
3653       mImpl->mModel->mScrollPosition.y = floorf( 0.5f * ( controlSize.height - layoutSize.height ) ); // try to avoid pixel alignment.
3654       break;
3655     }
3656     case VerticalAlignment::BOTTOM:
3657     {
3658       mImpl->mModel->mScrollPosition.y = controlSize.height - layoutSize.height;
3659       break;
3660     }
3661   }
3662 }
3663
3664 // private : Events.
3665
3666 void Controller::ProcessModifyEvents()
3667 {
3668   Vector<ModifyEvent>& events = mImpl->mModifyEvents;
3669
3670   if( 0u == events.Count() )
3671   {
3672     // Nothing to do.
3673     return;
3674   }
3675
3676   for( Vector<ModifyEvent>::ConstIterator it = events.Begin(),
3677          endIt = events.End();
3678        it != endIt;
3679        ++it )
3680   {
3681     const ModifyEvent& event = *it;
3682
3683     if( ModifyEvent::TEXT_REPLACED == event.type )
3684     {
3685       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
3686       DALI_ASSERT_DEBUG( it == events.Begin() && "Unexpected TEXT_REPLACED event" );
3687
3688       TextReplacedEvent();
3689     }
3690     else if( ModifyEvent::TEXT_INSERTED == event.type )
3691     {
3692       TextInsertedEvent();
3693     }
3694     else if( ModifyEvent::TEXT_DELETED == event.type )
3695     {
3696       // Placeholder-text cannot be deleted
3697       if( !mImpl->IsShowingPlaceholderText() )
3698       {
3699         TextDeletedEvent();
3700       }
3701     }
3702   }
3703
3704   if( NULL != mImpl->mEventData )
3705   {
3706     // When the text is being modified, delay cursor blinking
3707     mImpl->mEventData->mDecorator->DelayCursorBlink();
3708
3709     // Update selection position after modifying the text
3710     mImpl->mEventData->mLeftSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
3711     mImpl->mEventData->mRightSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
3712   }
3713
3714   // Discard temporary text
3715   events.Clear();
3716 }
3717
3718 void Controller::TextReplacedEvent()
3719 {
3720   // The natural size needs to be re-calculated.
3721   mImpl->mRecalculateNaturalSize = true;
3722
3723   // The text direction needs to be updated.
3724   mImpl->mUpdateTextDirection = true;
3725
3726   // Apply modifications to the model
3727   mImpl->mOperationsPending = ALL_OPERATIONS;
3728 }
3729
3730 void Controller::TextInsertedEvent()
3731 {
3732   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" );
3733
3734   if( NULL == mImpl->mEventData )
3735   {
3736     return;
3737   }
3738
3739   mImpl->mEventData->mCheckScrollAmount = true;
3740
3741   // The natural size needs to be re-calculated.
3742   mImpl->mRecalculateNaturalSize = true;
3743
3744   // The text direction needs to be updated.
3745   mImpl->mUpdateTextDirection = true;
3746
3747   // Apply modifications to the model; TODO - Optimize this
3748   mImpl->mOperationsPending = ALL_OPERATIONS;
3749 }
3750
3751 void Controller::TextDeletedEvent()
3752 {
3753   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" );
3754
3755   if( NULL == mImpl->mEventData )
3756   {
3757     return;
3758   }
3759
3760   mImpl->mEventData->mCheckScrollAmount = true;
3761
3762   // The natural size needs to be re-calculated.
3763   mImpl->mRecalculateNaturalSize = true;
3764
3765   // The text direction needs to be updated.
3766   mImpl->mUpdateTextDirection = true;
3767
3768   // Apply modifications to the model; TODO - Optimize this
3769   mImpl->mOperationsPending = ALL_OPERATIONS;
3770 }
3771
3772 void Controller::SelectEvent( float x, float y, bool selectAll )
3773 {
3774   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" );
3775
3776   if( NULL != mImpl->mEventData )
3777   {
3778     if( selectAll )
3779     {
3780       Event event( Event::SELECT_ALL );
3781       mImpl->mEventData->mEventQueue.push_back( event );
3782     }
3783     else
3784     {
3785       Event event( Event::SELECT );
3786       event.p2.mFloat = x;
3787       event.p3.mFloat = y;
3788       mImpl->mEventData->mEventQueue.push_back( event );
3789     }
3790
3791     mImpl->mEventData->mCheckScrollAmount = true;
3792     mImpl->mEventData->mIsLeftHandleSelected = true;
3793     mImpl->mEventData->mIsRightHandleSelected = true;
3794     mImpl->RequestRelayout();
3795   }
3796 }
3797
3798 bool Controller::DeleteEvent( int keyCode )
3799 {
3800   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p KeyCode : %d \n", this, keyCode );
3801
3802   bool removed = false;
3803
3804   if( NULL == mImpl->mEventData )
3805   {
3806     return removed;
3807   }
3808
3809   // IMF manager is no longer handling key-events
3810   mImpl->ClearPreEditFlag();
3811
3812   if( EventData::SELECTING == mImpl->mEventData->mState )
3813   {
3814     removed = RemoveSelectedText();
3815   }
3816   else if( ( mImpl->mEventData->mPrimaryCursorPosition > 0 ) && ( keyCode == Dali::DALI_KEY_BACKSPACE) )
3817   {
3818     // Remove the character before the current cursor position
3819     removed = RemoveText( -1,
3820                           1,
3821                           UPDATE_INPUT_STYLE );
3822   }
3823   else if( keyCode == Dali::DevelKey::DALI_KEY_DELETE )
3824   {
3825     // Remove the character after the current cursor position
3826     removed = RemoveText( 0,
3827                           1,
3828                           UPDATE_INPUT_STYLE );
3829   }
3830
3831   if( removed )
3832   {
3833     if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
3834         !mImpl->IsPlaceholderAvailable() )
3835     {
3836       mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
3837     }
3838     else
3839     {
3840       ShowPlaceholderText();
3841     }
3842     mImpl->mEventData->mUpdateCursorPosition = true;
3843     mImpl->mEventData->mScrollAfterDelete = true;
3844   }
3845
3846   return removed;
3847 }
3848
3849 // private : Helpers.
3850
3851 void Controller::ResetText()
3852 {
3853   // Reset buffers.
3854   mImpl->mModel->mLogicalModel->mText.Clear();
3855
3856   // We have cleared everything including the placeholder-text
3857   mImpl->PlaceholderCleared();
3858
3859   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3860   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3861   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
3862
3863   // Clear any previous text.
3864   mImpl->mTextUpdateInfo.mClearAll = true;
3865
3866   // The natural size needs to be re-calculated.
3867   mImpl->mRecalculateNaturalSize = true;
3868
3869   // The text direction needs to be updated.
3870   mImpl->mUpdateTextDirection = true;
3871
3872   // Apply modifications to the model
3873   mImpl->mOperationsPending = ALL_OPERATIONS;
3874 }
3875
3876 void Controller::ShowPlaceholderText()
3877 {
3878   if( mImpl->IsPlaceholderAvailable() )
3879   {
3880     DALI_ASSERT_DEBUG( mImpl->mEventData && "No placeholder text available" );
3881
3882     if( NULL == mImpl->mEventData )
3883     {
3884       return;
3885     }
3886
3887     mImpl->mEventData->mIsShowingPlaceholderText = true;
3888
3889     // Disable handles when showing place-holder text
3890     mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
3891     mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
3892     mImpl->mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
3893
3894     const char* text( NULL );
3895     size_t size( 0 );
3896
3897     // TODO - Switch Placeholder text when changing state
3898     if( ( EventData::INACTIVE != mImpl->mEventData->mState ) &&
3899         ( 0u != mImpl->mEventData->mPlaceholderTextActive.c_str() ) )
3900     {
3901       text = mImpl->mEventData->mPlaceholderTextActive.c_str();
3902       size = mImpl->mEventData->mPlaceholderTextActive.size();
3903     }
3904     else
3905     {
3906       text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
3907       size = mImpl->mEventData->mPlaceholderTextInactive.size();
3908     }
3909
3910     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3911     mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3912
3913     // Reset model for showing placeholder.
3914     mImpl->mModel->mLogicalModel->mText.Clear();
3915     mImpl->mModel->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor );
3916
3917     // Convert text into UTF-32
3918     Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
3919     utf32Characters.Resize( size );
3920
3921     // This is a bit horrible but std::string returns a (signed) char*
3922     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text );
3923
3924     // Transform a text array encoded in utf8 into an array encoded in utf32.
3925     // It returns the actual number of characters.
3926     const Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() );
3927     utf32Characters.Resize( characterCount );
3928
3929     // The characters to be added.
3930     mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount;
3931
3932     // Reset the cursor position
3933     mImpl->mEventData->mPrimaryCursorPosition = 0;
3934
3935     // The natural size needs to be re-calculated.
3936     mImpl->mRecalculateNaturalSize = true;
3937
3938     // The text direction needs to be updated.
3939     mImpl->mUpdateTextDirection = true;
3940
3941     // Apply modifications to the model
3942     mImpl->mOperationsPending = ALL_OPERATIONS;
3943
3944     // Update the rest of the model during size negotiation
3945     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
3946   }
3947 }
3948
3949 void Controller::ClearFontData()
3950 {
3951   if( mImpl->mFontDefaults )
3952   {
3953     mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
3954   }
3955
3956   // Set flags to update the model.
3957   mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3958   mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3959   mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
3960
3961   mImpl->mTextUpdateInfo.mClearAll = true;
3962   mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
3963   mImpl->mRecalculateNaturalSize = true;
3964
3965   mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
3966                                                            VALIDATE_FONTS            |
3967                                                            SHAPE_TEXT                |
3968                                                            BIDI_INFO                 |
3969                                                            GET_GLYPH_METRICS         |
3970                                                            LAYOUT                    |
3971                                                            UPDATE_LAYOUT_SIZE        |
3972                                                            REORDER                   |
3973                                                            ALIGN );
3974 }
3975
3976 void Controller::ClearStyleData()
3977 {
3978   mImpl->mModel->mLogicalModel->mColorRuns.Clear();
3979   mImpl->mModel->mLogicalModel->ClearFontDescriptionRuns();
3980 }
3981
3982 void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
3983 {
3984   // Reset the cursor position
3985   if( NULL != mImpl->mEventData )
3986   {
3987     mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
3988
3989     // Update the cursor if it's in editing mode.
3990     if( EventData::IsEditingState( mImpl->mEventData->mState )  )
3991     {
3992       mImpl->mEventData->mUpdateCursorPosition = true;
3993     }
3994   }
3995 }
3996
3997 void Controller::ResetScrollPosition()
3998 {
3999   if( NULL != mImpl->mEventData )
4000   {
4001     // Reset the scroll position.
4002     mImpl->mModel->mScrollPosition = Vector2::ZERO;
4003     mImpl->mEventData->mScrollAfterUpdatePosition = true;
4004   }
4005 }
4006
4007 void Controller::SetControlInterface( ControlInterface* controlInterface )
4008 {
4009   mImpl->mControlInterface = controlInterface;
4010 }
4011
4012 bool Controller::ShouldClearFocusOnEscape() const
4013 {
4014   return mImpl->mShouldClearFocusOnEscape;
4015 }
4016
4017 // private : Private contructors & copy operator.
4018
4019 Controller::Controller()
4020 : mImpl( NULL )
4021 {
4022   mImpl = new Controller::Impl( NULL, NULL );
4023 }
4024
4025 Controller::Controller( ControlInterface* controlInterface )
4026 {
4027   mImpl = new Controller::Impl( controlInterface, NULL );
4028 }
4029
4030 Controller::Controller( ControlInterface* controlInterface,
4031                         EditableControlInterface* editableControlInterface )
4032 {
4033   mImpl = new Controller::Impl( controlInterface,
4034                                 editableControlInterface );
4035 }
4036
4037 // The copy constructor and operator are left unimplemented.
4038
4039 // protected : Destructor.
4040
4041 Controller::~Controller()
4042 {
4043   delete mImpl;
4044 }
4045
4046 } // namespace Text
4047
4048 } // namespace Toolkit
4049
4050 } // namespace Dali