7ef076f8ff9035e4e6d973c384e726e0c2c7bfac
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / public-api / 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/public-api/text/shaper.h>
20
21 // INTERNAL INCLUDES
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>
27
28 namespace Dali
29 {
30
31 namespace Toolkit
32 {
33
34 namespace Text
35 {
36
37 CharacterIndex min( CharacterIndex index0,
38                     CharacterIndex index1 )
39 {
40   return ( index0 < index1 ) ? index0 : index1;
41 }
42
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 )
50 {
51   const Length numberOfCharacters = text.Count();
52
53   if( 0u == numberOfCharacters )
54   {
55     // Nothing to do if there are no characters.
56     return;
57   }
58
59 #ifdef DEBUG_ENABLED
60   const Length numberOfFontRuns = fonts.Count();
61   const Length numberOfScriptRuns = scripts.Count();
62 #endif
63
64   DALI_ASSERT_DEBUG( ( 0u != numberOfFontRuns ) &&
65                      ( numberOfCharacters == fonts[numberOfFontRuns - 1u].characterRun.characterIndex + fonts[numberOfFontRuns - 1u].characterRun.numberOfCharacters ) &&
66                      "Toolkit::Text::ShapeText. All characters must have a font set." );
67
68   DALI_ASSERT_DEBUG( ( 0u != numberOfScriptRuns ) &&
69                      ( numberOfCharacters == scripts[numberOfScriptRuns - 1u].characterRun.characterIndex + scripts[numberOfScriptRuns - 1u].characterRun.numberOfCharacters ) &&
70                      "Toolkit::Text::ShapeText. All characters must have a script set." );
71
72   // The text needs to be split in chunks of consecutive characters.
73   // Each chunk must contain characters with the same font id and script set.
74   // A chunk of consecutive characters must not contain a LINE_MUST_BREAK, if there is one a new chunk have to be created.
75
76   TextAbstraction::Shaping shaping = TextAbstraction::Shaping::Get();
77
78   // To shape the text a font and an script is needed.
79   Vector<FontRun>::ConstIterator fontRunIt = fonts.Begin();
80   Vector<ScriptRun>::ConstIterator scriptRunIt = scripts.Begin();
81
82   // The line must break token converted to LineBreakInfo to be compared and avoid a compile error.
83   const LineBreakInfo MUST_BREAK = static_cast<LineBreakInfo>( TextAbstraction::LINE_MUST_BREAK );
84
85   // Index to the the next one to be shaped. Is pointing the character after the last one it was shaped.
86   CharacterIndex previousIndex = 0u;
87
88   // The current font id and script used to shape the text.
89   FontId currentFontId = 0u;
90   Script currentScript = TextAbstraction::UNKNOWN;
91
92   // Reserve some space to allocate the glyphs and the glyph to character map.
93   // There is no way to know the number of glyphs before shaping the text.
94   // To avoid reallocations it's reserved space for a slightly biger number of glyphs than the number of characters.
95
96   Length numberOfGlyphsReserved = static_cast<Length>( numberOfCharacters * 1.3f );
97   glyphs.Resize( numberOfGlyphsReserved );
98   charactersPerGlyph.Resize( numberOfGlyphsReserved );
99
100   // The actual number of glyphs.
101   Length totalNumberOfGlyphs = 0u;
102
103   // Traverse the characters and shape the text.
104   for( previousIndex = 0; previousIndex < numberOfCharacters; )
105   {
106     // Get the font id and the script.
107     const FontRun& fontRun = *fontRunIt;
108     const ScriptRun& scriptRun = *scriptRunIt;
109
110     currentFontId = fontRun.fontId;
111     currentScript = scriptRun.script;
112
113     // Get the min index to the last character of both runs.
114     CharacterIndex currentIndex = min( fontRun.characterRun.characterIndex + fontRun.characterRun.numberOfCharacters,
115                                        scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters );
116
117     // Check if there is a line must break.
118     for( CharacterIndex index = previousIndex; index < currentIndex; ++index )
119     {
120       if( MUST_BREAK == lineBreakInfo.Begin() + index )
121       {
122         currentIndex = index;
123         break;
124       }
125     }
126
127     // Shape the text for the current chunk.
128     const Length numberOfGlyphs = shaping.Shape( text.Begin() + previousIndex,
129                                                  currentIndex - previousIndex,
130                                                  currentFontId,
131                                                  currentScript );
132
133     const Length glyphIndex = totalNumberOfGlyphs;
134     totalNumberOfGlyphs += numberOfGlyphs;
135
136     if( totalNumberOfGlyphs > numberOfGlyphsReserved )
137     {
138       // Resize the vectors to get enough space.
139       numberOfGlyphsReserved = static_cast<Length>( totalNumberOfGlyphs * 1.3f );
140       glyphs.Resize( numberOfGlyphsReserved );
141       charactersPerGlyph.Resize( numberOfGlyphsReserved );
142     }
143
144     // Retrieve the glyphs and the glyph to character conversion map.
145     shaping.GetGlyphs( glyphs.Begin() + glyphIndex,
146                        charactersPerGlyph.Begin() + glyphIndex );
147
148     // Update the iterators to get the next font or script run.
149     if( currentIndex == fontRun.characterRun.characterIndex + fontRun.characterRun.numberOfCharacters )
150     {
151       ++fontRunIt;
152     }
153     if( currentIndex == scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters )
154     {
155       ++scriptRunIt;
156     }
157
158     // Update the previous index.
159     previousIndex = currentIndex;
160   }
161
162   characterIndices.Reserve( totalNumberOfGlyphs );
163   CharacterIndex characterIndex = 0u;
164   characterIndices.PushBack( characterIndex );
165   for( Length index = 0u, length = totalNumberOfGlyphs - 1u; index < length; ++index )
166   {
167     characterIndex += *( charactersPerGlyph.Begin() + index );
168     characterIndices.PushBack( characterIndex );
169   }
170
171   // Resize the vectors to set the right number of items.
172   glyphs.Resize( totalNumberOfGlyphs );
173   // characterIndices.Resize( totalNumberOfGlyphs );
174   charactersPerGlyph.Resize( totalNumberOfGlyphs );
175 }
176
177 } // namespace Text
178
179 } // namespace Toolkit
180
181 } // namespace Dali