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