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