&utf32[0u] );
utf32.Resize( numberOfCharacters );
- // 2) Set the line break info.
- Vector<LineBreakInfo> lineBreakInfo;
- lineBreakInfo.Resize( numberOfCharacters );
-
- SetLineBreakInfo( utf32, lineBreakInfo );
-
- // 3) Set the script info.
+ // 2) Set the script info.
Vector<ScriptRun> scripts;
multilanguageSupport.SetScripts( utf32,
- lineBreakInfo,
scripts );
- // 4) Compare the results.
+ // 3) Compare the results.
+ tet_printf( "Testing %s\n", data.description.c_str() );
if( scripts.Count() != data.scriptRuns.Count() )
{
- tet_infoline("ScriptsTest: different number of scripts.");
+ tet_printf("ScriptsTest FAIL: different number of scripts. %d, should be %d\n", scripts.Count(), data.scriptRuns.Count() );
return false;
}
if( scriptRun1.characterRun.characterIndex != scriptRun2.characterRun.characterIndex )
{
- tet_infoline("ScriptsTest: different character index.");
+ tet_printf("ScriptsTest FAIL: different character index. %d, should be %d\n", scriptRun1.characterRun.characterIndex, scriptRun2.characterRun.characterIndex );
return false;
}
if( scriptRun1.characterRun.numberOfCharacters != scriptRun2.characterRun.numberOfCharacters )
{
- tet_infoline("ScriptsTest: different number of characters.");
+ tet_printf("ScriptsTest FAIL: different number of characters. %d, should be %d\n", scriptRun1.characterRun.numberOfCharacters, scriptRun2.characterRun.numberOfCharacters );
return false;
}
if( scriptRun1.script != scriptRun2.script )
{
- tet_infoline("ScriptsTest: different script.");
+ tet_printf("ScriptsTest FAIL: different script. %s, should be %s\n", TextAbstraction::ScriptName[scriptRun1.script], TextAbstraction::ScriptName[scriptRun2.script] );
return false;
}
}
&utf32[0u] );
utf32.Resize( numberOfCharacters );
- // 2) Set the line break info.
- Vector<LineBreakInfo> lineBreakInfo;
- lineBreakInfo.Resize( numberOfCharacters );
-
- SetLineBreakInfo( utf32, lineBreakInfo );
-
- // 3) Set the script info.
+ // 2) Set the script info.
Vector<ScriptRun> scripts;
multilanguageSupport.SetScripts( utf32,
- lineBreakInfo,
scripts );
Vector<FontRun> fonts;
- // 4) Validate the fonts
+ // 3) Validate the fonts
multilanguageSupport.ValidateFonts( utf32,
scripts,
fonts );
};
scriptRuns01.PushBack( scriptRun0100 );
+ // Mix of LTR '\n'and RTL
+ Vector<ScriptRun> scriptRuns02;
+ ScriptRun scriptRun0200 =
+ {
+ 0u,
+ 12u,
+ TextAbstraction::LATIN
+ };
+ ScriptRun scriptRun0201 =
+ {
+ 12u,
+ 13u,
+ TextAbstraction::ARABIC
+ };
+ scriptRuns02.PushBack( scriptRun0200 );
+ scriptRuns02.PushBack( scriptRun0201 );
+
+ // Mix of RTL '\n'and LTR
+ Vector<ScriptRun> scriptRuns03;
+ ScriptRun scriptRun0300 =
+ {
+ 0u,
+ 14u,
+ TextAbstraction::ARABIC
+ };
+ ScriptRun scriptRun0301 =
+ {
+ 14u,
+ 11u,
+ TextAbstraction::LATIN
+ };
+ scriptRuns03.PushBack( scriptRun0300 );
+ scriptRuns03.PushBack( scriptRun0301 );
+
+ // White spaces. At the beginning of the text.
+ Vector<ScriptRun> scriptRuns04;
+ ScriptRun scriptRun0400 =
+ {
+ 0u,
+ 16u,
+ TextAbstraction::LATIN
+ };
+ scriptRuns04.PushBack( scriptRun0400 );
+
+ // White spaces. At the end of the text.
+ Vector<ScriptRun> scriptRuns05;
+ ScriptRun scriptRun0500 =
+ {
+ 0u,
+ 16u,
+ TextAbstraction::LATIN
+ };
+ scriptRuns05.PushBack( scriptRun0500 );
+
+ // White spaces. At the middle of the text.
+ Vector<ScriptRun> scriptRuns06;
+ ScriptRun scriptRun0600 =
+ {
+ 0u,
+ 16u,
+ TextAbstraction::LATIN
+ };
+ scriptRuns06.PushBack( scriptRun0600 );
+
+ // White spaces between different scripts.
+ Vector<ScriptRun> scriptRuns07;
+ ScriptRun scriptRun0700 =
+ {
+ 0u,
+ 8u,
+ TextAbstraction::LATIN
+ };
+ ScriptRun scriptRun0701 =
+ {
+ 8u,
+ 5u,
+ TextAbstraction::HANGUL
+ };
+ scriptRuns07.PushBack( scriptRun0700 );
+ scriptRuns07.PushBack( scriptRun0701 );
+
+ // White spaces between different scripts and differetn directions. Starting LTR.
+ Vector<ScriptRun> scriptRuns08;
+ ScriptRun scriptRun0800 =
+ {
+ 0u,
+ 18u,
+ TextAbstraction::LATIN
+ };
+ ScriptRun scriptRun0801 =
+ {
+ 18u,
+ 14u,
+ TextAbstraction::ARABIC
+ };
+ ScriptRun scriptRun0802 =
+ {
+ 32u,
+ 18u,
+ TextAbstraction::HANGUL
+ };
+ scriptRuns08.PushBack( scriptRun0800 );
+ scriptRuns08.PushBack( scriptRun0801 );
+ scriptRuns08.PushBack( scriptRun0802 );
+
+ // White spaces between different scripts and differetn directions. Starting RTL.
+ Vector<ScriptRun> scriptRuns09;
+ ScriptRun scriptRun0900 =
+ {
+ 0u,
+ 21u,
+ TextAbstraction::ARABIC
+ };
+ ScriptRun scriptRun0901 =
+ {
+ 21u,
+ 16u,
+ TextAbstraction::LATIN
+ };
+ ScriptRun scriptRun0902 =
+ {
+ 37u,
+ 10u,
+ TextAbstraction::HANGUL
+ };
+ ScriptRun scriptRun0903 =
+ {
+ 47u,
+ 20u,
+ TextAbstraction::ARABIC
+ };
+ scriptRuns09.PushBack( scriptRun0900 );
+ scriptRuns09.PushBack( scriptRun0901 );
+ scriptRuns09.PushBack( scriptRun0902 );
+ scriptRuns09.PushBack( scriptRun0903 );
+
+ // Paragraphs with different directions.
+ Vector<ScriptRun> scriptRuns10;
+ ScriptRun scriptRun1000 =
+ {
+ 0u,
+ 20u,
+ TextAbstraction::ARABIC
+ };
+ ScriptRun scriptRun1001 =
+ {
+ 20u,
+ 12u,
+ TextAbstraction::HEBREW
+ };
+ ScriptRun scriptRun1002 =
+ {
+ 32u,
+ 17u,
+ TextAbstraction::ARABIC
+ };
+ ScriptRun scriptRun1003 =
+ {
+ 49u,
+ 18u,
+ TextAbstraction::LATIN
+ };
+ ScriptRun scriptRun1004 =
+ {
+ 67u,
+ 14u,
+ TextAbstraction::HANGUL
+ };
+ ScriptRun scriptRun1005 =
+ {
+ 81u,
+ 19u,
+ TextAbstraction::ARABIC
+ };
+ ScriptRun scriptRun1006 =
+ {
+ 100u,
+ 13u,
+ TextAbstraction::LATIN
+ };
+ ScriptRun scriptRun1007 =
+ {
+ 113u,
+ 16u,
+ TextAbstraction::HEBREW
+ };
+ ScriptRun scriptRun1008 =
+ {
+ 129u,
+ 20u,
+ TextAbstraction::LATIN
+ };
+ ScriptRun scriptRun1009 =
+ {
+ 149u,
+ 14u,
+ TextAbstraction::ARABIC
+ };
+ ScriptRun scriptRun1010 =
+ {
+ 163u,
+ 35u,
+ TextAbstraction::HANGUL
+ };
+ scriptRuns10.PushBack( scriptRun1000 );
+ scriptRuns10.PushBack( scriptRun1001 );
+ scriptRuns10.PushBack( scriptRun1002 );
+ scriptRuns10.PushBack( scriptRun1003 );
+ scriptRuns10.PushBack( scriptRun1004 );
+ scriptRuns10.PushBack( scriptRun1005 );
+ scriptRuns10.PushBack( scriptRun1006 );
+ scriptRuns10.PushBack( scriptRun1007 );
+ scriptRuns10.PushBack( scriptRun1008 );
+ scriptRuns10.PushBack( scriptRun1009 );
+ scriptRuns10.PushBack( scriptRun1010 );
+
+ // Paragraphs with no scripts mixed with paragraphs with scripts.
+ Vector<ScriptRun> scriptRuns11;
+ ScriptRun scriptRun1100 =
+ {
+ 0u,
+ 31u,
+ TextAbstraction::LATIN
+ };
+ ScriptRun scriptRun1101 =
+ {
+ 31u,
+ 21u,
+ TextAbstraction::HEBREW
+ };
+ scriptRuns11.PushBack( scriptRun1100 );
+ scriptRuns11.PushBack( scriptRun1101 );
+
+ // Paragraphs with no scripts.
+ Vector<ScriptRun> scriptRuns12;
+ ScriptRun scriptRun1200 =
+ {
+ 0u,
+ 11u,
+ TextAbstraction::LATIN
+ };
+ scriptRuns12.PushBack( scriptRun1200 );
+
const ScriptsData data[] =
{
{
"Hello world",
scriptRuns01,
},
+ {
+ "Mix of LTR '\\n'and RTL",
+ "Hello world\nمرحبا بالعالم",
+ scriptRuns02,
+ },
+ {
+ "Mix of RTL '\\n'and LTR",
+ "مرحبا بالعالم\nHello world",
+ scriptRuns03,
+ },
+ {
+ "White spaces. At the beginning of the text.",
+ " Hello world.",
+ scriptRuns04,
+ },
+ {
+ "White spaces. At the end of the text.",
+ "Hello world. ",
+ scriptRuns05,
+ },
+ {
+ "White spaces. At the middle of the text.",
+ "Hello world.",
+ scriptRuns06,
+ },
+ {
+ "White spaces between different scripts.",
+ " Hel 세계 ",
+ scriptRuns07,
+ },
+ {
+ "White spaces between different scripts and differetn directions. Starting LTR.",
+ " Hello world مرحبا بالعالم 안녕하세요 세계 ",
+ scriptRuns08,
+ },
+ {
+ "White spaces between different scripts and differetn directions. Starting RTL.",
+ " مرحبا بالعالم Hello world 안녕하세요 세계 مرحبا بالعالم ",
+ scriptRuns09
+ },
+ {
+ "Paragraphs with different directions.",
+ " مرحبا بالعالم שלום עולם مرحبا بالعالم \n "
+ " Hello world 안녕하세요 세계 \n "
+ " مرحبا بالعالم Hello world שלום עולם \n "
+ " Hello world مرحبا بالعالم 안녕하세요 세계 \n "
+ " 안녕하세요 세계 ",
+ scriptRuns10
+ },
+ {
+ "Paragraphs with no scripts mixed with paragraphs with scripts.",
+ " \n \n Hello world \n \n \n שלום עולם \n \n \n ",
+ scriptRuns11
+ },
+ {
+ "Paragraphs with no scripts.",
+ " \n \n \n ",
+ scriptRuns12
+ }
};
- const unsigned int numberOfTests = 2u;
+ const unsigned int numberOfTests = 13u;
for( unsigned int index = 0u; index < numberOfTests; ++index )
{
}
bool GetMirroredText( const Vector<Character>& text,
- Vector<Character>& mirroredText )
+ Vector<Character>& mirroredText,
+ const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo )
{
+ bool hasTextMirrored = false;
+
// Handle to the bidirectional info module in text-abstraction.
TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
mirroredText = text;
- return bidirectionalSupport.GetMirroredText( mirroredText.Begin(),
- mirroredText.Count() );
+ Character* mirroredTextBuffer = mirroredText.Begin();
+
+ // Traverse the paragraphs and mirror the right to left ones.
+ for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalInfo.Begin(),
+ endIt = bidirectionalInfo.End();
+ it != endIt;
+ ++it )
+ {
+ const BidirectionalParagraphInfoRun& run = *it;
+
+ const bool tmpMirrored = bidirectionalSupport.GetMirroredText( mirroredTextBuffer + run.characterRun.characterIndex,
+ run.characterRun.numberOfCharacters );
+
+ hasTextMirrored = hasTextMirrored || tmpMirrored;
+ }
+
+ return hasTextMirrored;
}
void GetCharactersDirection( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
Vector<BidirectionalLineInfoRun>& lineInfoRuns );
/**
- * @brief Replaces any character which could be mirrored.
+ * @brief Replaces any character in the right to left paragraphs which could be mirrored.
*
* @param[in] text The text.
* @param[in] mirroredText The mirroredText.
+ * @param[in] bidirectionalInfo Vector with the bidirectional infor for each paragraph.
*
* @return @e true if a character has been replaced.
*/
bool GetMirroredText( const Vector<Character>& text,
- Vector<Character>& mirroredText );
+ Vector<Character>& mirroredText,
+ const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo );
/**
* @brief Retrieves the character's directions.
lineRun.numberOfGlyphs = layout.numberOfGlyphs;
lineRun.characterRun.characterIndex = layout.characterIndex;
lineRun.characterRun.numberOfCharacters = layout.numberOfCharacters;
- if( isLastLine )
+ if( isLastLine && !layoutParameters.isLastNewParagraph )
{
const float width = layout.extraBearing + layout.length + layout.extraWidth + layout.wsLengthEndOfLine;
if( MULTI_LINE_BOX == mLayout )
// Increase the glyph index.
index += layout.numberOfGlyphs;
+
+ if( isLastLine &&
+ layoutParameters.isLastNewParagraph &&
+ ( mLayout == MULTI_LINE_BOX ) )
+ {
+ // Need to add a new line with no characters but with height to increase the actualSize.height
+ const GlyphInfo& glyphInfo = *( layoutParameters.glyphsBuffer + layoutParameters.totalNumberOfGlyphs - 1u );
+
+ Text::FontMetrics fontMetrics;
+ mFontClient.GetFontMetrics( glyphInfo.fontId, fontMetrics );
+
+ LineRun lineRun;
+ lineRun.glyphIndex = 0u;
+ lineRun.numberOfGlyphs = 0u;
+ lineRun.characterRun.characterIndex = 0u;
+ lineRun.characterRun.numberOfCharacters = 0u;
+ lineRun.width = 0.f;
+ lineRun.ascender = fontMetrics.ascender;
+ lineRun.descender = fontMetrics.descender;
+ lineRun.extraLength = 0.f;
+ lineRun.alignmentOffset = 0.f;
+ lineRun.direction = !RTL;
+ lineRun.ellipsis = false;
+
+ actualSize.height += ( lineRun.ascender + -lineRun.descender );
+
+ lines.PushBack( lineRun );
+ }
}
- }
+ } // end for() traversing glyphs.
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--LayoutText\n\n" );
charactersToGlyphsBuffer( NULL ),
glyphsPerCharacterBuffer( NULL ),
lineBidirectionalInfoRunsBuffer( NULL ),
- numberOfBidirectionalInfoRuns( 0u )
+ numberOfBidirectionalInfoRuns( 0u ),
+ isLastNewParagraph( false )
{}
Vector2 boundingBox;
Length* glyphsPerCharacterBuffer; ///< The number of glyphs per character.
BidirectionalLineInfoRun* lineBidirectionalInfoRunsBuffer; ///< Bidirectional conversion tables per line.
Length numberOfBidirectionalInfoRuns; ///< The number of lines with bidirectional info.
+ bool isLastNewParagraph; ///< Whether the last character is a new paragraph character.
};
} // namespace Text
}
void MultilanguageSupport::SetScripts( const Vector<Character>& text,
- const Vector<LineBreakInfo>& lineBreakInfo,
Vector<ScriptRun>& scripts )
{
const Length numberOfCharacters = text.Count();
// Reserve some space to reduce the number of reallocations.
scripts.Reserve( numberOfCharacters << 2u );
- // Whether the first valid script need to be set.
- bool firstValidScript = true;
+ // Whether the first valid script needs to be set.
+ bool isFirstScriptToBeSet = true;
// Whether the first valid script is a right to left script.
bool isParagraphRTL = false;
Length numberOfAllScriptCharacters = 0u;
// Pointers to the text and break info buffers.
- const Character* textBuffer = text.Begin();
- const LineBreakInfo* breakInfoBuffer = lineBreakInfo.Begin();
+ const Character* const textBuffer = text.Begin();
// Traverse all characters and set the scripts.
for( Length index = 0u; index < numberOfCharacters; ++index )
{
Character character = *( textBuffer + index );
- LineBreakInfo breakInfo = *( breakInfoBuffer + index );
+
+ // Get the script of the character.
+ Script script = TextAbstraction::GetCharacterScript( character );
// Some characters (like white spaces) are valid for many scripts. The rules to set a script
// for them are:
// Skip those characters valid for many scripts like white spaces or '\n'.
bool endOfText = index == numberOfCharacters;
while( !endOfText &&
- TextAbstraction::IsCommonScript( character ) )
+ ( TextAbstraction::COMMON == script ) )
{
// Count all these characters to be added into a script.
++numberOfAllScriptCharacters;
- if( TextAbstraction::LINE_MUST_BREAK == breakInfo )
+ if( TextAbstraction::IsNewParagraph( character ) )
{
- // The next character is a new paragraph.
- // Know when there is a new paragraph is needed because if there is a white space
+ // The character is a new paragraph.
+ // To know when there is a new paragraph is needed because if there is a white space
// between two scripts with different directions, it is added to the script with
// the same direction than the first script of the paragraph.
- firstValidScript = true;
- isParagraphRTL = false;
+ isFirstScriptToBeSet = true;
+
+ // Characters common to all scripts at the end of the paragraph are added to the last script (if the last one is not unknown).
+ if( TextAbstraction::UNKNOWN != currentScriptRun.script )
+ {
+ currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters;
+ numberOfAllScriptCharacters = 0u;
+ }
}
// Get the next character.
if( !endOfText )
{
character = *( textBuffer + index );
- breakInfo = *( breakInfoBuffer + index );
+ script = TextAbstraction::GetCharacterScript( character );
}
}
break;
}
- // Get the script of the character.
- Script script = TextAbstraction::GetCharacterScript( character );
-
// Check if it is the first character of a paragraph.
- if( firstValidScript &&
- ( TextAbstraction::UNKNOWN != script ) )
+ if( isFirstScriptToBeSet &&
+ ( TextAbstraction::UNKNOWN != script ) &&
+ ( TextAbstraction::COMMON != script ) )
{
// Sets the direction of the first valid script.
isParagraphRTL = TextAbstraction::IsRightToLeftScript( script );
- firstValidScript = false;
+ isFirstScriptToBeSet = false;
}
- if( script != currentScriptRun.script )
+ if( ( script != currentScriptRun.script ) &&
+ ( TextAbstraction::COMMON != script ) )
{
// Current run needs to be stored and a new one initialized.
- if( isParagraphRTL != TextAbstraction::IsRightToLeftScript( script ) )
+ if( ( isParagraphRTL == TextAbstraction::IsRightToLeftScript( currentScriptRun.script ) ) &&
+ ( TextAbstraction::UNKNOWN != currentScriptRun.script ) )
{
- // Current script has different direction than the first script of the paragraph.
+ // Previous script has the same direction than the first script of the paragraph.
+ // All the previously skipped characters need to be added to the previous script before it's stored.
+ currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters;
+ numberOfAllScriptCharacters = 0u;
+ }
+ else if( ( TextAbstraction::IsRightToLeftScript( currentScriptRun.script ) == TextAbstraction::IsRightToLeftScript( script ) ) &&
+ ( TextAbstraction::UNKNOWN != currentScriptRun.script ) )
+ {
+ // Current script and previous one have the same direction.
// All the previously skipped characters need to be added to the previous script before it's stored.
currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters;
numberOfAllScriptCharacters = 0u;
// Initialize the new one.
currentScriptRun.characterRun.characterIndex = currentScriptRun.characterRun.characterIndex + currentScriptRun.characterRun.numberOfCharacters;
- currentScriptRun.characterRun.numberOfCharacters = numberOfAllScriptCharacters; // Adds the white spaces which are at the begining of the script.
+ currentScriptRun.characterRun.numberOfCharacters = numberOfAllScriptCharacters + 1u; // Adds the white spaces which are at the begining of the script.
currentScriptRun.script = script;
numberOfAllScriptCharacters = 0u;
}
else
{
- // Adds white spaces between characters.
- currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters;
- numberOfAllScriptCharacters = 0u;
- }
+ if( TextAbstraction::UNKNOWN != currentScriptRun.script )
+ {
+ // Adds white spaces between characters.
+ currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters;
+ numberOfAllScriptCharacters = 0u;
- if( TextAbstraction::LINE_MUST_BREAK == breakInfo )
- {
- // The next character is a new paragraph.
- firstValidScript = true;
- isParagraphRTL = false;
+ // Add one more character to the run.
+ ++currentScriptRun.characterRun.numberOfCharacters;
+ }
}
-
- // Add one more character to the run.
- ++currentScriptRun.characterRun.numberOfCharacters;
}
// Add remaining characters into the last script.
* @copydoc Dali::MultilanguageSupport::SetScripts()
*/
void SetScripts( const Vector<Character>& text,
- const Vector<LineBreakInfo>& lineBreakInfo,
Vector<ScriptRun>& scripts );
/**
}
void MultilanguageSupport::SetScripts( const Vector<Character>& text,
- const Vector<LineBreakInfo>& lineBreakInfo,
Vector<ScriptRun>& scripts )
{
GetImplementation( *this ).SetScripts( text,
- lineBreakInfo,
scripts );
}
* script of the first character of the paragraph with a defined script.
*
* @param[in] text Vector of UTF-32 characters.
- * @param[in] lineBreakInfo Vector with the line break info.
* @param[out] scripts Vector containing the script runs for the whole text.
*/
void SetScripts( const Vector<Character>& text,
- const Vector<LineBreakInfo>& lineBreakInfo,
Vector<ScriptRun>& scripts );
/**
const Vector<FontRun>& fonts,
Vector<GlyphInfo>& glyphs,
Vector<CharacterIndex>& glyphToCharacterMap,
- Vector<Length>& charactersPerGlyph )
+ Vector<Length>& charactersPerGlyph,
+ Vector<GlyphIndex>& newParagraphGlyphs )
{
const Length numberOfCharacters = text.Count();
// The text needs to be split in chunks of consecutive characters.
// Each chunk must contain characters with the same font id and script set.
- // A chunk of consecutive characters must not contain a LINE_MUST_BREAK, if there is one a new chunk have to be created.
+ // A chunk of consecutive characters must not contain a LINE_MUST_BREAK, if there is one a new chunk has to be created.
TextAbstraction::Shaping shaping = TextAbstraction::Shaping::Get();
// The actual number of glyphs.
Length totalNumberOfGlyphs = 0u;
- const Character* textBuffer = text.Begin();
- const LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
+ const Character* const textBuffer = text.Begin();
+ const LineBreakInfo* const lineBreakInfoBuffer = lineBreakInfo.Begin();
GlyphInfo* glyphsBuffer = glyphs.Begin();
CharacterIndex* glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
// Check if there is a line must break.
bool mustBreak = false;
+
+ // Check if the current index is a new paragraph character.
+ // A new paragraph character is going to be shaped in order to not to mess the conversion tables.
+ // However, the metrics need to be changed in order to not to draw a square.
+ bool isNewParagraph = false;
+
for( CharacterIndex index = previousIndex; index < currentIndex; ++index )
{
mustBreak = TextAbstraction::LINE_MUST_BREAK == *( lineBreakInfoBuffer + index );
if( mustBreak )
{
- currentIndex = index;
+ isNewParagraph = TextAbstraction::IsNewParagraph( *( textBuffer + index ) );
+ currentIndex = index + 1u;
break;
}
}
- // Check if the current index is a new paragraph character.
- // A \n is going to be shaped in order to not to mess the conversion tables.
- // After the \n character is shaped, the glyph is going to be reset to its
- // default in order to not to get any metric or font index for it.
- const bool isNewParagraph = TextAbstraction::IsNewParagraph( *( textBuffer + currentIndex ) );
-
- // The last character is always a must-break even if it's not a \n.
- Length numberOfCharactersToShape = currentIndex - previousIndex;
- if( mustBreak )
- {
- // Add one more character to shape.
- ++numberOfCharactersToShape;
- }
-
// Shape the text for the current chunk.
const Length numberOfGlyphs = shaping.Shape( textBuffer + previousIndex,
- numberOfCharactersToShape,
+ ( currentIndex - previousIndex ), // The number of characters to shape.
currentFontId,
currentScript );
if( isNewParagraph )
{
- // TODO : This is a work around to avoid drawing a square in the
- // place of a new line character.
-
- // If the last character is a \n, it resets the glyph to the default
- // to avoid getting any metric for it.
- GlyphInfo& glyph = *( glyphsBuffer + glyphIndex + ( numberOfGlyphs - 1u ) );
-
- glyph = GlyphInfo();
+ // Add the index of the new paragraph glyph to a vector.
+ // Their metrics will be updated in a following step.
+ newParagraphGlyphs.PushBack( totalNumberOfGlyphs - 1u );
}
// Update indices.
++scriptRunIt;
}
- // Update the previous index. Jumps the \n if needed.
- previousIndex = mustBreak ? currentIndex + 1u : currentIndex;
+ // Update the previous index.
+ previousIndex = currentIndex;
}
// Add the number of characters per glyph.
* @param[out] glyphs Vector of glyphs in the visual order.
* @param[out] glyphToCharacterMap Vector containing the first character in the logical model that each glyph relates to.
* @param[out] charactersPerGlyph Vector containing the number of characters per glyph.
+ * @param[out] newParagraphGlyphs Vector containing the indices to the new paragraph glyphs.
*/
void ShapeText( const Vector<Character>& text,
const Vector<LineBreakInfo>& lineBreakInfo,
const Vector<FontRun>& fonts,
Vector<GlyphInfo>& glyphs,
Vector<CharacterIndex>& glyphToCharacterMap,
- Vector<Length>& charactersPerGlyph );
+ Vector<Length>& charactersPerGlyph,
+ Vector<GlyphIndex>& newParagraphGlyphs );
} // namespace Text
{
// Retrieves the scripts used in the text.
multilanguageSupport.SetScripts( utf32Characters,
- lineBreakInfo,
scripts );
}
Vector<Character> mirroredUtf32Characters;
bool textMirrored = false;
+ Length numberOfParagraphs = 0u;
if( BIDI_INFO & operations )
{
// 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 < numberOfCharacters; ++index )
{
// This paragraph has right to left text. Some characters may need to be mirrored.
// TODO: consider if the mirrored string can be stored as well.
- textMirrored = GetMirroredText( utf32Characters, mirroredUtf32Characters );
+ textMirrored = GetMirroredText( utf32Characters,
+ mirroredUtf32Characters,
+ bidirectionalInfo );
// Only set the character directions if there is right to left characters.
Vector<CharacterDirection>& directions = mLogicalModel->mCharacterDirections;
Vector<GlyphInfo>& glyphs = mVisualModel->mGlyphs;
Vector<CharacterIndex>& glyphsToCharactersMap = mVisualModel->mGlyphsToCharacters;
Vector<Length>& charactersPerGlyph = mVisualModel->mCharactersPerGlyph;
+ Vector<GlyphIndex> newParagraphGlyphs;
+ newParagraphGlyphs.Reserve( numberOfParagraphs );
+
if( SHAPE_TEXT & operations )
{
const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
validFonts,
glyphs,
glyphsToCharactersMap,
- charactersPerGlyph );
+ charactersPerGlyph,
+ newParagraphGlyphs );
// Create the 'number of glyphs' per character and the glyph to character conversion tables.
mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
if( GET_GLYPH_METRICS & operations )
{
- mFontClient.GetGlyphMetrics( glyphs.Begin(), numberOfGlyphs );
+ GlyphInfo* glyphsBuffer = glyphs.Begin();
+ mFontClient.GetGlyphMetrics( glyphsBuffer, numberOfGlyphs );
+
+ // Update the width and advance of all new paragraph characters.
+ for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it )
+ {
+ const GlyphIndex index = *it;
+ GlyphInfo& glyph = *( glyphsBuffer + index );
+
+ glyph.xBearing = 0.f;
+ glyph.width = 0.f;
+ glyph.advance = 0.f;
+ }
}
}
// after the first time the text has been laid out.
// Fill the vectors again.
- Length numberOfGlyphs = mImpl->mVisualModel->mGlyphs.Count();
+ const Length numberOfGlyphs = mImpl->mVisualModel->mGlyphs.Count();
if( 0u == numberOfGlyphs )
{
return true;
}
- Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
- Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
- Vector<CharacterDirection>& characterDirection = mImpl->mLogicalModel->mCharacterDirections;
- Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
- Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
- Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
+ const Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
+ const Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
+ const Vector<CharacterDirection>& characterDirection = mImpl->mLogicalModel->mCharacterDirections;
+ const Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
+ const Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
+ const Vector<Length>& charactersPerGlyph = mImpl->mVisualModel->mCharactersPerGlyph;
+ const Character* const textBuffer = mImpl->mLogicalModel->mText.Begin();
// Set the layout parameters.
LayoutParameters layoutParameters( size,
- mImpl->mLogicalModel->mText.Begin(),
+ textBuffer,
lineBreakInfo.Begin(),
wordBreakInfo.Begin(),
( 0u != characterDirection.Count() ) ? characterDirection.Begin() : NULL,
Vector<Vector2>& glyphPositions = mImpl->mVisualModel->mGlyphPositions;
glyphPositions.Resize( numberOfGlyphs );
+ // Whether the last character is a new paragraph character.
+ layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mLogicalModel->mText.Count() - 1u ) ) );
+
// Update the visual model.
viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
glyphPositions,
// Set the alignment.
mImpl->mLayoutEngine.SetVerticalAlignment( alignment );
- // Set the flag to redo the alignment operation.
- // TODO : Is not needed re-layout and reorder again but with the current implementation it is.
- // Im working on a different patch to fix an issue with the alignment. When that patch
- // is in, this issue can be fixed.
- const OperationsMask layoutOperations = static_cast<OperationsMask>( LAYOUT |
- UPDATE_ACTUAL_SIZE |
- ALIGN |
- REORDER );
-
- mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | layoutOperations );
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
mImpl->RequestRelayout();
}