Add the font width, weight and slant to the font style.
[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 <dali/public-api/adaptor-framework/key.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/devel-api/adaptor-framework/clipboard-event-notifier.h>
26
27 // INTERNAL INCLUDES
28 #include <dali-toolkit/internal/text/bidirectional-support.h>
29 #include <dali-toolkit/internal/text/character-set-conversion.h>
30 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
31 #include <dali-toolkit/internal/text/text-controller-impl.h>
32
33 namespace
34 {
35
36 #if defined(DEBUG_ENABLED)
37   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
38 #endif
39
40 const float MAX_FLOAT = std::numeric_limits<float>::max();
41 const unsigned int POINTS_PER_INCH = 72;
42
43 const std::string EMPTY_STRING("");
44 const unsigned int ZERO = 0u;
45
46 float ConvertToEven( float value )
47 {
48   int intValue(static_cast<int>( value ));
49   return static_cast<float>(intValue % 2 == 0) ? intValue : (intValue + 1);
50 }
51
52 } // namespace
53
54 namespace Dali
55 {
56
57 namespace Toolkit
58 {
59
60 namespace Text
61 {
62
63 ControllerPtr Controller::New( ControlInterface& controlInterface )
64 {
65   return ControllerPtr( new Controller( controlInterface ) );
66 }
67
68 void Controller::EnableTextInput( DecoratorPtr decorator )
69 {
70   if( !mImpl->mEventData )
71   {
72     mImpl->mEventData = new EventData( decorator );
73   }
74 }
75
76 void Controller::SetText( const std::string& text )
77 {
78   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText\n" );
79
80   // Remove the previously set text
81   ResetText();
82
83   CharacterIndex lastCursorIndex = 0u;
84
85   if( mImpl->mEventData )
86   {
87     // If popup shown then hide it by switching to Editing state
88     if( ( EventData::SELECTING == mImpl->mEventData->mState )          ||
89         ( EventData::SELECTION_CHANGED == mImpl->mEventData->mState )  ||
90         ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
91         ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) )
92     {
93       mImpl->ChangeState( EventData::EDITING );
94     }
95   }
96
97   if( !text.empty() )
98   {
99     //  Convert text into UTF-32
100     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
101     utf32Characters.Resize( text.size() );
102
103     // This is a bit horrible but std::string returns a (signed) char*
104     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
105
106     // Transform a text array encoded in utf8 into an array encoded in utf32.
107     // It returns the actual number of characters.
108     Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
109     utf32Characters.Resize( characterCount );
110
111     DALI_ASSERT_DEBUG( text.size() >= characterCount && "Invalid UTF32 conversion length" );
112     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, text.size(), mImpl->mLogicalModel->mText.Count() );
113
114     // To reset the cursor position
115     lastCursorIndex = characterCount;
116
117     // Update the rest of the model during size negotiation
118     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
119
120     // The natural size needs to be re-calculated.
121     mImpl->mRecalculateNaturalSize = true;
122
123     // Apply modifications to the model
124     mImpl->mOperationsPending = ALL_OPERATIONS;
125   }
126   else
127   {
128     ShowPlaceholderText();
129   }
130
131   // Resets the cursor position.
132   ResetCursorPosition( lastCursorIndex );
133
134   // Scrolls the text to make the cursor visible.
135   ResetScrollPosition();
136
137   mImpl->RequestRelayout();
138
139   if( mImpl->mEventData )
140   {
141     // Cancel previously queued events
142     mImpl->mEventData->mEventQueue.clear();
143   }
144
145   // Reset keyboard as text changed
146   mImpl->ResetImfManager();
147
148   // Do this last since it provides callbacks into application code
149   mImpl->mControlInterface.TextChanged();
150 }
151
152 void Controller::GetText( std::string& text ) const
153 {
154   if( ! mImpl->IsShowingPlaceholderText() )
155   {
156     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
157
158     if( 0u != utf32Characters.Count() )
159     {
160       Utf32ToUtf8( &utf32Characters[0], utf32Characters.Count(), text );
161     }
162   }
163   else
164   {
165     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this );
166   }
167 }
168
169 unsigned int Controller::GetLogicalCursorPosition() const
170 {
171   if( mImpl->mEventData )
172   {
173     return mImpl->mEventData->mPrimaryCursorPosition;
174   }
175
176   return 0u;
177 }
178
179 void Controller::SetPlaceholderText( PlaceholderType type, const std::string& text )
180 {
181   if( mImpl->mEventData )
182   {
183     if( PLACEHOLDER_TYPE_INACTIVE == type )
184     {
185       mImpl->mEventData->mPlaceholderTextInactive = text;
186     }
187     else
188     {
189       mImpl->mEventData->mPlaceholderTextActive = text;
190     }
191
192     // Update placeholder if there is no text
193     if( mImpl->IsShowingPlaceholderText() ||
194         0u == mImpl->mLogicalModel->mText.Count() )
195     {
196       ShowPlaceholderText();
197     }
198   }
199 }
200
201 void Controller::GetPlaceholderText( PlaceholderType type, std::string& text ) const
202 {
203   if( mImpl->mEventData )
204   {
205     if( PLACEHOLDER_TYPE_INACTIVE == type )
206     {
207       text = mImpl->mEventData->mPlaceholderTextInactive;
208     }
209     else
210     {
211       text = mImpl->mEventData->mPlaceholderTextActive;
212     }
213   }
214 }
215
216 void Controller::SetMaximumNumberOfCharacters( int maxCharacters )
217 {
218   if ( maxCharacters >= 0 )
219   {
220     mImpl->mMaximumNumberOfCharacters = maxCharacters;
221   }
222 }
223
224 int Controller::GetMaximumNumberOfCharacters()
225 {
226   return mImpl->mMaximumNumberOfCharacters;
227 }
228
229 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily, bool userDefined )
230 {
231   if( !mImpl->mFontDefaults )
232   {
233     mImpl->mFontDefaults = new FontDefaults();
234   }
235
236   mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
237   mImpl->mUserDefinedFontFamily = userDefined;
238
239   // Clear the font-specific data
240   ClearFontData();
241
242   mImpl->mOperationsPending = ALL_OPERATIONS;
243   mImpl->mRecalculateNaturalSize = true;
244
245   mImpl->RequestRelayout();
246 }
247
248 const std::string& Controller::GetDefaultFontFamily() const
249 {
250   if( mImpl->mFontDefaults )
251   {
252     return mImpl->mFontDefaults->mFontDescription.family;
253   }
254
255   return EMPTY_STRING;
256 }
257
258 void Controller::SetDefaultFontStyle( const std::string& style )
259 {
260   if( !mImpl->mFontDefaults )
261   {
262     mImpl->mFontDefaults = new FontDefaults();
263   }
264
265   mImpl->mFontDefaults->mFontStyle = style;
266 }
267
268 const std::string& Controller::GetDefaultFontStyle() const
269 {
270   if( mImpl->mFontDefaults )
271   {
272     return mImpl->mFontDefaults->mFontStyle;
273   }
274
275   return EMPTY_STRING;
276 }
277
278 void Controller::SetDefaultFontWidth( FontWidth width )
279 {
280   if( !mImpl->mFontDefaults )
281   {
282     mImpl->mFontDefaults = new FontDefaults();
283   }
284
285   mImpl->mFontDefaults->mFontDescription.width = width;
286
287   // Clear the font-specific data
288   ClearFontData();
289
290   mImpl->mOperationsPending = ALL_OPERATIONS;
291   mImpl->mRecalculateNaturalSize = true;
292
293   mImpl->RequestRelayout();
294 }
295
296 FontWidth Controller::GetDefaultFontWidth() const
297 {
298   if( mImpl->mFontDefaults )
299   {
300     return mImpl->mFontDefaults->mFontDescription.width;
301   }
302
303   return TextAbstraction::FontWidth::NORMAL;
304 }
305
306 void Controller::SetDefaultFontWeight( FontWeight weight )
307 {
308   if( !mImpl->mFontDefaults )
309   {
310     mImpl->mFontDefaults = new FontDefaults();
311   }
312
313   mImpl->mFontDefaults->mFontDescription.weight = weight;
314
315   // Clear the font-specific data
316   ClearFontData();
317
318   mImpl->mOperationsPending = ALL_OPERATIONS;
319   mImpl->mRecalculateNaturalSize = true;
320
321   mImpl->RequestRelayout();
322 }
323
324 FontWeight Controller::GetDefaultFontWeight() const
325 {
326   if( mImpl->mFontDefaults )
327   {
328     return mImpl->mFontDefaults->mFontDescription.weight;
329   }
330
331   return TextAbstraction::FontWeight::NORMAL;
332 }
333
334 void Controller::SetDefaultFontSlant( FontSlant slant )
335 {
336   if( !mImpl->mFontDefaults )
337   {
338     mImpl->mFontDefaults = new FontDefaults();
339   }
340
341   mImpl->mFontDefaults->mFontDescription.slant = slant;
342
343   // Clear the font-specific data
344   ClearFontData();
345
346   mImpl->mOperationsPending = ALL_OPERATIONS;
347   mImpl->mRecalculateNaturalSize = true;
348
349   mImpl->RequestRelayout();
350 }
351
352 FontSlant Controller::GetDefaultFontSlant() const
353 {
354   if( mImpl->mFontDefaults )
355   {
356     return mImpl->mFontDefaults->mFontDescription.slant;
357   }
358
359   return TextAbstraction::FontSlant::NORMAL;
360 }
361
362 void Controller::SetDefaultPointSize( float pointSize )
363 {
364   if( !mImpl->mFontDefaults )
365   {
366     mImpl->mFontDefaults = new FontDefaults();
367   }
368
369   mImpl->mFontDefaults->mDefaultPointSize = pointSize;
370
371   unsigned int horizontalDpi( 0u );
372   unsigned int verticalDpi( 0u );
373   mImpl->mFontClient.GetDpi( horizontalDpi, verticalDpi );
374
375   // Adjust the metrics if the fixed-size font should be down-scaled
376   int maxEmojiSize( pointSize/POINTS_PER_INCH * verticalDpi );
377   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultPointSize %p setting MaxEmojiSize %d\n", this, maxEmojiSize );
378   mImpl->mMetrics->SetMaxEmojiSize( maxEmojiSize );
379
380   // Clear the font-specific data
381   ClearFontData();
382
383   mImpl->mOperationsPending = ALL_OPERATIONS;
384   mImpl->mRecalculateNaturalSize = true;
385
386   mImpl->RequestRelayout();
387 }
388
389 float Controller::GetDefaultPointSize() const
390 {
391   if( mImpl->mFontDefaults )
392   {
393     return mImpl->mFontDefaults->mDefaultPointSize;
394   }
395
396   return 0.0f;
397 }
398
399 void Controller::UpdateAfterFontChange( std::string& newDefaultFont )
400 {
401   DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange");
402
403   ClearFontData();
404
405   if ( !mImpl->mUserDefinedFontFamily ) // If user defined font then should not update when system font changes
406   {
407     DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str() );
408     mImpl->mFontDefaults->mFontDescription.family = newDefaultFont;
409     mImpl->UpdateModel( ALL_OPERATIONS );
410     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
411     mImpl->mRecalculateNaturalSize = true;
412     mImpl->RequestRelayout();
413   }
414 }
415
416 void Controller::SetTextColor( const Vector4& textColor )
417 {
418   mImpl->mTextColor = textColor;
419
420   if( !mImpl->IsShowingPlaceholderText() )
421   {
422     mImpl->mVisualModel->SetTextColor( textColor );
423
424     mImpl->RequestRelayout();
425   }
426 }
427
428 const Vector4& Controller::GetTextColor() const
429 {
430   return mImpl->mTextColor;
431 }
432
433 bool Controller::RemoveText( int cursorOffset, int numberOfChars )
434 {
435   bool removed( false );
436
437   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfChars %d\n",
438                  this, mImpl->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfChars );
439
440   if( !mImpl->IsShowingPlaceholderText() )
441   {
442     // Delete at current cursor position
443     Vector<Character>& currentText = mImpl->mLogicalModel->mText;
444     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
445
446     CharacterIndex cursorIndex = oldCursorIndex;
447
448     // Validate the cursor position & number of characters
449     if( static_cast< CharacterIndex >( std::abs( cursorOffset ) ) <= cursorIndex )
450     {
451       cursorIndex = oldCursorIndex + cursorOffset;
452     }
453
454     if( (cursorIndex + numberOfChars) > currentText.Count() )
455     {
456       numberOfChars = currentText.Count() - cursorIndex;
457     }
458
459     if( (cursorIndex + numberOfChars) <= currentText.Count() )
460     {
461       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
462       Vector<Character>::Iterator last  = first + numberOfChars;
463
464       currentText.Erase( first, last );
465
466       // Cursor position retreat
467       oldCursorIndex = cursorIndex;
468
469       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfChars );
470       removed = true;
471     }
472   }
473
474   return removed;
475 }
476
477 void Controller::SetPlaceholderTextColor( const Vector4& textColor )
478 {
479   if( mImpl->mEventData )
480   {
481     mImpl->mEventData->mPlaceholderTextColor = textColor;
482   }
483
484   if( mImpl->IsShowingPlaceholderText() )
485   {
486     mImpl->mVisualModel->SetTextColor( textColor );
487     mImpl->RequestRelayout();
488   }
489 }
490
491 const Vector4& Controller::GetPlaceholderTextColor() const
492 {
493   if( mImpl->mEventData )
494   {
495     return mImpl->mEventData->mPlaceholderTextColor;
496   }
497
498   return Color::BLACK;
499 }
500
501 void Controller::SetShadowOffset( const Vector2& shadowOffset )
502 {
503   mImpl->mVisualModel->SetShadowOffset( shadowOffset );
504
505   mImpl->RequestRelayout();
506 }
507
508 const Vector2& Controller::GetShadowOffset() const
509 {
510   return mImpl->mVisualModel->GetShadowOffset();
511 }
512
513 void Controller::SetShadowColor( const Vector4& shadowColor )
514 {
515   mImpl->mVisualModel->SetShadowColor( shadowColor );
516
517   mImpl->RequestRelayout();
518 }
519
520 const Vector4& Controller::GetShadowColor() const
521 {
522   return mImpl->mVisualModel->GetShadowColor();
523 }
524
525 void Controller::SetUnderlineColor( const Vector4& color )
526 {
527   mImpl->mVisualModel->SetUnderlineColor( color );
528
529   mImpl->RequestRelayout();
530 }
531
532 const Vector4& Controller::GetUnderlineColor() const
533 {
534   return mImpl->mVisualModel->GetUnderlineColor();
535 }
536
537 void Controller::SetUnderlineEnabled( bool enabled )
538 {
539   mImpl->mVisualModel->SetUnderlineEnabled( enabled );
540
541   mImpl->RequestRelayout();
542 }
543
544 bool Controller::IsUnderlineEnabled() const
545 {
546   return mImpl->mVisualModel->IsUnderlineEnabled();
547 }
548
549 void Controller::SetUnderlineHeight( float height )
550 {
551   mImpl->mVisualModel->SetUnderlineHeight( height );
552
553   mImpl->RequestRelayout();
554 }
555
556 float Controller::GetUnderlineHeight() const
557 {
558   return mImpl->mVisualModel->GetUnderlineHeight();
559 }
560
561 void Controller::SetEnableCursorBlink( bool enable )
562 {
563   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" );
564
565   if( mImpl->mEventData )
566   {
567     mImpl->mEventData->mCursorBlinkEnabled = enable;
568
569     if( !enable &&
570         mImpl->mEventData->mDecorator )
571     {
572       mImpl->mEventData->mDecorator->StopCursorBlink();
573     }
574   }
575 }
576
577 bool Controller::GetEnableCursorBlink() const
578 {
579   if( mImpl->mEventData )
580   {
581     return mImpl->mEventData->mCursorBlinkEnabled;
582   }
583
584   return false;
585 }
586
587 const Vector2& Controller::GetScrollPosition() const
588 {
589   if( mImpl->mEventData )
590   {
591     return mImpl->mEventData->mScrollPosition;
592   }
593
594   return Vector2::ZERO;
595 }
596
597 const Vector2& Controller::GetAlignmentOffset() const
598 {
599   return mImpl->mAlignmentOffset;
600 }
601
602 Vector3 Controller::GetNaturalSize()
603 {
604   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n" );
605   Vector3 naturalSize;
606
607   // Make sure the model is up-to-date before layouting
608   ProcessModifyEvents();
609
610   if( mImpl->mRecalculateNaturalSize )
611   {
612     // Operations that can be done only once until the text changes.
613     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
614                                                                            GET_SCRIPTS       |
615                                                                            VALIDATE_FONTS    |
616                                                                            GET_LINE_BREAKS   |
617                                                                            GET_WORD_BREAKS   |
618                                                                            BIDI_INFO         |
619                                                                            SHAPE_TEXT        |
620                                                                            GET_GLYPH_METRICS );
621     // Make sure the model is up-to-date before layouting
622     mImpl->UpdateModel( onlyOnceOperations );
623
624     // Operations that need to be done if the size changes.
625     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
626                                                                         ALIGN  |
627                                                                         REORDER );
628
629     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
630                 static_cast<OperationsMask>( onlyOnceOperations |
631                                              sizeOperations ),
632                 naturalSize.GetVectorXY() );
633
634     // Do not do again the only once operations.
635     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
636
637     // Do the size related operations again.
638     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
639
640     // Stores the natural size to avoid recalculate it again
641     // unless the text/style changes.
642     mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
643
644     mImpl->mRecalculateNaturalSize = false;
645
646     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
647   }
648   else
649   {
650     naturalSize = mImpl->mVisualModel->GetNaturalSize();
651
652     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
653   }
654
655   naturalSize.x = ConvertToEven( naturalSize.x );
656   naturalSize.y = ConvertToEven( naturalSize.y );
657
658   return naturalSize;
659 }
660
661 float Controller::GetHeightForWidth( float width )
662 {
663   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width );
664   // Make sure the model is up-to-date before layouting
665   ProcessModifyEvents();
666
667   Size layoutSize;
668   if( width != mImpl->mVisualModel->mControlSize.width )
669   {
670     // Operations that can be done only once until the text changes.
671     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
672                                                                            GET_SCRIPTS       |
673                                                                            VALIDATE_FONTS    |
674                                                                            GET_LINE_BREAKS   |
675                                                                            GET_WORD_BREAKS   |
676                                                                            BIDI_INFO         |
677                                                                            SHAPE_TEXT        |
678                                                                            GET_GLYPH_METRICS );
679     // Make sure the model is up-to-date before layouting
680     mImpl->UpdateModel( onlyOnceOperations );
681
682     // Operations that need to be done if the size changes.
683     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
684                                                                         ALIGN  |
685                                                                         REORDER );
686
687     DoRelayout( Size( width, MAX_FLOAT ),
688                 static_cast<OperationsMask>( onlyOnceOperations |
689                                              sizeOperations ),
690                 layoutSize );
691
692     // Do not do again the only once operations.
693     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
694
695     // Do the size related operations again.
696     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
697     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height );
698   }
699   else
700   {
701     layoutSize = mImpl->mVisualModel->GetActualSize();
702     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height );
703   }
704
705   return layoutSize.height;
706 }
707
708 bool Controller::Relayout( const Size& size )
709 {
710   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f\n", this, size.width, size.height );
711
712   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
713   {
714     bool glyphsRemoved( false );
715     if( 0u != mImpl->mVisualModel->mGlyphPositions.Count() )
716     {
717       mImpl->mVisualModel->mGlyphPositions.Clear();
718       glyphsRemoved = true;
719     }
720     // Not worth to relayout if width or height is equal to zero.
721     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
722     return glyphsRemoved;
723   }
724
725   if( size != mImpl->mVisualModel->mControlSize )
726   {
727     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mVisualModel->mControlSize.width, mImpl->mVisualModel->mControlSize.height );
728
729     // Operations that need to be done if the size changes.
730     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
731                                                              LAYOUT                    |
732                                                              ALIGN                     |
733                                                              UPDATE_ACTUAL_SIZE        |
734                                                              REORDER );
735
736     mImpl->mVisualModel->mControlSize = size;
737   }
738
739   // Make sure the model is up-to-date before layouting
740   ProcessModifyEvents();
741   mImpl->UpdateModel( mImpl->mOperationsPending );
742
743   Size layoutSize;
744   bool updated = DoRelayout( mImpl->mVisualModel->mControlSize,
745                              mImpl->mOperationsPending,
746                              layoutSize );
747
748   // Do not re-do any operation until something changes.
749   mImpl->mOperationsPending = NO_OPERATION;
750
751   // Keep the current offset and alignment as it will be used to update the decorator's positions.
752   Vector2 offset;
753   if( mImpl->mEventData )
754   {
755     offset = mImpl->mAlignmentOffset + mImpl->mEventData->mScrollPosition;
756   }
757
758   // After doing the text layout, the alignment offset to place the actor in the desired position can be calculated.
759   CalculateTextAlignment( size );
760
761   if( mImpl->mEventData )
762   {
763     // If there is a nex size, the scroll position needs to be clamped.
764     mImpl->ClampHorizontalScroll( layoutSize );
765
766     // Update the decorator's positions.
767     mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mAlignmentOffset + mImpl->mEventData->mScrollPosition - offset );
768
769     // Move the cursor, grab handle etc.
770     updated = mImpl->ProcessInputEvents() || updated;
771   }
772
773   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
774   return updated;
775 }
776
777 void Controller::ProcessModifyEvents()
778 {
779   std::vector<ModifyEvent>& events = mImpl->mModifyEvents;
780
781   for( unsigned int i=0; i<events.size(); ++i )
782   {
783     if( ModifyEvent::TEXT_REPLACED == events[0].type )
784     {
785       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
786       DALI_ASSERT_DEBUG( 0 == i && "Unexpected TEXT_REPLACED event" );
787
788       TextReplacedEvent();
789     }
790     else if( ModifyEvent::TEXT_INSERTED == events[0].type )
791     {
792       TextInsertedEvent();
793     }
794     else if( ModifyEvent::TEXT_DELETED == events[0].type )
795     {
796       // Placeholder-text cannot be deleted
797       if( !mImpl->IsShowingPlaceholderText() )
798       {
799         TextDeletedEvent();
800       }
801     }
802   }
803
804   if( mImpl->mEventData &&
805       0 != events.size() )
806   {
807     // When the text is being modified, delay cursor blinking
808     mImpl->mEventData->mDecorator->DelayCursorBlink();
809   }
810
811   // Discard temporary text
812   events.clear();
813 }
814
815 void Controller::ResetText()
816 {
817   // Reset buffers.
818   mImpl->mLogicalModel->mText.Clear();
819   ClearModelData();
820
821   // We have cleared everything including the placeholder-text
822   mImpl->PlaceholderCleared();
823
824   // The natural size needs to be re-calculated.
825   mImpl->mRecalculateNaturalSize = true;
826
827   // Apply modifications to the model
828   mImpl->mOperationsPending = ALL_OPERATIONS;
829 }
830
831 void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
832 {
833   // Reset the cursor position
834   if( NULL != mImpl->mEventData )
835   {
836     mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
837
838     // Update the cursor if it's in editing mode.
839     if( ( EventData::EDITING == mImpl->mEventData->mState )            ||
840         ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
841         ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) )
842     {
843       mImpl->mEventData->mUpdateCursorPosition = true;
844     }
845   }
846 }
847
848 void Controller::ResetScrollPosition()
849 {
850   if( NULL != mImpl->mEventData )
851   {
852     // Reset the scroll position.
853     mImpl->mEventData->mScrollPosition = Vector2::ZERO;
854     mImpl->mEventData->mScrollAfterUpdatePosition = true;
855   }
856 }
857
858 void Controller::TextReplacedEvent()
859 {
860   // Reset buffers.
861   ClearModelData();
862
863   // The natural size needs to be re-calculated.
864   mImpl->mRecalculateNaturalSize = true;
865
866   // Apply modifications to the model
867   mImpl->mOperationsPending = ALL_OPERATIONS;
868   mImpl->UpdateModel( ALL_OPERATIONS );
869   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
870                                                            ALIGN              |
871                                                            UPDATE_ACTUAL_SIZE |
872                                                            REORDER );
873 }
874
875 void Controller::TextInsertedEvent()
876 {
877   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" );
878
879   // TODO - Optimize this
880   ClearModelData();
881
882   // The natural size needs to be re-calculated.
883   mImpl->mRecalculateNaturalSize = true;
884
885   // Apply modifications to the model; TODO - Optimize this
886   mImpl->mOperationsPending = ALL_OPERATIONS;
887   mImpl->UpdateModel( ALL_OPERATIONS );
888   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
889                                                            ALIGN              |
890                                                            UPDATE_ACTUAL_SIZE |
891                                                            REORDER );
892
893   // Queue a cursor reposition event; this must wait until after DoRelayout()
894   if( ( EventData::EDITING == mImpl->mEventData->mState )            ||
895       ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
896       ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) )
897   {
898     mImpl->mEventData->mUpdateCursorPosition = true;
899     mImpl->mEventData->mScrollAfterUpdatePosition = true;
900   }
901 }
902
903 void Controller::TextDeletedEvent()
904 {
905   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" );
906
907   // TODO - Optimize this
908   ClearModelData();
909
910   // The natural size needs to be re-calculated.
911   mImpl->mRecalculateNaturalSize = true;
912
913   // Apply modifications to the model; TODO - Optimize this
914   mImpl->mOperationsPending = ALL_OPERATIONS;
915   mImpl->UpdateModel( ALL_OPERATIONS );
916   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
917                                                            ALIGN              |
918                                                            UPDATE_ACTUAL_SIZE |
919                                                            REORDER );
920
921   // Queue a cursor reposition event; this must wait until after DoRelayout()
922   if( 0u == mImpl->mLogicalModel->mText.Count() )
923   {
924     mImpl->mEventData->mUpdateCursorPosition = true;
925   }
926   else
927   {
928     mImpl->mEventData->mScrollAfterDelete = true;
929   }
930 }
931
932 bool Controller::DoRelayout( const Size& size,
933                              OperationsMask operationsRequired,
934                              Size& layoutSize )
935 {
936   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height );
937   bool viewUpdated( false );
938
939   // Calculate the operations to be done.
940   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
941
942   if( LAYOUT & operations )
943   {
944     // Some vectors with data needed to layout and reorder may be void
945     // after the first time the text has been laid out.
946     // Fill the vectors again.
947
948     const Length numberOfGlyphs = mImpl->mVisualModel->mGlyphs.Count();
949
950     if( 0u == numberOfGlyphs )
951     {
952       // Nothing else to do if there is no glyphs.
953       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n" );
954       return true;
955     }
956
957     const Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
958     const Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
959     const Vector<CharacterDirection>& characterDirection = mImpl->mLogicalModel->mCharacterDirections;
960     const Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
961     const Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
962     const Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
963     const Character* const textBuffer = mImpl->mLogicalModel->mText.Begin();
964
965     // Set the layout parameters.
966     LayoutParameters layoutParameters( size,
967                                        textBuffer,
968                                        lineBreakInfo.Begin(),
969                                        wordBreakInfo.Begin(),
970                                        ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
971                                        numberOfGlyphs,
972                                        glyphs.Begin(),
973                                        glyphsToCharactersMap.Begin(),
974                                        charactersPerGlyph.Begin() );
975
976     // The laid-out lines.
977     // It's not possible to know in how many lines the text is going to be laid-out,
978     // but it can be resized at least with the number of 'paragraphs' to avoid
979     // some re-allocations.
980     Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
981
982     // Delete any previous laid out lines before setting the new ones.
983     lines.Clear();
984
985     // The capacity of the bidirectional paragraph info is the number of paragraphs.
986     lines.Reserve( mImpl->mLogicalModel->mBidirectionalParagraphInfo.Capacity() );
987
988     // Resize the vector of positions to have the same size than the vector of glyphs.
989     Vector<Vector2>& glyphPositions = mImpl->mVisualModel->mGlyphPositions;
990     glyphPositions.Resize( numberOfGlyphs );
991
992     // Whether the last character is a new paragraph character.
993     layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mLogicalModel->mText.Count() - 1u ) ) );
994
995     // Update the visual model.
996     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
997                                                    glyphPositions,
998                                                    lines,
999                                                    layoutSize );
1000
1001     if( viewUpdated )
1002     {
1003       // Reorder the lines
1004       if( REORDER & operations )
1005       {
1006         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
1007
1008         // Check first if there are paragraphs with bidirectional info.
1009         if( 0u != bidirectionalInfo.Count() )
1010         {
1011           // Get the lines
1012           const Length numberOfLines = mImpl->mVisualModel->mLines.Count();
1013
1014           // Reorder the lines.
1015           Vector<BidirectionalLineInfoRun> lineBidirectionalInfoRuns;
1016           lineBidirectionalInfoRuns.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
1017           ReorderLines( bidirectionalInfo,
1018                         lines,
1019                         lineBidirectionalInfoRuns );
1020
1021           // Set the bidirectional info into the model.
1022           const Length numberOfBidirectionalInfoRuns = lineBidirectionalInfoRuns.Count();
1023           mImpl->mLogicalModel->SetVisualToLogicalMap( lineBidirectionalInfoRuns.Begin(),
1024                                                        numberOfBidirectionalInfoRuns );
1025
1026           // Set the bidirectional info per line into the layout parameters.
1027           layoutParameters.lineBidirectionalInfoRunsBuffer = lineBidirectionalInfoRuns.Begin();
1028           layoutParameters.numberOfBidirectionalInfoRuns = numberOfBidirectionalInfoRuns;
1029
1030           // Get the character to glyph conversion table and set into the layout.
1031           layoutParameters.charactersToGlyphsBuffer = mImpl->mVisualModel->mCharactersToGlyph.Begin();
1032
1033           // Get the glyphs per character table and set into the layout.
1034           layoutParameters.glyphsPerCharacterBuffer = mImpl->mVisualModel->mGlyphsPerCharacter.Begin();
1035
1036           // Re-layout the text. Reorder those lines with right to left characters.
1037           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
1038                                                          glyphPositions );
1039
1040           // Free the allocated memory used to store the conversion table in the bidirectional line info run.
1041           for( Vector<BidirectionalLineInfoRun>::Iterator it = lineBidirectionalInfoRuns.Begin(),
1042                  endIt = lineBidirectionalInfoRuns.End();
1043                it != endIt;
1044                ++it )
1045           {
1046             BidirectionalLineInfoRun& bidiLineInfo = *it;
1047
1048             free( bidiLineInfo.visualToLogicalMap );
1049           }
1050         }
1051       } // REORDER
1052
1053       // Sets the actual size.
1054       if( UPDATE_ACTUAL_SIZE & operations )
1055       {
1056         mImpl->mVisualModel->SetActualSize( layoutSize );
1057       }
1058     } // view updated
1059   }
1060   else
1061   {
1062     layoutSize = mImpl->mVisualModel->GetActualSize();
1063   }
1064
1065   if( ALIGN & operations )
1066   {
1067     // The laid-out lines.
1068     Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
1069
1070     mImpl->mLayoutEngine.Align( layoutSize,
1071                                 lines );
1072
1073     viewUpdated = true;
1074   }
1075
1076   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
1077   return viewUpdated;
1078 }
1079
1080 void Controller::SetMultiLineEnabled( bool enable )
1081 {
1082   const LayoutEngine::Layout layout = enable ? LayoutEngine::MULTI_LINE_BOX : LayoutEngine::SINGLE_LINE_BOX;
1083
1084   if( layout != mImpl->mLayoutEngine.GetLayout() )
1085   {
1086     // Set the layout type.
1087     mImpl->mLayoutEngine.SetLayout( layout );
1088
1089     // Set the flags to redo the layout operations
1090     const OperationsMask layoutOperations =  static_cast<OperationsMask>( LAYOUT             |
1091                                                                           UPDATE_ACTUAL_SIZE |
1092                                                                           ALIGN              |
1093                                                                           REORDER );
1094
1095     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | layoutOperations );
1096
1097     mImpl->RequestRelayout();
1098   }
1099 }
1100
1101 bool Controller::IsMultiLineEnabled() const
1102 {
1103   return LayoutEngine::MULTI_LINE_BOX == mImpl->mLayoutEngine.GetLayout();
1104 }
1105
1106 void Controller::SetHorizontalAlignment( LayoutEngine::HorizontalAlignment alignment )
1107 {
1108   if( alignment != mImpl->mLayoutEngine.GetHorizontalAlignment() )
1109   {
1110     // Set the alignment.
1111     mImpl->mLayoutEngine.SetHorizontalAlignment( alignment );
1112
1113     // Set the flag to redo the alignment operation.
1114     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
1115
1116     mImpl->RequestRelayout();
1117   }
1118 }
1119
1120 LayoutEngine::HorizontalAlignment Controller::GetHorizontalAlignment() const
1121 {
1122   return mImpl->mLayoutEngine.GetHorizontalAlignment();
1123 }
1124
1125 void Controller::SetVerticalAlignment( LayoutEngine::VerticalAlignment alignment )
1126 {
1127   if( alignment != mImpl->mLayoutEngine.GetVerticalAlignment() )
1128   {
1129     // Set the alignment.
1130     mImpl->mLayoutEngine.SetVerticalAlignment( alignment );
1131
1132     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
1133
1134     mImpl->RequestRelayout();
1135   }
1136 }
1137
1138 LayoutEngine::VerticalAlignment Controller::GetVerticalAlignment() const
1139 {
1140   return mImpl->mLayoutEngine.GetVerticalAlignment();
1141 }
1142
1143 void Controller::CalculateTextAlignment( const Size& size )
1144 {
1145   // Get the direction of the first character.
1146   const CharacterDirection firstParagraphDirection = mImpl->mLogicalModel->GetCharacterDirection( 0u );
1147
1148   Size actualSize = mImpl->mVisualModel->GetActualSize();
1149   if( fabsf( actualSize.height ) < Math::MACHINE_EPSILON_1000 )
1150   {
1151     // Get the line height of the default font.
1152     actualSize.height = mImpl->GetDefaultFontLineHeight();
1153   }
1154
1155   // If the first paragraph is right to left swap ALIGN_BEGIN and ALIGN_END;
1156   LayoutEngine::HorizontalAlignment horizontalAlignment = mImpl->mLayoutEngine.GetHorizontalAlignment();
1157   if( firstParagraphDirection &&
1158       ( LayoutEngine::HORIZONTAL_ALIGN_CENTER != horizontalAlignment ) )
1159   {
1160     if( LayoutEngine::HORIZONTAL_ALIGN_BEGIN == horizontalAlignment )
1161     {
1162       horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_END;
1163     }
1164     else
1165     {
1166       horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_BEGIN;
1167     }
1168   }
1169
1170   switch( horizontalAlignment )
1171   {
1172     case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
1173     {
1174       mImpl->mAlignmentOffset.x = 0.f;
1175       break;
1176     }
1177     case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
1178     {
1179       const int intOffset = static_cast<int>( 0.5f * ( size.width - actualSize.width ) ); // try to avoid pixel alignment.
1180       mImpl->mAlignmentOffset.x = static_cast<float>( intOffset );
1181       break;
1182     }
1183     case LayoutEngine::HORIZONTAL_ALIGN_END:
1184     {
1185       mImpl->mAlignmentOffset.x = size.width - actualSize.width;
1186       break;
1187     }
1188   }
1189
1190   const LayoutEngine::VerticalAlignment verticalAlignment = mImpl->mLayoutEngine.GetVerticalAlignment();
1191   switch( verticalAlignment )
1192   {
1193     case LayoutEngine::VERTICAL_ALIGN_TOP:
1194     {
1195       mImpl->mAlignmentOffset.y = 0.f;
1196       break;
1197     }
1198     case LayoutEngine::VERTICAL_ALIGN_CENTER:
1199     {
1200       const int intOffset = static_cast<int>( 0.5f * ( size.height - actualSize.height ) ); // try to avoid pixel alignment.
1201       mImpl->mAlignmentOffset.y = static_cast<float>( intOffset );
1202       break;
1203     }
1204     case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
1205     {
1206       mImpl->mAlignmentOffset.y = size.height - actualSize.height;
1207       break;
1208     }
1209   }
1210 }
1211
1212 LayoutEngine& Controller::GetLayoutEngine()
1213 {
1214   return mImpl->mLayoutEngine;
1215 }
1216
1217 View& Controller::GetView()
1218 {
1219   return mImpl->mView;
1220 }
1221
1222 void Controller::KeyboardFocusGainEvent()
1223 {
1224   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
1225
1226   if( mImpl->mEventData )
1227   {
1228     if( ( EventData::INACTIVE == mImpl->mEventData->mState ) ||
1229         ( EventData::INTERRUPTED == mImpl->mEventData->mState ) )
1230     {
1231       mImpl->ChangeState( EventData::EDITING );
1232       mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
1233     }
1234
1235     if( mImpl->IsShowingPlaceholderText() )
1236     {
1237       // Show alternative placeholder-text when editing
1238       ShowPlaceholderText();
1239     }
1240
1241     mImpl->RequestRelayout();
1242   }
1243 }
1244
1245 void Controller::KeyboardFocusLostEvent()
1246 {
1247   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
1248
1249   if( mImpl->mEventData )
1250   {
1251     if ( EventData::INTERRUPTED != mImpl->mEventData->mState )
1252     {
1253       mImpl->ChangeState( EventData::INACTIVE );
1254
1255       if( mImpl->IsShowingPlaceholderText() )
1256       {
1257         // Revert to regular placeholder-text when not editing
1258         ShowPlaceholderText();
1259       }
1260     }
1261   }
1262   mImpl->RequestRelayout();
1263 }
1264
1265 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
1266 {
1267   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
1268
1269   bool textChanged( false );
1270
1271   if( mImpl->mEventData &&
1272       keyEvent.state == KeyEvent::Down )
1273   {
1274     int keyCode = keyEvent.keyCode;
1275     const std::string& keyString = keyEvent.keyPressed;
1276
1277     // Pre-process to separate modifying events from non-modifying input events.
1278     if( Dali::DALI_KEY_ESCAPE == keyCode )
1279     {
1280       // Escape key is a special case which causes focus loss
1281       KeyboardFocusLostEvent();
1282     }
1283     else if( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ||
1284              Dali::DALI_KEY_CURSOR_RIGHT == keyCode ||
1285              Dali::DALI_KEY_CURSOR_UP    == keyCode ||
1286              Dali::DALI_KEY_CURSOR_DOWN  == keyCode )
1287     {
1288       Event event( Event::CURSOR_KEY_EVENT );
1289       event.p1.mInt = keyCode;
1290       mImpl->mEventData->mEventQueue.push_back( event );
1291     }
1292     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
1293     {
1294       textChanged = BackspaceKeyEvent();
1295     }
1296     else if ( IsKey( keyEvent,  Dali::DALI_KEY_POWER ) )
1297     {
1298       mImpl->ChangeState( EventData::INTERRUPTED ); // State is not INACTIVE as expect to return to edit mode.
1299       // Avoids calling the InsertText() method which can delete selected text
1300     }
1301     else if ( IsKey( keyEvent, Dali::DALI_KEY_MENU ) ||
1302               IsKey( keyEvent, Dali::DALI_KEY_HOME ) )
1303     {
1304       mImpl->ChangeState( EventData::INACTIVE );
1305       // Menu/Home key behaviour does not allow edit mode to resume like Power key
1306       // Avoids calling the InsertText() method which can delete selected text
1307     }
1308     else if( Dali::DALI_KEY_SHIFT_LEFT == keyCode )
1309     {
1310       // DALI_KEY_SHIFT_LEFT is the key code for the Left Shift. It's sent (by the imf?) when the predictive text is enabled
1311       // and a character is typed after the type of a upper case latin character.
1312
1313       // Do nothing.
1314     }
1315     else
1316     {
1317       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() );
1318
1319       // IMF manager is no longer handling key-events
1320       mImpl->ClearPreEditFlag();
1321
1322       InsertText( keyString, COMMIT );
1323       textChanged = true;
1324     }
1325
1326     if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
1327          ( mImpl->mEventData->mState != EventData::INACTIVE ) )
1328     {
1329       mImpl->ChangeState( EventData::EDITING );
1330     }
1331
1332     mImpl->RequestRelayout();
1333   }
1334
1335   if( textChanged )
1336   {
1337     // Do this last since it provides callbacks into application code
1338     mImpl->mControlInterface.TextChanged();
1339   }
1340
1341   return false;
1342 }
1343
1344 void Controller::InsertText( const std::string& text, Controller::InsertType type )
1345 {
1346   bool removedPrevious( false );
1347   bool maxLengthReached( false );
1348
1349   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
1350   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
1351                  this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
1352                  mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
1353
1354   // TODO: At the moment the underline runs are only for pre-edit.
1355   mImpl->mVisualModel->mUnderlineRuns.Clear();
1356
1357   Vector<Character> utf32Characters;
1358   Length characterCount( 0u );
1359
1360   // Remove the previous IMF pre-edit (predicitive text)
1361   if( mImpl->mEventData &&
1362       mImpl->mEventData->mPreEditFlag &&
1363       0 != mImpl->mEventData->mPreEditLength )
1364   {
1365     CharacterIndex offset = mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition;
1366
1367     removedPrevious = RemoveText( -static_cast<int>(offset), mImpl->mEventData->mPreEditLength );
1368
1369     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
1370     mImpl->mEventData->mPreEditLength = 0;
1371   }
1372   else
1373   {
1374     // Remove the previous Selection
1375     removedPrevious = RemoveSelectedText();
1376   }
1377
1378   if( !text.empty() )
1379   {
1380     //  Convert text into UTF-32
1381     utf32Characters.Resize( text.size() );
1382
1383     // This is a bit horrible but std::string returns a (signed) char*
1384     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
1385
1386     // Transform a text array encoded in utf8 into an array encoded in utf32.
1387     // It returns the actual number of characters.
1388     characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
1389     utf32Characters.Resize( characterCount );
1390
1391     DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
1392     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
1393   }
1394
1395   if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
1396   {
1397     // The placeholder text is no longer needed
1398     if( mImpl->IsShowingPlaceholderText() )
1399     {
1400       ResetText();
1401     }
1402
1403     mImpl->ChangeState( EventData::EDITING );
1404
1405     // Handle the IMF (predicitive text) state changes
1406     if( mImpl->mEventData )
1407     {
1408       if( COMMIT == type )
1409       {
1410         // IMF manager is no longer handling key-events
1411         mImpl->ClearPreEditFlag();
1412       }
1413       else // PRE_EDIT
1414       {
1415         if( !mImpl->mEventData->mPreEditFlag )
1416         {
1417           DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state" );
1418
1419           // Record the start of the pre-edit text
1420           mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
1421         }
1422
1423         mImpl->mEventData->mPreEditLength = utf32Characters.Count();
1424         mImpl->mEventData->mPreEditFlag = true;
1425
1426         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
1427       }
1428     }
1429
1430     const Length numberOfCharactersInModel = mImpl->mLogicalModel->mText.Count();
1431
1432     // Restrict new text to fit within Maximum characters setting
1433     Length maxSizeOfNewText = std::min ( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
1434     maxLengthReached = ( characterCount > maxSizeOfNewText );
1435
1436     // Insert at current cursor position
1437     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
1438
1439     Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
1440
1441     if( cursorIndex < numberOfCharactersInModel )
1442     {
1443       modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
1444     }
1445     else
1446     {
1447       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
1448     }
1449
1450     cursorIndex += maxSizeOfNewText;
1451
1452     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Inserted %d characters, new size %d new cursor %d\n", maxSizeOfNewText, mImpl->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition );
1453   }
1454
1455   if( 0u == mImpl->mLogicalModel->mText.Count() &&
1456       mImpl->IsPlaceholderAvailable() )
1457   {
1458     // Show place-holder if empty after removing the pre-edit text
1459     ShowPlaceholderText();
1460     mImpl->mEventData->mUpdateCursorPosition = true;
1461     mImpl->ClearPreEditFlag();
1462   }
1463   else if( removedPrevious ||
1464            0 != utf32Characters.Count() )
1465   {
1466     // Queue an inserted event
1467     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
1468   }
1469
1470   if( maxLengthReached )
1471   {
1472     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mLogicalModel->mText.Count() );
1473
1474     mImpl->ResetImfManager();
1475
1476     // Do this last since it provides callbacks into application code
1477     mImpl->mControlInterface.MaxLengthReached();
1478   }
1479 }
1480
1481 bool Controller::RemoveSelectedText()
1482 {
1483   bool textRemoved( false );
1484
1485   if ( EventData::SELECTING         == mImpl->mEventData->mState ||
1486        EventData::SELECTION_CHANGED == mImpl->mEventData->mState )
1487   {
1488     std::string removedString;
1489     mImpl->RetrieveSelection( removedString, true );
1490
1491     if( !removedString.empty() )
1492     {
1493       textRemoved = true;
1494       mImpl->ChangeState( EventData::EDITING );
1495     }
1496   }
1497
1498   return textRemoved;
1499 }
1500
1501 void Controller::TapEvent( unsigned int tapCount, float x, float y )
1502 {
1503   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
1504
1505   if( NULL != mImpl->mEventData )
1506   {
1507     if( 1u == tapCount )
1508     {
1509       // This is to avoid unnecessary relayouts when tapping an empty text-field
1510       bool relayoutNeeded( false );
1511
1512       if( mImpl->IsShowingRealText() &&
1513           EventData::EDITING == mImpl->mEventData->mState )
1514       {
1515         // Show grab handle on second tap
1516         mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
1517         relayoutNeeded = true;
1518       }
1519       else if( EventData::EDITING                  != mImpl->mEventData->mState &&
1520                EventData::EDITING_WITH_GRAB_HANDLE != mImpl->mEventData->mState )
1521       {
1522         // Show cursor on first tap
1523         mImpl->ChangeState( EventData::EDITING );
1524         relayoutNeeded = true;
1525       }
1526       else if( mImpl->IsShowingRealText() )
1527       {
1528         // Move the cursor
1529         relayoutNeeded = true;
1530       }
1531
1532       // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
1533       if( relayoutNeeded )
1534       {
1535         Event event( Event::TAP_EVENT );
1536         event.p1.mUint = tapCount;
1537         event.p2.mFloat = x;
1538         event.p3.mFloat = y;
1539         mImpl->mEventData->mEventQueue.push_back( event );
1540
1541         mImpl->RequestRelayout();
1542       }
1543     }
1544     else if( 2u == tapCount )
1545     {
1546       if( mImpl->mEventData->mSelectionEnabled &&
1547           mImpl->IsShowingRealText() )
1548       {
1549         SelectEvent( x, y, false );
1550       }
1551     }
1552   }
1553
1554   // Reset keyboard as tap event has occurred.
1555   mImpl->ResetImfManager();
1556 }
1557
1558 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
1559 {
1560   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
1561
1562   if( mImpl->mEventData )
1563   {
1564     Event event( Event::PAN_EVENT );
1565     event.p1.mInt = state;
1566     event.p2.mFloat = displacement.x;
1567     event.p3.mFloat = displacement.y;
1568     mImpl->mEventData->mEventQueue.push_back( event );
1569
1570     mImpl->RequestRelayout();
1571   }
1572 }
1573
1574 void Controller::LongPressEvent( Gesture::State state, float x, float y  )
1575 {
1576   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
1577
1578   if  ( mImpl->IsShowingPlaceholderText() || mImpl->mLogicalModel->mText.Count() == 0u )
1579   {
1580     if ( mImpl->mEventData )
1581     {
1582       Event event( Event::LONG_PRESS_EVENT );
1583       event.p1.mInt = state;
1584       mImpl->mEventData->mEventQueue.push_back( event );
1585       mImpl->RequestRelayout();
1586     }
1587   }
1588   else if( mImpl->mEventData )
1589   {
1590     SelectEvent( x, y, false );
1591   }
1592 }
1593
1594 void Controller::SelectEvent( float x, float y, bool selectAll )
1595 {
1596   if( mImpl->mEventData )
1597   {
1598     if ( mImpl->mEventData->mState == EventData::SELECTING )
1599     {
1600       mImpl->ChangeState( EventData::SELECTION_CHANGED );
1601     }
1602     else
1603     {
1604       mImpl->ChangeState( EventData::SELECTING );
1605     }
1606
1607     if( selectAll )
1608     {
1609       Event event( Event::SELECT_ALL );
1610       mImpl->mEventData->mEventQueue.push_back( event );
1611     }
1612     else
1613     {
1614       Event event( Event::SELECT );
1615       event.p2.mFloat = x;
1616       event.p3.mFloat = y;
1617       mImpl->mEventData->mEventQueue.push_back( event );
1618     }
1619
1620     mImpl->RequestRelayout();
1621   }
1622 }
1623
1624 void Controller::GetTargetSize( Vector2& targetSize )
1625 {
1626   targetSize = mImpl->mVisualModel->mControlSize;
1627 }
1628
1629 void Controller::AddDecoration( Actor& actor, bool needsClipping )
1630 {
1631   mImpl->mControlInterface.AddDecoration( actor, needsClipping );
1632 }
1633
1634 void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
1635 {
1636   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
1637
1638   if( mImpl->mEventData )
1639   {
1640     switch( handleType )
1641     {
1642       case GRAB_HANDLE:
1643       {
1644         Event event( Event::GRAB_HANDLE_EVENT );
1645         event.p1.mUint  = state;
1646         event.p2.mFloat = x;
1647         event.p3.mFloat = y;
1648
1649         mImpl->mEventData->mEventQueue.push_back( event );
1650         break;
1651       }
1652       case LEFT_SELECTION_HANDLE:
1653       {
1654         Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
1655         event.p1.mUint  = state;
1656         event.p2.mFloat = x;
1657         event.p3.mFloat = y;
1658
1659         mImpl->mEventData->mEventQueue.push_back( event );
1660         break;
1661       }
1662       case RIGHT_SELECTION_HANDLE:
1663       {
1664         Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
1665         event.p1.mUint  = state;
1666         event.p2.mFloat = x;
1667         event.p3.mFloat = y;
1668
1669         mImpl->mEventData->mEventQueue.push_back( event );
1670         break;
1671       }
1672       case LEFT_SELECTION_HANDLE_MARKER:
1673       case RIGHT_SELECTION_HANDLE_MARKER:
1674       {
1675         // Markers do not move the handles.
1676         break;
1677       }
1678       case HANDLE_TYPE_COUNT:
1679       {
1680         DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
1681       }
1682     }
1683
1684     mImpl->RequestRelayout();
1685   }
1686 }
1687
1688 void Controller::PasteText( const std::string& stringToPaste )
1689 {
1690   InsertText( stringToPaste, Text::Controller::COMMIT );
1691   mImpl->ChangeState( EventData::EDITING );
1692   mImpl->RequestRelayout();
1693 }
1694
1695 void Controller::PasteClipboardItemEvent()
1696 {
1697   ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
1698   std::string stringToPaste( notifier.GetContent() );
1699   PasteText( stringToPaste );
1700 }
1701
1702 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
1703 {
1704   if( NULL == mImpl->mEventData )
1705   {
1706     return;
1707   }
1708
1709   switch( button )
1710   {
1711     case Toolkit::TextSelectionPopup::CUT:
1712     {
1713       mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
1714       mImpl->mOperationsPending = ALL_OPERATIONS;
1715       if( 0u != mImpl->mLogicalModel->mText.Count() ||
1716           !mImpl->IsPlaceholderAvailable() )
1717       {
1718         mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
1719       }
1720       else
1721       {
1722         ShowPlaceholderText();
1723         mImpl->mEventData->mUpdateCursorPosition = true;
1724       }
1725       mImpl->RequestRelayout();
1726       mImpl->mControlInterface.TextChanged();
1727       break;
1728     }
1729     case Toolkit::TextSelectionPopup::COPY:
1730     {
1731       mImpl->SendSelectionToClipboard( false ); // Text not modified
1732       mImpl->RequestRelayout(); // Handles, Selection Highlight, Popup
1733       break;
1734     }
1735     case Toolkit::TextSelectionPopup::PASTE:
1736     {
1737       std::string stringToPaste("");
1738       mImpl->GetTextFromClipboard( 0, stringToPaste ); // Paste latest item from system clipboard
1739       PasteText( stringToPaste );
1740       break;
1741     }
1742     case Toolkit::TextSelectionPopup::SELECT:
1743     {
1744       const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
1745
1746       if( mImpl->mEventData->mSelectionEnabled  )
1747       {
1748         // Creates a SELECT event.
1749         SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false );
1750       }
1751       break;
1752     }
1753     case Toolkit::TextSelectionPopup::SELECT_ALL:
1754     {
1755       // Creates a SELECT_ALL event
1756       SelectEvent( 0.f, 0.f, true );
1757       break;
1758     }
1759     case Toolkit::TextSelectionPopup::CLIPBOARD:
1760     {
1761       mImpl->ShowClipboard();
1762       break;
1763     }
1764     case Toolkit::TextSelectionPopup::NONE:
1765     {
1766       // Nothing to do.
1767       break;
1768     }
1769   }
1770 }
1771
1772 ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
1773 {
1774   bool update( false );
1775   bool requestRelayout = false;
1776
1777   std::string text;
1778   unsigned int cursorPosition( 0 );
1779
1780   switch ( imfEvent.eventName )
1781   {
1782     case ImfManager::COMMIT:
1783     {
1784       InsertText( imfEvent.predictiveString, Text::Controller::COMMIT );
1785       requestRelayout = true;
1786       break;
1787     }
1788     case ImfManager::PREEDIT:
1789     {
1790       InsertText( imfEvent.predictiveString, Text::Controller::PRE_EDIT );
1791       update = true;
1792       requestRelayout = true;
1793       break;
1794     }
1795     case ImfManager::DELETESURROUNDING:
1796     {
1797       update = RemoveText( imfEvent.cursorOffset, imfEvent.numberOfChars );
1798
1799       if( update )
1800       {
1801         if( 0u != mImpl->mLogicalModel->mText.Count() ||
1802             !mImpl->IsPlaceholderAvailable() )
1803         {
1804           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
1805         }
1806         else
1807         {
1808           ShowPlaceholderText();
1809           mImpl->mEventData->mUpdateCursorPosition = true;
1810         }
1811       }
1812       requestRelayout = true;
1813       break;
1814     }
1815     case ImfManager::GETSURROUNDING:
1816     {
1817       GetText( text );
1818       cursorPosition = GetLogicalCursorPosition();
1819
1820       imfManager.SetSurroundingText( text );
1821       imfManager.SetCursorPosition( cursorPosition );
1822       break;
1823     }
1824     case ImfManager::VOID:
1825     {
1826       // do nothing
1827       break;
1828     }
1829   } // end switch
1830
1831   if( ImfManager::GETSURROUNDING != imfEvent.eventName )
1832   {
1833     GetText( text );
1834     cursorPosition = GetLogicalCursorPosition();
1835   }
1836
1837   if( requestRelayout )
1838   {
1839     mImpl->mOperationsPending = ALL_OPERATIONS;
1840     mImpl->RequestRelayout();
1841
1842     // Do this last since it provides callbacks into application code
1843     mImpl->mControlInterface.TextChanged();
1844   }
1845
1846   ImfManager::ImfCallbackData callbackData( update, cursorPosition, text, false );
1847
1848   return callbackData;
1849 }
1850
1851 Controller::~Controller()
1852 {
1853   delete mImpl;
1854 }
1855
1856 bool Controller::BackspaceKeyEvent()
1857 {
1858   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p DALI_KEY_BACKSPACE\n", this );
1859
1860   // IMF manager is no longer handling key-events
1861   mImpl->ClearPreEditFlag();
1862
1863   bool removed( false );
1864
1865   if ( EventData::SELECTING         == mImpl->mEventData->mState ||
1866        EventData::SELECTION_CHANGED == mImpl->mEventData->mState )
1867   {
1868     removed = RemoveSelectedText();
1869   }
1870   else if( mImpl->mEventData->mPrimaryCursorPosition > 0 )
1871   {
1872     // Remove the character before the current cursor position
1873     removed = RemoveText( -1, 1 );
1874   }
1875
1876   if( removed )
1877   {
1878     if( 0u != mImpl->mLogicalModel->mText.Count() ||
1879         !mImpl->IsPlaceholderAvailable() )
1880     {
1881       mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
1882     }
1883     else
1884     {
1885       ShowPlaceholderText();
1886       mImpl->mEventData->mUpdateCursorPosition = true;
1887     }
1888   }
1889
1890   return removed;
1891 }
1892
1893 void Controller::ShowPlaceholderText()
1894 {
1895   if( mImpl->IsPlaceholderAvailable() )
1896   {
1897     DALI_ASSERT_DEBUG( mImpl->mEventData && "No placeholder text available" );
1898
1899     mImpl->mEventData->mIsShowingPlaceholderText = true;
1900
1901     // Disable handles when showing place-holder text
1902     mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
1903     mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1904     mImpl->mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1905
1906     const char* text( NULL );
1907     size_t size( 0 );
1908
1909     // TODO - Switch placeholder text styles when changing state
1910     if( EventData::INACTIVE != mImpl->mEventData->mState &&
1911         0u != mImpl->mEventData->mPlaceholderTextActive.c_str() )
1912     {
1913       text = mImpl->mEventData->mPlaceholderTextActive.c_str();
1914       size = mImpl->mEventData->mPlaceholderTextActive.size();
1915     }
1916     else
1917     {
1918       text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
1919       size = mImpl->mEventData->mPlaceholderTextInactive.size();
1920     }
1921
1922     // Reset model for showing placeholder.
1923     mImpl->mLogicalModel->mText.Clear();
1924     ClearModelData();
1925     mImpl->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor );
1926
1927     // Convert text into UTF-32
1928     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
1929     utf32Characters.Resize( size );
1930
1931     // This is a bit horrible but std::string returns a (signed) char*
1932     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text );
1933
1934     // Transform a text array encoded in utf8 into an array encoded in utf32.
1935     // It returns the actual number of characters.
1936     Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() );
1937     utf32Characters.Resize( characterCount );
1938
1939     // Reset the cursor position
1940     mImpl->mEventData->mPrimaryCursorPosition = 0;
1941
1942     // The natural size needs to be re-calculated.
1943     mImpl->mRecalculateNaturalSize = true;
1944
1945     // Apply modifications to the model
1946     mImpl->mOperationsPending = ALL_OPERATIONS;
1947
1948     // Update the rest of the model during size negotiation
1949     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
1950   }
1951 }
1952
1953 void Controller::ClearModelData()
1954 {
1955   // n.b. This does not Clear the mText from mLogicalModel
1956   mImpl->mLogicalModel->mScriptRuns.Clear();
1957   mImpl->mLogicalModel->mFontRuns.Clear();
1958   mImpl->mLogicalModel->mLineBreakInfo.Clear();
1959   mImpl->mLogicalModel->mWordBreakInfo.Clear();
1960   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
1961   mImpl->mLogicalModel->mCharacterDirections.Clear();
1962   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
1963   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
1964   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
1965   mImpl->mVisualModel->mGlyphs.Clear();
1966   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1967   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1968   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1969   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1970   mImpl->mVisualModel->mGlyphPositions.Clear();
1971   mImpl->mVisualModel->mLines.Clear();
1972   mImpl->mVisualModel->ClearCaches();
1973 }
1974
1975 void Controller::ClearFontData()
1976 {
1977   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
1978   mImpl->mLogicalModel->mFontRuns.Clear();
1979   mImpl->mVisualModel->mGlyphs.Clear();
1980   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1981   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1982   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1983   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1984   mImpl->mVisualModel->mGlyphPositions.Clear();
1985   mImpl->mVisualModel->mLines.Clear();
1986   mImpl->mVisualModel->ClearCaches();
1987 }
1988
1989 Controller::Controller( ControlInterface& controlInterface )
1990 : mImpl( NULL )
1991 {
1992   mImpl = new Controller::Impl( controlInterface );
1993 }
1994
1995 } // namespace Text
1996
1997 } // namespace Toolkit
1998
1999 } // namespace Dali