{
CharacterRun characterRun; ///< The initial character index within the whole text and the number of characters of the run.
CharacterIndex* visualToLogicalMap; ///< Pointer to the visual to logical map table.
- CharacterIndex* logicalToVisualMap; ///< Pointer to the logical to visual map table.
};
} // namespace Text
// FILE HEADER
#include <dali-toolkit/internal/text/bidirectional-support.h>
+// EXTERNAL INCLUDES
+#include <dali/public-api/text-abstraction/bidirectional-support.h>
+
namespace Dali
{
namespace Text
{
+namespace
+{
+
+/**
+ * @brief Get the lines of a paragraph.
+ *
+ * @param[in] paragraphInfo The paragraph.
+ * @param[in] lines The lines.
+ * @param[in] lineIndex Index pointing the first line to be checked.
+ * @param[out] firstLine Index to the first line of the paragraph.
+ * @param[out] numberOfLines The number of lines.
+ */
+void GetLines( const BidirectionalParagraphInfoRun& paragraphInfo,
+ const Vector<LineRun>& lines,
+ unsigned int lineIndex,
+ unsigned int& firstLine,
+ unsigned int& numberOfLines )
+{
+ firstLine = lineIndex;
+ numberOfLines = 0u;
+
+ const CharacterIndex lastCharacterIndex = paragraphInfo.characterRun.characterIndex + paragraphInfo.characterRun.numberOfCharacters;
+ bool firstLineFound = false;
+
+ for( Vector<LineRun>::ConstIterator it = lines.Begin() + lineIndex,
+ endIt = lines.End();
+ it != endIt;
+ ++it )
+ {
+ const LineRun& line = *it;
+
+ if( ( line.characterRun.characterIndex + line.characterRun.numberOfCharacters > paragraphInfo.characterRun.characterIndex ) &&
+ ( lastCharacterIndex > line.characterRun.characterIndex ) )
+ {
+ firstLineFound = true;
+ ++numberOfLines;
+ }
+ else if( lastCharacterIndex <= line.characterRun.characterIndex )
+ {
+ // nothing else to do.
+ break;
+ }
+
+ if( !firstLineFound )
+ {
+ ++firstLine;
+ }
+ }
+}
+
+} // namespace
+
void SetBidirectionalInfo( const Vector<Character>& text,
+ const Vector<ScriptRun>& scripts,
const Vector<LineBreakInfo>& lineBreakInfo,
Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo )
{
+ // Traverse the script runs. If there is one with a right to left script, create the bidirectional info for the paragraph containing that script is needed.
+ // From the bidirectional point of view, a paragraph is the piece of text between two LINE_MUST_BREAK.
+
+ // Index pointing the first character of the current paragraph.
+ CharacterIndex paragraphCharacterIndex = 0u;
+
+ // Pointer to the text buffer.
+ const Character* textBuffer = text.Begin();
+
+ // Pointer to the line break info buffer.
+ const LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
+
+ // The number of characters.
+ const Length numberOfCharacters = text.Count();
+
+ // Handle to the bidirectional info module in text-abstraction.
+ TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
+
+ for( Vector<ScriptRun>::ConstIterator it = scripts.Begin(),
+ endIt = scripts.End();
+ it != endIt;
+ ++it )
+ {
+ const ScriptRun& scriptRun = *it;
+ const CharacterIndex lastScriptRunIndex = scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters;
+
+ if( TextAbstraction::IsRightToLeftScript( scriptRun.script ) && // The script is right to left.
+ ( lastScriptRunIndex > paragraphCharacterIndex ) ) // It isn't part of a previous paragraph.
+ {
+ // Find the paragraphs which contains this script run.
+ // Consider:
+ // 1) Different paragraphs may contain this script run.
+ // ------||------------------- rtl sr ------------------------||-------------------
+ // --||----- p -----||------------------ p -------------||-------- p ------||------
+ //
+ // 2) The paragraph which contains this script run may contain other right to left script runs.
+ // -----||--- rtl sr ---||---- ltr sr ----||---------- rtl sr -----------||--------
+ // -----||---------------------------------- p -----------------------------------|
+
+ while( lastScriptRunIndex > paragraphCharacterIndex )
+ {
+ // There is a paragraph which contains the current script.
+
+ Length index = paragraphCharacterIndex;
+ while( ( index < numberOfCharacters ) && ( paragraphCharacterIndex < lastScriptRunIndex ) )
+ {
+ if( TextAbstraction::LINE_MUST_BREAK == *( lineBreakInfoBuffer + index ) )
+ {
+ if( index >= scriptRun.characterRun.characterIndex )
+ {
+ // The Bidirectional run must have the same number of characters than the paragraph.
+ BidirectionalParagraphInfoRun bidirectionalRun;
+ bidirectionalRun.characterRun.characterIndex = paragraphCharacterIndex;
+ bidirectionalRun.characterRun.numberOfCharacters = ( index - paragraphCharacterIndex ) + 1u; // The must break character is part of the paragrah.
+
+ // Create the bidirectional info for the whole paragraph and store the index to the table with this info in the run.
+ bidirectionalRun.bidirectionalInfoIndex = bidirectionalSupport.CreateInfo( textBuffer + bidirectionalRun.characterRun.characterIndex,
+ bidirectionalRun.characterRun.numberOfCharacters );
+
+ bidirectionalInfo.PushBack( bidirectionalRun );
+ }
+
+ // Update the character index of the next paragraph.
+ paragraphCharacterIndex = index + 1u;
+ }
+ ++index;
+ }
+
+ // The last character is always a must-break, so there is no need to check if there is characters left.
+ }
+ }
+ }
}
void ReplaceBidirectionalInfo( LogicalModel& model,
}
void ReorderLines( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
- const Vector<CharacterRun>& lineRuns,
+ const Vector<LineRun>& lineRuns,
Vector<BidirectionalLineInfoRun>& lineInfoRuns )
{
+ // Handle to the bidirectional info module in text-abstraction.
+ TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
+
+ // Keep an index to the first line to be checked if it's contained inside the paragraph.
+ // Avoids check the lines from the beginning for each paragraph.
+ unsigned int lineIndex = 0u;
+
+ for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalInfo.Begin(),
+ endIt = bidirectionalInfo.End();
+ it != endIt;
+ ++it )
+ {
+ const BidirectionalParagraphInfoRun& paragraphInfo = *it;
+
+ // Get the lines for this paragraph.
+ unsigned int firstLine = 0u;
+ unsigned int numberOfLines = 0u;
+
+ // Get an index to the first line and the number of lines of the current paragraph.
+ GetLines( paragraphInfo,
+ lineRuns,
+ lineIndex,
+ firstLine,
+ numberOfLines );
+
+ lineIndex = firstLine + numberOfLines;
+
+ // Traverse the lines and reorder them
+ for( Vector<LineRun>::ConstIterator lineIt = lineRuns.Begin() + firstLine,
+ endLineIt = lineRuns.Begin() + firstLine + numberOfLines;
+ lineIt != endLineIt;
+ ++lineIt )
+ {
+ const LineRun& line = *lineIt;
+
+ // Creates a bidirectional info for the line run.
+ BidirectionalLineInfoRun lineInfoRun;
+ lineInfoRun.characterRun.characterIndex = line.characterRun.characterIndex;
+ lineInfoRun.characterRun.numberOfCharacters = line.characterRun.numberOfCharacters;
+
+ // Allocate space for the conversion maps.
+ // The memory is freed after the visual to logical to visual conversion tables are built in the logical model.
+ lineInfoRun.visualToLogicalMap = reinterpret_cast<CharacterIndex*>( malloc( line.characterRun.numberOfCharacters * sizeof( CharacterIndex ) ) );
+
+ // Reorders the line.
+ bidirectionalSupport.Reorder( paragraphInfo.bidirectionalInfoIndex,
+ line.characterRun.characterIndex,
+ line.characterRun.numberOfCharacters,
+ lineInfoRun.visualToLogicalMap );
+
+ // Push the run into the vector.
+ lineInfoRuns.PushBack( lineInfoRun );
+ }
+ }
}
void ReorderLines( LogicalModel& logicalModel,
*
*/
-// INTERNAL INCLUDES
+// EXTERNAL INCLUDES
#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/bidirectional-line-info-run.h>
#include <dali-toolkit/internal/text/bidirectional-paragraph-info-run.h>
+#include <dali-toolkit/internal/text/line-run.h>
+#include <dali-toolkit/internal/text/script-run.h>
namespace Dali
{
* Sets the bidirectional info into the logical model.
*
* @param[in] text Vector of UTF-32 characters.
+ * @param[in] scripts Vector containing the script runs for the whole text.
* @param[in] lineBreakInfo The line break info.
* @param[out] bidirectionalInfo Vector with the bidirectional infor for each paragraph.
*/
void SetBidirectionalInfo( const Vector<Character>& text,
+ const Vector<ScriptRun>& scripts,
const Vector<LineBreakInfo>& lineBreakInfo,
Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo );
* @param[out] lineInfoRuns line runs with the visual to logical and logical to visual conversion maps.
*/
void ReorderLines( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
- const Vector<CharacterRun>& lineRuns,
+ const Vector<LineRun>& lineRuns,
Vector<BidirectionalLineInfoRun>& lineInfoRuns );
/**
*
*/
-// INTERNAL INCLUDES
-#include <dali/public-api/common/dali-common.h>
-
// EXTERNAL INCLUDES
#include <stdint.h>
+// INTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+
namespace Dali
{
// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
+#include <dali-toolkit/internal/text/bidirectional-line-info-run.h>
namespace Dali
{
return update;
}
- // TODO - Rewrite this to handle bidi
+ void ReLayoutRightToLeftLines( const LayoutParameters& layoutParameters,
+ Vector<Vector2>& glyphPositions )
+ {
+ for( Length lineIndex = 0u; lineIndex < layoutParameters.numberOfBidirectionalInfoRuns; ++lineIndex )
+ {
+ const BidirectionalLineInfoRun& bidiLine = *( layoutParameters.lineBidirectionalInfoRunsBuffer +lineIndex );
+
+ float penX = 0.f;
+
+ Vector2* glyphPositionsBuffer = glyphPositions.Begin();
+
+ for( CharacterIndex characterLogicalIndex = 0u;
+ characterLogicalIndex < bidiLine.characterRun.numberOfCharacters;
+ ++characterLogicalIndex )
+ {
+ // Convert the character in the logical order into the character in the visual order.
+ const CharacterIndex characterVisualIndex = bidiLine.characterRun.characterIndex + *( bidiLine.visualToLogicalMap + characterLogicalIndex );
+
+ // Get the number of glyphs of the character.
+ const Length numberOfGlyphs = *( layoutParameters.glyphsPerCharacterBuffer + characterVisualIndex );
+
+ for( GlyphIndex index = 0u; index < numberOfGlyphs; ++index )
+ {
+ // Convert the character in the visual order into the glyph in the visual order.
+ GlyphIndex glyphIndex = 1u + *( layoutParameters.charactersToGlyphsBuffer + characterVisualIndex + index ) - numberOfGlyphs;
+
+ const GlyphInfo& glyph = *( layoutParameters.glyphsBuffer + glyphIndex );
+ Vector2& position = *( glyphPositionsBuffer + glyphIndex );
+
+ position.x = penX + glyph.xBearing;
+
+ penX += glyph.advance;
+ }
+ }
+ }
+ }
+
bool SingleLineLayout( const LayoutParameters& layoutParameters,
Vector<Vector2>& glyphPositions,
Vector<LineRun>& lines,
return true;
}
- // TODO - Rewrite this to handle bidi
bool MultiLineLayout( const LayoutParameters& layoutParameters,
Vector<Vector2>& glyphPositions,
Vector<LineRun>& lines,
actualSize );
}
+void LayoutEngine::ReLayoutRightToLeftLines( const LayoutParameters& layoutParameters,
+ Vector<Vector2>& glyphPositions )
+{
+ mImpl->ReLayoutRightToLeftLines( layoutParameters,
+ glyphPositions );
+}
+
} // namespace Text
} // namespace Toolkit
*
*/
-// INTERNAL INCLUDE
-#include <dali-toolkit/internal/text/line-run.h>
-
// EXTERNAL INCLUDE
#include <dali/public-api/common/dali-vector.h>
#include <dali/public-api/math/vector2.h>
+// INTERNAL INCLUDE
+#include <dali-toolkit/internal/text/line-run.h>
+
namespace Dali
{
Vector<LineRun>& lines,
Size& actualSize );
+ /**
+ * Re-lays out those lines with right to left characters.
+ *
+ * It doesn't change the phisical position of the glyphs in the model but sets their new position.
+ *
+ * @param[in] layoutParameters The parameters needed to layout the text.
+ * @param[in,out] glyphPositions The positions of all the glyphs.
+ */
+ void ReLayoutRightToLeftLines( const LayoutParameters& layoutParameters,
+ Vector<Vector2>& glyphPositions );
+
private:
// Undefined
namespace Text
{
+struct BidirectionalLineInfoRun;
+
/**
* @brief Struct used to pass parameters.
*/
totalNumberOfGlyphs( totalNumberOfGlyphs ),
glyphsBuffer( glyphsBuffer ),
glyphsToCharactersBuffer( glyphsToCharactersBuffer ),
- charactersPerGlyphBuffer( charactersPerGlyphBuffer )
+ charactersPerGlyphBuffer( charactersPerGlyphBuffer ),
+ charactersToGlyphsBuffer( NULL ),
+ glyphsPerCharacterBuffer( NULL ),
+ lineBidirectionalInfoRunsBuffer( NULL ),
+ numberOfBidirectionalInfoRuns( 0u )
{}
Vector2 boundingBox;
const GlyphInfo* const glyphsBuffer;
const CharacterIndex* const glyphsToCharactersBuffer;
const Length* const charactersPerGlyphBuffer;
+ GlyphIndex* charactersToGlyphsBuffer; ///< The character to glyph conversion table.
+ Length* glyphsPerCharacterBuffer; ///< The number of glyphs per character.
+ BidirectionalLineInfoRun* lineBidirectionalInfoRunsBuffer; ///< Bidirectional conversion tables per line.
+ Length numberOfBidirectionalInfoRuns; ///< The number of lines with bidirectional info.
};
} // namespace Text
// CLASS HEADER
#include <dali-toolkit/internal/text/logical-model.h>
+// EXTERNAL INCLUDES
+#include <memory.h>
+
// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/bidirectional-line-info-run.h>
#include <dali-toolkit/internal/text/bidirectional-paragraph-info-run.h>
#include <dali-toolkit/internal/text/font-run.h>
#include <dali-toolkit/internal/text/script-run.h>
-// EXTERNAL INCLUDES
-#include <memory.h>
-
namespace Dali
{
struct LogicalModel::Impl
{
- Vector<Character> mText;
- Vector<ScriptRun> mScriptRuns;
- Vector<FontRun> mFontRuns;
- Vector<LineBreakInfo> mLineBreakInfo;
- Vector<WordBreakInfo> mWordBreakInfo;
+ Vector<Character> mText;
+ Vector<ScriptRun> mScriptRuns;
+ Vector<FontRun> mFontRuns;
+ Vector<LineBreakInfo> mLineBreakInfo;
+ Vector<WordBreakInfo> mWordBreakInfo;
+ Vector<BidirectionalParagraphInfoRun> mBidirectionalParagraphInfo;
+
+ Vector<BidirectionalLineInfoRun> mBidirectionalLineInfo;
+ Vector<CharacterIndex> mLogicalToVisualMap; ///< Bidirectional logical to visual conversion table.
+ Vector<CharacterIndex> mVisualToLogicalMap; ///< Bidirectional visual to logical conversion table.
- GetRunCache mGetScriptCache; ///< Caches the GetNumberOfScriptRuns( characterIndex, numberOfCharacters ) operation.
- GetRunCache mGetFontCache; ///< Caches the GetNumberOfFontRuns( characterIndex, numberOfCharacters ) operation.
+ GetRunCache mGetScriptCache; ///< Caches the GetNumberOfScriptRuns( characterIndex, numberOfCharacters ) operation.
+ GetRunCache mGetFontCache; ///< Caches the GetNumberOfFontRuns( characterIndex, numberOfCharacters ) operation.
+ GetRunCache mGetBidirectionalCache; ///< Caches the GetNumberOfBidirectionalInfoRuns( characterIndex, numberOfCharacters ) operation.
};
LogicalModelPtr LogicalModel::New()
return mImpl->mText.Count();
}
-void LogicalModel::GetText( CharacterIndex characterIndex,
- Character* text,
+void LogicalModel::GetText( Character* text,
+ CharacterIndex characterIndex,
Length numberOfCharacters ) const
{
Vector<Character>& modelText = mImpl->mText;
void LogicalModel::SetBidirectionalInfo( const BidirectionalParagraphInfoRun* const bidirectionalInfo,
Length numberOfRuns )
{
+ Vector<BidirectionalParagraphInfoRun>& modelBidirectionalParagraphInfo = mImpl->mBidirectionalParagraphInfo;
+
+ if( 0u == numberOfRuns )
+ {
+ modelBidirectionalParagraphInfo.Clear();
+ }
+ else
+ {
+ modelBidirectionalParagraphInfo.Resize( numberOfRuns );
+ memcpy( modelBidirectionalParagraphInfo.Begin(), bidirectionalInfo, numberOfRuns * sizeof( BidirectionalParagraphInfoRun ) );
+ }
+
+ mImpl->mGetBidirectionalCache.characterIndex = 0u;
+ mImpl->mGetBidirectionalCache.numberOfCharacters = 0u;
+ mImpl->mGetBidirectionalCache.firstRun = 0u;
+ mImpl->mGetBidirectionalCache.numberOfRuns = 0u;
}
Length LogicalModel::GetNumberOfBidirectionalInfoRuns( CharacterIndex characterIndex,
Length numberOfCharacters ) const
{
- return 0u;
+ GetRunCache& bidiCache = mImpl->mGetBidirectionalCache;
+
+ // Set the character index and the number of characters into the cache.
+ bidiCache.characterIndex = characterIndex;
+ bidiCache.numberOfCharacters = numberOfCharacters;
+
+ if( ( 0u == characterIndex ) &&
+ ( mImpl->mText.Count() == numberOfCharacters ) )
+ {
+ bidiCache.firstRun = 0u;
+ bidiCache.numberOfRuns = mImpl->mBidirectionalParagraphInfo.Count();
+ return bidiCache.numberOfRuns;
+ }
+
+ // Initialize the number of bidi paragraphs and the index to the first paragraph.
+ bidiCache.firstRun = 0u;
+ bidiCache.numberOfRuns = 0;
+ bool firstParagraphFound = false;
+
+ const Vector<BidirectionalParagraphInfoRun>& modelBidirectionalParagraphInfo = mImpl->mBidirectionalParagraphInfo;
+
+ // Traverse the bidirectional paragraph info and count those bidi paragraphs within the range of characters.
+ for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = modelBidirectionalParagraphInfo.Begin(),
+ endIt = modelBidirectionalParagraphInfo.End();
+ it != endIt;
+ ++it )
+ {
+ const BidirectionalParagraphInfoRun& bidi = *it;
+
+ if( ( bidi.characterRun.characterIndex + bidi.characterRun.numberOfCharacters > characterIndex ) &&
+ ( characterIndex + numberOfCharacters > bidi.characterRun.characterIndex ) )
+ {
+ firstParagraphFound = true;
+ ++bidiCache.numberOfRuns;
+ }
+
+ if( !firstParagraphFound )
+ {
+ ++bidiCache.firstRun;
+ }
+ }
+
+ return bidiCache.numberOfRuns;
+}
+
+void LogicalModel::GetBidirectionalInfo( BidirectionalParagraphInfoRun* bidirectionalInfo,
+ CharacterIndex characterIndex,
+ Length numberOfCharacters ) const
+{
+ const Vector<BidirectionalParagraphInfoRun>& modelBidirectionalParagraphInfo = mImpl->mBidirectionalParagraphInfo;
+ GetRunCache& bidiCache = mImpl->mGetBidirectionalCache;
+
+ if( ( characterIndex != bidiCache.characterIndex ) ||
+ ( numberOfCharacters != bidiCache.numberOfCharacters ) )
+ {
+ GetNumberOfBidirectionalInfoRuns( characterIndex,
+ numberOfCharacters );
+ }
+
+ memcpy( bidirectionalInfo, modelBidirectionalParagraphInfo.Begin() + bidiCache.firstRun, bidiCache.numberOfRuns * sizeof( BidirectionalParagraphInfoRun ) );
}
void LogicalModel::GetCharacterDirections( CharacterDirection* directions,
void LogicalModel::SetVisualToLogicalMap( const BidirectionalLineInfoRun* const bidirectionalInfo,
Length numberOfRuns )
{
+ Vector<CharacterIndex>& modelVisualToLogicalMap = mImpl->mVisualToLogicalMap;
+ Vector<CharacterIndex>& modelLogicalToVisualMap = mImpl->mLogicalToVisualMap;
+
+ if( 0u == numberOfRuns )
+ {
+ modelVisualToLogicalMap.Clear();
+ modelLogicalToVisualMap.Clear();
+ }
+ else
+ {
+ const Length numberOfCharacters = mImpl->mText.Count();
+ modelVisualToLogicalMap.Resize( numberOfCharacters );
+ modelLogicalToVisualMap.Resize( numberOfCharacters );
+
+ CharacterIndex* modelVisualToLogicalMapBuffer = modelVisualToLogicalMap.Begin();
+ CharacterIndex* modelLogicalToVisualMapBuffer = modelLogicalToVisualMap.Begin();
+
+ CharacterIndex lastIndex = 0u;
+ for( unsigned int bidiIndex = 0u; bidiIndex < numberOfRuns; ++bidiIndex )
+ {
+ const BidirectionalLineInfoRun& bidiLineInfo = *( bidirectionalInfo + bidiIndex );
+
+ if( lastIndex < bidiLineInfo.characterRun.characterIndex )
+ {
+ // Fill with the identity.
+ for( ; lastIndex < bidiLineInfo.characterRun.characterIndex; ++lastIndex )
+ {
+ *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
+ }
+ }
+
+ // Fill the conversion table of the run.
+ for( CharacterIndex index = 0u;
+ index < bidiLineInfo.characterRun.numberOfCharacters;
+ ++index, ++lastIndex )
+ {
+ *( modelVisualToLogicalMapBuffer + lastIndex ) = bidiLineInfo.characterRun.characterIndex + *( bidiLineInfo.visualToLogicalMap + index );
+ }
+ }
+
+ // Complete with the identity if there are some left to right characters after the last right to left.
+ for( ; lastIndex < numberOfCharacters; ++lastIndex )
+ {
+ *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
+ }
+
+ // Sets the logical to visual conversion map.
+ for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
+ {
+ *( modelLogicalToVisualMapBuffer + *( modelVisualToLogicalMapBuffer + index ) ) = index;
+ }
+ }
}
CharacterIndex LogicalModel::GetVisualCharacterIndex( CharacterIndex logicalCharacterIndex ) const
{
- return 0u;
+ if( 0u == mImpl->mLogicalToVisualMap.Count() )
+ {
+ // If there is no logical to visual info is because the whole text is left to right.
+ // Return the identity.
+ return logicalCharacterIndex;
+ }
+
+ return *( mImpl->mLogicalToVisualMap.Begin() + logicalCharacterIndex );
}
CharacterIndex LogicalModel::GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex ) const
{
- return 0u;
+ if( 0u == mImpl->mVisualToLogicalMap.Count() )
+ {
+ // If there is no visual to logical info is because the whole text is left to right.
+ // Return the identity.
+ return visualCharacterIndex;
+ }
+
+ return *( mImpl->mVisualToLogicalMap.Begin() + visualCharacterIndex );
}
void LogicalModel::GetLogicalToVisualMap( CharacterIndex* logicalToVisualMap,
CharacterIndex characterIndex,
Length numberOfCharacters ) const
{
+ memcpy( logicalToVisualMap, mImpl->mLogicalToVisualMap.Begin() + characterIndex, numberOfCharacters * sizeof( CharacterIndex ) );
}
void LogicalModel::GetVisualToLogicalMap( CharacterIndex* visualToLogicalMap,
CharacterIndex characterIndex,
Length numberOfCharacters ) const
{
+ memcpy( visualToLogicalMap, mImpl->mVisualToLogicalMap.Begin() + characterIndex, numberOfCharacters * sizeof( CharacterIndex ) );
}
LogicalModel::~LogicalModel()
*
*/
-// INTERNAL INCLUDES
+// EXTERNAL INCLUDES
#include <dali/public-api/common/dali-vector.h>
#include <dali/public-api/common/intrusive-ptr.h>
#include <dali/public-api/object/ref-object.h>
+
+// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/text-definitions.h>
namespace Dali
* @brief Retrieves characters from the text in the given buffer.
*
* @pre The size of the @p text buffer needs to be big enough to copy the @p numberOfCharacters.
- * @param[in] characterIndex The index to the first character to copy.
* @param[out] text Pointer to a buffer where the text is copied.
+ * @param[in] characterIndex The index to the first character to copy.
* @param[in] numberOfCharacters The number of characters to be copied.
*/
- void GetText( CharacterIndex characterIndex,
- Character* text,
+ void GetText( Character* text,
+ CharacterIndex characterIndex,
Length numberOfCharacters ) const;
/**
Length numberOfCharacters ) const;
/**
+ * Retrieves the bidirectional paragraph info runs for the given range of characters.
+ *
+ * The @p bidirectionalInfo buffer needs to be big enough to copy the number of bidirectional
+ * paragraph info runs.
+ * Call GetNumberOfBidirectionalInfoRuns() to retrieve the number of bidirectional runs.
+ *
+ * @param[out] bidirectionalInfo Pointer to a buffer where the bidirectional info runs are copied.
+ * @param[in] characterIndex Index to the first character.
+ * @param[in] numberOfCharacters The number of characters.
+ */
+ void GetBidirectionalInfo( BidirectionalParagraphInfoRun* bidirectionalInfo,
+ CharacterIndex characterIndex,
+ Length numberOfCharacters ) const;
+
+ /**
* Retrieves the direction of the characters.
*
* It sets @c true for right to left characters and @c false for left to right.
*
*/
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/multi-language-support.h>
-
// EXTERNAL INCLUDES
#include <dali/public-api/object/base-object.h>
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/multi-language-support.h>
+
namespace Dali
{
*
*/
-// INTERNAL INCLUDES
+// EXTERNAL INCLUDES
#include <dali/public-api/common/dali-vector.h>
#include <dali/public-api/object/base-handle.h>
+
+// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/font-run.h>
#include <dali-toolkit/internal/text/script-run.h>
*
*/
-// INTERNAL INCLUDES
+// EXTERNAL INCLUDES
#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/text-definitions.h>
namespace Dali
*
*/
-// INTERNAL INCLUDES
+// EXTERNAL INCLUDES
#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/font-run.h>
#include <dali-toolkit/internal/text/script-run.h>
// CLASS HEADER
#include <dali-toolkit/internal/text/text-controller.h>
+// EXTERNAL INCLUDES
+#include <limits>
+#include <vector>
+#include <dali/public-api/adaptor-framework/key.h>
+#include <dali/public-api/text-abstraction/font-client.h>
+
// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/bidirectional-support.h>
#include <dali-toolkit/internal/text/character-set-conversion.h>
#include <dali-toolkit/internal/text/layouts/layout-engine.h>
#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
#include <dali-toolkit/internal/text/text-view.h>
#include <dali-toolkit/internal/text/visual-model.h>
-// EXTERNAL INCLUDES
-#include <limits>
-#include <vector>
-#include <dali/public-api/adaptor-framework/key.h>
-#include <dali/public-api/text-abstraction/font-client.h>
-
using std::vector;
namespace
// 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 )
{
// Cancel previously queued events
}
}
+ Vector<BidirectionalParagraphInfoRun> 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.
+
+ const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
+
+ 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<GlyphInfo> glyphs;
Vector<CharacterIndex> glyphsToCharactersMap;
Vector<Length> charactersPerGlyph;
if( LAYOUT & operations )
{
+ // 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.
+
const Length numberOfCharacters = mImpl->mLogicalModel->GetNumberOfCharacters();
+ numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
- if( 0u == numberOfGlyphs )
+ if( 0u == lineBreakInfo.Count() )
{
- numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
-
lineBreakInfo.Resize( numberOfCharacters );
- wordBreakInfo.Resize( numberOfCharacters );
- glyphs.Resize( numberOfGlyphs );
- glyphsToCharactersMap.Resize( numberOfGlyphs );
- charactersPerGlyph.Resize( numberOfGlyphs );
-
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 );
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<BidirectionalLineInfoRun> 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<GlyphIndex> 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<Length> 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<BidirectionalLineInfoRun>::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 )
{
*
*/
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/decorator/text-decorator.h>
-#include <dali-toolkit/internal/text/text-control-interface.h>
-#include <dali-toolkit/internal/text/text-view.h>
-
// EXTERNAL INCLUDES
+#include <string>
#include <dali/public-api/common/intrusive-ptr.h>
#include <dali/public-api/events/key-event.h>
#include <dali/public-api/math/vector3.h>
#include <dali/public-api/math/vector2.h>
#include <dali/public-api/object/ref-object.h>
-#include <string>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/decorator/text-decorator.h>
+#include <dali-toolkit/internal/text/text-control-interface.h>
+#include <dali-toolkit/internal/text/text-view.h>
namespace Dali
{
VALIDATE_FONTS = 0x0004,
GET_LINE_BREAKS = 0x0008,
GET_WORD_BREAKS = 0x0010,
- SHAPE_TEXT = 0x0020,
- GET_GLYPH_METRICS = 0x0040,
- LAYOUT = 0x0080,
- UPDATE_ACTUAL_SIZE = 0x0100,
- UPDATE_POSITIONS = 0x0200,
- UPDATE_LINES = 0x0400,
- REORDER = 0x0800,
- ALIGNMENT = 0x1000,
- RENDER = 0x2000,
+ BIDI_INFO = 0x0020,
+ SHAPE_TEXT = 0x0040,
+ GET_GLYPH_METRICS = 0x0080,
+ LAYOUT = 0x0100,
+ UPDATE_ACTUAL_SIZE = 0x0200,
+ UPDATE_POSITIONS = 0x0400,
+ UPDATE_LINES = 0x0800,
+ REORDER = 0x1000,
+ ALIGNMENT = 0x2000,
+ RENDER = 0x4000,
ALL_OPERATIONS = 0xFFFF
};
// EXTERNAL INCLUDES
#include <memory.h>
-
-// INTERNAL INCLUDES
#include <dali/public-api/common/dali-vector.h>
#include <dali/public-api/math/vector2.h>
+
+// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/line-run.h>
namespace Dali
Vector<CharacterIndex> mGlyphsToCharacters; ///< For each glyph, the index of the first character.
Vector<GlyphIndex> mCharactersToGlyph; ///< For each character, the index of the first glyph.
Vector<Length> mCharactersPerGlyph; ///< For each glyph, the number of characters that form the glyph.
+ Vector<Length> mGlyphsPerCharacter; ///< For each character, the number of glyphs that are shaped.
Vector<Vector2> mGlyphPositions; ///< For each glyph, the position.
Vector<LineRun> mLines; ///< The laid out lines.
{
Vector<GlyphInfo>& modelGlyphs = mImpl->mGlyphs;
Vector<CharacterIndex>& modelGlyphsToCharacters = mImpl->mGlyphsToCharacters;
- Vector<Length>& modelCharactersPerGlyph = mImpl->mCharactersPerGlyph;
Vector<GlyphIndex>& modelCharactersToGlyph = mImpl->mCharactersToGlyph;
+ Vector<Length>& modelCharactersPerGlyph = mImpl->mCharactersPerGlyph;
+ Vector<Length>& modelGlyphsPerCharacter = mImpl->mGlyphsPerCharacter;
if( 0u == numberOfGlyphs )
{
modelGlyphsToCharacters.Clear();
modelCharactersToGlyph.Clear();
modelCharactersPerGlyph.Clear();
+ modelGlyphsPerCharacter.Clear();
}
else
{
// Build the characters to glyph conversion table.
// 1) Reserve some space for the characters to avoid reallocations.
- modelCharactersToGlyph.Reserve( static_cast<Length> ( static_cast<float>( numberOfGlyphs ) * 1.3f ) );
+ const Length numberOfCharacters = static_cast<Length> ( static_cast<float>( numberOfGlyphs ) * 1.3f );
+ modelCharactersToGlyph.Reserve( numberOfCharacters );
+ modelGlyphsPerCharacter.Reserve( numberOfCharacters );
+
+ // 2) Traverse the glyphs and set the glyph indices and the glyphs per character.
- // 2) Traverse the glyphs and set the glyph indices.
+ // The number of 'characters per glyph' equal to zero.
+ Length zeroCharactersPerGlyph = 0u;
+
+ // Index to the glyph.
GlyphIndex glyphIndex = 0u;
- Length totalNumberOfCharacters = 0u;
for( Vector<Length>::ConstIterator it = modelCharactersPerGlyph.Begin(),
endIt = modelCharactersPerGlyph.End();
it != endIt;
{
const Length numberOfCharacters = *it;
- for( Length index = 0u; index < numberOfCharacters; ++index, ++totalNumberOfCharacters )
+ // Set the glyph indices.
+ for( Length index = 0u; index < numberOfCharacters; ++index )
{
modelCharactersToGlyph.PushBack( glyphIndex );
}
+
+ // Set the glyphs per character.
+ if( 0u == numberOfCharacters )
+ {
+ ++zeroCharactersPerGlyph;
+ }
+ else
+ {
+ const Length numberOfZeroGlyphsPerCharacter = ( numberOfCharacters - 1u );
+ for( Length zeroIndex = 0u; zeroIndex < numberOfZeroGlyphsPerCharacter ; ++zeroIndex )
+ {
+ modelGlyphsPerCharacter.PushBack( 0u );
+ }
+
+ modelGlyphsPerCharacter.PushBack( 1u + zeroCharactersPerGlyph );
+
+ zeroCharactersPerGlyph = 0u;
+ }
}
}
}
memcpy( characterToGlyphMap, modelCharactersToGlyph.Begin() + characterIndex, numberOfCharacters * sizeof( GlyphIndex ) );
}
+void VisualModel::GetGlyphToCharacterMap( CharacterIndex* glyphToCharacter,
+ GlyphIndex glyphIndex,
+ Length numberOfGlyphs ) const
+{
+ const Vector<CharacterIndex>& modelGlyphsToCharacters = mImpl->mGlyphsToCharacters;
+ memcpy( glyphToCharacter, modelGlyphsToCharacters.Begin() + glyphIndex, numberOfGlyphs * sizeof( CharacterIndex ) );
+}
+
void VisualModel::GetCharactersPerGlyphMap( Length* charactersPerGlyph,
GlyphIndex glyphIndex,
Length numberOfGlyphs ) const
memcpy( charactersPerGlyph, modelCharactersPerGlyph.Begin() + glyphIndex, numberOfGlyphs * sizeof( Length ) );
}
-void VisualModel::GetGlyphToCharacterMap( CharacterIndex* glyphToCharacter,
- GlyphIndex glyphIndex,
- Length numberOfGlyphs ) const
+void VisualModel::GetGlyphsPerCharacterMap( Length* glyphsPerCharacter,
+ CharacterIndex characterIndex,
+ Length numberOfCharacters ) const
{
- const Vector<CharacterIndex>& modelGlyphsToCharacters = mImpl->mGlyphsToCharacters;
- memcpy( glyphToCharacter, modelGlyphsToCharacters.Begin() + glyphIndex, numberOfGlyphs * sizeof( CharacterIndex ) );
+ const Vector<Length>& modelGlyphsPerCharacter = mImpl->mGlyphsPerCharacter;
+ memcpy( glyphsPerCharacter, modelGlyphsPerCharacter.Begin() + characterIndex, numberOfCharacters * sizeof( Length ) );
}
void VisualModel::SetGlyphPositions( const Vector2* glyphPositions,
const Vector<LineRun>& modelLines = mImpl->mLines;
const GlyphIndex lastGlyphIndex = glyphIndex + numberOfGlyphs;
- // Traverse the lines and cound those lines within the range of glyphs.
+ // Traverse the lines and count those lines within the range of glyphs.
for( Vector<LineRun>::ConstIterator it = modelLines.Begin(),
endIt = modelLines.End();
it != endIt;
*
*/
-// INTERNAL INCLUDES
+// EXTERNAL INCLUDES
#include <dali/public-api/common/intrusive-ptr.h>
#include <dali/public-api/object/ref-object.h>
+
+// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/text-definitions.h>
namespace Dali
Length numberOfCharacters ) const;
/**
+ * Retrieves the whole or part of the glyph to character conversion map.
+ *
+ * The size of the buffer needs to be big enough to copy the @p numberOfGlyphs.
+ *
+ * @param[out] glyphToCharacter Pointer to a buffer where the conversion map is copied.
+ * @param[in] glyphIndex Index to the first glyph.
+ * @param[in] numberOfGlyphs The number of glyphs.
+ */
+ void GetGlyphToCharacterMap( CharacterIndex* glyphToCharacter,
+ GlyphIndex glyphIndex,
+ Length numberOfGlyphs ) const;
+
+ /**
* Retrieves for each glyph the number of characters the glyph represents.
*
* @param[out] charactersPerGlyph Pointer to a buffer where the number of characters for each glyph are copied.
Length numberOfGlyphs ) const;
/**
- * Retrieves the whole or part of the glyph to character conversion map.
+ * Retrieves for each character the number of glyphs the character is shaped.
*
- * The size of the buffer needs to be big enough to copy the @p numberOfGlyphs.
- *
- * @param[out] glyphToCharacter Pointer to a buffer where the conversion map is copied.
- * @param[in] glyphIndex Index to the first glyph.
- * @param[in] numberOfGlyphs The number of glyphs.
+ * @param[out] glyphsPerCharacter Pointer to a buffer where the number of glyphs for each character are copied.
+ * @param[in] characterIndex Index to the first character.
+ * @param[in] numberOfCharacters The number of characters.
*/
- void GetGlyphToCharacterMap( CharacterIndex* glyphToCharacter,
- GlyphIndex glyphIndex,
- Length numberOfGlyphs ) const;
+ void GetGlyphsPerCharacterMap( Length* glyphsPerCharacter,
+ CharacterIndex characterIndex,
+ Length numberOfCharacters ) const;
// Position interface