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/public-api/text/shaper.h>
22 #include <dali/public-api/text-abstraction/shaping.h>
23 #include <dali-toolkit/public-api/text/font-run.h>
24 #include <dali-toolkit/public-api/text/logical-model.h>
25 #include <dali-toolkit/public-api/text/script-run.h>
26 #include <dali-toolkit/public-api/text/visual-model.h>
37 CharacterIndex min( CharacterIndex index0,
38 CharacterIndex index1 )
40 return ( index0 < index1 ) ? index0 : index1;
43 void ShapeText( const Vector<Character>& text,
44 const Vector<LineBreakInfo>& lineBreakInfo,
45 const Vector<ScriptRun>& scripts,
46 const Vector<FontRun>& fonts,
47 Vector<GlyphInfo>& glyphs,
48 Vector<CharacterIndex>& characterIndices,
49 Vector<Length>& charactersPerGlyph )
51 const Length numberOfCharacters = text.Count();
53 if( 0u == numberOfCharacters )
55 // Nothing to do if there are no characters.
59 const Length numberOfFontRuns = fonts.Count();
61 DALI_ASSERT_DEBUG( ( 0u != numberOfFontRuns ) &&
62 ( numberOfCharacters == fonts[numberOfFontRuns - 1u].characterRun.characterIndex + fonts[numberOfFontRuns - 1u].characterRun.numberOfCharacters ) &&
63 "Toolkit::Text::ShapeText. All characters must have a font set." );
65 const Length numberOfScriptRuns = scripts.Count();
67 DALI_ASSERT_DEBUG( ( 0u != numberOfScriptRuns ) &&
68 ( numberOfCharacters == scripts[numberOfScriptRuns - 1u].characterRun.characterIndex + scripts[numberOfScriptRuns - 1u].characterRun.numberOfCharacters ) &&
69 "Toolkit::Text::ShapeText. All characters must have a script set." );
71 // The text needs to be split in chunks of consecutive characters.
72 // Each chunk must contain characters with the same font id and script set.
73 // A chunk of consecutive characters must not contain a LINE_MUST_BREAK, if there is one a new chunk have to be created.
75 TextAbstraction::Shaping shaping = TextAbstraction::Shaping::Get();
77 // To shape the text a font and an script is needed.
78 Vector<FontRun>::ConstIterator fontRunIt = fonts.Begin();
79 Vector<ScriptRun>::ConstIterator scriptRunIt = scripts.Begin();
81 // The line must break token converted to LineBreakInfo to be compared and avoid a compile error.
82 const LineBreakInfo MUST_BREAK = static_cast<LineBreakInfo>( TextAbstraction::LINE_MUST_BREAK );
84 // Index to the the next one to be shaped. Is pointing the character after the last one it was shaped.
85 CharacterIndex previousIndex = 0u;
87 // The current font id and script used to shape the text.
88 FontId currentFontId = 0u;
89 Script currentScript = TextAbstraction::UNKNOWN;
91 // Reserve some space to allocate the glyphs and the glyph to character map.
92 // There is no way to know the number of glyphs before shaping the text.
93 // To avoid reallocations it's reserved space for a slightly biger number of glyphs than the number of characters.
95 Length numberOfGlyphsReserved = static_cast<Length>( numberOfCharacters * 1.3f );
96 glyphs.Resize( numberOfGlyphsReserved );
97 charactersPerGlyph.Resize( numberOfGlyphsReserved );
99 // The actual number of glyphs.
100 Length totalNumberOfGlyphs = 0u;
102 // Traverse the characters and shape the text.
103 for( previousIndex = 0; previousIndex < numberOfCharacters; )
105 // Get the font id and the script.
106 const FontRun& fontRun = *fontRunIt;
107 const ScriptRun& scriptRun = *scriptRunIt;
109 currentFontId = fontRun.fontId;
110 currentScript = scriptRun.script;
112 // Get the min index to the last character of both runs.
113 CharacterIndex currentIndex = min( fontRun.characterRun.characterIndex + fontRun.characterRun.numberOfCharacters,
114 scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters );
116 // Check if there is a line must break.
117 for( CharacterIndex index = previousIndex; index < currentIndex; ++index )
119 if( MUST_BREAK == lineBreakInfo.Begin() + index )
121 currentIndex = index;
126 // Shape the text for the current chunk.
127 const Length numberOfGlyphs = shaping.Shape( text.Begin() + previousIndex,
128 currentIndex - previousIndex,
132 const Length glyphIndex = totalNumberOfGlyphs;
133 totalNumberOfGlyphs += numberOfGlyphs;
135 if( totalNumberOfGlyphs > numberOfGlyphsReserved )
137 // Resize the vectors to get enough space.
138 numberOfGlyphsReserved = static_cast<Length>( totalNumberOfGlyphs * 1.3f );
139 glyphs.Resize( numberOfGlyphsReserved );
140 charactersPerGlyph.Resize( numberOfGlyphsReserved );
143 // Retrieve the glyphs and the glyph to character conversion map.
144 shaping.GetGlyphs( glyphs.Begin() + glyphIndex,
145 charactersPerGlyph.Begin() + glyphIndex );
147 // Update the iterators to get the next font or script run.
148 if( currentIndex == fontRun.characterRun.characterIndex + fontRun.characterRun.numberOfCharacters )
152 if( currentIndex == scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters )
157 // Update the previous index.
158 previousIndex = currentIndex;
161 characterIndices.Reserve( totalNumberOfGlyphs );
162 CharacterIndex characterIndex = 0u;
163 characterIndices.PushBack( characterIndex );
164 for( Length index = 0u, length = totalNumberOfGlyphs - 1u; index < length; ++index )
166 characterIndex += *( charactersPerGlyph.Begin() + index );
167 characterIndices.PushBack( characterIndex );
170 // Resize the vectors to set the right number of items.
171 glyphs.Resize( totalNumberOfGlyphs );
172 // characterIndices.Resize( totalNumberOfGlyphs );
173 charactersPerGlyph.Resize( totalNumberOfGlyphs );
178 } // namespace Toolkit