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-impl.h>
22 #include <dali-toolkit/internal/text/input-style.h>
23 #include <dali-toolkit/internal/text/text-run-container.h>
34 void FreeFontFamilyNames( Vector<FontDescriptionRun>& fontDescriptionRuns )
36 for( Vector<FontDescriptionRun>::Iterator it = fontDescriptionRuns.Begin(),
37 endIt = fontDescriptionRuns.End();
41 delete (*it).familyName;
44 fontDescriptionRuns.Clear();
47 LogicalModelPtr LogicalModel::New()
49 return LogicalModelPtr( new LogicalModel() );
52 Script LogicalModel::GetScript( CharacterIndex characterIndex ) const
54 // If this operation is too slow, consider a binary search.
56 for( Length index = 0u, length = mScriptRuns.Count(); index < length; ++index )
58 const ScriptRun* const scriptRun = mScriptRuns.Begin() + index;
60 if( ( scriptRun->characterRun.characterIndex <= characterIndex ) &&
61 ( characterIndex < scriptRun->characterRun.characterIndex + scriptRun->characterRun.numberOfCharacters ) )
63 return scriptRun->script;
67 return TextAbstraction::UNKNOWN;
70 CharacterDirection LogicalModel::GetCharacterDirection( CharacterIndex characterIndex ) const
72 if( characterIndex >= mCharacterDirections.Count() )
74 // The model has no right to left characters, so the vector of directions is void.
78 return *( mCharacterDirections.Begin() + characterIndex );
81 CharacterIndex LogicalModel::GetLogicalCursorIndex( CharacterIndex visualCursorIndex )
83 // The character's directions buffer.
84 const CharacterDirection* const modelCharacterDirections = mCharacterDirections.Begin();
86 // The bidirectional line info.
87 const BidirectionalLineInfoRun* const bidirectionalLineInfo = mBidirectionalLineInfo.Begin() + mBidirectionalLineIndex;
89 // Whether the paragraph starts with a right to left character.
90 const bool isRightToLeftParagraph = bidirectionalLineInfo->direction;
92 // The total number of characters of the line.
93 const Length lastCharacterIndex = bidirectionalLineInfo->characterRun.characterIndex + bidirectionalLineInfo->characterRun.numberOfCharacters;
95 CharacterIndex logicalCursorIndex = 0u;
97 if( bidirectionalLineInfo->characterRun.characterIndex == visualCursorIndex )
99 if( isRightToLeftParagraph )
101 logicalCursorIndex = lastCharacterIndex;
103 else // else logical position is the first of the line.
105 logicalCursorIndex = bidirectionalLineInfo->characterRun.characterIndex;
108 else if( lastCharacterIndex == visualCursorIndex )
110 if( isRightToLeftParagraph )
112 logicalCursorIndex = bidirectionalLineInfo->characterRun.characterIndex;
114 else // else logical position is the number of characters.
116 logicalCursorIndex = lastCharacterIndex;
121 // Get the character indexed by index - 1 and index
122 // and calculate the logical position according the directions of
123 // both characters and the direction of the paragraph.
125 const CharacterIndex previousVisualCursorIndex = visualCursorIndex - 1u;
126 const CharacterIndex previousLogicalCursorIndex = *( bidirectionalLineInfo->visualToLogicalMap + previousVisualCursorIndex - bidirectionalLineInfo->characterRun.characterIndex ) + bidirectionalLineInfo->characterRun.characterIndex;
127 const CharacterIndex currentLogicalCursorIndex = *( bidirectionalLineInfo->visualToLogicalMap + visualCursorIndex - bidirectionalLineInfo->characterRun.characterIndex ) + bidirectionalLineInfo->characterRun.characterIndex;
129 const CharacterDirection previousCharacterDirection = *( modelCharacterDirections + previousLogicalCursorIndex );
130 const CharacterDirection currentCharacterDirection = *( modelCharacterDirections + currentLogicalCursorIndex );
132 if( previousCharacterDirection == currentCharacterDirection )
134 // Both glyphs have the same direction.
135 if( previousCharacterDirection )
137 logicalCursorIndex = previousLogicalCursorIndex;
141 logicalCursorIndex = currentLogicalCursorIndex;
146 if( isRightToLeftParagraph )
148 if( currentCharacterDirection )
150 logicalCursorIndex = currentLogicalCursorIndex + 1u;
154 logicalCursorIndex = previousLogicalCursorIndex;
159 if( previousCharacterDirection )
161 logicalCursorIndex = currentLogicalCursorIndex;
165 logicalCursorIndex = previousLogicalCursorIndex + 1u;
171 return logicalCursorIndex;
174 CharacterIndex LogicalModel::GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex )
176 // The bidirectional line info.
177 const BidirectionalLineInfoRun* const bidirectionalLineInfo = mBidirectionalLineInfo.Begin() + mBidirectionalLineIndex;
179 return *( bidirectionalLineInfo->visualToLogicalMap + visualCharacterIndex - bidirectionalLineInfo->characterRun.characterIndex ) + bidirectionalLineInfo->characterRun.characterIndex;
182 bool LogicalModel::FetchBidirectionalLineInfo( CharacterIndex characterIndex )
184 // The number of bidirectional lines.
185 const Length numberOfBidirectionalLines = mBidirectionalLineInfo.Count();
187 if( 0u == numberOfBidirectionalLines )
189 // If there is no bidirectional info.
193 // Find the bidi line where the character is laid-out.
195 const BidirectionalLineInfoRun* const bidirectionalLineInfoBuffer = mBidirectionalLineInfo.Begin();
197 // Check first if the character is in the previously fetched line.
199 BidirectionalLineRunIndex bidiLineIndex = 0u;
200 CharacterIndex lastCharacterOfRightToLeftRun = 0u;
201 if( mBidirectionalLineIndex < numberOfBidirectionalLines )
203 const BidirectionalLineInfoRun& bidiLineRun = *( bidirectionalLineInfoBuffer + mBidirectionalLineIndex );
205 const CharacterIndex lastCharacterOfRunPlusOne = bidiLineRun.characterRun.characterIndex + bidiLineRun.characterRun.numberOfCharacters;
206 if( ( bidiLineRun.characterRun.characterIndex <= characterIndex ) &&
207 ( characterIndex < lastCharacterOfRunPlusOne ) )
209 // The character is in the previously fetched bidi line.
214 // The character is not in the previously fetched line.
215 // Set the bidi line index from where to start the fetch.
217 if( characterIndex < bidiLineRun.characterRun.characterIndex )
219 // Start the fetch from the beginning.
224 // Start the fetch from the next line.
225 bidiLineIndex = mBidirectionalLineIndex + 1u;
226 lastCharacterOfRightToLeftRun = lastCharacterOfRunPlusOne - 1u;
231 // The character has not been found in the previously fetched bidi line.
232 for( Vector<BidirectionalLineInfoRun>::ConstIterator it = bidirectionalLineInfoBuffer + bidiLineIndex,
233 endIt = mBidirectionalLineInfo.End();
235 ++it, ++bidiLineIndex )
237 const BidirectionalLineInfoRun& bidiLineRun = *it;
239 if( ( lastCharacterOfRightToLeftRun < characterIndex ) &&
240 ( characterIndex < bidiLineRun.characterRun.characterIndex ) )
242 // The character is not inside a bidi line.
246 const CharacterIndex lastCharacterOfRunPlusOne = bidiLineRun.characterRun.characterIndex + bidiLineRun.characterRun.numberOfCharacters;
247 lastCharacterOfRightToLeftRun = lastCharacterOfRunPlusOne - 1u;
248 if( ( bidiLineRun.characterRun.characterIndex <= characterIndex ) &&
249 ( characterIndex < lastCharacterOfRunPlusOne ) )
251 // Bidi line found. Fetch the line.
252 mBidirectionalLineIndex = bidiLineIndex;
260 BidirectionalLineRunIndex LogicalModel::GetBidirectionalLineInfo() const
262 return mBidirectionalLineIndex;
265 void LogicalModel::UpdateTextStyleRuns( CharacterIndex index, int numberOfCharacters )
267 const Length totalNumberOfCharacters = mText.Count();
269 // Process the color runs.
270 Vector<ColorRun> removedColorRuns;
271 UpdateCharacterRuns<ColorRun>( index,
273 totalNumberOfCharacters,
277 // Process the font description runs.
278 Vector<FontDescriptionRun> removedFontDescriptionRuns;
279 UpdateCharacterRuns<FontDescriptionRun>( index,
281 totalNumberOfCharacters,
282 mFontDescriptionRuns,
283 removedFontDescriptionRuns );
285 // Free memory allocated for the font family name.
286 FreeFontFamilyNames( removedFontDescriptionRuns );
289 void LogicalModel::RetrieveStyle( CharacterIndex index, InputStyle& style )
291 unsigned int runIndex = 0u;
293 // Set the text color.
294 bool colorOverriden = false;
295 unsigned int colorIndex = 0u;
296 const ColorRun* const colorRunsBuffer = mColorRuns.Begin();
297 for( Vector<ColorRun>::ConstIterator it = colorRunsBuffer,
298 endIt = mColorRuns.End();
302 const ColorRun& colorRun = *it;
304 if( ( colorRun.characterRun.characterIndex <= index ) &&
305 ( index < colorRun.characterRun.characterIndex + colorRun.characterRun.numberOfCharacters ) )
307 colorIndex = runIndex;
308 colorOverriden = true;
312 // Set the text's color if it's overriden.
315 style.textColor = ( *( colorRunsBuffer + colorIndex ) ).color;
316 style.isDefaultColor = false;
319 // Reset the run index.
322 // Set the font's parameters.
323 bool nameOverriden = false;
324 bool weightOverriden = false;
325 bool widthOverriden = false;
326 bool slantOverriden = false;
327 bool sizeOverriden = false;
328 unsigned int nameIndex = 0u;
329 unsigned int weightIndex = 0u;
330 unsigned int widthIndex = 0u;
331 unsigned int slantIndex = 0u;
332 unsigned int sizeIndex = 0u;
333 const FontDescriptionRun* const fontDescriptionRunsBuffer = mFontDescriptionRuns.Begin();
334 for( Vector<FontDescriptionRun>::ConstIterator it = fontDescriptionRunsBuffer,
335 endIt = mFontDescriptionRuns.End();
339 const FontDescriptionRun& fontDescriptionRun = *it;
341 if( ( fontDescriptionRun.characterRun.characterIndex <= index ) &&
342 ( index < fontDescriptionRun.characterRun.characterIndex + fontDescriptionRun.characterRun.numberOfCharacters ) )
344 if( fontDescriptionRun.familyDefined )
346 nameIndex = runIndex;
347 nameOverriden = true;
350 if( fontDescriptionRun.weightDefined )
352 weightIndex = runIndex;
353 weightOverriden = true;
356 if( fontDescriptionRun.widthDefined )
358 widthIndex = runIndex;
359 widthOverriden = true;
362 if( fontDescriptionRun.slantDefined )
364 slantIndex = runIndex;
365 slantOverriden = true;
368 if( fontDescriptionRun.sizeDefined )
370 sizeIndex = runIndex;
371 sizeOverriden = true;
376 // Set the font's family name if it's overriden.
379 const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + nameIndex );
381 style.familyName = std::string( fontDescriptionRun.familyName, fontDescriptionRun.familyLength );
382 style.familyDefined = true;
385 // Set the font's weight if it's overriden.
386 if( weightOverriden )
388 const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + weightIndex );
390 style.weight = fontDescriptionRun.weight;
391 style.weightDefined = true;
394 // Set the font's width if it's overriden.
397 const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + widthIndex );
399 style.width = fontDescriptionRun.width;
400 style.widthDefined = true;
403 // Set the font's slant if it's overriden.
406 const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + slantIndex );
408 style.slant = fontDescriptionRun.slant;
409 style.slantDefined = true;
412 // Set the font's size if it's overriden.
415 const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + sizeIndex );
417 style.size = static_cast<float>( fontDescriptionRun.size ) / 64.f;
418 style.sizeDefined = true;
422 void LogicalModel::ClearFontDescriptionRuns()
424 FreeFontFamilyNames( mFontDescriptionRuns );
427 void LogicalModel::CreateParagraphInfo( CharacterIndex startIndex,
428 Length numberOfCharacters )
430 const Length totalNumberOfCharacters = mLineBreakInfo.Count();
432 // Count the number of LINE_MUST_BREAK to reserve some space for the vector of paragraph's info.
433 Vector<CharacterIndex> paragraphs;
434 paragraphs.Reserve( numberOfCharacters );
435 const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = mLineBreakInfo.Begin();
436 const CharacterIndex lastCharacterIndexPlusOne = startIndex + numberOfCharacters;
437 for( Length index = startIndex; index < lastCharacterIndexPlusOne; ++index )
439 if( TextAbstraction::LINE_MUST_BREAK == *( lineBreakInfoBuffer + index ) )
441 paragraphs.PushBack( index );
445 // Whether the current paragraphs are updated or set from scratch.
446 const bool updateCurrentParagraphs = numberOfCharacters < totalNumberOfCharacters;
448 // Reserve space for current paragraphs plus new ones.
449 const Length numberOfNewParagraphs = paragraphs.Count();
450 const Length totalNumberOfParagraphs = mParagraphInfo.Count() + numberOfNewParagraphs;
451 mParagraphInfo.Resize( totalNumberOfParagraphs );
453 ParagraphRun* paragraphInfoBuffer = NULL;
454 Vector<ParagraphRun> newParagraphs;
456 if( updateCurrentParagraphs )
458 newParagraphs.Resize( numberOfNewParagraphs );
459 paragraphInfoBuffer = newParagraphs.Begin();
463 paragraphInfoBuffer = mParagraphInfo.Begin();
466 // Find where to insert the new paragraphs.
467 ParagraphRunIndex paragraphIndex = 0u;
468 CharacterIndex firstIndex = startIndex;
470 if( updateCurrentParagraphs )
472 for( Vector<ParagraphRun>::ConstIterator it = mParagraphInfo.Begin(),
473 endIt = mParagraphInfo.Begin() + totalNumberOfParagraphs - numberOfNewParagraphs;
477 const ParagraphRun& paragraph( *it );
479 if( startIndex < paragraph.characterRun.characterIndex + paragraph.characterRun.numberOfCharacters )
481 firstIndex = paragraph.characterRun.characterIndex;
489 // Create the paragraph info.
490 ParagraphRunIndex newParagraphIndex = 0u;
491 for( Vector<CharacterIndex>::ConstIterator it = paragraphs.Begin(),
492 endIt = paragraphs.End();
494 ++it, ++newParagraphIndex )
496 const CharacterIndex index = *it;
498 ParagraphRun& paragraph = *( paragraphInfoBuffer + newParagraphIndex );
499 paragraph.characterRun.characterIndex = firstIndex;
500 paragraph.characterRun.numberOfCharacters = 1u + index - firstIndex;
502 firstIndex += paragraph.characterRun.numberOfCharacters;
506 // Insert the new paragraphs.
507 if( updateCurrentParagraphs )
509 mParagraphInfo.Insert( mParagraphInfo.Begin() + paragraphIndex,
510 newParagraphs.Begin(),
511 newParagraphs.End() );
513 mParagraphInfo.Resize( totalNumberOfParagraphs );
515 // Update the next paragraph indices.
516 for( Vector<ParagraphRun>::Iterator it = mParagraphInfo.Begin() + paragraphIndex + newParagraphs.Count(),
517 endIt = mParagraphInfo.End();
521 ParagraphRun& paragraph( *it );
523 paragraph.characterRun.characterIndex += numberOfCharacters;
528 void LogicalModel::FindParagraphs( CharacterIndex index,
529 Length numberOfCharacters,
530 Vector<ParagraphRunIndex>& paragraphs )
532 // Reserve som space for the paragraph indices.
533 paragraphs.Reserve( mParagraphInfo.Count() );
535 // Traverse the paragraphs to find which ones contain the given characters.
536 ParagraphRunIndex paragraphIndex = 0u;
537 for( Vector<ParagraphRun>::ConstIterator it = mParagraphInfo.Begin(),
538 endIt = mParagraphInfo.End();
540 ++it, ++paragraphIndex )
542 const ParagraphRun& paragraph( *it );
544 if( ( paragraph.characterRun.characterIndex + paragraph.characterRun.numberOfCharacters > index ) &&
545 ( paragraph.characterRun.characterIndex < index + numberOfCharacters ) )
547 paragraphs.PushBack( paragraphIndex );
552 LogicalModel::~LogicalModel()
554 ClearFontDescriptionRuns();
557 LogicalModel::LogicalModel()
558 : mBidirectionalLineIndex( 0u )
564 } // namespace Toolkit