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/internal/text/logical-model.h>
22 #include <dali-toolkit/internal/text/bidirectional-line-info-run.h>
23 #include <dali-toolkit/internal/text/bidirectional-paragraph-info-run.h>
24 #include <dali-toolkit/internal/text/font-run.h>
25 #include <dali-toolkit/internal/text/script-run.h>
39 * @brief caches some temporary values of the GetNumberOfScriptRuns( characterIndex, numberOfCharacters )
40 * operation and the GetNumberOfFontRuns( characterIndex, numberOfCharacters ) as they are going to be
41 * used in the GetScriptRuns() and the GetFontRuns() calls.
45 CharacterIndex characterIndex; ///< The character index.
46 Length numberOfCharacters; ///< The number of characters.
47 Length firstRun; ///< Index to the first run.
48 Length numberOfRuns; ///< The number of runs.
51 struct LogicalModel::Impl
53 Vector<Character> mText;
54 Vector<ScriptRun> mScriptRuns;
55 Vector<FontRun> mFontRuns;
56 Vector<LineBreakInfo> mLineBreakInfo;
57 Vector<WordBreakInfo> mWordBreakInfo;
59 GetRunCache mGetScriptCache; ///< Caches the GetNumberOfScriptRuns( characterIndex, numberOfCharacters ) operation.
60 GetRunCache mGetFontCache; ///< Caches the GetNumberOfFontRuns( characterIndex, numberOfCharacters ) operation.
63 LogicalModelPtr LogicalModel::New()
65 return LogicalModelPtr( new LogicalModel() );
68 void LogicalModel::SetText( const Character* const text,
69 Length numberOfCharacters )
71 Vector<Character>& modelText = mImpl->mText;
73 if( 0u == numberOfCharacters )
79 modelText.Resize( numberOfCharacters );
80 memcpy( modelText.Begin(), text, numberOfCharacters * sizeof( Character ) );
84 Length LogicalModel::GetNumberOfCharacters() const
86 return mImpl->mText.Count();
89 void LogicalModel::GetText( CharacterIndex characterIndex,
91 Length numberOfCharacters ) const
93 Vector<Character>& modelText = mImpl->mText;
94 memcpy( text, modelText.Begin() + characterIndex, numberOfCharacters * sizeof( Character ) );
97 Character LogicalModel::GetCharacter( CharacterIndex characterIndex ) const
99 return mImpl->mText[characterIndex];
102 void LogicalModel::SetScripts( const ScriptRun* const scripts,
103 Length numberOfRuns )
105 Vector<ScriptRun>& scriptRuns = mImpl->mScriptRuns;
107 if( 0u == numberOfRuns )
113 scriptRuns.Resize( numberOfRuns );
114 memcpy( scriptRuns.Begin(), scripts, numberOfRuns * sizeof( ScriptRun ) );
117 mImpl->mGetScriptCache.characterIndex = 0u;
118 mImpl->mGetScriptCache.numberOfCharacters = 0u;
119 mImpl->mGetScriptCache.firstRun = 0u;
120 mImpl->mGetScriptCache.numberOfRuns = 0u;
123 Length LogicalModel::GetNumberOfScriptRuns( CharacterIndex characterIndex,
124 Length numberOfCharacters ) const
126 GetRunCache& scriptCache = mImpl->mGetScriptCache;
128 // Set the character index and the number of characters into the cache.
129 scriptCache.characterIndex = characterIndex;
130 scriptCache.numberOfCharacters = numberOfCharacters;
132 if( ( 0u == characterIndex ) &&
133 ( mImpl->mText.Count() == numberOfCharacters ) )
135 scriptCache.firstRun = 0u;
136 scriptCache.numberOfRuns = mImpl->mScriptRuns.Count();
137 return scriptCache.numberOfRuns;
140 // Initialize the number of scripts and the index to the first script.
141 scriptCache.firstRun = 0u;
142 scriptCache.numberOfRuns = 0;
143 bool firstScriptFound = false;
145 const Vector<ScriptRun>& modelScripts = mImpl->mScriptRuns;
146 const CharacterIndex lastCharacterIndex = characterIndex + numberOfCharacters;
148 // Traverse the scripts and count those scripts within the range of characters.
149 for( Vector<ScriptRun>::ConstIterator it = modelScripts.Begin(),
150 endIt = modelScripts.End();
154 const ScriptRun& script = *it;
156 if( ( script.characterRun.characterIndex + script.characterRun.numberOfCharacters > characterIndex ) &&
157 ( lastCharacterIndex > script.characterRun.characterIndex ) )
159 firstScriptFound = true;
160 ++scriptCache.numberOfRuns;
162 else if( lastCharacterIndex <= script.characterRun.characterIndex )
164 // nothing else to do.
168 if( !firstScriptFound )
170 ++scriptCache.firstRun;
174 return scriptCache.numberOfRuns;
177 void LogicalModel::GetScriptRuns( ScriptRun* scriptRuns,
178 CharacterIndex characterIndex,
179 Length numberOfCharacters ) const
181 const Vector<ScriptRun>& modelScripts = mImpl->mScriptRuns;
182 GetRunCache& scriptCache = mImpl->mGetScriptCache;
184 if( ( characterIndex != scriptCache.characterIndex ) ||
185 ( numberOfCharacters != scriptCache.numberOfCharacters ) )
187 GetNumberOfScriptRuns( characterIndex,
188 numberOfCharacters );
191 memcpy( scriptRuns, modelScripts.Begin() + scriptCache.firstRun, scriptCache.numberOfRuns * sizeof( ScriptRun ) );
194 Script LogicalModel::GetScript( CharacterIndex characterIndex ) const
196 // If this operation is too slow, consider a binary search.
198 for( Length index = 0u, length = mImpl->mScriptRuns.Count(); index < length; ++index )
200 const ScriptRun* const scriptRun = mImpl->mScriptRuns.Begin() + index;
202 if( ( scriptRun->characterRun.characterIndex <= characterIndex ) &&
203 ( characterIndex < scriptRun->characterRun.characterIndex + scriptRun->characterRun.numberOfCharacters ) )
205 return scriptRun->script;
209 return TextAbstraction::UNKNOWN;
212 void LogicalModel::SetFonts( const FontRun* const fonts,
213 Length numberOfRuns )
215 Vector<FontRun>& fontRuns = mImpl->mFontRuns;
217 if( 0u == numberOfRuns )
223 fontRuns.Resize( numberOfRuns );
224 memcpy( fontRuns.Begin(), fonts, numberOfRuns * sizeof( FontRun ) );
227 mImpl->mGetFontCache.characterIndex = 0u;
228 mImpl->mGetFontCache.numberOfCharacters = 0u;
229 mImpl->mGetFontCache.firstRun = 0u;
230 mImpl->mGetFontCache.numberOfRuns = 0u;
233 Length LogicalModel::GetNumberOfFontRuns( CharacterIndex characterIndex,
234 Length numberOfCharacters ) const
236 GetRunCache& fontCache = mImpl->mGetFontCache;
238 // Set the character index and the number of characters into the cache.
239 fontCache.characterIndex = characterIndex;
240 fontCache.numberOfCharacters = numberOfCharacters;
242 if( ( 0u == characterIndex ) &&
243 ( mImpl->mText.Count() == numberOfCharacters ) )
245 fontCache.firstRun = 0u;
246 fontCache.numberOfRuns = mImpl->mFontRuns.Count();
247 return fontCache.numberOfRuns;
250 // Initialize the number of fonts and the index to the first font.
251 fontCache.firstRun = 0u;
252 fontCache.numberOfRuns = 0;
253 bool firstFontFound = false;
255 const Vector<FontRun>& modelFonts = mImpl->mFontRuns;
256 const CharacterIndex lastCharacterIndex = characterIndex + numberOfCharacters;
258 // Traverse the fonts and count those fonts within the range of characters.
259 for( Vector<FontRun>::ConstIterator it = modelFonts.Begin(),
260 endIt = modelFonts.End();
264 const FontRun& font = *it;
266 if( ( font.characterRun.characterIndex + font.characterRun.numberOfCharacters > characterIndex ) &&
267 ( characterIndex + numberOfCharacters > font.characterRun.characterIndex ) )
269 firstFontFound = true;
270 ++fontCache.numberOfRuns;
272 else if( lastCharacterIndex <= font.characterRun.characterIndex )
274 // nothing else to do.
278 if( !firstFontFound )
280 ++fontCache.firstRun;
284 return fontCache.numberOfRuns;
287 void LogicalModel::GetFontRuns( FontRun* fontRuns,
288 CharacterIndex characterIndex,
289 Length numberOfCharacters ) const
291 const Vector<FontRun>& modelFonts = mImpl->mFontRuns;
292 GetRunCache& fontCache = mImpl->mGetFontCache;
294 if( ( characterIndex != fontCache.characterIndex ) ||
295 ( numberOfCharacters != fontCache.numberOfCharacters ) )
297 GetNumberOfFontRuns( characterIndex,
298 numberOfCharacters );
301 memcpy( fontRuns, modelFonts.Begin() + fontCache.firstRun, fontCache.numberOfRuns * sizeof( FontRun ) );
304 FontId LogicalModel::GetFont( CharacterIndex characterIndex ) const
306 for( Length index = 0u, length = mImpl->mFontRuns.Count(); index < length; ++index )
308 const FontRun* const fontRun = mImpl->mFontRuns.Begin() + index;
310 if( ( fontRun->characterRun.characterIndex <= characterIndex ) &&
311 ( characterIndex < fontRun->characterRun.characterIndex + fontRun->characterRun.numberOfCharacters ) )
313 return fontRun->fontId;
320 void LogicalModel::SetLineBreakInfo( const LineBreakInfo* const lineBreakInfo,
323 Vector<LineBreakInfo>& modelLineBreakInfo = mImpl->mLineBreakInfo;
327 modelLineBreakInfo.Clear();
331 modelLineBreakInfo.Resize( length );
332 memcpy( modelLineBreakInfo.Begin(), lineBreakInfo, length * sizeof( LineBreakInfo ) );
336 void LogicalModel::GetLineBreakInfo( LineBreakInfo* lineBreakInfo,
337 CharacterIndex characterIndex,
338 Length numberOfItems ) const
340 memcpy( lineBreakInfo, mImpl->mLineBreakInfo.Begin() + characterIndex, numberOfItems * sizeof( LineBreakInfo ) );
343 LineBreakInfo LogicalModel::GetLineBreakInfo( CharacterIndex characterIndex ) const
345 return *( mImpl->mLineBreakInfo.Begin() + characterIndex );
348 void LogicalModel::SetWordBreakInfo( const WordBreakInfo* const wordBreakInfo,
351 Vector<WordBreakInfo>& modelWordBreakInfo = mImpl->mWordBreakInfo;
355 modelWordBreakInfo.Clear();
359 modelWordBreakInfo.Resize( length );
360 memcpy( modelWordBreakInfo.Begin(), wordBreakInfo, length * sizeof( WordBreakInfo ) );
364 void LogicalModel::GetWordBreakInfo( WordBreakInfo* wordBreakInfo,
365 CharacterIndex characterIndex,
366 Length numberOfItems ) const
368 memcpy( wordBreakInfo, mImpl->mWordBreakInfo.Begin() + characterIndex, numberOfItems * sizeof( WordBreakInfo ) );
371 WordBreakInfo LogicalModel::GetWordBreakInfo( CharacterIndex characterIndex ) const
373 return *( mImpl->mWordBreakInfo.Begin() + characterIndex );
376 void LogicalModel::SetBidirectionalInfo( const BidirectionalParagraphInfoRun* const bidirectionalInfo,
377 Length numberOfRuns )
381 Length LogicalModel::GetNumberOfBidirectionalInfoRuns( CharacterIndex characterIndex,
382 Length numberOfCharacters ) const
387 void LogicalModel::GetCharacterDirections( CharacterDirection* directions,
388 CharacterIndex characterIndex,
389 Length numberOfCharacters ) const
393 CharacterDirection LogicalModel::GetCharacterDirection( CharacterIndex characterIndex ) const
398 void LogicalModel::SetVisualToLogicalMap( const BidirectionalLineInfoRun* const bidirectionalInfo,
399 Length numberOfRuns )
403 CharacterIndex LogicalModel::GetVisualCharacterIndex( CharacterIndex logicalCharacterIndex ) const
408 CharacterIndex LogicalModel::GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex ) const
413 void LogicalModel::GetLogicalToVisualMap( CharacterIndex* logicalToVisualMap,
414 CharacterIndex characterIndex,
415 Length numberOfCharacters ) const
419 void LogicalModel::GetVisualToLogicalMap( CharacterIndex* visualToLogicalMap,
420 CharacterIndex characterIndex,
421 Length numberOfCharacters ) const
425 LogicalModel::~LogicalModel()
430 LogicalModel::LogicalModel()
433 mImpl = new LogicalModel::Impl();
438 } // namespace Toolkit