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