X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ftext%2Ftext-controller.cpp;h=c302440a70521bf2f873cec2f0ca9f4afa9e2b40;hp=60016d243a246723c5fe930e4eb03a505fc874a3;hb=bbb87601fa60e55b9fab364747befef8c8ca9042;hpb=f384d637fc0bfd41b4b93221f246719904501c57 diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp index 60016d2..c302440 100644 --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -18,7 +18,14 @@ // CLASS HEADER #include +// EXTERNAL INCLUDES +#include +#include +#include +#include + // INTERNAL INCLUDES +#include #include #include #include @@ -30,14 +37,14 @@ #include #include -// EXTERNAL INCLUDES -#include -#include -#include -#include - using std::vector; +namespace +{ +const float MAX_FLOAT = std::numeric_limits::max(); +const std::string EMPTY_STRING; +} // namespace + namespace Dali { @@ -235,8 +242,14 @@ struct Controller::TextInput GetClosestCursorPosition( xPosition, yPosition, height ); mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height ); + mDecorator->HidePopup(); mDecoratorUpdated = true; } + else if ( GRAB_HANDLE_RELEASED == state ) + { + mDecorator->ShowPopup(); + } + } void ChangeState( State newState ) @@ -251,6 +264,7 @@ struct Controller::TextInput mDecorator->StopCursorBlink(); mDecorator->SetGrabHandleActive( false ); mDecorator->SetSelectionActive( false ); + mDecorator->HidePopup(); mDecoratorUpdated = true; } else if ( SELECTING == mState ) @@ -284,19 +298,23 @@ struct Controller::TextInput Vector glyphs; glyphs.Resize( numberOfGlyphs ); - mVisualModel->GetGlyphs( &glyphs[0], 0, numberOfGlyphs ); + mVisualModel->GetGlyphs( glyphs.Begin(), 0, numberOfGlyphs ); + const GlyphInfo* const glyphsBuffer = glyphs.Begin(); - std::vector positions; - positions.resize( numberOfGlyphs ); - mVisualModel->GetGlyphPositions( &positions[0], 0, numberOfGlyphs ); + Vector positions; + positions.Resize( numberOfGlyphs ); + mVisualModel->GetGlyphPositions( positions.Begin(), 0, numberOfGlyphs ); + const Vector2* const positionsBuffer = positions.Begin(); unsigned int closestGlyph = 0; - float closestDistance = std::numeric_limits::max(); + float closestDistance = MAX_FLOAT; - for( unsigned int i=0; imNewText = text; - mImpl->mOperations = ALL_OPERATIONS; + + // All operations need to be done. (convert to utf32, get break info, ..., layout, ...) + mImpl->mOperationsPending = ALL_OPERATIONS; + + // The natural size needs to be re-calculated. + mImpl->mRecalculateNaturalSize = true; + + // Reset buffers. + mImpl->mLogicalModel->SetText( NULL, 0u ); + mImpl->mLogicalModel->SetScripts( NULL, 0u ); + mImpl->mLogicalModel->SetFonts( NULL, 0u ); + mImpl->mLogicalModel->SetLineBreakInfo( NULL, 0u ); + mImpl->mLogicalModel->SetWordBreakInfo( NULL, 0u ); + mImpl->mLogicalModel->SetBidirectionalInfo( NULL, 0u ); + mImpl->mLogicalModel->SetVisualToLogicalMap( NULL, 0u ); + mImpl->mVisualModel->SetGlyphs( NULL, NULL, NULL, 0u ); + mImpl->mVisualModel->SetGlyphPositions( NULL, 0u ); + mImpl->mVisualModel->SetLines( NULL, 0u ); if( mImpl->mTextInput ) { @@ -462,7 +493,8 @@ void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily ) mImpl->mFontDefaults->mDefaultFontFamily = defaultFontFamily; mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID - mImpl->mOperations = ALL_OPERATIONS; + mImpl->mOperationsPending = ALL_OPERATIONS; + mImpl->mRecalculateNaturalSize = true; } const std::string& Controller::GetDefaultFontFamily() const @@ -472,7 +504,7 @@ const std::string& Controller::GetDefaultFontFamily() const return mImpl->mFontDefaults->mDefaultFontFamily; } - return Dali::String::EMPTY; + return EMPTY_STRING; } void Controller::SetDefaultFontStyle( const std::string& defaultFontStyle ) @@ -484,7 +516,8 @@ void Controller::SetDefaultFontStyle( const std::string& defaultFontStyle ) mImpl->mFontDefaults->mDefaultFontStyle = defaultFontStyle; mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID - mImpl->mOperations = ALL_OPERATIONS; + mImpl->mOperationsPending = ALL_OPERATIONS; + mImpl->mRecalculateNaturalSize = true; } const std::string& Controller::GetDefaultFontStyle() const @@ -494,7 +527,7 @@ const std::string& Controller::GetDefaultFontStyle() const return mImpl->mFontDefaults->mDefaultFontStyle; } - return Dali::String::EMPTY; + return EMPTY_STRING; } void Controller::SetDefaultPointSize( float pointSize ) @@ -506,7 +539,8 @@ void Controller::SetDefaultPointSize( float pointSize ) mImpl->mFontDefaults->mDefaultPointSize = pointSize; mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID - mImpl->mOperations = ALL_OPERATIONS; + mImpl->mOperationsPending = ALL_OPERATIONS; + mImpl->mRecalculateNaturalSize = true; } float Controller::GetDefaultPointSize() const @@ -519,6 +553,20 @@ float Controller::GetDefaultPointSize() const return 0.0f; } +void Controller::GetDefaultFonts( Vector& fonts, Length numberOfCharacters ) +{ + if( mImpl->mFontDefaults ) + { + FontRun fontRun; + fontRun.characterRun.characterIndex = 0; + fontRun.characterRun.numberOfCharacters = numberOfCharacters; + fontRun.fontId = mImpl->mFontDefaults->GetFontId( mImpl->mFontClient ); + fontRun.isDefault = true; + + fonts.PushBack( fontRun ); + } +} + void Controller::EnableTextInput( DecoratorPtr decorator ) { if( !mImpl->mTextInput ) @@ -535,18 +583,27 @@ bool Controller::Relayout( const Vector2& size ) return false; } - bool updated = false; - if( size != mImpl->mControlSize ) { - updated = DoRelayout( size, mImpl->mOperations ); - - // Do not re-do any operation until something changes. - mImpl->mOperations = NO_OPERATION; + // Operations that need to be done if the size changes. + mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | + LAYOUT | + UPDATE_ACTUAL_SIZE | + UPDATE_POSITIONS | + UPDATE_LINES | + REORDER ); mImpl->mControlSize = size; } + Size layoutSize; + bool updated = DoRelayout( mImpl->mControlSize, + mImpl->mOperationsPending, + layoutSize ); + + // Do not re-do any operation until something changes. + mImpl->mOperationsPending = NO_OPERATION; + if( mImpl->mTextInput ) { // Move the cursor, grab handle etc. @@ -556,10 +613,15 @@ bool Controller::Relayout( const Vector2& size ) return updated; } -bool Controller::DoRelayout( const Vector2& size, OperationsMask operations ) +bool Controller::DoRelayout( const Vector2& size, + OperationsMask operationsRequired, + Size& layoutSize ) { bool viewUpdated( false ); + // Calculate the operations to be done. + const OperationsMask operations = static_cast( mImpl->mOperationsPending & operationsRequired ); + Vector utf32Characters; Length characterCount = 0u; if( CONVERT_TO_UTF32 & operations ) @@ -581,9 +643,11 @@ bool Controller::DoRelayout( const Vector2& size, OperationsMask operations ) mImpl->mLogicalModel->SetText( utf32Characters.Begin(), characterCount ); // Discard temporary text - //text.clear(); temporary keep the text. will be fixed in the next patch. + text.clear(); } + const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters(); + Vector lineBreakInfo; if( GET_LINE_BREAKS & operations ) { @@ -615,12 +679,7 @@ bool Controller::DoRelayout( const Vector2& size, OperationsMask operations ) const bool validateFonts = VALIDATE_FONTS & operations; Vector scripts; - Vector fonts; - - if( mImpl->mFontDefaults ) - { - // TODO - pass into ValidateFonts - } + Vector validFonts; if( getScripts || validateFonts ) { @@ -641,15 +700,79 @@ bool Controller::DoRelayout( const Vector2& size, OperationsMask operations ) if( validateFonts ) { + // Copy the requested font defaults received via the property system. + // These may not be valid i.e. may not contain glyphs for the necessary scripts. + GetDefaultFonts( validFonts, numberOfCharacters ); + // Validates the fonts. If there is a character with no assigned font it sets a default one. // After this call, fonts are validated. multilanguageSupport.ValidateFonts( utf32Characters, scripts, - fonts ); + validFonts ); // Sets the fonts into the model. - mImpl->mLogicalModel->SetFonts( fonts.Begin(), fonts.Count() ); + mImpl->mLogicalModel->SetFonts( validFonts.Begin(), validFonts.Count() ); + } + } + + Vector bidirectionalInfo; + if( BIDI_INFO & operations ) + { + // Some vectors with data needed to get the paragraph's bidirectional info may be void + // after the first time the text has been laid out. + // Fill the vectors again. + + if( 0u == utf32Characters.Count() ) + { + utf32Characters.Resize( numberOfCharacters ); + + mImpl->mLogicalModel->GetText( utf32Characters.Begin(), + 0u, + numberOfCharacters ); + } + + if( 0u == lineBreakInfo.Count() ) + { + lineBreakInfo.Resize( numberOfCharacters ); + + mImpl->mLogicalModel->GetLineBreakInfo( lineBreakInfo.Begin(), + 0u, + numberOfCharacters ); + } + + if( 0u == scripts.Count() ) + { + scripts.Resize( mImpl->mLogicalModel->GetNumberOfScriptRuns( 0u, + numberOfCharacters ) ); + mImpl->mLogicalModel->GetScriptRuns( scripts.Begin(), + 0u, + numberOfCharacters ); + } + + // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's + // bidirectional info. + + Length numberOfParagraphs = 0u; + + const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin(); + for( Length index = 0u; index < characterCount; ++index ) + { + if( TextAbstraction::LINE_NO_BREAK == *( lineBreakInfoBuffer + index ) ) + { + ++numberOfParagraphs; + } } + + bidirectionalInfo.Reserve( numberOfParagraphs ); + + // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts. + SetBidirectionalInfo( utf32Characters, + scripts, + lineBreakInfo, + bidirectionalInfo ); + + mImpl->mLogicalModel->SetBidirectionalInfo( bidirectionalInfo.Begin(), + bidirectionalInfo.Count() ); } Vector glyphs; @@ -657,11 +780,20 @@ bool Controller::DoRelayout( const Vector2& size, OperationsMask operations ) Vector charactersPerGlyph; if( SHAPE_TEXT & operations ) { + if( 0u == validFonts.Count() ) + { + validFonts.Resize( mImpl->mLogicalModel->GetNumberOfFontRuns( 0u, + numberOfCharacters ) ); + mImpl->mLogicalModel->GetFontRuns( validFonts.Begin(), + 0u, + numberOfCharacters ); + } + // Shapes the text. ShapeText( utf32Characters, lineBreakInfo, scripts, - fonts, + validFonts, glyphs, glyphsToCharactersMap, charactersPerGlyph ); @@ -684,33 +816,48 @@ bool Controller::DoRelayout( const Vector2& size, OperationsMask operations ) if( LAYOUT & operations ) { - if( 0u == numberOfGlyphs ) - { - const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters(); - numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs(); + // Some vectors with data needed to layout and reorder may be void + // after the first time the text has been laid out. + // Fill the vectors again. - lineBreakInfo.Resize( numberOfCharacters ); - wordBreakInfo.Resize( numberOfCharacters ); - glyphs.Resize( numberOfGlyphs ); - glyphsToCharactersMap.Resize( numberOfGlyphs ); - charactersPerGlyph.Resize( numberOfGlyphs ); + const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters(); + numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs(); + if( 0u == lineBreakInfo.Count() ) + { + lineBreakInfo.Resize( numberOfCharacters ); mImpl->mLogicalModel->GetLineBreakInfo( lineBreakInfo.Begin(), 0u, numberOfCharacters ); + } + if( 0u == wordBreakInfo.Count() ) + { + wordBreakInfo.Resize( numberOfCharacters ); mImpl->mLogicalModel->GetWordBreakInfo( wordBreakInfo.Begin(), 0u, numberOfCharacters ); + } + if( 0u == glyphs.Count() ) + { + glyphs.Resize( numberOfGlyphs ); mImpl->mVisualModel->GetGlyphs( glyphs.Begin(), 0u, numberOfGlyphs ); + } + if( 0u == glyphsToCharactersMap.Count() ) + { + glyphsToCharactersMap.Resize( numberOfGlyphs ); mImpl->mVisualModel->GetGlyphToCharacterMap( glyphsToCharactersMap.Begin(), 0u, numberOfGlyphs ); + } + if( 0u == charactersPerGlyph.Count() ) + { + charactersPerGlyph.Resize( numberOfGlyphs ); mImpl->mVisualModel->GetCharactersPerGlyphMap( charactersPerGlyph.Begin(), 0u, numberOfGlyphs ); @@ -729,19 +876,115 @@ bool Controller::DoRelayout( const Vector2& size, OperationsMask operations ) Vector glyphPositions; glyphPositions.Resize( numberOfGlyphs ); - Size layoutSize; + // The laid-out lines. + // It's not possible to know in how many lines the text is going to be laid-out, + // but it can be resized at least with the number of 'paragraphs' to avoid + // some re-allocations. + Vector lines; + lines.Reserve( mImpl->mLogicalModel->GetNumberOfBidirectionalInfoRuns( 0u, numberOfCharacters ) ); - // Update the visual model + // Update the visual model. viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters, glyphPositions, + lines, layoutSize ); - // Sets the positions into the model. - mImpl->mVisualModel->SetGlyphPositions( glyphPositions.Begin(), - numberOfGlyphs ); + if( viewUpdated ) + { + // Reorder the lines + if( REORDER & operations ) + { + const Length numberOfBidiParagraphs = mImpl->mLogicalModel->GetNumberOfBidirectionalInfoRuns( 0u, numberOfCharacters ); + + if( 0u == bidirectionalInfo.Count() ) + { + bidirectionalInfo.Resize( numberOfBidiParagraphs ); + mImpl->mLogicalModel->GetBidirectionalInfo( bidirectionalInfo.Begin(), + 0u, + numberOfCharacters ); + } + + // Check first if there are paragraphs with bidirectional info. + if( 0u != bidirectionalInfo.Count() ) + { + // Get the lines + const Length numberOfLines = mImpl->mVisualModel->GetNumberOfLines(); + + // Reorder the lines. + Vector lineBidirectionalInfoRuns; + lineBidirectionalInfoRuns.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters. + ReorderLines( bidirectionalInfo, + lines, + lineBidirectionalInfoRuns ); + + // Set the bidirectional info into the model. + const Length numberOfBidirectionalInfoRuns = lineBidirectionalInfoRuns.Count(); + mImpl->mLogicalModel->SetVisualToLogicalMap( lineBidirectionalInfoRuns.Begin(), + numberOfBidirectionalInfoRuns ); + + // Set the bidirectional info per line into the layout parameters. + layoutParameters.lineBidirectionalInfoRunsBuffer = lineBidirectionalInfoRuns.Begin(); + layoutParameters.numberOfBidirectionalInfoRuns = numberOfBidirectionalInfoRuns; + + // Get the character to glyph conversion table and set into the layout. + Vector characterToGlyphMap; + characterToGlyphMap.Resize( numberOfCharacters ); + + layoutParameters.charactersToGlyphsBuffer = characterToGlyphMap.Begin(); + mImpl->mVisualModel->GetCharacterToGlyphMap( layoutParameters.charactersToGlyphsBuffer, + 0u, + numberOfCharacters ); + + // Get the glyphs per character table and set into the layout. + Vector glyphsPerCharacter; + glyphsPerCharacter.Resize( numberOfCharacters ); + + layoutParameters.glyphsPerCharacterBuffer = glyphsPerCharacter.Begin(); + mImpl->mVisualModel->GetGlyphsPerCharacterMap( layoutParameters.glyphsPerCharacterBuffer, + 0u, + numberOfCharacters ); + + // Re-layout the text. Reorder those lines with right to left characters. + mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters, + glyphPositions ); + + // Free the allocated memory used to store the conversion table in the bidirectional line info run. + for( Vector::Iterator it = lineBidirectionalInfoRuns.Begin(), + endIt = lineBidirectionalInfoRuns.End(); + it != endIt; + ++it ) + { + BidirectionalLineInfoRun& bidiLineInfo = *it; + + free( bidiLineInfo.visualToLogicalMap ); + } + } + } + + // Sets the positions into the model. + if( UPDATE_POSITIONS & operations ) + { + mImpl->mVisualModel->SetGlyphPositions( glyphPositions.Begin(), + numberOfGlyphs ); + } - // Sets the actual size. - mImpl->mVisualModel->SetActualSize( layoutSize ); + // Sets the lines into the model. + if( UPDATE_LINES & operations ) + { + mImpl->mVisualModel->SetLines( lines.Begin(), + lines.Count() ); + } + + // Sets the actual size. + if( UPDATE_ACTUAL_SIZE & operations ) + { + mImpl->mVisualModel->SetActualSize( layoutSize ); + } + } + } + else + { + layoutSize = mImpl->mVisualModel->GetActualSize(); } return viewUpdated; @@ -749,62 +992,83 @@ bool Controller::DoRelayout( const Vector2& size, OperationsMask operations ) Vector3 Controller::GetNaturalSize() { - // TODO - Finish implementing - return Vector3::ZERO; + Vector3 naturalSize; - // Operations that can be done only once until the text changes. - const OperationsMask onlyOnceOperations = static_cast( CONVERT_TO_UTF32 | - GET_SCRIPTS | - VALIDATE_FONTS | - GET_LINE_BREAKS | - GET_WORD_BREAKS | - SHAPE_TEXT | - GET_GLYPH_METRICS ); - - // Operations that need to be done if the size or the text changes. - const OperationsMask sizeOperations = static_cast( LAYOUT | - REORDER ); - - const float maxFloat = std::numeric_limits::max(); - DoRelayout( Vector2( maxFloat, maxFloat ), - static_cast( onlyOnceOperations | - sizeOperations ) ); - - // Do not do again the only once operations. - mImpl->mOperations = static_cast( mImpl->mOperations & ~onlyOnceOperations ); - - // Do the size related operations again. - mImpl->mOperations = static_cast( mImpl->mOperations | sizeOperations ); + if( mImpl->mRecalculateNaturalSize ) + { + // Operations that can be done only once until the text changes. + const OperationsMask onlyOnceOperations = static_cast( CONVERT_TO_UTF32 | + GET_SCRIPTS | + VALIDATE_FONTS | + GET_LINE_BREAKS | + GET_WORD_BREAKS | + SHAPE_TEXT | + GET_GLYPH_METRICS ); + + // Operations that need to be done if the size changes. + const OperationsMask sizeOperations = static_cast( LAYOUT | + REORDER ); + + DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ), + static_cast( onlyOnceOperations | + sizeOperations ), + naturalSize.GetVectorXY() ); + + // Do not do again the only once operations. + mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending & ~onlyOnceOperations ); + + // Do the size related operations again. + mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | sizeOperations ); + + // Stores the natural size to avoid recalculate it again + // unless the text/style changes. + mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() ); + + mImpl->mRecalculateNaturalSize = false; + } + else + { + naturalSize = mImpl->mVisualModel->GetNaturalSize(); + } - return Vector3( mImpl->mVisualModel->GetNaturalSize() ); + return naturalSize; } float Controller::GetHeightForWidth( float width ) { - // Operations that can be done only once until the text changes. - const OperationsMask onlyOnceOperations = static_cast( CONVERT_TO_UTF32 | - GET_SCRIPTS | - VALIDATE_FONTS | - GET_LINE_BREAKS | - GET_WORD_BREAKS | - SHAPE_TEXT | - GET_GLYPH_METRICS ); - - // Operations that need to be done if the size or the text changes. - const OperationsMask sizeOperations = static_cast( LAYOUT | - REORDER ); - - DoRelayout( Size( width, 0.f ), - static_cast( onlyOnceOperations | - sizeOperations ) ); - - // Do not do again the only once operations. - mImpl->mOperations = static_cast( mImpl->mOperations & ~onlyOnceOperations ); - - // Do the size related operations again. - mImpl->mOperations = static_cast( mImpl->mOperations | sizeOperations ); + Size layoutSize; + if( width != mImpl->mControlSize.width ) + { + // Operations that can be done only once until the text changes. + const OperationsMask onlyOnceOperations = static_cast( CONVERT_TO_UTF32 | + GET_SCRIPTS | + VALIDATE_FONTS | + GET_LINE_BREAKS | + GET_WORD_BREAKS | + SHAPE_TEXT | + GET_GLYPH_METRICS ); + + // Operations that need to be done if the size changes. + const OperationsMask sizeOperations = static_cast( LAYOUT | + REORDER ); + + DoRelayout( Size( width, MAX_FLOAT ), + static_cast( onlyOnceOperations | + sizeOperations ), + layoutSize ); + + // Do not do again the only once operations. + mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending & ~onlyOnceOperations ); + + // Do the size related operations again. + mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | sizeOperations ); + } + else + { + layoutSize = mImpl->mVisualModel->GetActualSize(); + } - return mImpl->mVisualModel->GetActualSize().height; + return layoutSize.height; } View& Controller::GetView()