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