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