2 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali-toolkit/internal/text/text-controller.h>
24 #include <dali/public-api/adaptor-framework/key.h>
25 #include <dali/public-api/text-abstraction/font-client.h>
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-engine.h>
31 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
32 #include <dali-toolkit/internal/text/logical-model-impl.h>
33 #include <dali-toolkit/internal/text/multi-language-support.h>
34 #include <dali-toolkit/internal/text/script-run.h>
35 #include <dali-toolkit/internal/text/segmentation.h>
36 #include <dali-toolkit/internal/text/shaper.h>
37 #include <dali-toolkit/internal/text/text-view.h>
38 #include <dali-toolkit/internal/text/visual-model-impl.h>
44 const float MAX_FLOAT = std::numeric_limits<float>::max();
45 const std::string EMPTY_STRING;
57 struct Controller::TextInput
59 // Used to queue input events until DoRelayout()
62 KEYBOARD_FOCUS_GAIN_EVENT,
63 KEYBOARD_FOCUS_LOST_EVENT,
79 Event( EventType eventType )
99 TextInput( LogicalModelPtr logicalModel,
100 VisualModelPtr visualModel,
101 DecoratorPtr decorator )
102 : mLogicalModel( logicalModel ),
103 mVisualModel( visualModel ),
104 mDecorator( decorator ),
106 mDecoratorUpdated( false ),
107 mCursorBlinkEnabled( true )
112 * @brief Helper to move the cursor, grab handle etc.
114 bool ProcessInputEvents()
116 mDecoratorUpdated = false;
120 for( vector<TextInput::Event>::iterator iter = mEventQueue.begin(); iter != mEventQueue.end(); ++iter )
124 case KEYBOARD_FOCUS_GAIN_EVENT:
126 OnKeyboardFocus( true );
129 case KEYBOARD_FOCUS_LOST_EVENT:
131 OnKeyboardFocus( false );
144 case GRAB_HANDLE_EVENT:
146 OnGrabHandleEvent( *iter );
155 return mDecoratorUpdated;
158 void OnKeyboardFocus( bool hasFocus )
162 ChangeState( INACTIVE );
166 ChangeState( EDITING );
170 void OnKeyEvent( const Event& event )
172 int keyCode = event.p1.mInt;
174 // Handle state changes
175 if( Dali::DALI_KEY_ESCAPE == keyCode )
177 ChangeState( INACTIVE ); // Escape key ends edit mode
179 else if ( event.p2.mString )
181 // Some text may be selected, hiding keyboard causes an empty keystring to be sent, we don't want to delete highlight in this case
182 ChangeState( EDITING );
185 // Handle the actual key event
186 if( Dali::DALI_KEY_BACKSPACE == keyCode )
188 HandleBackspaceKey();
190 else if( Dali::DALI_KEY_CURSOR_LEFT == keyCode ||
191 Dali::DALI_KEY_CURSOR_RIGHT == keyCode ||
192 Dali::DALI_KEY_CURSOR_UP == keyCode ||
193 Dali::DALI_KEY_CURSOR_DOWN == keyCode )
195 HandleCursorKey( keyCode );
197 else if ( event.p2.mString )
199 HandleKeyString( event.p2.mString );
201 delete [] event.p2.mString;
205 void HandleBackspaceKey()
210 void HandleCursorKey( int keyCode )
215 void HandleKeyString( const char* keyString )
220 void OnTapEvent( const Event& event )
222 unsigned int tapCount = event.p1.mUint;
226 ChangeState( EDITING );
228 float xPosition = event.p2.mFloat;
229 float yPosition = event.p3.mFloat;
231 GetClosestCursorPosition( xPosition, yPosition, height );
232 mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height );
234 mDecoratorUpdated = true;
236 else if( 2u == tapCount )
238 ChangeState( SELECTING );
242 void OnGrabHandleEvent( const Event& event )
244 unsigned int state = event.p1.mUint;
246 if( GRAB_HANDLE_PRESSED == state )
248 float xPosition = event.p2.mFloat;
249 float yPosition = event.p3.mFloat;
252 GetClosestCursorPosition( xPosition, yPosition, height );
254 mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height );
255 mDecorator->HidePopup();
256 mDecoratorUpdated = true;
258 else if ( GRAB_HANDLE_RELEASED == state )
260 mDecorator->ShowPopup();
265 void ChangeState( State newState )
267 if( mState != newState )
271 if( INACTIVE == mState )
273 mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
274 mDecorator->StopCursorBlink();
275 mDecorator->SetGrabHandleActive( false );
276 mDecorator->SetSelectionActive( false );
277 mDecorator->HidePopup();
278 mDecoratorUpdated = true;
280 else if ( SELECTING == mState )
282 mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
283 mDecorator->StopCursorBlink();
284 mDecorator->SetGrabHandleActive( false );
285 mDecorator->SetSelectionActive( true );
286 mDecoratorUpdated = true;
288 else if( EDITING == mState )
290 mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
291 if( mCursorBlinkEnabled )
293 mDecorator->StartCursorBlink();
295 mDecorator->SetGrabHandleActive( true );
296 mDecorator->SetSelectionActive( false );
297 mDecoratorUpdated = true;
302 void GetClosestCursorPosition( float& x, float& y, float& height )
304 // TODO - Look at LineRuns first
306 Text::Length numberOfGlyphs = mVisualModel->GetNumberOfGlyphs();
307 if( 0 == numberOfGlyphs )
312 Vector<GlyphInfo>& glyphs = mVisualModel->mGlyphs;
313 const GlyphInfo* const glyphsBuffer = glyphs.Begin();
315 Vector<Vector2>& positions = mVisualModel->mGlyphPositions;
316 const Vector2* const positionsBuffer = positions.Begin();
318 unsigned int closestGlyph = 0;
319 float closestDistance = MAX_FLOAT;
321 for( unsigned int i = 0, numberOfGLyphs = glyphs.Count(); i < numberOfGLyphs; ++i )
323 const GlyphInfo& glyphInfo = *( glyphsBuffer + i );
324 const Vector2& position = *( positionsBuffer + i );
325 float glyphX = position.x + glyphInfo.width*0.5f;
326 float glyphY = position.y + glyphInfo.height*0.5f;
328 float distanceToGlyph = fabsf( glyphX - x ) + fabsf( glyphY - y );
330 if( distanceToGlyph < closestDistance )
332 closestDistance = distanceToGlyph;
337 // TODO - Consider RTL languages
338 x = positions[closestGlyph].x + glyphs[closestGlyph].width;
342 TextAbstraction::FontClient::Get().GetFontMetrics( glyphs[closestGlyph].fontId, metrics );
343 height = metrics.height; // TODO - Fix for multi-line
346 LogicalModelPtr mLogicalModel;
347 VisualModelPtr mVisualModel;
348 DecoratorPtr mDecorator;
350 std::string mPlaceholderText;
353 * This is used to delay handling events until after the model has been updated.
354 * The number of updates to the model is minimized to improve performance.
356 vector<Event> mEventQueue; ///< The queue of touch events etc.
360 bool mDecoratorUpdated : 1;
361 bool mCursorBlinkEnabled : 1;
364 struct Controller::FontDefaults
367 : mDefaultPointSize(0.0f),
372 FontId GetFontId( TextAbstraction::FontClient& fontClient )
376 Dali::TextAbstraction::PointSize26Dot6 pointSize = mDefaultPointSize*64;
377 mFontId = fontClient.GetFontId( mDefaultFontFamily, mDefaultFontStyle, pointSize );
383 std::string mDefaultFontFamily;
384 std::string mDefaultFontStyle;
385 float mDefaultPointSize;
389 struct Controller::Impl
391 Impl( ControlInterface& controlInterface )
392 : mControlInterface( controlInterface ),
395 mFontDefaults( NULL ),
402 mOperationsPending( NO_OPERATION ),
403 mRecalculateNaturalSize( true )
405 mLogicalModel = LogicalModel::New();
406 mVisualModel = VisualModel::New();
408 mFontClient = TextAbstraction::FontClient::Get();
410 mView.SetVisualModel( mVisualModel );
418 ControlInterface& mControlInterface; ///< Reference to the text controller.
419 LogicalModelPtr mLogicalModel; ///< Pointer to the logical model.
420 VisualModelPtr mVisualModel; ///< Pointer to the visual model.
421 FontDefaults* mFontDefaults; ///< Avoid allocating this when the user does not specify a font.
422 Controller::TextInput* mTextInput; ///< Avoid allocating everything for text input until EnableTextInput().
423 TextAbstraction::FontClient mFontClient; ///< Handle to the font client.
424 View mView; ///< The view interface to the rendering back-end.
425 LayoutEngine mLayoutEngine; ///< The layout engine.
426 std::string mNewText; ///< Temporary stores the text set until the next relayout.
427 Size mControlSize; ///< The size of the control.
428 OperationsMask mOperationsPending; ///< Operations pending to be done to layout the text.
429 bool mRecalculateNaturalSize:1; ///< Whether the natural size needs to be recalculated.
432 ControllerPtr Controller::New( ControlInterface& controlInterface )
434 return ControllerPtr( new Controller( controlInterface ) );
437 void Controller::SetText( const std::string& text )
439 // Keep until size negotiation
440 mImpl->mNewText = text;
442 // All operations need to be done. (convert to utf32, get break info, ..., layout, ...)
443 mImpl->mOperationsPending = ALL_OPERATIONS;
445 // The natural size needs to be re-calculated.
446 mImpl->mRecalculateNaturalSize = true;
449 mImpl->mLogicalModel->SetText( NULL, 0u );
450 mImpl->mLogicalModel->SetScripts( NULL, 0u );
451 mImpl->mLogicalModel->SetFonts( NULL, 0u );
452 mImpl->mLogicalModel->SetLineBreakInfo( NULL, 0u );
453 mImpl->mLogicalModel->SetWordBreakInfo( NULL, 0u );
454 mImpl->mLogicalModel->SetBidirectionalInfo( NULL, 0u );
455 mImpl->mLogicalModel->SetVisualToLogicalMap( NULL, 0u );
456 mImpl->mVisualModel->SetGlyphs( NULL, NULL, NULL, 0u );
457 mImpl->mVisualModel->SetGlyphPositions( NULL, 0u );
458 mImpl->mVisualModel->SetLines( NULL, 0u );
460 if( mImpl->mTextInput )
462 // Cancel previously queued events
463 mImpl->mTextInput->mEventQueue.clear();
465 // TODO - Hide selection decorations
469 void Controller::GetText( std::string& text ) const
471 if( !mImpl->mNewText.empty() )
473 text = mImpl->mNewText;
477 // TODO - Convert from UTF-32
481 void Controller::SetPlaceholderText( const std::string& text )
483 if( !mImpl->mTextInput )
485 mImpl->mTextInput->mPlaceholderText = text;
489 void Controller::GetPlaceholderText( std::string& text ) const
491 if( !mImpl->mTextInput )
493 text = mImpl->mTextInput->mPlaceholderText;
497 void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
499 if( !mImpl->mFontDefaults )
501 mImpl->mFontDefaults = new Controller::FontDefaults();
504 mImpl->mFontDefaults->mDefaultFontFamily = defaultFontFamily;
505 mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
506 mImpl->mOperationsPending = ALL_OPERATIONS;
507 mImpl->mRecalculateNaturalSize = true;
510 const std::string& Controller::GetDefaultFontFamily() const
512 if( mImpl->mFontDefaults )
514 return mImpl->mFontDefaults->mDefaultFontFamily;
520 void Controller::SetDefaultFontStyle( const std::string& defaultFontStyle )
522 if( !mImpl->mFontDefaults )
524 mImpl->mFontDefaults = new Controller::FontDefaults();
527 mImpl->mFontDefaults->mDefaultFontStyle = defaultFontStyle;
528 mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
529 mImpl->mOperationsPending = ALL_OPERATIONS;
530 mImpl->mRecalculateNaturalSize = true;
533 const std::string& Controller::GetDefaultFontStyle() const
535 if( mImpl->mFontDefaults )
537 return mImpl->mFontDefaults->mDefaultFontStyle;
543 void Controller::SetDefaultPointSize( float pointSize )
545 if( !mImpl->mFontDefaults )
547 mImpl->mFontDefaults = new Controller::FontDefaults();
550 mImpl->mFontDefaults->mDefaultPointSize = pointSize;
551 mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
552 mImpl->mOperationsPending = ALL_OPERATIONS;
553 mImpl->mRecalculateNaturalSize = true;
556 float Controller::GetDefaultPointSize() const
558 if( mImpl->mFontDefaults )
560 return mImpl->mFontDefaults->mDefaultPointSize;
566 void Controller::GetDefaultFonts( Vector<FontRun>& fonts, Length numberOfCharacters )
568 if( mImpl->mFontDefaults )
571 fontRun.characterRun.characterIndex = 0;
572 fontRun.characterRun.numberOfCharacters = numberOfCharacters;
573 fontRun.fontId = mImpl->mFontDefaults->GetFontId( mImpl->mFontClient );
574 fontRun.isDefault = true;
576 fonts.PushBack( fontRun );
580 void Controller::EnableTextInput( DecoratorPtr decorator )
582 if( !mImpl->mTextInput )
584 mImpl->mTextInput = new TextInput( mImpl->mLogicalModel, mImpl->mVisualModel, decorator );
588 void Controller::SetEnableCursorBlink( bool enable )
590 DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "TextInput disabled" );
592 if( mImpl->mTextInput )
594 mImpl->mTextInput->mCursorBlinkEnabled = enable;
597 mImpl->mTextInput->mDecorator )
599 mImpl->mTextInput->mDecorator->StopCursorBlink();
604 bool Controller::GetEnableCursorBlink() const
606 if( mImpl->mTextInput )
608 return mImpl->mTextInput->mCursorBlinkEnabled;
614 Vector3 Controller::GetNaturalSize()
618 if( mImpl->mRecalculateNaturalSize )
620 // Operations that can be done only once until the text changes.
621 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
628 // Make sure the model is up-to-date before layouting
629 ReplaceText( onlyOnceOperations );
631 // Operations that need to be done if the size changes.
632 const OperationsMask sizeOperations = static_cast<OperationsMask>( LAYOUT |
635 DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
636 static_cast<OperationsMask>( onlyOnceOperations |
638 naturalSize.GetVectorXY() );
640 // Do not do again the only once operations.
641 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
643 // Do the size related operations again.
644 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
646 // Stores the natural size to avoid recalculate it again
647 // unless the text/style changes.
648 mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
650 mImpl->mRecalculateNaturalSize = false;
654 naturalSize = mImpl->mVisualModel->GetNaturalSize();
660 float Controller::GetHeightForWidth( float width )
663 if( width != mImpl->mControlSize.width )
665 // Operations that can be done only once until the text changes.
666 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
674 // Make sure the model is up-to-date before layouting
675 ReplaceText( onlyOnceOperations );
677 // Operations that need to be done if the size changes.
678 const OperationsMask sizeOperations = static_cast<OperationsMask>( LAYOUT |
681 DoRelayout( Size( width, MAX_FLOAT ),
682 static_cast<OperationsMask>( onlyOnceOperations |
686 // Do not do again the only once operations.
687 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
689 // Do the size related operations again.
690 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
694 layoutSize = mImpl->mVisualModel->GetActualSize();
697 return layoutSize.height;
700 bool Controller::Relayout( const Vector2& size )
702 if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
704 bool glyphsRemoved( false );
705 if( 0u != mImpl->mVisualModel->GetNumberOfGlyphPositions() )
707 mImpl->mVisualModel->SetGlyphPositions( NULL, 0u );
708 glyphsRemoved = true;
711 // Not worth to relayout if width or height is equal to zero.
712 return glyphsRemoved;
715 if( size != mImpl->mControlSize )
717 // Operations that need to be done if the size changes.
718 mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
723 mImpl->mControlSize = size;
726 // Make sure the model is up-to-date before layouting
727 ReplaceText( mImpl->mOperationsPending );
730 bool updated = DoRelayout( mImpl->mControlSize,
731 mImpl->mOperationsPending,
734 // Do not re-do any operation until something changes.
735 mImpl->mOperationsPending = NO_OPERATION;
737 if( mImpl->mTextInput )
739 // Move the cursor, grab handle etc.
740 updated = mImpl->mTextInput->ProcessInputEvents() || updated;
746 void Controller::ReplaceText( OperationsMask operationsRequired )
748 // Calculate the operations to be done.
749 const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
751 Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
752 if( CONVERT_TO_UTF32 & operations )
754 std::string& text = mImpl->mNewText;
756 // Convert text into UTF-32
757 utf32Characters.Resize( text.size() );
759 // This is a bit horrible but std::string returns a (signed) char*
760 const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
762 // Transform a text array encoded in utf8 into an array encoded in utf32.
763 // It returns the actual number of characters.
764 const Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
765 utf32Characters.Resize( characterCount );
767 // Discard temporary text
771 const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
773 Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
774 if( GET_LINE_BREAKS & operations )
776 // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
777 // calculate the bidirectional info for each 'paragraph'.
778 // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
779 // is not shaped together).
780 lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
782 SetLineBreakInfo( utf32Characters,
786 Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
787 if( GET_WORD_BREAKS & operations )
789 // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
790 wordBreakInfo.Resize( numberOfCharacters, TextAbstraction::WORD_NO_BREAK );
792 SetWordBreakInfo( utf32Characters,
796 const bool getScripts = GET_SCRIPTS & operations;
797 const bool validateFonts = VALIDATE_FONTS & operations;
799 Vector<ScriptRun>& scripts = mImpl->mLogicalModel->mScriptRuns;
800 Vector<FontRun>& validFonts = mImpl->mLogicalModel->mFontRuns;
802 if( getScripts || validateFonts )
804 // Validates the fonts assigned by the application or assigns default ones.
805 // It makes sure all the characters are going to be rendered by the correct font.
806 MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
810 // Retrieves the scripts used in the text.
811 multilanguageSupport.SetScripts( utf32Characters,
818 if( 0u == validFonts.Count() )
820 // Copy the requested font defaults received via the property system.
821 // These may not be valid i.e. may not contain glyphs for the necessary scripts.
822 GetDefaultFonts( validFonts, numberOfCharacters );
825 // Validates the fonts. If there is a character with no assigned font it sets a default one.
826 // After this call, fonts are validated.
827 multilanguageSupport.ValidateFonts( utf32Characters,
833 if( BIDI_INFO & operations )
835 // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's
836 // bidirectional info.
838 Length numberOfParagraphs = 0u;
840 const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
841 for( Length index = 0u; index < numberOfCharacters; ++index )
843 if( TextAbstraction::LINE_NO_BREAK == *( lineBreakInfoBuffer + index ) )
845 ++numberOfParagraphs;
849 Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
850 bidirectionalInfo.Reserve( numberOfParagraphs );
852 // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
853 SetBidirectionalInfo( utf32Characters,
859 Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
860 Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
861 Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
862 if( SHAPE_TEXT & operations )
865 ShapeText( utf32Characters,
870 glyphsToCharactersMap,
871 charactersPerGlyph );
874 const Length numberOfGlyphs = glyphs.Count();
876 if( GET_GLYPH_METRICS & operations )
878 mImpl->mFontClient.GetGlyphMetrics( glyphs.Begin(), numberOfGlyphs );
881 if( 0u != numberOfGlyphs )
883 // Create the glyph to character conversion table and the 'number of glyphs' per character.
884 mImpl->mVisualModel->CreateCharacterToGlyphTable(numberOfCharacters );
885 mImpl->mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
889 bool Controller::DoRelayout( const Vector2& size,
890 OperationsMask operationsRequired,
893 bool viewUpdated( false );
895 // Calculate the operations to be done.
896 const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
898 if( LAYOUT & operations )
900 // Some vectors with data needed to layout and reorder may be void
901 // after the first time the text has been laid out.
902 // Fill the vectors again.
904 const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
905 Length numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
907 Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
908 Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
909 Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
910 Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
911 Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
913 // Set the layout parameters.
914 LayoutParameters layoutParameters( size,
915 lineBreakInfo.Begin(),
916 wordBreakInfo.Begin(),
919 glyphsToCharactersMap.Begin(),
920 charactersPerGlyph.Begin() );
922 // The laid-out lines.
923 // It's not possible to know in how many lines the text is going to be laid-out,
924 // but it can be resized at least with the number of 'paragraphs' to avoid
925 // some re-allocations.
926 Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
928 // Resize the vector of positions to have the same size than the vector of glyphs.
929 Vector<Vector2>& glyphPositions = mImpl->mVisualModel->mGlyphPositions;
930 glyphPositions.Resize( numberOfGlyphs );
932 BidirectionalRunIndex firstBidiRunIndex = 0u;
933 Length numberOfBidiRuns = 0u;
934 mImpl->mLogicalModel->GetNumberOfBidirectionalInfoRuns( 0u, numberOfCharacters, firstBidiRunIndex, numberOfBidiRuns );
936 // Delete any previous laid out lines before setting the new ones.
938 lines.Reserve( numberOfBidiRuns );
940 // Update the visual model.
941 viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
949 if( REORDER & operations )
951 Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
953 // Check first if there are paragraphs with bidirectional info.
954 if( 0u != bidirectionalInfo.Count() )
957 const Length numberOfLines = mImpl->mVisualModel->GetNumberOfLines();
959 // Reorder the lines.
960 Vector<BidirectionalLineInfoRun> lineBidirectionalInfoRuns;
961 lineBidirectionalInfoRuns.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
962 ReorderLines( bidirectionalInfo,
964 lineBidirectionalInfoRuns );
966 // Set the bidirectional info into the model.
967 const Length numberOfBidirectionalInfoRuns = lineBidirectionalInfoRuns.Count();
968 mImpl->mLogicalModel->SetVisualToLogicalMap( lineBidirectionalInfoRuns.Begin(),
969 numberOfBidirectionalInfoRuns );
971 // Set the bidirectional info per line into the layout parameters.
972 layoutParameters.lineBidirectionalInfoRunsBuffer = lineBidirectionalInfoRuns.Begin();
973 layoutParameters.numberOfBidirectionalInfoRuns = numberOfBidirectionalInfoRuns;
975 // Get the character to glyph conversion table and set into the layout.
976 layoutParameters.charactersToGlyphsBuffer = mImpl->mVisualModel->mCharactersToGlyph.Begin();
978 // Get the glyphs per character table and set into the layout.
979 layoutParameters.glyphsPerCharacterBuffer = mImpl->mVisualModel->mGlyphsPerCharacter.Begin();
981 // Re-layout the text. Reorder those lines with right to left characters.
982 mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
985 // Free the allocated memory used to store the conversion table in the bidirectional line info run.
986 for( Vector<BidirectionalLineInfoRun>::Iterator it = lineBidirectionalInfoRuns.Begin(),
987 endIt = lineBidirectionalInfoRuns.End();
991 BidirectionalLineInfoRun& bidiLineInfo = *it;
993 free( bidiLineInfo.visualToLogicalMap );
998 // Sets the actual size.
999 if( UPDATE_ACTUAL_SIZE & operations )
1001 mImpl->mVisualModel->SetActualSize( layoutSize );
1007 layoutSize = mImpl->mVisualModel->GetActualSize();
1013 View& Controller::GetView()
1015 return mImpl->mView;
1018 LayoutEngine& Controller::GetLayoutEngine()
1020 return mImpl->mLayoutEngine;
1023 void Controller::RequestRelayout()
1025 mImpl->mControlInterface.RequestTextRelayout();
1028 void Controller::KeyboardFocusGainEvent()
1030 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusGainEvent" );
1032 if( mImpl->mTextInput )
1034 TextInput::Event event( TextInput::KEYBOARD_FOCUS_GAIN_EVENT );
1035 mImpl->mTextInput->mEventQueue.push_back( event );
1041 void Controller::KeyboardFocusLostEvent()
1043 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusLostEvent" );
1045 if( mImpl->mTextInput )
1047 TextInput::Event event( TextInput::KEYBOARD_FOCUS_LOST_EVENT );
1048 mImpl->mTextInput->mEventQueue.push_back( event );
1054 bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
1056 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyEvent" );
1058 if( mImpl->mTextInput )
1060 TextInput::Event event( TextInput::KEY_EVENT );
1061 event.p1.mInt = keyEvent.keyCode;
1062 event.p2.mString = NULL;
1064 const std::string& keyString = keyEvent.keyPressed;
1065 if ( !keyString.empty() )
1067 event.p2.mString = new char[keyString.size() + 1];
1068 std::copy(keyString.begin(), keyString.end(), event.p2.mString);
1069 event.p2.mString[keyString.size()] = '\0';
1072 mImpl->mTextInput->mEventQueue.push_back( event );
1080 void Controller::TapEvent( unsigned int tapCount, float x, float y )
1082 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected TapEvent" );
1084 if( mImpl->mTextInput )
1086 TextInput::Event event( TextInput::TAP_EVENT );
1087 event.p1.mUint = tapCount;
1088 event.p2.mFloat = x;
1089 event.p3.mFloat = y;
1090 mImpl->mTextInput->mEventQueue.push_back( event );
1096 void Controller::GrabHandleEvent( GrabHandleState state, float x, float y )
1098 DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected GrabHandleEvent" );
1100 if( mImpl->mTextInput )
1102 TextInput::Event event( TextInput::GRAB_HANDLE_EVENT );
1103 event.p1.mUint = state;
1104 event.p2.mFloat = x;
1105 event.p3.mFloat = y;
1106 mImpl->mTextInput->mEventQueue.push_back( event );
1112 Controller::~Controller()
1117 Controller::Controller( ControlInterface& controlInterface )
1120 mImpl = new Controller::Impl( controlInterface );
1125 } // namespace Toolkit