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