Reposition the grab/selection handles position.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / shaper.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/text/shaper.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/text-abstraction/shaping.h>
23
24 namespace Dali
25 {
26
27 namespace Toolkit
28 {
29
30 namespace Text
31 {
32
33 CharacterIndex min( CharacterIndex index0,
34                     CharacterIndex index1 )
35 {
36   return ( index0 < index1 ) ? index0 : index1;
37 }
38
39 void ShapeText( const Vector<Character>& text,
40                 const Vector<LineBreakInfo>& lineBreakInfo,
41                 const Vector<ScriptRun>& scripts,
42                 const Vector<FontRun>& fonts,
43                 Vector<GlyphInfo>& glyphs,
44                 Vector<CharacterIndex>& glyphToCharacterMap,
45                 Vector<Length>& charactersPerGlyph,
46                 Vector<GlyphIndex>& newParagraphGlyphs )
47 {
48   const Length numberOfCharacters = text.Count();
49
50   if( 0u == numberOfCharacters )
51   {
52     // Nothing to do if there are no characters.
53     return;
54   }
55
56 #ifdef DEBUG_ENABLED
57   const Length numberOfFontRuns = fonts.Count();
58   const Length numberOfScriptRuns = scripts.Count();
59 #endif
60
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." );
64
65   DALI_ASSERT_DEBUG( ( 0u != numberOfScriptRuns ) &&
66                      ( numberOfCharacters == scripts[numberOfScriptRuns - 1u].characterRun.characterIndex + scripts[numberOfScriptRuns - 1u].characterRun.numberOfCharacters ) &&
67                      "Toolkit::Text::ShapeText. All characters must have a script set." );
68
69   // The text needs to be split in chunks of consecutive characters.
70   // Each chunk must contain characters with the same font id and script set.
71   // A chunk of consecutive characters must not contain a LINE_MUST_BREAK, if there is one a new chunk has to be created.
72
73   TextAbstraction::Shaping shaping = TextAbstraction::Shaping::Get();
74
75   // To shape the text a font and an script is needed.
76   Vector<FontRun>::ConstIterator fontRunIt = fonts.Begin();
77   Vector<ScriptRun>::ConstIterator scriptRunIt = scripts.Begin();
78
79   // Index to the the next one to be shaped. Is pointing the character after the last one it was shaped.
80   CharacterIndex previousIndex = 0u;
81
82   // The current font id and script used to shape the text.
83   FontId currentFontId = 0u;
84   Script currentScript = TextAbstraction::UNKNOWN;
85
86   // Reserve some space to allocate the glyphs and the glyph to character map.
87   // There is no way to know the number of glyphs before shaping the text.
88   // To avoid reallocations it's reserved space for a slightly biger number of glyphs than the number of characters.
89
90   Length numberOfGlyphsReserved = static_cast<Length>( numberOfCharacters * 1.3f );
91   glyphs.Resize( numberOfGlyphsReserved );
92   glyphToCharacterMap.Resize( numberOfGlyphsReserved );
93
94   // The actual number of glyphs.
95   Length totalNumberOfGlyphs = 0u;
96
97   const Character* const textBuffer = text.Begin();
98   const LineBreakInfo* const lineBreakInfoBuffer = lineBreakInfo.Begin();
99   GlyphInfo* glyphsBuffer = glyphs.Begin();
100   CharacterIndex* glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
101
102   // Traverse the characters and shape the text.
103   for( previousIndex = 0; previousIndex < numberOfCharacters; )
104   {
105     // Get the font id and the script.
106     const FontRun& fontRun = *fontRunIt;
107     const ScriptRun& scriptRun = *scriptRunIt;
108
109     currentFontId = fontRun.fontId;
110     currentScript = scriptRun.script;
111
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 );
115
116     // Check if there is a line must break.
117     bool mustBreak = false;
118
119     // Check if the current index is a new paragraph character.
120     // A new paragraph character is going to be shaped in order to not to mess the conversion tables.
121     // However, the metrics need to be changed in order to not to draw a square.
122     bool isNewParagraph = false;
123
124     for( CharacterIndex index = previousIndex; index < currentIndex; ++index )
125     {
126       mustBreak = TextAbstraction::LINE_MUST_BREAK == *( lineBreakInfoBuffer + index );
127       if( mustBreak )
128       {
129         isNewParagraph = TextAbstraction::IsNewParagraph( *( textBuffer + index ) );
130         currentIndex = index + 1u;
131         break;
132       }
133     }
134
135     // Shape the text for the current chunk.
136     const Length numberOfGlyphs = shaping.Shape( textBuffer + previousIndex,
137                                                  ( currentIndex - previousIndex ), // The number of characters to shape.
138                                                  currentFontId,
139                                                  currentScript );
140
141     const Length glyphIndex = totalNumberOfGlyphs;
142     totalNumberOfGlyphs += numberOfGlyphs;
143
144     if( totalNumberOfGlyphs > numberOfGlyphsReserved )
145     {
146       // Resize the vectors to get enough space.
147       numberOfGlyphsReserved = static_cast<Length>( totalNumberOfGlyphs * 1.3f );
148       glyphs.Resize( numberOfGlyphsReserved );
149       glyphToCharacterMap.Resize( numberOfGlyphsReserved );
150
151       // Iterators are not valid anymore, set them again.
152       glyphsBuffer = glyphs.Begin();
153       glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
154     }
155
156     // Retrieve the glyphs and the glyph to character conversion map.
157     shaping.GetGlyphs( glyphsBuffer + glyphIndex,
158                        glyphToCharacterMapBuffer + glyphIndex );
159
160     if( isNewParagraph )
161     {
162       // Add the index of the new paragraph glyph to a vector.
163       // Their metrics will be updated in a following step.
164       newParagraphGlyphs.PushBack( totalNumberOfGlyphs - 1u );
165     }
166
167     // Update indices.
168     if( 0u != glyphIndex )
169     {
170       for( Length index = glyphIndex; index < glyphIndex + numberOfGlyphs; ++index )
171       {
172         CharacterIndex& characterIndex = *( glyphToCharacterMapBuffer + index );
173         characterIndex += previousIndex;
174       }
175     }
176
177     // Update the iterators to get the next font or script run.
178     if( currentIndex == fontRun.characterRun.characterIndex + fontRun.characterRun.numberOfCharacters )
179     {
180       ++fontRunIt;
181     }
182     if( currentIndex == scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters )
183     {
184       ++scriptRunIt;
185     }
186
187     // Update the previous index.
188     previousIndex = currentIndex;
189   }
190
191   // Add the number of characters per glyph.
192   charactersPerGlyph.Reserve( totalNumberOfGlyphs );
193   previousIndex = 0u;
194   for( Length index = 1u; index < totalNumberOfGlyphs; ++index )
195   {
196     const CharacterIndex characterIndex = *( glyphToCharacterMapBuffer + index );
197
198     charactersPerGlyph.PushBack( characterIndex - previousIndex );
199
200     previousIndex = characterIndex;
201   }
202
203   charactersPerGlyph.PushBack( numberOfCharacters - previousIndex );
204
205   // Resize the vectors to set the right number of items.
206   glyphs.Resize( totalNumberOfGlyphs );
207   glyphToCharacterMap.Resize( totalNumberOfGlyphs );
208 }
209
210 } // namespace Text
211
212 } // namespace Toolkit
213
214 } // namespace Dali