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