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