Merge "Type registry macros made namespace-generic: toolkit" into tizen
[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
25 // INTERNAL INCLUDES
26 #include <dali-toolkit/internal/text/bidirectional-support.h>
27 #include <dali-toolkit/internal/text/character-set-conversion.h>
28 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
29 #include <dali-toolkit/internal/text/multi-language-support.h>
30 #include <dali-toolkit/internal/text/script-run.h>
31 #include <dali-toolkit/internal/text/segmentation.h>
32 #include <dali-toolkit/internal/text/shaper.h>
33 #include <dali-toolkit/internal/text/text-controller-impl.h>
34 #include <dali-toolkit/internal/text/text-io.h>
35 #include <dali-toolkit/internal/text/text-view.h>
36
37 namespace
38 {
39
40 const float MAX_FLOAT = std::numeric_limits<float>::max();
41
42 const std::string EMPTY_STRING("");
43
44 } // namespace
45
46 namespace Dali
47 {
48
49 namespace Toolkit
50 {
51
52 namespace Text
53 {
54
55 ControllerPtr Controller::New( ControlInterface& controlInterface )
56 {
57   return ControllerPtr( new Controller( controlInterface ) );
58 }
59
60 void Controller::SetText( const std::string& text )
61 {
62   // Cancel previously queued inserts etc.
63   mImpl->mModifyEvents.clear();
64
65   // Keep until size negotiation
66   ModifyEvent event;
67   event.type = ModifyEvent::REPLACE_TEXT;
68   event.text = text;
69   mImpl->mModifyEvents.push_back( event );
70
71   if( mImpl->mEventData )
72   {
73     // Cancel previously queued events
74     mImpl->mEventData->mEventQueue.clear();
75
76     // TODO - Hide selection decorations
77   }
78 }
79
80 void Controller::GetText( std::string& text ) const
81 {
82   if( !mImpl->mModifyEvents.empty() &&
83        ModifyEvent::REPLACE_TEXT == mImpl->mModifyEvents[0].type )
84   {
85     text = mImpl->mModifyEvents[0].text;
86   }
87   else
88   {
89     // TODO - Convert from UTF-32
90   }
91 }
92
93 void Controller::SetPlaceholderText( const std::string& text )
94 {
95   if( !mImpl->mEventData )
96   {
97     mImpl->mEventData->mPlaceholderText = text;
98   }
99 }
100
101 void Controller::GetPlaceholderText( std::string& text ) const
102 {
103   if( !mImpl->mEventData )
104   {
105     text = mImpl->mEventData->mPlaceholderText;
106   }
107 }
108
109 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
110 {
111   if( !mImpl->mFontDefaults )
112   {
113     mImpl->mFontDefaults = new FontDefaults();
114   }
115
116   mImpl->mFontDefaults->mDefaultFontFamily = defaultFontFamily;
117   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
118   mImpl->mOperationsPending = ALL_OPERATIONS;
119   mImpl->mRecalculateNaturalSize = true;
120
121   // Clear the font-specific data
122   mImpl->mLogicalModel->mFontRuns.Clear();
123   mImpl->mVisualModel->mGlyphs.Clear();
124   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
125   mImpl->mVisualModel->mCharactersToGlyph.Clear();
126   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
127   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
128   mImpl->mVisualModel->mGlyphPositions.Clear();
129   mImpl->mVisualModel->mLines.Clear();
130   mImpl->mVisualModel->ClearCaches();
131
132   mImpl->RequestRelayout();
133 }
134
135 const std::string& Controller::GetDefaultFontFamily() const
136 {
137   if( mImpl->mFontDefaults )
138   {
139     return mImpl->mFontDefaults->mDefaultFontFamily;
140   }
141
142   return EMPTY_STRING;
143 }
144
145 void Controller::SetDefaultFontStyle( const std::string& defaultFontStyle )
146 {
147   if( !mImpl->mFontDefaults )
148   {
149     mImpl->mFontDefaults = new FontDefaults();
150   }
151
152   mImpl->mFontDefaults->mDefaultFontStyle = defaultFontStyle;
153   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
154   mImpl->mOperationsPending = ALL_OPERATIONS;
155   mImpl->mRecalculateNaturalSize = true;
156
157   // Clear the font-specific data
158   mImpl->mLogicalModel->mFontRuns.Clear();
159   mImpl->mVisualModel->mGlyphs.Clear();
160   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
161   mImpl->mVisualModel->mCharactersToGlyph.Clear();
162   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
163   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
164   mImpl->mVisualModel->mGlyphPositions.Clear();
165   mImpl->mVisualModel->mLines.Clear();
166   mImpl->mVisualModel->ClearCaches();
167
168   mImpl->RequestRelayout();
169 }
170
171 const std::string& Controller::GetDefaultFontStyle() const
172 {
173   if( mImpl->mFontDefaults )
174   {
175     return mImpl->mFontDefaults->mDefaultFontStyle;
176   }
177
178   return EMPTY_STRING;
179 }
180
181 void Controller::SetDefaultPointSize( float pointSize )
182 {
183   if( !mImpl->mFontDefaults )
184   {
185     mImpl->mFontDefaults = new FontDefaults();
186   }
187
188   mImpl->mFontDefaults->mDefaultPointSize = pointSize;
189   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
190   mImpl->mOperationsPending = ALL_OPERATIONS;
191   mImpl->mRecalculateNaturalSize = true;
192
193   // Clear the font-specific data
194   mImpl->mLogicalModel->mFontRuns.Clear();
195   mImpl->mVisualModel->mGlyphs.Clear();
196   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
197   mImpl->mVisualModel->mCharactersToGlyph.Clear();
198   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
199   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
200   mImpl->mVisualModel->mGlyphPositions.Clear();
201   mImpl->mVisualModel->mLines.Clear();
202   mImpl->mVisualModel->ClearCaches();
203
204   mImpl->RequestRelayout();
205 }
206
207 float Controller::GetDefaultPointSize() const
208 {
209   if( mImpl->mFontDefaults )
210   {
211     return mImpl->mFontDefaults->mDefaultPointSize;
212   }
213
214   return 0.0f;
215 }
216
217 void Controller::GetDefaultFonts( Vector<FontRun>& fonts, Length numberOfCharacters ) const
218 {
219   if( mImpl->mFontDefaults )
220   {
221     FontRun fontRun;
222     fontRun.characterRun.characterIndex = 0;
223     fontRun.characterRun.numberOfCharacters = numberOfCharacters;
224     fontRun.fontId = mImpl->mFontDefaults->GetFontId( mImpl->mFontClient );
225     fontRun.isDefault = true;
226
227     fonts.PushBack( fontRun );
228   }
229 }
230
231 void Controller::SetTextColor( const Vector4& textColor )
232 {
233   mImpl->mVisualModel->SetTextColor( textColor );
234 }
235
236 const Vector4& Controller::GetTextColor() const
237 {
238   return mImpl->mVisualModel->GetTextColor();
239 }
240
241 void Controller::SetShadowOffset( const Vector2& shadowOffset )
242 {
243   mImpl->mVisualModel->SetShadowOffset( shadowOffset );
244 }
245
246 const Vector2& Controller::GetShadowOffset() const
247 {
248   return mImpl->mVisualModel->GetShadowOffset();
249 }
250
251 void Controller::SetShadowColor( const Vector4& shadowColor )
252 {
253   mImpl->mVisualModel->SetShadowColor( shadowColor );
254 }
255
256 const Vector4& Controller::GetShadowColor() const
257 {
258   return mImpl->mVisualModel->GetShadowColor();
259 }
260
261 void Controller::SetUnderlineColor( const Vector4& color )
262 {
263   mImpl->mVisualModel->SetUnderlineColor( color );
264 }
265
266 const Vector4& Controller::GetUnderlineColor() const
267 {
268   return mImpl->mVisualModel->GetUnderlineColor();
269 }
270
271 void Controller::SetUnderlineEnabled( bool enabled )
272 {
273   mImpl->mVisualModel->SetUnderlineEnabled( enabled );
274 }
275
276 bool Controller::IsUnderlineEnabled() const
277 {
278   return mImpl->mVisualModel->IsUnderlineEnabled();
279 }
280
281 void Controller::SetUnderlineHeight( float height )
282 {
283   mImpl->mVisualModel->SetUnderlineHeight( height );
284 }
285
286 float Controller::GetUnderlineHeight() const
287 {
288   return mImpl->mVisualModel->GetUnderlineHeight();
289 }
290
291 void Controller::EnableTextInput( DecoratorPtr decorator )
292 {
293   if( !mImpl->mEventData )
294   {
295     mImpl->mEventData = new EventData( decorator );
296   }
297 }
298
299 void Controller::SetEnableCursorBlink( bool enable )
300 {
301   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" );
302
303   if( mImpl->mEventData )
304   {
305     mImpl->mEventData->mCursorBlinkEnabled = enable;
306
307     if( !enable &&
308         mImpl->mEventData->mDecorator )
309     {
310       mImpl->mEventData->mDecorator->StopCursorBlink();
311     }
312   }
313 }
314
315 bool Controller::GetEnableCursorBlink() const
316 {
317   if( mImpl->mEventData )
318   {
319     return mImpl->mEventData->mCursorBlinkEnabled;
320   }
321
322   return false;
323 }
324
325 const Vector2& Controller::GetScrollPosition() const
326 {
327   if( mImpl->mEventData )
328   {
329     return mImpl->mEventData->mScrollPosition;
330   }
331
332   return Vector2::ZERO;
333 }
334
335 const Vector2& Controller::GetAlignmentOffset() const
336 {
337   return mImpl->mAlignmentOffset;
338 }
339
340 Vector3 Controller::GetNaturalSize()
341 {
342   Vector3 naturalSize;
343
344   // Make sure the model is up-to-date before layouting
345   ProcessModifyEvents();
346
347   if( mImpl->mRecalculateNaturalSize )
348   {
349     // Operations that can be done only once until the text changes.
350     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
351                                                                            GET_SCRIPTS       |
352                                                                            VALIDATE_FONTS    |
353                                                                            GET_LINE_BREAKS   |
354                                                                            GET_WORD_BREAKS   |
355                                                                            BIDI_INFO         |
356                                                                            SHAPE_TEXT        |
357                                                                            GET_GLYPH_METRICS );
358     // Make sure the model is up-to-date before layouting
359     UpdateModel( onlyOnceOperations );
360
361     // Operations that need to be done if the size changes.
362     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
363                                                                         ALIGN  |
364                                                                         REORDER );
365
366     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
367                 static_cast<OperationsMask>( onlyOnceOperations |
368                                              sizeOperations ),
369                 naturalSize.GetVectorXY() );
370
371     // Do not do again the only once operations.
372     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
373
374     // Do the size related operations again.
375     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
376
377     // Stores the natural size to avoid recalculate it again
378     // unless the text/style changes.
379     mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
380
381     mImpl->mRecalculateNaturalSize = false;
382   }
383   else
384   {
385     naturalSize = mImpl->mVisualModel->GetNaturalSize();
386   }
387
388   return naturalSize;
389 }
390
391 float Controller::GetHeightForWidth( float width )
392 {
393   // Make sure the model is up-to-date before layouting
394   ProcessModifyEvents();
395
396   Size layoutSize;
397   if( width != mImpl->mControlSize.width )
398   {
399     // Operations that can be done only once until the text changes.
400     const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
401                                                                            GET_SCRIPTS       |
402                                                                            VALIDATE_FONTS    |
403                                                                            GET_LINE_BREAKS   |
404                                                                            GET_WORD_BREAKS   |
405                                                                            BIDI_INFO         |
406                                                                            SHAPE_TEXT        |
407                                                                            GET_GLYPH_METRICS );
408     // Make sure the model is up-to-date before layouting
409     UpdateModel( onlyOnceOperations );
410
411     // Operations that need to be done if the size changes.
412     const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
413                                                                         ALIGN  |
414                                                                         REORDER );
415
416     DoRelayout( Size( width, MAX_FLOAT ),
417                 static_cast<OperationsMask>( onlyOnceOperations |
418                                              sizeOperations ),
419                 layoutSize );
420
421     // Do not do again the only once operations.
422     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
423
424     // Do the size related operations again.
425     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
426   }
427   else
428   {
429     layoutSize = mImpl->mVisualModel->GetActualSize();
430   }
431
432   return layoutSize.height;
433 }
434
435 bool Controller::Relayout( const Size& size )
436 {
437   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
438   {
439     bool glyphsRemoved( false );
440     if( 0u != mImpl->mVisualModel->GetNumberOfGlyphPositions() )
441     {
442       mImpl->mVisualModel->SetGlyphPositions( NULL, 0u );
443       glyphsRemoved = true;
444     }
445     // Not worth to relayout if width or height is equal to zero.
446     return glyphsRemoved;
447   }
448
449   if( size != mImpl->mControlSize )
450   {
451     // Operations that need to be done if the size changes.
452     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
453                                                              LAYOUT                    |
454                                                              ALIGN                     |
455                                                              UPDATE_ACTUAL_SIZE        |
456                                                              REORDER );
457
458     mImpl->mControlSize = size;
459   }
460
461   // Make sure the model is up-to-date before layouting
462   ProcessModifyEvents();
463   UpdateModel( mImpl->mOperationsPending );
464
465   Size layoutSize;
466   bool updated = DoRelayout( mImpl->mControlSize,
467                              mImpl->mOperationsPending,
468                              layoutSize );
469
470   // Do not re-do any operation until something changes.
471   mImpl->mOperationsPending = NO_OPERATION;
472
473   // After doing the text layout, the alignment offset to place the actor in the desired position can be calculated.
474   CalculateTextAlignment( size );
475
476   if( mImpl->mEventData )
477   {
478     // Move the cursor, grab handle etc.
479     updated = mImpl->ProcessInputEvents() || updated;
480   }
481
482   return updated;
483 }
484
485 void Controller::ProcessModifyEvents()
486 {
487   std::vector<ModifyEvent>& events = mImpl->mModifyEvents;
488
489   for( unsigned int i=0; i<events.size(); ++i )
490   {
491     if( ModifyEvent::REPLACE_TEXT == events[0].type )
492     {
493       // A (single) replace event should come first, otherwise we wasted time processing NOOP events
494       DALI_ASSERT_DEBUG( 0 == i && "Unexpected REPLACE event" );
495
496       ReplaceTextEvent( events[0].text );
497     }
498     else if( ModifyEvent::INSERT_TEXT == events[0].type )
499     {
500       InsertTextEvent( events[0].text );
501     }
502     else if( ModifyEvent::DELETE_TEXT == events[0].type )
503     {
504       DeleteTextEvent();
505     }
506   }
507
508   // Discard temporary text
509   events.clear();
510 }
511
512 void Controller::ReplaceTextEvent( const std::string& text )
513 {
514   // Reset buffers.
515   mImpl->mLogicalModel->mText.Clear();
516   mImpl->mLogicalModel->mScriptRuns.Clear();
517   mImpl->mLogicalModel->mFontRuns.Clear();
518   mImpl->mLogicalModel->mLineBreakInfo.Clear();
519   mImpl->mLogicalModel->mWordBreakInfo.Clear();
520   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
521   mImpl->mLogicalModel->mCharacterDirections.Clear();
522   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
523   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
524   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
525   mImpl->mVisualModel->mGlyphs.Clear();
526   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
527   mImpl->mVisualModel->mCharactersToGlyph.Clear();
528   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
529   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
530   mImpl->mVisualModel->mGlyphPositions.Clear();
531   mImpl->mVisualModel->mLines.Clear();
532   mImpl->mVisualModel->ClearCaches();
533
534   //  Convert text into UTF-32
535   Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
536   utf32Characters.Resize( text.size() );
537
538   // This is a bit horrible but std::string returns a (signed) char*
539   const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
540
541   // Transform a text array encoded in utf8 into an array encoded in utf32.
542   // It returns the actual number of characters.
543   Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
544   utf32Characters.Resize( characterCount );
545
546   // Reset the cursor position
547   if( mImpl->mEventData )
548   {
549     mImpl->mEventData->mPrimaryCursorPosition = characterCount;
550     // TODO - handle secondary cursor
551   }
552
553   // The natural size needs to be re-calculated.
554   mImpl->mRecalculateNaturalSize = true;
555
556   // Apply modifications to the model
557   mImpl->mOperationsPending = ALL_OPERATIONS;
558   UpdateModel( ALL_OPERATIONS );
559   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
560                                                            ALIGN              |
561                                                            UPDATE_ACTUAL_SIZE |
562                                                            REORDER );
563 }
564
565 void Controller::InsertTextEvent( const std::string& text )
566 {
567   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertTextEvent" );
568
569   // TODO - Optimize this
570   mImpl->mLogicalModel->mScriptRuns.Clear();
571   mImpl->mLogicalModel->mFontRuns.Clear();
572   mImpl->mLogicalModel->mLineBreakInfo.Clear();
573   mImpl->mLogicalModel->mWordBreakInfo.Clear();
574   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
575   mImpl->mLogicalModel->mCharacterDirections.Clear();
576   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
577   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
578   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
579   mImpl->mVisualModel->mGlyphs.Clear();
580   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
581   mImpl->mVisualModel->mCharactersToGlyph.Clear();
582   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
583   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
584   mImpl->mVisualModel->mGlyphPositions.Clear();
585   mImpl->mVisualModel->mLines.Clear();
586   mImpl->mVisualModel->ClearCaches();
587
588   //  Convert text into UTF-32
589   Vector<Character> utf32Characters;
590   utf32Characters.Resize( text.size() );
591
592   // This is a bit horrible but std::string returns a (signed) char*
593   const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
594
595   // Transform a text array encoded in utf8 into an array encoded in utf32.
596   // It returns the actual number of characters.
597   Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
598   utf32Characters.Resize( characterCount );
599
600   // Insert at current cursor position
601   Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
602   CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
603
604   if( cursorIndex < modifyText.Count() )
605   {
606     modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.End() );
607   }
608   else
609   {
610     modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.End() );
611   }
612
613   // Advance the cursor position
614   ++cursorIndex;
615
616   // The natural size needs to be re-calculated.
617   mImpl->mRecalculateNaturalSize = true;
618
619   // Apply modifications to the model; TODO - Optimize this
620   mImpl->mOperationsPending = ALL_OPERATIONS;
621   UpdateModel( ALL_OPERATIONS );
622   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
623                                                            ALIGN              |
624                                                            UPDATE_ACTUAL_SIZE |
625                                                            REORDER );
626
627   // Queue a cursor reposition event; this must wait until after DoRelayout()
628   mImpl->mEventData->mUpdateCursorPosition = true;
629 }
630
631 void Controller::DeleteTextEvent()
632 {
633   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertTextEvent" );
634
635   // TODO - Optimize this
636   mImpl->mLogicalModel->mScriptRuns.Clear();
637   mImpl->mLogicalModel->mFontRuns.Clear();
638   mImpl->mLogicalModel->mLineBreakInfo.Clear();
639   mImpl->mLogicalModel->mWordBreakInfo.Clear();
640   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
641   mImpl->mLogicalModel->mCharacterDirections.Clear();
642   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
643   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
644   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
645   mImpl->mVisualModel->mGlyphs.Clear();
646   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
647   mImpl->mVisualModel->mCharactersToGlyph.Clear();
648   mImpl->mVisualModel->mCharactersPerGlyph.Clear();
649   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
650   mImpl->mVisualModel->mGlyphPositions.Clear();
651   mImpl->mVisualModel->mLines.Clear();
652   mImpl->mVisualModel->ClearCaches();
653
654   // Delte at current cursor position
655   Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
656   CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
657
658   if( cursorIndex > 0 &&
659       cursorIndex-1 < modifyText.Count() )
660   {
661     modifyText.Remove( modifyText.Begin() + cursorIndex - 1 );
662
663     // Cursor position retreat
664     --cursorIndex;
665   }
666
667   // The natural size needs to be re-calculated.
668   mImpl->mRecalculateNaturalSize = true;
669
670   // Apply modifications to the model; TODO - Optimize this
671   mImpl->mOperationsPending = ALL_OPERATIONS;
672   UpdateModel( ALL_OPERATIONS );
673   mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT             |
674                                                            ALIGN              |
675                                                            UPDATE_ACTUAL_SIZE |
676                                                            REORDER );
677
678   // Queue a cursor reposition event; this must wait until after DoRelayout()
679   mImpl->mEventData->mUpdateCursorPosition = true;
680 }
681
682 void Controller::UpdateModel( OperationsMask operationsRequired )
683 {
684   // Calculate the operations to be done.
685   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
686
687   Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
688
689   const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
690
691   Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
692   if( GET_LINE_BREAKS & operations )
693   {
694     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
695     // calculate the bidirectional info for each 'paragraph'.
696     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
697     // is not shaped together).
698     lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
699
700     SetLineBreakInfo( utf32Characters,
701                       lineBreakInfo );
702   }
703
704   Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
705   if( GET_WORD_BREAKS & operations )
706   {
707     // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
708     wordBreakInfo.Resize( numberOfCharacters, TextAbstraction::WORD_NO_BREAK );
709
710     SetWordBreakInfo( utf32Characters,
711                       wordBreakInfo );
712   }
713
714   const bool getScripts = GET_SCRIPTS & operations;
715   const bool validateFonts = VALIDATE_FONTS & operations;
716
717   Vector<ScriptRun>& scripts = mImpl->mLogicalModel->mScriptRuns;
718   Vector<FontRun>& validFonts = mImpl->mLogicalModel->mFontRuns;
719
720   if( getScripts || validateFonts )
721   {
722     // Validates the fonts assigned by the application or assigns default ones.
723     // It makes sure all the characters are going to be rendered by the correct font.
724     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
725
726     if( getScripts )
727     {
728       // Retrieves the scripts used in the text.
729       multilanguageSupport.SetScripts( utf32Characters,
730                                        lineBreakInfo,
731                                        scripts );
732     }
733
734     if( validateFonts )
735     {
736       if( 0u == validFonts.Count() )
737       {
738         // Copy the requested font defaults received via the property system.
739         // These may not be valid i.e. may not contain glyphs for the necessary scripts.
740         GetDefaultFonts( validFonts, numberOfCharacters );
741       }
742
743       // Validates the fonts. If there is a character with no assigned font it sets a default one.
744       // After this call, fonts are validated.
745       multilanguageSupport.ValidateFonts( utf32Characters,
746                                           scripts,
747                                           validFonts );
748     }
749   }
750
751   Vector<Character> mirroredUtf32Characters;
752   bool textMirrored = false;
753   if( BIDI_INFO & operations )
754   {
755     // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's
756     // bidirectional info.
757
758     Length numberOfParagraphs = 0u;
759
760     const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
761     for( Length index = 0u; index < numberOfCharacters; ++index )
762     {
763       if( TextAbstraction::LINE_NO_BREAK == *( lineBreakInfoBuffer + index ) )
764       {
765         ++numberOfParagraphs;
766       }
767     }
768
769     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
770     bidirectionalInfo.Reserve( numberOfParagraphs );
771
772     // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
773     SetBidirectionalInfo( utf32Characters,
774                           scripts,
775                           lineBreakInfo,
776                           bidirectionalInfo );
777
778     if( 0u != bidirectionalInfo.Count() )
779     {
780       // This paragraph has right to left text. Some characters may need to be mirrored.
781       // TODO: consider if the mirrored string can be stored as well.
782
783       textMirrored = GetMirroredText( utf32Characters, mirroredUtf32Characters );
784
785       // Only set the character directions if there is right to left characters.
786       Vector<CharacterDirection>& directions = mImpl->mLogicalModel->mCharacterDirections;
787       directions.Resize( numberOfCharacters );
788
789       GetCharactersDirection( bidirectionalInfo,
790                               directions );
791     }
792     else
793     {
794       // There is no right to left characters. Clear the directions vector.
795       mImpl->mLogicalModel->mCharacterDirections.Clear();
796     }
797
798    }
799
800   Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
801   Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
802   Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
803   if( SHAPE_TEXT & operations )
804   {
805     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
806     // Shapes the text.
807     ShapeText( textToShape,
808                lineBreakInfo,
809                scripts,
810                validFonts,
811                glyphs,
812                glyphsToCharactersMap,
813                charactersPerGlyph );
814
815     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
816     mImpl->mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
817     mImpl->mVisualModel->CreateCharacterToGlyphTable( numberOfCharacters );
818   }
819
820   const Length numberOfGlyphs = glyphs.Count();
821
822   if( GET_GLYPH_METRICS & operations )
823   {
824     mImpl->mFontClient.GetGlyphMetrics( glyphs.Begin(), numberOfGlyphs );
825   }
826 }
827
828 bool Controller::DoRelayout( const Size& size,
829                              OperationsMask operationsRequired,
830                              Size& layoutSize )
831 {
832   bool viewUpdated( false );
833
834   // Calculate the operations to be done.
835   const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
836
837   if( LAYOUT & operations )
838   {
839     // Some vectors with data needed to layout and reorder may be void
840     // after the first time the text has been laid out.
841     // Fill the vectors again.
842
843     Length numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
844
845     if( 0u == numberOfGlyphs )
846     {
847       // Nothing else to do if there is no glyphs.
848       return true;
849     }
850
851     Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
852     Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
853     Vector<CharacterDirection>& characterDirection = mImpl->mLogicalModel->mCharacterDirections;
854     Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
855     Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
856     Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
857
858     // Set the layout parameters.
859     LayoutParameters layoutParameters( size,
860                                        mImpl->mLogicalModel->mText.Begin(),
861                                        lineBreakInfo.Begin(),
862                                        wordBreakInfo.Begin(),
863                                        ( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
864                                        numberOfGlyphs,
865                                        glyphs.Begin(),
866                                        glyphsToCharactersMap.Begin(),
867                                        charactersPerGlyph.Begin() );
868
869     // The laid-out lines.
870     // It's not possible to know in how many lines the text is going to be laid-out,
871     // but it can be resized at least with the number of 'paragraphs' to avoid
872     // some re-allocations.
873     Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
874
875     // Delete any previous laid out lines before setting the new ones.
876     lines.Clear();
877
878     // The capacity of the bidirectional paragraph info is the number of paragraphs.
879     lines.Reserve( mImpl->mLogicalModel->mBidirectionalParagraphInfo.Capacity() );
880
881     // Resize the vector of positions to have the same size than the vector of glyphs.
882     Vector<Vector2>& glyphPositions = mImpl->mVisualModel->mGlyphPositions;
883     glyphPositions.Resize( numberOfGlyphs );
884
885     // Update the visual model.
886     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
887                                                    glyphPositions,
888                                                    lines,
889                                                    layoutSize );
890
891     if( viewUpdated )
892     {
893       // Reorder the lines
894       if( REORDER & operations )
895       {
896         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
897
898         // Check first if there are paragraphs with bidirectional info.
899         if( 0u != bidirectionalInfo.Count() )
900         {
901           // Get the lines
902           const Length numberOfLines = mImpl->mVisualModel->GetNumberOfLines();
903
904           // Reorder the lines.
905           Vector<BidirectionalLineInfoRun> lineBidirectionalInfoRuns;
906           lineBidirectionalInfoRuns.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
907           ReorderLines( bidirectionalInfo,
908                         lines,
909                         lineBidirectionalInfoRuns );
910
911           // Set the bidirectional info into the model.
912           const Length numberOfBidirectionalInfoRuns = lineBidirectionalInfoRuns.Count();
913           mImpl->mLogicalModel->SetVisualToLogicalMap( lineBidirectionalInfoRuns.Begin(),
914                                                        numberOfBidirectionalInfoRuns );
915
916           // Set the bidirectional info per line into the layout parameters.
917           layoutParameters.lineBidirectionalInfoRunsBuffer = lineBidirectionalInfoRuns.Begin();
918           layoutParameters.numberOfBidirectionalInfoRuns = numberOfBidirectionalInfoRuns;
919
920           // Get the character to glyph conversion table and set into the layout.
921           layoutParameters.charactersToGlyphsBuffer = mImpl->mVisualModel->mCharactersToGlyph.Begin();
922
923           // Get the glyphs per character table and set into the layout.
924           layoutParameters.glyphsPerCharacterBuffer = mImpl->mVisualModel->mGlyphsPerCharacter.Begin();
925
926           // Re-layout the text. Reorder those lines with right to left characters.
927           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
928                                                          glyphPositions );
929
930           // Free the allocated memory used to store the conversion table in the bidirectional line info run.
931           for( Vector<BidirectionalLineInfoRun>::Iterator it = lineBidirectionalInfoRuns.Begin(),
932                  endIt = lineBidirectionalInfoRuns.End();
933                it != endIt;
934                ++it )
935           {
936             BidirectionalLineInfoRun& bidiLineInfo = *it;
937
938             free( bidiLineInfo.visualToLogicalMap );
939           }
940         }
941       } // REORDER
942
943       if( ALIGN & operations )
944       {
945         mImpl->mLayoutEngine.Align( layoutParameters,
946                                     layoutSize,
947                                     lines,
948                                     glyphPositions );
949       }
950
951       // Sets the actual size.
952       if( UPDATE_ACTUAL_SIZE & operations )
953       {
954         mImpl->mVisualModel->SetActualSize( layoutSize );
955       }
956     } // view updated
957   }
958   else
959   {
960     layoutSize = mImpl->mVisualModel->GetActualSize();
961   }
962
963   return viewUpdated;
964 }
965
966 void Controller::CalculateTextAlignment( const Size& size )
967 {
968   // Get the direction of the first character.
969   const CharacterDirection firstParagraphDirection = mImpl->mLogicalModel->GetCharacterDirection( 0u );
970
971   const Size& actualSize = mImpl->mVisualModel->GetActualSize();
972
973   // If the first paragraph is right to left swap ALIGN_BEGIN and ALIGN_END;
974   LayoutEngine::HorizontalAlignment horizontalAlignment = mImpl->mLayoutEngine.GetHorizontalAlignment();
975   if( firstParagraphDirection &&
976       ( LayoutEngine::HORIZONTAL_ALIGN_CENTER != horizontalAlignment ) )
977   {
978     if( LayoutEngine::HORIZONTAL_ALIGN_BEGIN == horizontalAlignment )
979     {
980       horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_END;
981     }
982     else
983     {
984       horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_BEGIN;
985     }
986   }
987
988   switch( horizontalAlignment )
989   {
990     case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
991     {
992       mImpl->mAlignmentOffset.x = 0.f;
993       break;
994     }
995     case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
996     {
997       const int intOffset = static_cast<int>( 0.5f * ( size.width - actualSize.width ) ); // try to avoid pixel alignment.
998       mImpl->mAlignmentOffset.x = static_cast<float>( intOffset );
999       break;
1000     }
1001     case LayoutEngine::HORIZONTAL_ALIGN_END:
1002     {
1003       mImpl->mAlignmentOffset.x = size.width - actualSize.width;
1004       break;
1005     }
1006   }
1007
1008   const LayoutEngine::VerticalAlignment verticalAlignment = mImpl->mLayoutEngine.GetVerticalAlignment();
1009   switch( verticalAlignment )
1010   {
1011     case LayoutEngine::VERTICAL_ALIGN_TOP:
1012     {
1013       mImpl->mAlignmentOffset.y = 0.f;
1014       break;
1015     }
1016     case LayoutEngine::VERTICAL_ALIGN_CENTER:
1017     {
1018       const int intOffset = static_cast<int>( 0.5f * ( size.height - actualSize.height ) ); // try to avoid pixel alignment.
1019       mImpl->mAlignmentOffset.y = static_cast<float>( intOffset );
1020       break;
1021     }
1022     case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
1023     {
1024       mImpl->mAlignmentOffset.y = size.height - actualSize.height;
1025       break;
1026     }
1027   }
1028 }
1029
1030 LayoutEngine& Controller::GetLayoutEngine()
1031 {
1032   return mImpl->mLayoutEngine;
1033 }
1034
1035 View& Controller::GetView()
1036 {
1037   return mImpl->mView;
1038 }
1039
1040 void Controller::KeyboardFocusGainEvent()
1041 {
1042   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
1043
1044   if( mImpl->mEventData )
1045   {
1046     Event event( Event::KEYBOARD_FOCUS_GAIN_EVENT );
1047     mImpl->mEventData->mEventQueue.push_back( event );
1048
1049     mImpl->RequestRelayout();
1050   }
1051 }
1052
1053 void Controller::KeyboardFocusLostEvent()
1054 {
1055   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
1056
1057   if( mImpl->mEventData )
1058   {
1059     Event event( Event::KEYBOARD_FOCUS_LOST_EVENT );
1060     mImpl->mEventData->mEventQueue.push_back( event );
1061
1062     mImpl->RequestRelayout();
1063   }
1064 }
1065
1066 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
1067 {
1068   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
1069
1070   if( mImpl->mEventData &&
1071       keyEvent.state == KeyEvent::Down )
1072   {
1073     int keyCode = keyEvent.keyCode;
1074     const std::string& keyString = keyEvent.keyPressed;
1075
1076     // Pre-process to separate modifying events from non-modifying input events.
1077     if( Dali::DALI_KEY_ESCAPE == keyCode )
1078     {
1079       // Escape key is a special case which causes focus loss
1080       KeyboardFocusLostEvent();
1081     }
1082     else if( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ||
1083              Dali::DALI_KEY_CURSOR_RIGHT == keyCode ||
1084              Dali::DALI_KEY_CURSOR_UP    == keyCode ||
1085              Dali::DALI_KEY_CURSOR_DOWN  == keyCode )
1086     {
1087       Event event( Event::CURSOR_KEY_EVENT );
1088       event.p1.mInt = keyCode;
1089       mImpl->mEventData->mEventQueue.push_back( event );
1090     }
1091     else if( Dali::DALI_KEY_BACKSPACE == keyCode )
1092     {
1093       // Queue a delete event
1094       ModifyEvent event;
1095       event.type = ModifyEvent::DELETE_TEXT;
1096       mImpl->mModifyEvents.push_back( event );
1097     }
1098     else if( !keyString.empty() )
1099     {
1100       // Queue an insert event
1101       ModifyEvent event;
1102       event.type = ModifyEvent::INSERT_TEXT;
1103       event.text = keyString;
1104       mImpl->mModifyEvents.push_back( event );
1105     }
1106
1107     mImpl->ChangeState( EventData::EDITING ); // todo Confirm this is the best place to change the state of
1108
1109     mImpl->RequestRelayout();
1110   }
1111
1112   return false;
1113 }
1114
1115 void Controller::TapEvent( unsigned int tapCount, float x, float y )
1116 {
1117   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
1118
1119   if( mImpl->mEventData )
1120   {
1121     Event event( Event::TAP_EVENT );
1122     event.p1.mUint = tapCount;
1123     event.p2.mFloat = x;
1124     event.p3.mFloat = y;
1125     mImpl->mEventData->mEventQueue.push_back( event );
1126
1127     mImpl->RequestRelayout();
1128   }
1129 }
1130
1131 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
1132 {
1133   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
1134
1135   if( mImpl->mEventData )
1136   {
1137     Event event( Event::PAN_EVENT );
1138     event.p1.mInt = state;
1139     event.p2.mFloat = displacement.x;
1140     event.p3.mFloat = displacement.y;
1141     mImpl->mEventData->mEventQueue.push_back( event );
1142
1143     mImpl->RequestRelayout();
1144   }
1145 }
1146
1147 void Controller::GrabHandleEvent( GrabHandleState state, float x, float y )
1148 {
1149   DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected GrabHandleEvent" );
1150
1151   if( mImpl->mEventData )
1152   {
1153     Event event( Event::GRAB_HANDLE_EVENT );
1154     event.p1.mUint  = state;
1155     event.p2.mFloat = x;
1156     event.p3.mFloat = y;
1157     
1158     mImpl->mEventData->mEventQueue.push_back( event );
1159
1160     mImpl->RequestRelayout();
1161   }
1162 }
1163
1164 Controller::~Controller()
1165 {
1166   delete mImpl;
1167 }
1168
1169 Controller::Controller( ControlInterface& controlInterface )
1170 : mImpl( NULL )
1171 {
1172   mImpl = new Controller::Impl( controlInterface );
1173 }
1174
1175 } // namespace Text
1176
1177 } // namespace Toolkit
1178
1179 } // namespace Dali