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