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