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