af0698694314e0cb967fbc16f03de046027ef14c
[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 <iostream>
24 #include <dali/public-api/adaptor-framework/key.h>
25 #include <dali/integration-api/debug.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/multi-language-support.h>
32 #include <dali-toolkit/internal/text/script-run.h>
33 #include <dali-toolkit/internal/text/segmentation.h>
34 #include <dali-toolkit/internal/text/shaper.h>
35 #include <dali-toolkit/internal/text/text-controller-impl.h>
36 #include <dali-toolkit/internal/text/text-io.h>
37 #include <dali-toolkit/internal/text/text-view.h>
38
39 namespace
40 {
41
42 #if defined(DEBUG_ENABLED)
43   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_CONTROLS");
44 #endif
45
46 const float MAX_FLOAT = std::numeric_limits<float>::max();
47
48 const std::string EMPTY_STRING("");
49
50 } // namespace
51
52 namespace Dali
53 {
54
55 namespace Toolkit
56 {
57
58 namespace Text
59 {
60
61 ControllerPtr Controller::New( ControlInterface& controlInterface )
62 {
63   return ControllerPtr( new Controller( controlInterface ) );
64 }
65
66 void Controller::EnableTextInput( DecoratorPtr decorator )
67 {
68   if( !mImpl->mEventData )
69   {
70     mImpl->mEventData = new EventData( decorator );
71   }
72 }
73
74 void Controller::SetText( const std::string& text )
75 {
76   // Cancel previously queued inserts etc.
77   mImpl->mModifyEvents.clear();
78
79   // Remove the previously set text
80   ResetText();
81
82   if( ! text.empty() )
83   {
84     //  Convert text into UTF-32
85     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
86     utf32Characters.Resize( text.size() );
87
88     // This is a bit horrible but std::string returns a (signed) char*
89     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
90
91     // Transform a text array encoded in utf8 into an array encoded in utf32.
92     // It returns the actual number of characters.
93     Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
94     utf32Characters.Resize( characterCount );
95
96     DALI_ASSERT_DEBUG( text.size() >= characterCount && "Invalid UTF32 conversion length" );
97     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, text.size(), mImpl->mLogicalModel->mText.Count() );
98
99     // Reset the cursor position
100     if( mImpl->mEventData )
101     {
102       mImpl->mEventData->mPrimaryCursorPosition = characterCount;
103     }
104
105     // Update the rest of the model during size negotiation
106     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
107   }
108   else
109   {
110     ShowPlaceholderText();
111   }
112
113   if( mImpl->mEventData )
114   {
115     // Cancel previously queued events
116     mImpl->mEventData->mEventQueue.clear();
117   }
118
119   // Reset keyboard as text changed
120   mImpl->PreEditReset();
121 }
122
123 void Controller::GetText( std::string& text ) const
124 {
125   if( ! mImpl->IsShowingPlaceholderText() )
126   {
127     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
128
129     if( 0u != utf32Characters.Count() )
130     {
131       Utf32ToUtf8( &utf32Characters[0], utf32Characters.Count(), text );
132     }
133   }
134   else
135   {
136     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this );
137   }
138 }
139
140 unsigned int Controller::GetLogicalCursorPosition() const
141 {
142   if( mImpl->mEventData )
143   {
144     return mImpl->mEventData->mPrimaryCursorPosition;
145   }
146
147   return 0u;
148 }
149
150 void Controller::SetPlaceholderText( PlaceholderType type, const std::string& text )
151 {
152   if( mImpl->mEventData )
153   {
154     if( PLACEHOLDER_TYPE_INACTIVE == type )
155     {
156       mImpl->mEventData->mPlaceholderTextInactive = text;
157     }
158     else
159     {
160       mImpl->mEventData->mPlaceholderTextActive = text;
161     }
162
163     ShowPlaceholderText();
164   }
165 }
166
167 void Controller::GetPlaceholderText( PlaceholderType type, std::string& text ) const
168 {
169   if( mImpl->mEventData )
170   {
171     if( PLACEHOLDER_TYPE_INACTIVE == type )
172     {
173       text = mImpl->mEventData->mPlaceholderTextInactive;
174     }
175     else
176     {
177       text = mImpl->mEventData->mPlaceholderTextActive;
178     }
179   }
180 }
181
182 void Controller::SetMaximumNumberOfCharacters( int maxCharacters )
183 {
184   if ( maxCharacters >= 0 )
185   {
186     mImpl->mMaximumNumberOfCharacters = maxCharacters;
187   }
188 }
189
190 int Controller::GetMaximumNumberOfCharacters()
191 {
192   return mImpl->mMaximumNumberOfCharacters;
193 }
194
195 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
196 {
197   if( !mImpl->mFontDefaults )
198   {
199     mImpl->mFontDefaults = new FontDefaults();
200   }
201
202   mImpl->mFontDefaults->mDefaultFontFamily = defaultFontFamily;
203
204   // Clear the font-specific data
205   ClearFontData();
206
207   mImpl->mOperationsPending = ALL_OPERATIONS;
208   mImpl->mRecalculateNaturalSize = true;
209
210   mImpl->RequestRelayout();
211 }
212
213 const std::string& Controller::GetDefaultFontFamily() const
214 {
215   if( mImpl->mFontDefaults )
216   {
217     return mImpl->mFontDefaults->mDefaultFontFamily;
218   }
219
220   return EMPTY_STRING;
221 }
222
223 void Controller::SetDefaultFontStyle( const std::string& defaultFontStyle )
224 {
225   if( !mImpl->mFontDefaults )
226   {
227     mImpl->mFontDefaults = new FontDefaults();
228   }
229
230   mImpl->mFontDefaults->mDefaultFontStyle = defaultFontStyle;
231
232   // Clear the font-specific data
233   ClearFontData();
234
235   mImpl->mOperationsPending = ALL_OPERATIONS;
236   mImpl->mRecalculateNaturalSize = true;
237
238   mImpl->RequestRelayout();
239 }
240
241 const std::string& Controller::GetDefaultFontStyle() const
242 {
243   if( mImpl->mFontDefaults )
244   {
245     return mImpl->mFontDefaults->mDefaultFontStyle;
246   }
247
248   return EMPTY_STRING;
249 }
250
251 void Controller::SetDefaultPointSize( float pointSize )
252 {
253   if( !mImpl->mFontDefaults )
254   {
255     mImpl->mFontDefaults = new FontDefaults();
256   }
257
258   mImpl->mFontDefaults->mDefaultPointSize = pointSize;
259
260   // Clear the font-specific data
261   ClearFontData();
262
263   mImpl->mOperationsPending = ALL_OPERATIONS;
264   mImpl->mRecalculateNaturalSize = true;
265
266   mImpl->RequestRelayout();
267 }
268
269 float Controller::GetDefaultPointSize() const
270 {
271   if( mImpl->mFontDefaults )
272   {
273     return mImpl->mFontDefaults->mDefaultPointSize;
274   }
275
276   return 0.0f;
277 }
278
279 void Controller::SetTextColor( const Vector4& textColor )
280 {
281   mImpl->mTextColor = textColor;
282
283   if( ! mImpl->IsShowingPlaceholderText() )
284   {
285     mImpl->mVisualModel->SetTextColor( textColor );
286   }
287 }
288
289 const Vector4& Controller::GetTextColor() const
290 {
291   return mImpl->mTextColor;
292 }
293
294 bool Controller::RemoveText( int cursorOffset, int numberOfChars )
295 {
296   bool removed( false );
297
298   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfChars %d\n",
299                  this, mImpl->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfChars );
300
301   if( ! mImpl->IsShowingPlaceholderText() )
302   {
303     // Delete at current cursor position
304     Vector<Character>& currentText = mImpl->mLogicalModel->mText;
305     CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
306
307     CharacterIndex cursorIndex = oldCursorIndex;
308
309     // Validate the cursor position & number of characters
310     if( static_cast< CharacterIndex >( std::abs( cursorOffset ) ) <= cursorIndex )
311     {
312       cursorIndex = oldCursorIndex + cursorOffset;
313     }
314
315     if( (cursorIndex + numberOfChars) > currentText.Count() )
316     {
317       numberOfChars = currentText.Count() - cursorIndex;
318     }
319
320     if( cursorIndex >= 0 &&
321         (cursorIndex + numberOfChars) <= currentText.Count() )
322     {
323       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
324       Vector<Character>::Iterator last  = first + numberOfChars;
325
326       currentText.Erase( first, last );
327
328       // Cursor position retreat
329       oldCursorIndex = cursorIndex;
330
331       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfChars );
332       removed = true;
333     }
334   }
335
336   return removed;
337 }
338
339 void Controller::SetPlaceholderTextColor( const Vector4& textColor )
340 {
341   if( mImpl->mEventData )
342   {
343     mImpl->mEventData->mPlaceholderTextColor = textColor;
344   }
345
346   if( mImpl->IsShowingPlaceholderText() )
347   {
348     mImpl->mVisualModel->SetTextColor( textColor );
349   }
350 }
351
352 const Vector4& Controller::GetPlaceholderTextColor() const
353 {
354   if( mImpl->mEventData )
355   {
356     return mImpl->mEventData->mPlaceholderTextColor;
357   }
358
359   return Color::BLACK;
360 }
361
362 void Controller::SetShadowOffset( const Vector2& shadowOffset )
363 {
364   mImpl->mVisualModel->SetShadowOffset( shadowOffset );
365 }
366
367 const Vector2& Controller::GetShadowOffset() const
368 {
369   return mImpl->mVisualModel->GetShadowOffset();
370 }
371
372 void Controller::SetShadowColor( const Vector4& shadowColor )
373 {
374   mImpl->mVisualModel->SetShadowColor( shadowColor );
375 }
376
377 const Vector4& Controller::GetShadowColor() const
378 {
379   return mImpl->mVisualModel->GetShadowColor();
380 }
381
382 void Controller::SetUnderlineColor( const Vector4& color )
383 {
384   mImpl->mVisualModel->SetUnderlineColor( color );
385 }
386
387 const Vector4& Controller::GetUnderlineColor() const
388 {
389   return mImpl->mVisualModel->GetUnderlineColor();
390 }
391
392 void Controller::SetUnderlineEnabled( bool enabled )
393 {
394   mImpl->mVisualModel->SetUnderlineEnabled( enabled );
395 }
396
397 bool Controller::IsUnderlineEnabled() const
398 {
399   return mImpl->mVisualModel->IsUnderlineEnabled();
400 }
401
402 void Controller::SetUnderlineHeight( float height )
403 {
404   mImpl->mVisualModel->SetUnderlineHeight( height );
405 }
406
407 float Controller::GetUnderlineHeight() const
408 {
409   return mImpl->mVisualModel->GetUnderlineHeight();
410 }
411
412 void Controller::SetEnableCursorBlink( bool enable )
413 {
414   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" );
415
416   if( mImpl->mEventData )
417   {
418     mImpl->mEventData->mCursorBlinkEnabled = enable;
419
420     if( !enable &&
421         mImpl->mEventData->mDecorator )
422     {
423       mImpl->mEventData->mDecorator->StopCursorBlink();
424     }
425   }
426 }
427
428 bool Controller::GetEnableCursorBlink() const
429 {
430   if( mImpl->mEventData )
431   {
432     return mImpl->mEventData->mCursorBlinkEnabled;
433   }
434
435   return false;
436 }
437
438 const Vector2& Controller::GetScrollPosition() const
439 {
440   if( mImpl->mEventData )
441   {
442     return mImpl->mEventData->mScrollPosition;
443   }
444
445   return Vector2::ZERO;
446 }
447
448 const Vector2& Controller::GetAlignmentOffset() const
449 {
450   return mImpl->mAlignmentOffset;
451 }
452
453 Vector3 Controller::GetNaturalSize()
454 {
455   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n" );
456   Vector3 naturalSize;
457
458   // Make sure the model is up-to-date before layouting
459   ProcessModifyEvents();
460
461   if( mImpl->mRecalculateNaturalSize )
462   {
463     // Operations that can be done only once until the text changes.
464     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
465                                                                            GET_SCRIPTS       |
466                                                                            VALIDATE_FONTS    |
467                                                                            GET_LINE_BREAKS   |
468                                                                            GET_WORD_BREAKS   |
469                                                                            BIDI_INFO         |
470                                                                            SHAPE_TEXT        |
471                                                                            GET_GLYPH_METRICS );
472     // Make sure the model is up-to-date before layouting
473     mImpl->UpdateModel( onlyOnceOperations );
474
475     // Operations that need to be done if the size changes.
476     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
477                                                                         ALIGN  |
478                                                                         REORDER );
479
480     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
481                 static_cast<OperationsMask>( onlyOnceOperations |
482                                              sizeOperations ),
483                 naturalSize.GetVectorXY() );
484
485     // Do not do again the only once operations.
486     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
487
488     // Do the size related operations again.
489     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
490
491     // Stores the natural size to avoid recalculate it again
492     // unless the text/style changes.
493     mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
494
495     mImpl->mRecalculateNaturalSize = false;
496
497     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
498   }
499   else
500   {
501     naturalSize = mImpl->mVisualModel->GetNaturalSize();
502
503     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
504   }
505
506   return naturalSize;
507 }
508
509 float Controller::GetHeightForWidth( float width )
510 {
511   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width );
512   // Make sure the model is up-to-date before layouting
513   ProcessModifyEvents();
514
515   Size layoutSize;
516   if( width != mImpl->mControlSize.width )
517   {
518     // Operations that can be done only once until the text changes.
519     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
520                                                                            GET_SCRIPTS       |
521                                                                            VALIDATE_FONTS    |
522                                                                            GET_LINE_BREAKS   |
523                                                                            GET_WORD_BREAKS   |
524                                                                            BIDI_INFO         |
525                                                                            SHAPE_TEXT        |
526                                                                            GET_GLYPH_METRICS );
527     // Make sure the model is up-to-date before layouting
528     mImpl->UpdateModel( onlyOnceOperations );
529
530     // Operations that need to be done if the size changes.
531     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
532                                                                         ALIGN  |
533                                                                         REORDER );
534
535     DoRelayout( Size( width, MAX_FLOAT ),
536                 static_cast<OperationsMask>( onlyOnceOperations |
537                                              sizeOperations ),
538                 layoutSize );
539
540     // Do not do again the only once operations.
541     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
542
543     // Do the size related operations again.
544     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
545     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height );
546   }
547   else
548   {
549     layoutSize = mImpl->mVisualModel->GetActualSize();
550     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height );
551   }
552
553   return layoutSize.height;
554 }
555
556 bool Controller::Relayout( const Size& size )
557 {
558   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f\n", this, size.width, size.height );
559
560   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
561   {
562     bool glyphsRemoved( false );
563     if( 0u != mImpl->mVisualModel->GetNumberOfGlyphPositions() )
564     {
565       mImpl->mVisualModel->SetGlyphPositions( NULL, 0u );
566       glyphsRemoved = true;
567     }
568     // Not worth to relayout if width or height is equal to zero.
569     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
570     return glyphsRemoved;
571   }
572
573   if( size != mImpl->mControlSize )
574   {
575     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mControlSize.width, mImpl->mControlSize.height );
576
577     // Operations that need to be done if the size changes.
578     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
579                                                              LAYOUT                    |
580                                                              ALIGN                     |
581                                                              UPDATE_ACTUAL_SIZE        |
582                                                              REORDER );
583
584     mImpl->mControlSize = size;
585   }
586
587   // Make sure the model is up-to-date before layouting
588   ProcessModifyEvents();
589   mImpl->UpdateModel( mImpl->mOperationsPending );
590
591   Size layoutSize;
592   bool updated = DoRelayout( mImpl->mControlSize,
593                              mImpl->mOperationsPending,
594                              layoutSize );
595
596   // Do not re-do any operation until something changes.
597   mImpl->mOperationsPending = NO_OPERATION;
598
599   // After doing the text layout, the alignment offset to place the actor in the desired position can be calculated.
600   CalculateTextAlignment( size );
601
602   if( mImpl->mEventData )
603   {
604     // Move the cursor, grab handle etc.
605     updated = mImpl->ProcessInputEvents() || updated;
606   }
607
608   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
609   return updated;
610 }
611
612 void Controller::ProcessModifyEvents()
613 {
614   std::vector<ModifyEvent>& events = mImpl->mModifyEvents;
615
616   for( unsigned int i=0; i<events.size(); ++i )
617   {
618     if( ModifyEvent::TEXT_REPLACED == events[0].type )
619     {
620       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
621       DALI_ASSERT_DEBUG( 0 == i && "Unexpected TEXT_REPLACED event" );
622
623       TextReplacedEvent();
624     }
625     else if( ModifyEvent::TEXT_INSERTED == events[0].type )
626     {
627       TextInsertedEvent();
628     }
629     else if( ModifyEvent::TEXT_DELETED == events[0].type )
630     {
631       // Placeholder-text cannot be deleted
632       if( !mImpl->IsShowingPlaceholderText() )
633       {
634         TextDeletedEvent();
635       }
636     }
637   }
638
639   // Discard temporary text
640   events.clear();
641 }
642
643 void Controller::ResetText()
644 {
645   // Reset buffers.
646   mImpl->mLogicalModel->mText.Clear();
647   ClearModelData();
648
649   // Reset the cursor position
650   if( mImpl->mEventData )
651   {
652     mImpl->mEventData->mPrimaryCursorPosition = 0;
653   }
654
655   // We have cleared everything including the placeholder-text
656   mImpl->PlaceholderCleared();
657
658   // The natural size needs to be re-calculated.
659   mImpl->mRecalculateNaturalSize = true;
660
661   // Apply modifications to the model
662   mImpl->mOperationsPending = ALL_OPERATIONS;
663 }
664
665 void Controller::TextReplacedEvent()
666 {
667   // Reset buffers.
668   ClearModelData();
669
670   // The natural size needs to be re-calculated.
671   mImpl->mRecalculateNaturalSize = true;
672
673   // Apply modifications to the model
674   mImpl->mOperationsPending = ALL_OPERATIONS;
675   mImpl->UpdateModel( ALL_OPERATIONS );
676   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
677                                                            ALIGN              |
678                                                            UPDATE_ACTUAL_SIZE |
679                                                            REORDER );
680 }
681
682 void Controller::TextInsertedEvent()
683 {
684   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" );
685
686   // TODO - Optimize this
687   ClearModelData();
688
689   // The natural size needs to be re-calculated.
690   mImpl->mRecalculateNaturalSize = true;
691
692   // Apply modifications to the model; TODO - Optimize this
693   mImpl->mOperationsPending = ALL_OPERATIONS;
694   mImpl->UpdateModel( ALL_OPERATIONS );
695   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
696                                                            ALIGN              |
697                                                            UPDATE_ACTUAL_SIZE |
698                                                            REORDER );
699
700   // Queue a cursor reposition event; this must wait until after DoRelayout()
701   mImpl->mEventData->mUpdateCursorPosition = true;
702   mImpl->mEventData->mScrollAfterUpdateCursorPosition = true;
703 }
704
705 void Controller::TextDeletedEvent()
706 {
707   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" );
708
709   // TODO - Optimize this
710   ClearModelData();
711
712   // The natural size needs to be re-calculated.
713   mImpl->mRecalculateNaturalSize = true;
714
715   // Apply modifications to the model; TODO - Optimize this
716   mImpl->mOperationsPending = ALL_OPERATIONS;
717   mImpl->UpdateModel( ALL_OPERATIONS );
718   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
719                                                            ALIGN              |
720                                                            UPDATE_ACTUAL_SIZE |
721                                                            REORDER );
722
723   // Queue a cursor reposition event; this must wait until after DoRelayout()
724   mImpl->mEventData->mUpdateCursorPosition = true;
725   mImpl->mEventData->mScrollAfterUpdateCursorPosition = true;
726 }
727
728 bool Controller::DoRelayout( const Size& size,
729                              OperationsMask operationsRequired,
730                              Size& layoutSize )
731 {
732   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height );
733   bool viewUpdated( false );
734
735   // Calculate the operations to be done.
736   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
737
738   if( LAYOUT & operations )
739   {
740     // Some vectors with data needed to layout and reorder may be void
741     // after the first time the text has been laid out.
742     // Fill the vectors again.
743
744     Length numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
745
746     if( 0u == numberOfGlyphs )
747     {
748       // Nothing else to do if there is no glyphs.
749       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n" );
750       return true;
751     }
752
753     Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
754     Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
755     Vector<CharacterDirection>& characterDirection = mImpl->mLogicalModel->mCharacterDirections;
756     Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
757     Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
758     Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
759
760     // Set the layout parameters.
761     LayoutParameters layoutParameters( size,
762                                        mImpl->mLogicalModel->mText.Begin(),
763                                        lineBreakInfo.Begin(),
764                                        wordBreakInfo.Begin(),
765                                        ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
766                                        numberOfGlyphs,
767                                        glyphs.Begin(),
768                                        glyphsToCharactersMap.Begin(),
769                                        charactersPerGlyph.Begin() );
770
771     // The laid-out lines.
772     // It's not possible to know in how many lines the text is going to be laid-out,
773     // but it can be resized at least with the number of 'paragraphs' to avoid
774     // some re-allocations.
775     Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
776
777     // Delete any previous laid out lines before setting the new ones.
778     lines.Clear();
779
780     // The capacity of the bidirectional paragraph info is the number of paragraphs.
781     lines.Reserve( mImpl->mLogicalModel->mBidirectionalParagraphInfo.Capacity() );
782
783     // Resize the vector of positions to have the same size than the vector of glyphs.
784     Vector<Vector2>& glyphPositions = mImpl->mVisualModel->mGlyphPositions;
785     glyphPositions.Resize( numberOfGlyphs );
786
787     // Update the visual model.
788     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
789                                                    glyphPositions,
790                                                    lines,
791                                                    layoutSize );
792
793     if( viewUpdated )
794     {
795       // Reorder the lines
796       if( REORDER & operations )
797       {
798         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
799
800         // Check first if there are paragraphs with bidirectional info.
801         if( 0u != bidirectionalInfo.Count() )
802         {
803           // Get the lines
804           const Length numberOfLines = mImpl->mVisualModel->GetNumberOfLines();
805
806           // Reorder the lines.
807           Vector<BidirectionalLineInfoRun> lineBidirectionalInfoRuns;
808           lineBidirectionalInfoRuns.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
809           ReorderLines( bidirectionalInfo,
810                         lines,
811                         lineBidirectionalInfoRuns );
812
813           // Set the bidirectional info into the model.
814           const Length numberOfBidirectionalInfoRuns = lineBidirectionalInfoRuns.Count();
815           mImpl->mLogicalModel->SetVisualToLogicalMap( lineBidirectionalInfoRuns.Begin(),
816                                                        numberOfBidirectionalInfoRuns );
817
818           // Set the bidirectional info per line into the layout parameters.
819           layoutParameters.lineBidirectionalInfoRunsBuffer = lineBidirectionalInfoRuns.Begin();
820           layoutParameters.numberOfBidirectionalInfoRuns = numberOfBidirectionalInfoRuns;
821
822           // Get the character to glyph conversion table and set into the layout.
823           layoutParameters.charactersToGlyphsBuffer = mImpl->mVisualModel->mCharactersToGlyph.Begin();
824
825           // Get the glyphs per character table and set into the layout.
826           layoutParameters.glyphsPerCharacterBuffer = mImpl->mVisualModel->mGlyphsPerCharacter.Begin();
827
828           // Re-layout the text. Reorder those lines with right to left characters.
829           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
830                                                          glyphPositions );
831
832           // Free the allocated memory used to store the conversion table in the bidirectional line info run.
833           for( Vector<BidirectionalLineInfoRun>::Iterator it = lineBidirectionalInfoRuns.Begin(),
834                  endIt = lineBidirectionalInfoRuns.End();
835                it != endIt;
836                ++it )
837           {
838             BidirectionalLineInfoRun& bidiLineInfo = *it;
839
840             free( bidiLineInfo.visualToLogicalMap );
841           }
842         }
843       } // REORDER
844
845       if( ALIGN & operations )
846       {
847         mImpl->mLayoutEngine.Align( layoutParameters,
848                                     layoutSize,
849                                     lines,
850                                     glyphPositions );
851       }
852
853       // Sets the actual size.
854       if( UPDATE_ACTUAL_SIZE & operations )
855       {
856         mImpl->mVisualModel->SetActualSize( layoutSize );
857       }
858     } // view updated
859   }
860   else
861   {
862     layoutSize = mImpl->mVisualModel->GetActualSize();
863   }
864
865   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
866   return viewUpdated;
867 }
868
869 void Controller::CalculateTextAlignment( const Size& size )
870 {
871   // Get the direction of the first character.
872   const CharacterDirection firstParagraphDirection = mImpl->mLogicalModel->GetCharacterDirection( 0u );
873
874   const Size& actualSize = mImpl->mVisualModel->GetActualSize();
875
876   // If the first paragraph is right to left swap ALIGN_BEGIN and ALIGN_END;
877   LayoutEngine::HorizontalAlignment horizontalAlignment = mImpl->mLayoutEngine.GetHorizontalAlignment();
878   if( firstParagraphDirection &&
879       ( LayoutEngine::HORIZONTAL_ALIGN_CENTER != horizontalAlignment ) )
880   {
881     if( LayoutEngine::HORIZONTAL_ALIGN_BEGIN == horizontalAlignment )
882     {
883       horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_END;
884     }
885     else
886     {
887       horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_BEGIN;
888     }
889   }
890
891   switch( horizontalAlignment )
892   {
893     case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
894     {
895       mImpl->mAlignmentOffset.x = 0.f;
896       break;
897     }
898     case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
899     {
900       const int intOffset = static_cast<int>( 0.5f * ( size.width - actualSize.width ) ); // try to avoid pixel alignment.
901       mImpl->mAlignmentOffset.x = static_cast<float>( intOffset );
902       break;
903     }
904     case LayoutEngine::HORIZONTAL_ALIGN_END:
905     {
906       mImpl->mAlignmentOffset.x = size.width - actualSize.width;
907       break;
908     }
909   }
910
911   const LayoutEngine::VerticalAlignment verticalAlignment = mImpl->mLayoutEngine.GetVerticalAlignment();
912   switch( verticalAlignment )
913   {
914     case LayoutEngine::VERTICAL_ALIGN_TOP:
915     {
916       mImpl->mAlignmentOffset.y = 0.f;
917       break;
918     }
919     case LayoutEngine::VERTICAL_ALIGN_CENTER:
920     {
921       const int intOffset = static_cast<int>( 0.5f * ( size.height - actualSize.height ) ); // try to avoid pixel alignment.
922       mImpl->mAlignmentOffset.y = static_cast<float>( intOffset );
923       break;
924     }
925     case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
926     {
927       mImpl->mAlignmentOffset.y = size.height - actualSize.height;
928       break;
929     }
930   }
931 }
932
933 LayoutEngine& Controller::GetLayoutEngine()
934 {
935   return mImpl->mLayoutEngine;
936 }
937
938 View& Controller::GetView()
939 {
940   return mImpl->mView;
941 }
942
943 void Controller::KeyboardFocusGainEvent()
944 {
945   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
946
947   if( mImpl->mEventData )
948   {
949     Event event( Event::KEYBOARD_FOCUS_GAIN_EVENT );
950     mImpl->mEventData->mEventQueue.push_back( event );
951
952     mImpl->RequestRelayout();
953   }
954 }
955
956 void Controller::KeyboardFocusLostEvent()
957 {
958   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
959
960   if( mImpl->mEventData )
961   {
962     Event event( Event::KEYBOARD_FOCUS_LOST_EVENT );
963     mImpl->mEventData->mEventQueue.push_back( event );
964
965     mImpl->RequestRelayout();
966   }
967 }
968
969 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
970 {
971   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
972
973   if( mImpl->mEventData &&
974       keyEvent.state == KeyEvent::Down )
975   {
976     int keyCode = keyEvent.keyCode;
977     const std::string& keyString = keyEvent.keyPressed;
978
979     // Pre-process to separate modifying events from non-modifying input events.
980     if( Dali::DALI_KEY_ESCAPE == keyCode )
981     {
982       // Escape key is a special case which causes focus loss
983       KeyboardFocusLostEvent();
984     }
985     else if( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ||
986              Dali::DALI_KEY_CURSOR_RIGHT == keyCode ||
987              Dali::DALI_KEY_CURSOR_UP    == keyCode ||
988              Dali::DALI_KEY_CURSOR_DOWN  == keyCode )
989     {
990       Event event( Event::CURSOR_KEY_EVENT );
991       event.p1.mInt = keyCode;
992       mImpl->mEventData->mEventQueue.push_back( event );
993     }
994     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
995     {
996       // Remove the character before the current cursor position
997       bool removed = RemoveText( -1, 1 );
998
999       if( removed )
1000       {
1001         if( 0u == mImpl->mLogicalModel->mText.Count() )
1002         {
1003           ShowPlaceholderText();
1004           mImpl->mEventData->mUpdateCursorPosition = true;
1005         }
1006         else
1007         {
1008           mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
1009         }
1010       }
1011     }
1012     else
1013     {
1014       InsertText( keyString, COMMIT );
1015     }
1016
1017     mImpl->ChangeState( EventData::EDITING ); // todo Confirm this is the best place to change the state of
1018
1019     mImpl->RequestRelayout();
1020   }
1021
1022   return false;
1023 }
1024
1025 void Controller::InsertText( const std::string& text, Controller::InsertType type )
1026 {
1027   bool removedPreEdit( false );
1028   bool maxLengthReached( false );
1029
1030   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
1031   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPreEditFlag %d cursor %d\n",
1032                  this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"), mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPrimaryCursorPosition );
1033
1034   if( ! text.empty() )
1035   {
1036     if( mImpl->IsShowingPlaceholderText() )
1037     {
1038       ResetText();
1039     }
1040   }
1041
1042   if( mImpl->mEventData )
1043   {
1044     if( COMMIT == type )
1045     {
1046       mImpl->mEventData->mPreEditFlag = false;
1047     }
1048     else // PRE_EDIT
1049     {
1050       if( mImpl->mEventData->mPreEditFlag &&
1051           0 != mImpl->mEventData->mPreEditLength )
1052       {
1053         // Remove previous pre-edit text
1054         mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
1055         removedPreEdit = RemoveText( -1, mImpl->mEventData->mPreEditLength );
1056       }
1057       else
1058       {
1059         // Record the start of the pre-edit text
1060         mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
1061         mImpl->mEventData->mPreEditLength = text.size();
1062
1063         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
1064       }
1065
1066       mImpl->mEventData->mPreEditFlag = true;
1067     }
1068   }
1069
1070   if( ! text.empty() )
1071   {
1072     //  Convert text into UTF-32
1073     Vector<Character> utf32Characters;
1074     utf32Characters.Resize( text.size() );
1075
1076     // This is a bit horrible but std::string returns a (signed) char*
1077     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
1078
1079     // Transform a text array encoded in utf8 into an array encoded in utf32.
1080     // It returns the actual number of characters.
1081     Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
1082     utf32Characters.Resize( characterCount );
1083
1084     DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
1085     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
1086
1087     const Length numberOfCharactersInModel = mImpl->mLogicalModel->GetNumberOfCharacters();
1088
1089     // Restrict new text to fit within Maximum characters setting
1090     Length maxSizeOfNewText = std::min ( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
1091     maxLengthReached = ( characterCount > maxSizeOfNewText );
1092
1093     // Insert at current cursor position
1094     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
1095
1096     Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
1097
1098     if( cursorIndex < numberOfCharactersInModel )
1099     {
1100       modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
1101     }
1102     else
1103     {
1104       modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
1105     }
1106
1107     cursorIndex += maxSizeOfNewText;
1108
1109     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Inserted %d characters, new size %d new cursor %d\n", maxSizeOfNewText, mImpl->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition );
1110   }
1111
1112   if( removedPreEdit || !text.empty() )
1113   {
1114     // Queue an inserted event
1115     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
1116   }
1117
1118   if( maxLengthReached )
1119   {
1120     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mLogicalModel->mText.Count() );
1121
1122     mImpl->mControlInterface.MaxLengthReached();
1123
1124     mImpl->PreEditReset();
1125   }
1126 }
1127
1128 void Controller::TapEvent( unsigned int tapCount, float x, float y )
1129 {
1130   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
1131
1132   if( NULL != mImpl->mEventData )
1133   {
1134     if( 1u == tapCount )
1135     {
1136       bool tapDuringEditMode( EventData::EDITING == mImpl->mEventData->mState );
1137
1138       mImpl->ChangeState( EventData::EDITING );
1139
1140       if( mImpl->IsShowingPlaceholderText() )
1141       {
1142         // Alternative placeholder-text is used when editing
1143         ShowPlaceholderText();
1144       }
1145       else if( EventData::EDITING == mImpl->mEventData->mState )
1146       {
1147         // Grab handle is not shown until a tap is received whilst EDITING
1148         if( tapDuringEditMode )
1149         {
1150           mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
1151         }
1152         mImpl->mEventData->mDecorator->SetPopupActive( false );
1153       }
1154     }
1155     else if( mImpl->mEventData->mSelectionEnabled &&
1156              ( 2u == tapCount ) )
1157     {
1158       mImpl->ChangeState( EventData::SELECTING );
1159     }
1160   }
1161
1162   // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
1163   if( mImpl->mEventData )
1164   {
1165     Event event( Event::TAP_EVENT );
1166     event.p1.mUint = tapCount;
1167     event.p2.mFloat = x;
1168     event.p3.mFloat = y;
1169     mImpl->mEventData->mEventQueue.push_back( event );
1170
1171     mImpl->RequestRelayout();
1172   }
1173
1174   // Reset keyboard as tap event has occurred.
1175   mImpl->PreEditReset();
1176 }
1177
1178 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
1179 {
1180   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
1181
1182   if( mImpl->mEventData )
1183   {
1184     Event event( Event::PAN_EVENT );
1185     event.p1.mInt = state;
1186     event.p2.mFloat = displacement.x;
1187     event.p3.mFloat = displacement.y;
1188     mImpl->mEventData->mEventQueue.push_back( event );
1189
1190     mImpl->RequestRelayout();
1191   }
1192 }
1193
1194 void Controller::HandleEvent( HandleType handleType, HandleState state, float x, float y )
1195 {
1196   DALI_ASSERT_DEBUG( mImpl->mEventData && "Controller::HandleEvent. Unexpected HandleEvent" );
1197
1198   if( mImpl->mEventData )
1199   {
1200     switch( handleType )
1201     {
1202       case GRAB_HANDLE:
1203       {
1204         Event event( Event::GRAB_HANDLE_EVENT );
1205         event.p1.mUint  = state;
1206         event.p2.mFloat = x;
1207         event.p3.mFloat = y;
1208
1209         mImpl->mEventData->mEventQueue.push_back( event );
1210         break;
1211       }
1212       case LEFT_SELECTION_HANDLE:
1213       {
1214         Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
1215         event.p1.mUint  = state;
1216         event.p2.mFloat = x;
1217         event.p3.mFloat = y;
1218
1219         mImpl->mEventData->mEventQueue.push_back( event );
1220         break;
1221       }
1222       case RIGHT_SELECTION_HANDLE:
1223       {
1224         Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
1225         event.p1.mUint  = state;
1226         event.p2.mFloat = x;
1227         event.p3.mFloat = y;
1228
1229         mImpl->mEventData->mEventQueue.push_back( event );
1230         break;
1231       }
1232       case HANDLE_TYPE_COUNT:
1233       {
1234         DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
1235       }
1236     }
1237
1238     mImpl->RequestRelayout();
1239   }
1240 }
1241
1242 Controller::~Controller()
1243 {
1244   delete mImpl;
1245 }
1246
1247 void Controller::ShowPlaceholderText()
1248 {
1249   if( mImpl->IsPlaceholderAvailable() )
1250   {
1251     DALI_ASSERT_DEBUG( mImpl->mEventData && "No placeholder text available" );
1252
1253     mImpl->mEventData->mIsShowingPlaceholderText = true;
1254
1255     // Cancel previously queued inserts etc.
1256     mImpl->mModifyEvents.clear();
1257
1258     // Disable handles when showing place-holder text
1259     mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
1260     mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
1261     mImpl->mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
1262
1263     const char* text( NULL );
1264     size_t size( 0 );
1265
1266     // TODO - Switch placeholder text styles when changing state
1267     if( EventData::INACTIVE != mImpl->mEventData->mState &&
1268         0u != mImpl->mEventData->mPlaceholderTextActive.c_str() )
1269     {
1270       text = mImpl->mEventData->mPlaceholderTextActive.c_str();
1271       size = mImpl->mEventData->mPlaceholderTextActive.size();
1272     }
1273     else
1274     {
1275       text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
1276       size = mImpl->mEventData->mPlaceholderTextInactive.size();
1277     }
1278
1279     // Reset model for showing placeholder.
1280     mImpl->mLogicalModel->mText.Clear();
1281     ClearModelData();
1282     mImpl->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor );
1283
1284     // Convert text into UTF-32
1285     Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
1286     utf32Characters.Resize( size );
1287
1288     // This is a bit horrible but std::string returns a (signed) char*
1289     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text );
1290
1291     // Transform a text array encoded in utf8 into an array encoded in utf32.
1292     // It returns the actual number of characters.
1293     Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() );
1294     utf32Characters.Resize( characterCount );
1295
1296     // Reset the cursor position
1297     mImpl->mEventData->mPrimaryCursorPosition = 0;
1298
1299     // The natural size needs to be re-calculated.
1300     mImpl->mRecalculateNaturalSize = true;
1301
1302     // Apply modifications to the model
1303     mImpl->mOperationsPending = ALL_OPERATIONS;
1304     mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
1305   }
1306 }
1307
1308 void Controller::ClearModelData()
1309 {
1310   // n.b. This does not Clear the mText from mLogicalModel
1311   mImpl->mLogicalModel->mScriptRuns.Clear();
1312   mImpl->mLogicalModel->mFontRuns.Clear();
1313   mImpl->mLogicalModel->mLineBreakInfo.Clear();
1314   mImpl->mLogicalModel->mWordBreakInfo.Clear();
1315   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
1316   mImpl->mLogicalModel->mCharacterDirections.Clear();
1317   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
1318   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
1319   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
1320   mImpl->mVisualModel->mGlyphs.Clear();
1321   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1322   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1323   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1324   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1325   mImpl->mVisualModel->mGlyphPositions.Clear();
1326   mImpl->mVisualModel->mLines.Clear();
1327   mImpl->mVisualModel->ClearCaches();
1328 }
1329
1330 void Controller::ClearFontData()
1331 {
1332   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
1333   mImpl->mLogicalModel->mFontRuns.Clear();
1334   mImpl->mVisualModel->mGlyphs.Clear();
1335   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
1336   mImpl->mVisualModel->mCharactersToGlyph.Clear();
1337   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
1338   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
1339   mImpl->mVisualModel->mGlyphPositions.Clear();
1340   mImpl->mVisualModel->mLines.Clear();
1341   mImpl->mVisualModel->ClearCaches();
1342 }
1343
1344 Controller::Controller( ControlInterface& controlInterface )
1345 : mImpl( NULL )
1346 {
1347   mImpl = new Controller::Impl( controlInterface );
1348 }
1349
1350 } // namespace Text
1351
1352 } // namespace Toolkit
1353
1354 } // namespace Dali