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