From: Paul Wisbey Date: Mon, 14 Mar 2016 13:11:26 +0000 (-0700) Subject: Merge "Added Emscripten guide" into devel/master X-Git-Tag: dali_1.1.26~2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=5b4982566aba41b5e21c3b8ce3e01a7e86db8f28;hp=469f5a14469849a28463710288da51a34a40e9da Merge "Added Emscripten guide" into devel/master --- diff --git a/automated-tests/src/dali-toolkit-internal/CMakeLists.txt b/automated-tests/src/dali-toolkit-internal/CMakeLists.txt index 7e21216..0852234 100644 --- a/automated-tests/src/dali-toolkit-internal/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit-internal/CMakeLists.txt @@ -13,6 +13,8 @@ SET(TC_SOURCES utc-Dali-Text-MultiLanguage.cpp utc-Dali-LogicalModel.cpp utc-Dali-BidirectionalSupport.cpp + utc-Dali-Text-Shaping.cpp + utc-Dali-VisualModel.cpp ) # Append list of test harness files (Won't get parsed for test cases) diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Shaping.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Shaping.cpp new file mode 100644 index 0000000..0dd3144 --- /dev/null +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Shaping.cpp @@ -0,0 +1,528 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include + +#include +#include +#include +#include + +using namespace Dali; +using namespace Toolkit; +using namespace Text; + +// Tests the following function. +// void ShapeText( const Vector& text, +// const Vector& lineBreakInfo, +// const Vector& scripts, +// const Vector& fonts, +// CharacterIndex startCharacterIndex, +// GlyphIndex startGlyphIndex, +// Length numberOfCharacters, +// Vector& glyphs, +// Vector& glyphToCharacterMap, +// Vector& charactersPerGlyph, +// Vector& newParagraphGlyphs ); + +////////////////////////////////////////////////////////// + +namespace +{ + +struct GlyphInfoData +{ + FontId fontId; ///< Identifies the font containing the glyph + GlyphIndex index; ///< Uniquely identifies a glyph for a given FontId + float width; ///< The width of the glyph + float height; ///< The height of the glyph + float xBearing; ///< The distance from the cursor position to the leftmost border of the glyph + float yBearing; ///< The distance from the baseline to the topmost border of the glyph + float advance; ///< The distance to move the cursor for this glyph + float scaleFactor; ///< The scaling applied (fixed-size fonts only) +}; + +bool IsEqualGlyph ( const GlyphInfoData& glyphData, const GlyphInfo& glyph ) +{ + if( glyphData.fontId != glyph.fontId ) + { + return false; + } + if( glyphData.index != glyph.index ) + { + return false; + } + if( fabsf( glyphData.width - glyph.width ) > Math::MACHINE_EPSILON_1000 ) + { + return false; + } + if( fabsf( glyphData.height - glyph.height ) > Math::MACHINE_EPSILON_1000 ) + { + return false; + } + if( fabsf( glyphData.xBearing - glyph.xBearing ) > Math::MACHINE_EPSILON_1000 ) + { + return false; + } + if( fabsf( glyphData.yBearing - glyph.yBearing ) > Math::MACHINE_EPSILON_1000 ) + { + return false; + } + if( fabsf( glyphData.advance - glyph.advance ) > Math::MACHINE_EPSILON_1000 ) + { + return false; + } + if( fabsf( glyphData.scaleFactor - glyph.scaleFactor ) > Math::MACHINE_EPSILON_1000 ) + { + return false; + } + + return true; +} + +struct ShapeInfoData +{ + std::string description; ///< Description of the test. + std::string text; ///< input text. + uint32_t index; ///< The index from where to start to query the break info. + uint32_t numberOfCharacters; ///< The requested number of characters. + uint32_t expectedNumberOfGlyphs; ///< The expected number of glyphs. + GlyphInfoData* glyphs; ///< The glyphs. + CharacterIndex* characterIndices; ///< The character index for each glyph. + Length* charactersPerGlyph; ///< The characters per glyph. + uint32_t expectedNumberOfNewParagraphGlyphs; ///< The expected number of glyphs. + GlyphIndex* newParagraphGlyphs; ///< Indices to the new paragraphs glyphs. +}; + +bool ShapeInfoTest( const ShapeInfoData& data ) +{ + // 1) Create the model. + LogicalModelPtr logicalModel = LogicalModel::New(); + VisualModelPtr visualModel = VisualModel::New(); + Size textArea(100.f, 60.f); + Size layoutSize; + + CreateTextModel( data.text, + textArea, + layoutSize, + logicalModel, + visualModel ); + + // 2) Clear the model. + + Vector& glyphs = visualModel->mGlyphs; + Vector& glyphToCharacter = visualModel->mGlyphsToCharacters; + Vector& charactersPerGlyph = visualModel->mCharactersPerGlyph; + Vector& charactersToGlyph = visualModel->mCharactersToGlyph; + Vector& glyphsPerCharacter = visualModel->mGlyphsPerCharacter; + + // Get the glyph index. + GlyphIndex glyphIndex = 0u; + if( 0u != visualModel->mCharactersToGlyph.Count() ) + { + glyphIndex = *( visualModel->mCharactersToGlyph.Begin() + data.index ); + + const CharacterIndex lastCharacterIndex = data.index + data.numberOfCharacters - 1u; + const Length numberOfGlyphs = *( visualModel->mCharactersToGlyph.Begin() + lastCharacterIndex ) + *( visualModel->mGlyphsPerCharacter.Begin() + lastCharacterIndex ) - glyphIndex; + + // Erase the glyph info from the text model. + // Got from the ShapeText() function. + glyphs.Erase( glyphs.Begin() + glyphIndex, glyphs.Begin() + glyphIndex + numberOfGlyphs ); + glyphToCharacter.Erase( glyphToCharacter.Begin() + glyphIndex, glyphToCharacter.Begin() + glyphIndex + numberOfGlyphs ); + charactersPerGlyph.Erase( charactersPerGlyph.Begin() + glyphIndex, charactersPerGlyph.Begin() + glyphIndex + numberOfGlyphs ); + + // Got from the VisualModel::CreateCharacterToGlyphTable() and the VisualModel::CreateGlyphsPerCharacterTable() methods. + charactersToGlyph.Erase( charactersToGlyph.Begin() + data.index, + charactersToGlyph.Begin() + data.index + data.numberOfCharacters ); + glyphsPerCharacter.Erase( glyphsPerCharacter.Begin() + data.index, + glyphsPerCharacter.Begin() + data.index + data.numberOfCharacters ); + + // Update the glyph to character indices. + for( Vector::Iterator it = glyphToCharacter.Begin() + glyphIndex, + endIt = glyphToCharacter.End(); + it != endIt; + ++it ) + { + CharacterIndex& index = *it; + index -= data.numberOfCharacters; + } + + } + + // Reset the metrics got from the model as the ShapeText() function doesn't retrieve them. + for( Vector::Iterator it = glyphs.Begin(), + endIt = glyphs.End(); + it != endIt; + ++it ) + { + GlyphInfo& info = *it; + info.width = 0.f; + info.height = 0.f; + info.xBearing = 0.f; + info.yBearing = 0.f; + info.scaleFactor = 0.f; + } + + // 3) Call the ShapeText() function. + + Vector newParagraphGlyphs; + + ShapeText( logicalModel->mText, + logicalModel->mLineBreakInfo, + logicalModel->mScriptRuns, + logicalModel->mFontRuns, + data.index, + glyphIndex, + data.numberOfCharacters, + glyphs, + glyphToCharacter, + charactersPerGlyph, + newParagraphGlyphs ); + + // Clear the advance of the new paragraph glyphs. + for( Vector::Iterator it = newParagraphGlyphs.Begin(), + endIt = newParagraphGlyphs.End(); + it != endIt; + ++it ) + { + GlyphInfo& info = *( glyphs.Begin() + *it ); + info.advance = 0.f; + } + + // 4) Compare the results. + + if( data.expectedNumberOfGlyphs != glyphs.Count() ) + { + std::cout << " Different number of glyphs : " << glyphs.Count() << ", expected : " << data.expectedNumberOfGlyphs << std::endl; + return false; + } + + for( unsigned int index = 0u; index < data.expectedNumberOfGlyphs; ++index ) + { + if( !IsEqualGlyph( data.glyphs[index], glyphs[index] ) ) + { + std::cout << " different glyph info, index : " << index << std::endl; + return false; + } + } + + for( unsigned int index = 0u; index < data.expectedNumberOfGlyphs; ++index ) + { + if( data.characterIndices[index] != glyphToCharacter[index] ) + { + std::cout << " different character index, index : " << index << std::endl; + return false; + } + } + + for( unsigned int index = 0u; index < data.expectedNumberOfGlyphs; ++index ) + { + if( data.charactersPerGlyph[index] != charactersPerGlyph[index] ) + { + std::cout << " different character per glyph, index : " << index << std::endl; + return false; + } + } + + if( data.expectedNumberOfNewParagraphGlyphs != newParagraphGlyphs.Count() ) + { + std::cout << " Different number of new paragraph glyphs : " << newParagraphGlyphs.Count() << ", expected : " << data.expectedNumberOfNewParagraphGlyphs << std::endl; + return false; + } + + for( unsigned int index = 0u; index < data.expectedNumberOfNewParagraphGlyphs; ++index ) + { + if( data.newParagraphGlyphs[index] != newParagraphGlyphs[index] ) + { + std::cout << " different new paragraph glyph, index : " << index << std::endl; + return false; + } + } + + return true; +} + +} // namespace + +////////////////////////////////////////////////////////// + +int UtcDaliTextShape(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliTextShape"); + + struct GlyphInfoData glyphs02[] = + { + { 1u, 43u, 0.f, 0.f, 0.f, 0.f, 12.f, 0.f }, + { 1u, 72u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 79u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f }, + { 1u, 79u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f }, + { 1u, 82u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 3u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f }, + { 1u, 90u, 0.f, 0.f, 0.f, 0.f, 13.f, 0.f }, + { 1u, 82u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 85u, 0.f, 0.f, 0.f, 0.f, 6.f, 0.f }, + { 1u, 79u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f }, + { 1u, 71u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f }, + }; + + CharacterIndex characterIndices02[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u }; + Length charactersPerGlyph02[] = { 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u }; + + struct GlyphInfoData glyphs03[] = + { + { 1u, 43u, 0.f, 0.f, 0.f, 0.f, 12.f, 0.f }, + { 1u, 72u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 79u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f }, + { 1u, 79u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f }, + { 1u, 82u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 3u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f }, + { 1u, 90u, 0.f, 0.f, 0.f, 0.f, 13.f, 0.f }, + { 1u, 82u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 85u, 0.f, 0.f, 0.f, 0.f, 6.f, 0.f }, + { 1u, 79u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f }, + { 1u, 71u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f }, + { 1u, 0u, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f }, + { 1u, 71u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f }, + { 1u, 72u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 80u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f }, + { 1u, 82u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 0u, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f }, + }; + + CharacterIndex characterIndices03[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, 15u, 16u }; + Length charactersPerGlyph03[] = { 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u }; + CharacterIndex newParagraphGlyphs03[] = { 11u, 16u }; + + struct GlyphInfoData glyphs04[] = + { + { 2u, 160u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f }, + { 2u, 123u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 2u, 153u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f }, + { 2u, 160u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f }, + { 2u, 150u, 0.f, 0.f, 0.f, 0.f, 14.f, 0.f }, + { 2u, 153u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f }, + { 2u, 160u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f }, + { 2u, 151u, 0.f, 0.f, 0.f, 0.f, 12.f, 0.f }, + { 2u, 153u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f }, + { 2u, 160u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f }, + { 2u, 147u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 2u, 153u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f }, + }; + + CharacterIndex characterIndices04[] = { 0u, 0u, 0u, 2u, 2u, 2u, 4u, 4u, 4u, 6u, 6u, 6u }; + Length charactersPerGlyph04[] = { 0u, 0u, 2u, 0u, 0u, 2u, 0u, 0u, 2u, 0u, 0u, 2u }; + + struct GlyphInfoData glyphs05[] = + { + { 1u, 47u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f }, + { 1u, 82u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 85u, 0.f, 0.f, 0.f, 0.f, 6.f, 0.f }, + { 1u, 72u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 80u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f }, + { 1u, 3u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f }, + { 1u, 76u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f }, + { 1u, 83u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f }, + { 1u, 86u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f }, + { 1u, 88u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f }, + { 1u, 80u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f }, + { 1u, 3u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f }, + { 1u, 71u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f }, + { 1u, 82u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 79u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f }, + { 1u, 82u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 85u, 0.f, 0.f, 0.f, 0.f, 6.f, 0.f }, + { 1u, 3u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f }, + { 1u, 86u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f }, + { 1u, 76u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f }, + { 1u, 87u, 0.f, 0.f, 0.f, 0.f, 6.f, 0.f }, + { 1u, 3u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f }, + { 1u, 68u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 80u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f }, + { 1u, 72u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 87u, 0.f, 0.f, 0.f, 0.f, 6.f, 0.f }, + { 1u, 0u, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f }, + { 1u, 68u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 72u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 84u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f }, + { 1u, 88u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f }, + { 1u, 72u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 3u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f }, + { 1u, 71u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f }, + { 1u, 72u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 5034u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f }, + { 1u, 81u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f }, + { 1u, 76u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f }, + { 1u, 72u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 69u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f }, + { 1u, 68u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 86u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f }, + { 1u, 3u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f }, + { 1u, 72u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 68u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 3u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f }, + { 1u, 80u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f }, + { 1u, 72u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 76u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f }, + { 1u, 0u, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f }, + { 1u, 83u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f }, + { 1u, 82u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 86u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f }, + { 1u, 86u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f }, + { 1u, 72u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 3u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f }, + { 1u, 76u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f }, + { 1u, 85u, 0.f, 0.f, 0.f, 0.f, 6.f, 0.f }, + { 1u, 68u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 70u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f }, + { 1u, 88u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f }, + { 1u, 81u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f }, + { 1u, 71u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f }, + { 1u, 76u, 0.f, 0.f, 0.f, 0.f, 4.f, 0.f }, + { 1u, 68u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 3u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f }, + { 1u, 81u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f }, + { 1u, 72u, 0.f, 0.f, 0.f, 0.f, 9.f, 0.f }, + { 1u, 3u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f }, + { 1u, 70u, 0.f, 0.f, 0.f, 0.f, 8.f, 0.f }, + { 1u, 88u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f }, + { 1u, 80u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f }, + { 1u, 17u, 0.f, 0.f, 0.f, 0.f, 5.f, 0.f }, + { 1u, 0u, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f }, + }; + + CharacterIndex characterIndices05[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, + 10u, 11u, 12u, 13u, 14u, 15u, 16u, 17u, 18u, 19u, + 20u, 21u, 22u, 23u, 24u, 25u, 26u, 27u, 28u, 29u, + 30u, 31u, 32u, 33u, 34u, 35u, 37u, 38u, 39u, 40u, + 41u, 42u, 43u, 44u, 45u, 46u, 47u, 48u, 49u, 50u, + 51u, 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u, + 61u, 62u, 63u, 64u, 65u, 66u, 67u, 68u, 69u, 70u, + 71u, 72u, 73u, 74u }; + Length charactersPerGlyph05[] = { 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, + 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, + 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, + 1u, 1u, 1u, 1u, 1u, 2u, 1u, 1u, 1u, 1u, + 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, + 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, + 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, + 1u, 1u, 1u, 1u }; + CharacterIndex newParagraphGlyphs05[] = { 26u }; + CharacterIndex newParagraphGlyphs06[] = { 49u }; + CharacterIndex newParagraphGlyphs07[] = { 73u }; + + struct ShapeInfoData data[] = + { + { + "Zero characters", + "", + 0u, + 0u, + 0u, + NULL, + NULL, + NULL, + 0u, + NULL + }, + { + "Latin script", + "Hello world", + 0u, + 11u, + 11u, + glyphs02, + characterIndices02, + charactersPerGlyph02, + 0u, + NULL + }, + { + "Latin script. Some paragraphs.", + "Hello world\ndemo\n", + 0u, + 17u, + 17u, + glyphs03, + characterIndices03, + charactersPerGlyph03, + 2u, + newParagraphGlyphs03 + }, + { + "Malayalam script. More glyphs than characters.", + "ജോസോഹോവോ", + 0u, + 8u, + 12u, + glyphs04, + characterIndices04, + charactersPerGlyph04, + 0u, + NULL + }, + { + "Latin script with some paragraphs. Update initial paragraph.", + "Lorem ipsum dolor sit amet\naeque definiebas ea mei\nposse iracundia ne cum.\n", + 0u, + 27u, + 74u, + glyphs05, + characterIndices05, + charactersPerGlyph05, + 1u, + newParagraphGlyphs05 + }, + { + "Latin script with some paragraphs. Update mid paragraph.", + "Lorem ipsum dolor sit amet\naeque definiebas ea mei\nposse iracundia ne cum.\n", + 27u, + 24u, + 74u, + glyphs05, + characterIndices05, + charactersPerGlyph05, + 1u, + newParagraphGlyphs06 + }, + { + "Latin script with some paragraphs. Update final paragraph.", + "Lorem ipsum dolor sit amet\naeque definiebas ea mei\nposse iracundia ne cum.\n", + 51u, + 24u, + 74u, + glyphs05, + characterIndices05, + charactersPerGlyph05, + 1u, + newParagraphGlyphs07 + }, + }; + const unsigned int numberOfTests = 7u; + + for( unsigned int index = 0u; index < numberOfTests; ++index ) + { + if( !ShapeInfoTest( data[index] ) ) + { + tet_result(TET_FAIL); + } + } + + tet_result(TET_PASS); + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualModel.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualModel.cpp new file mode 100644 index 0000000..18faa9e --- /dev/null +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualModel.cpp @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include + +#include + +#include +#include +#include + + +using namespace Dali; +using namespace Toolkit; +using namespace Text; + +// Tests the following functions. +// +// void CreateCharacterToGlyphTable( CharacterIndex startIndex, +// Length numberOfCharacters ) +// +// void CreateGlyphsPerCharacterTable( CharacterIndex startIndex, +// Length numberOfCharacters ) + + +////////////////////////////////////////////////////////// + +namespace +{ + +struct SetGlyphsPerCharacterData +{ + std::string description; ///< Description of the test. + std::string text; ///< Input text. + unsigned int startIndex; ///< The start index from where the glyphs per character table is set. + unsigned int numberOfCharacters; ///< The number of characters to set. + unsigned int totalNumberOfCharacters; ///< The total number of characters. + unsigned int* glyphsPerCharacter; ///< The number of glyphs per character. +}; + +struct SetCharacterToGlyphData +{ + std::string description; ///< Description of the test. + std::string text; ///< Input text. + unsigned int startIndex; ///< The start index from where the character to glyph table is set. + unsigned int numberOfCharacters; ///< The number of characters to set. + unsigned int totalNumberOfCharacters; ///< The total number of characters. + unsigned int* glyphsIndices; ///< The glyph indices. +}; + +bool SetGlyphsPerCharacterTest( const SetGlyphsPerCharacterData& data ) +{ + // 1) Create the model. + LogicalModelPtr logicalModel = LogicalModel::New(); + VisualModelPtr visualModel = VisualModel::New(); + Size textArea(100.f, 60.f); + Size layoutSize; + + CreateTextModel( data.text, + textArea, + layoutSize, + logicalModel, + visualModel ); + + // 2) Clear the model. + Vector& charactersToGlyph = visualModel->mCharactersToGlyph; + Vector& glyphsPerCharacter = visualModel->mGlyphsPerCharacter; + + if( 0u != charactersToGlyph.Count() ) + { + // The number of glyphs to be removed. + const Length numberOfGlyphs = charactersToGlyph[data.startIndex + data.numberOfCharacters - 1u] + glyphsPerCharacter[data.startIndex + data.numberOfCharacters - 1u] - charactersToGlyph[data.startIndex]; + + charactersToGlyph.Erase( charactersToGlyph.Begin() + data.startIndex, + charactersToGlyph.Begin() + data.startIndex + data.numberOfCharacters ); + glyphsPerCharacter.Erase( glyphsPerCharacter.Begin() + data.startIndex, + glyphsPerCharacter.Begin() + data.startIndex + data.numberOfCharacters ); + + // Update the character to glyph indices. + for( Vector::Iterator it = charactersToGlyph.Begin() + data.startIndex, + endIt = charactersToGlyph.End(); + it != endIt; + ++it ) + { + *it -= numberOfGlyphs; + } + } + + // 3) Call the CreateGlyphsPerCharacterTable() function + visualModel->CreateGlyphsPerCharacterTable( data.startIndex, + data.numberOfCharacters ); + + // 4) Compare the results. + if( data.totalNumberOfCharacters != glyphsPerCharacter.Count() ) + { + std::cout << " Different number of characters : " << glyphsPerCharacter.Count() << ", expected : " << data.totalNumberOfCharacters << std::endl; + return false; + } + + for( unsigned int i = 0u; i < data.totalNumberOfCharacters; ++i ) + { + if( data.glyphsPerCharacter[i] != glyphsPerCharacter[i] ) + { + std::cout << " Different number of glyphs for index " << i << std::endl; + for( unsigned int j = 0; j < data.totalNumberOfCharacters; ++j ) + { + std::cout << glyphsPerCharacter[j] << " "; + } + std::cout << std::endl; + std::cout << " expected" << std::endl; + for( unsigned int j = 0; j < data.totalNumberOfCharacters; ++j ) + { + std::cout << data.glyphsPerCharacter[j] << " "; + } + std::cout << std::endl; + return false; + } + } + + return true; +} + +bool SetCharacterToGlyphTest( const SetCharacterToGlyphData& data ) +{ + // 1) Create the model. + LogicalModelPtr logicalModel = LogicalModel::New(); + VisualModelPtr visualModel = VisualModel::New(); + Size textArea(100.f, 60.f); + Size layoutSize; + + CreateTextModel( data.text, + textArea, + layoutSize, + logicalModel, + visualModel ); + + // 2) Clear the model. + Vector& charactersToGlyph = visualModel->mCharactersToGlyph; + Vector& glyphsPerCharacter = visualModel->mGlyphsPerCharacter; + + if( 0u != charactersToGlyph.Count() ) + { + // The number of glyphs to be removed. + const Length numberOfGlyphs = charactersToGlyph[data.startIndex + data.numberOfCharacters - 1u] + glyphsPerCharacter[data.startIndex + data.numberOfCharacters - 1u] - charactersToGlyph[data.startIndex]; + + charactersToGlyph.Erase( charactersToGlyph.Begin() + data.startIndex, + charactersToGlyph.Begin() + data.startIndex + data.numberOfCharacters ); + + // Update the character to glyph indices. + for( Vector::Iterator it = charactersToGlyph.Begin() + data.startIndex, + endIt = charactersToGlyph.End(); + it != endIt; + ++it ) + { + *it -= numberOfGlyphs; + } + } + + // 3) Call the CreateCharacterToGlyphTable() function + visualModel->CreateCharacterToGlyphTable( data.startIndex, + data.numberOfCharacters ); + + // 4) Compare the results. + if( data.totalNumberOfCharacters != charactersToGlyph.Count() ) + { + std::cout << " Different number of character : " << charactersToGlyph.Count() << ", expected : " << data.totalNumberOfCharacters << std::endl; + return false; + } + + for( unsigned int i = 0u; i < data.totalNumberOfCharacters; ++i ) + { + if( data.glyphsIndices[i] != charactersToGlyph[i] ) + { + std::cout << " Different number of character to glyph index " << i << std::endl; + for( unsigned int j = 0; j < data.totalNumberOfCharacters; ++j ) + { + std::cout << charactersToGlyph[j] << " "; + } + std::cout << std::endl; + std::cout << " expected" << std::endl; + for( unsigned int j = 0; j < data.totalNumberOfCharacters; ++j ) + { + std::cout << data.glyphsIndices[j] << " "; + } + std::cout << std::endl; + return false; + } + } + + return true; +} + +} // namespace + +////////////////////////////////////////////////////////// + +int UtcDaliSetGlyphsPerCharacter(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliSetGlyphsPerCharacter"); + + Length glyphsPerCharacter02[] = { 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u }; + Length glyphsPerCharacter03[] = { 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 0u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u }; + Length glyphsPerCharacter04[] = { 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 0u, 1u, + 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, + 1u, 1u, 1u, 1u, 0u, 1u, 0u, 2u, 1u, 0u, + 2u, 0u, 2u, 0u, 2u, 1u, 1u, 0u, 0u, 0u, + 2u, 1u, 1u, 1u, 1u, 1u, 0u, 0u, 2u, 1u, + 0u, 2u, 1u, 1u }; + + struct SetGlyphsPerCharacterData data[] = + { + { + "Zero characters text", + "", + 0u, + 0u, + 0u, + NULL + }, + { + "Simple 1 to 1 text", + "Hello world", + 0u, + 11u, + 11u, + glyphsPerCharacter02, + }, + { + "Text with different number of glyphs and characters.", + "Hello different world", + 0u, + 21u, + 21u, + glyphsPerCharacter03, + }, + { + "Text paragraphs with different number of glyphs and characters. Update initial paragraphs.", + "Hello different world\nनमस्ते दुनिया\nမင်္ဂလာပါကမ္ဘာလောက", + 0u, + 22u, + 54u, + glyphsPerCharacter04, + }, + { + "Text paragraphs with different number of glyphs and characters. Update mid paragraphs.", + "Hello different world\nनमस्ते दुनिया\nမင်္ဂလာပါကမ္ဘာလောက", + 22u, + 14u, + 54u, + glyphsPerCharacter04, + }, + { + "Text paragraphs with different number of glyphs and characters. Update final paragraphs.", + "Hello different world\nनमस्ते दुनिया\nမင်္ဂလာပါကမ္ဘာလောက", + 36u, + 18u, + 54u, + glyphsPerCharacter04, + }, + }; + const unsigned int numberOfTests = 6u; + + for( unsigned int index = 0u; index < numberOfTests; ++index ) + { + if( !SetGlyphsPerCharacterTest( data[index] ) ) + { + tet_result(TET_FAIL); + } + } + + tet_result(TET_PASS); + END_TEST; +} + +int UtcDaliSetCharacterToGlyph(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliSetGlyphsPerCharacter"); + + GlyphIndex glyphIndices02[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u }; + GlyphIndex glyphIndices03[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, 15u, 16u, 17u, 18u, 19u }; + GlyphIndex glyphIndices04[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, 15u, 16u, 17u, 18u, 19u, 20u, + 21u, 22u, 23u, 23u, 24u, 24u, 26u, 27u, 27u, 29u, 29u, 31u, 31u, 33u, + 34u, 35u, 35u, 35u, 35u, 37u, 38u, 39u, 40u, 41u, 42u, 42u, 42u, 44u, 45u, 45u, 47u, 48u }; + + struct SetCharacterToGlyphData data[] = + { + { + "Zero characters text", + "", + 0u, + 0u, + 0u, + NULL + }, + { + "Simple 1 to 1 text", + "Hello world", + 0u, + 11u, + 11u, + glyphIndices02, + }, + { + "Text with different number of glyphs and characters.", + "Hello different world", + 0u, + 21u, + 21u, + glyphIndices03, + }, + { + "Text paragraphs with different number of glyphs and characters. Update initial paragraphs.", + "Hello different world\nनमस्ते दुनिया\nမင်္ဂလာပါကမ္ဘာလောက", + 0u, + 22u, + 54u, + glyphIndices04, + }, + { + "Text paragraphs with different number of glyphs and characters. Update mid paragraphs.", + "Hello different world\nनमस्ते दुनिया\nမင်္ဂလာပါကမ္ဘာလောက", + 22u, + 14u, + 54u, + glyphIndices04, + }, + { + "Text paragraphs with different number of glyphs and characters. Update final paragraphs.", + "Hello different world\nनमस्ते दुनिया\nမင်္ဂလာပါကမ္ဘာလောက", + 36u, + 18u, + 54u, + glyphIndices04, + }, + }; + + const unsigned int numberOfTests = 6u; + + for( unsigned int index = 0u; index < numberOfTests; ++index ) + { + if( !SetCharacterToGlyphTest( data[index] ) ) + { + tet_result(TET_FAIL); + } + } + + tet_result(TET_PASS); + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-text-model.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-text-model.cpp index 10f910c..6786bc5 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-text-model.cpp +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-text-model.cpp @@ -214,30 +214,30 @@ void CreateTextModel( const std::string& text, Vector& charactersPerGlyph = visualModel->mCharactersPerGlyph; Vector newParagraphGlyphs; - const Length currentNumberOfGlyphs = glyphs.Count(); const Vector& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters; ShapeText( textToShape, lineBreakInfo, scripts, validFonts, + 0u, + 0u, + numberOfCharacters, glyphs, glyphsToCharactersMap, charactersPerGlyph, newParagraphGlyphs ); // Create the 'number of glyphs' per character and the glyph to character conversion tables. - visualModel->CreateGlyphsPerCharacterTable( numberOfCharacters ); - visualModel->CreateCharacterToGlyphTable( numberOfCharacters ); + visualModel->CreateGlyphsPerCharacterTable( 0u, numberOfCharacters ); + visualModel->CreateCharacterToGlyphTable( 0u, numberOfCharacters ); - const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs; + const Length numberOfGlyphs = glyphs.Count(); // 8) Get the glyph metrics MetricsPtr metrics = Metrics::New( fontClient ); - const GlyphIndex glyphIndex = currentNumberOfGlyphs; - - GlyphInfo* glyphsBuffer = glyphs.Begin() + glyphIndex; + GlyphInfo* glyphsBuffer = glyphs.Begin(); metrics->GetGlyphMetrics( glyphsBuffer, numberOfGlyphs ); // Update the width and advance of all new paragraph characters. @@ -247,7 +247,7 @@ void CreateTextModel( const std::string& text, ++it ) { const GlyphIndex index = *it; - GlyphInfo& glyph = *( glyphsBuffer + ( index - glyphIndex ) ); + GlyphInfo& glyph = *( glyphsBuffer + index ); glyph.xBearing = 0.f; glyph.width = 0.f; diff --git a/automated-tests/src/dali-toolkit/utc-Dali-RendererFactory.cpp b/automated-tests/src/dali-toolkit/utc-Dali-RendererFactory.cpp index 2d30cd8..dd7012d 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-RendererFactory.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-RendererFactory.cpp @@ -531,9 +531,16 @@ int UtcDaliRendererFactoryGetImageRenderer1(void) Actor actor = Actor::New(); // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied. // Image with a size smaller than 512*512 will be uploaded as a part of the atlas. + + const int width=512; + const int height=513; + + Integration::Bitmap* bitmap = Integration::Bitmap::New( Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD ); + bitmap->GetPackedPixelsProfile()->ReserveBuffer( Pixel::RGBA8888, width, height,width, height ); + TestControlRendererRender( application, actor, controlRenderer, 1u, - ImageDimensions(512, 513), - Integration::ResourcePointer(Integration::Bitmap::New(Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD))); + ImageDimensions(width, height), + Integration::ResourcePointer( bitmap ) ); TestGlAbstraction& gl = application.GetGlAbstraction(); int textureUnit = -1; @@ -560,9 +567,16 @@ int UtcDaliRendererFactoryGetImageRenderer2(void) Actor actor = Actor::New(); // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied. // Image with a size smaller than 512*512 will be uploaded as a part of the atlas. + + const int width=512; + const int height=513; + + Integration::Bitmap* bitmap = Integration::Bitmap::New( Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD ); + bitmap->GetPackedPixelsProfile()->ReserveBuffer( Pixel::RGBA8888, width, height,width, height ); + TestControlRendererRender( application, actor, controlRenderer, 1u, - ImageDimensions(512, 513), - Integration::ResourcePointer(Integration::Bitmap::New(Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD)) ); + ImageDimensions(width, height), + Integration::ResourcePointer(bitmap) ); TestGlAbstraction& gl = application.GetGlAbstraction(); int textureUnit = -1; @@ -775,10 +789,13 @@ int UtcDaliRendererFactoryGetNPatchRendererN1(void) DALI_TEST_CHECK( controlRenderer ); Actor actor = Actor::New(); + //The testkit still has to load a bitmap for the broken renderer image + Integration::Bitmap* bitmap = Integration::Bitmap::New(Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD); + bitmap->GetPackedPixelsProfile()->ReserveBuffer( Pixel::RGBA8888, 100, 100, 100, 100 ); TestControlRendererRender( application, actor, controlRenderer, 1u, ImageDimensions(), - Integration::ResourcePointer(Integration::Bitmap::New(Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD)) ); + Integration::ResourcePointer(bitmap) ); TestGlAbstraction& gl = application.GetGlAbstraction(); int textureUnit = -1; @@ -806,10 +823,13 @@ int UtcDaliRendererFactoryGetNPatchRendererN2(void) DALI_TEST_CHECK( controlRenderer ); Actor actor = Actor::New(); + //The testkit still has to load a bitmap for the broken renderer image + Integration::Bitmap* bitmap = Integration::Bitmap::New(Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD); + bitmap->GetPackedPixelsProfile()->ReserveBuffer( Pixel::RGBA8888, 100, 100, 100, 100 ); TestControlRendererRender( application, actor, controlRenderer, 1u, ImageDimensions(), - Integration::ResourcePointer(Integration::Bitmap::New(Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD)) ); + Integration::ResourcePointer(bitmap) ); TestGlAbstraction& gl = application.GetGlAbstraction(); int textureUnit = -1; diff --git a/dali-toolkit/internal/text/shaper.cpp b/dali-toolkit/internal/text/shaper.cpp index 5061193..5313d0c 100644 --- a/dali-toolkit/internal/text/shaper.cpp +++ b/dali-toolkit/internal/text/shaper.cpp @@ -40,13 +40,14 @@ void ShapeText( const Vector& text, const Vector& lineBreakInfo, const Vector& scripts, const Vector& fonts, + CharacterIndex startCharacterIndex, + GlyphIndex startGlyphIndex, + Length numberOfCharacters, Vector& glyphs, Vector& glyphToCharacterMap, Vector& charactersPerGlyph, Vector& newParagraphGlyphs ) { - const Length numberOfCharacters = text.Count(); - if( 0u == numberOfCharacters ) { // Nothing to do if there are no characters. @@ -56,14 +57,15 @@ void ShapeText( const Vector& text, #ifdef DEBUG_ENABLED const Length numberOfFontRuns = fonts.Count(); const Length numberOfScriptRuns = scripts.Count(); + const Length totalNumberOfCharacters = text.Count(); #endif DALI_ASSERT_DEBUG( ( 0u != numberOfFontRuns ) && - ( numberOfCharacters == fonts[numberOfFontRuns - 1u].characterRun.characterIndex + fonts[numberOfFontRuns - 1u].characterRun.numberOfCharacters ) && + ( totalNumberOfCharacters == fonts[numberOfFontRuns - 1u].characterRun.characterIndex + fonts[numberOfFontRuns - 1u].characterRun.numberOfCharacters ) && "Toolkit::Text::ShapeText. All characters must have a font set." ); DALI_ASSERT_DEBUG( ( 0u != numberOfScriptRuns ) && - ( numberOfCharacters == scripts[numberOfScriptRuns - 1u].characterRun.characterIndex + scripts[numberOfScriptRuns - 1u].characterRun.numberOfCharacters ) && + ( totalNumberOfCharacters == scripts[numberOfScriptRuns - 1u].characterRun.characterIndex + scripts[numberOfScriptRuns - 1u].characterRun.numberOfCharacters ) && "Toolkit::Text::ShapeText. All characters must have a script set." ); // The text needs to be split in chunks of consecutive characters. @@ -73,8 +75,30 @@ void ShapeText( const Vector& text, TextAbstraction::Shaping shaping = TextAbstraction::Shaping::Get(); // To shape the text a font and an script is needed. + + // Get the font run containing the startCharacterIndex character. Vector::ConstIterator fontRunIt = fonts.Begin(); + for( Vector::ConstIterator endIt = fonts.End(); fontRunIt < endIt; ++fontRunIt ) + { + const FontRun& run = *fontRunIt; + if( startCharacterIndex < run.characterRun.characterIndex + run.characterRun.numberOfCharacters ) + { + // Found. + break; + } + } + + // Get the script run containing the startCharacterIndex character. Vector::ConstIterator scriptRunIt = scripts.Begin(); + for( Vector::ConstIterator endIt = scripts.End(); scriptRunIt < endIt; ++scriptRunIt ) + { + const ScriptRun& run = *scriptRunIt; + if( startCharacterIndex < run.characterRun.characterIndex + run.characterRun.numberOfCharacters ) + { + // Found. + break; + } + } // Index to the the next one to be shaped. Is pointing the character after the last one it was shaped. CharacterIndex previousIndex = 0u; @@ -87,20 +111,25 @@ void ShapeText( const Vector& text, // There is no way to know the number of glyphs before shaping the text. // To avoid reallocations it's reserved space for a slightly biger number of glyphs than the number of characters. - Length numberOfGlyphsReserved = static_cast( numberOfCharacters * 1.3f ); - glyphs.Resize( numberOfGlyphsReserved ); - glyphToCharacterMap.Resize( numberOfGlyphsReserved ); + const Length currentNumberOfGlyphs = glyphs.Count(); + const Length numberOfGlyphsReserved = static_cast( numberOfCharacters * 1.3f ); + glyphs.Resize( currentNumberOfGlyphs + numberOfGlyphsReserved ); + glyphToCharacterMap.Resize( currentNumberOfGlyphs + numberOfGlyphsReserved ); // The actual number of glyphs. - Length totalNumberOfGlyphs = 0u; + Length totalNumberOfGlyphs = currentNumberOfGlyphs; + // The number of new glyphs. + Length numberOfNewGlyphs = 0u; const Character* const textBuffer = text.Begin(); const LineBreakInfo* const lineBreakInfoBuffer = lineBreakInfo.Begin(); - GlyphInfo* glyphsBuffer = glyphs.Begin(); CharacterIndex* glyphToCharacterMapBuffer = glyphToCharacterMap.Begin(); + Length glyphIndex = startGlyphIndex; + // Traverse the characters and shape the text. - for( previousIndex = 0; previousIndex < numberOfCharacters; ) + const CharacterIndex lastCharacter = startCharacterIndex + numberOfCharacters; + for( previousIndex = startCharacterIndex; previousIndex < lastCharacter; ) { // Get the font id and the script. const FontRun& fontRun = *fontRunIt; @@ -138,40 +167,41 @@ void ShapeText( const Vector& text, currentFontId, currentScript ); - const Length glyphIndex = totalNumberOfGlyphs; - totalNumberOfGlyphs += numberOfGlyphs; - - if( totalNumberOfGlyphs > numberOfGlyphsReserved ) + // Retrieve the glyphs and the glyph to character conversion map. + Vector tmpGlyphs; + Vector tmpGlyphToCharacterMap; + tmpGlyphs.Resize( numberOfGlyphs ); + tmpGlyphToCharacterMap.Resize( numberOfGlyphs ); + shaping.GetGlyphs( tmpGlyphs.Begin(), + tmpGlyphToCharacterMap.Begin() ); + + // Update the indices. + if( 0u != totalNumberOfGlyphs ) { - // Resize the vectors to get enough space. - numberOfGlyphsReserved = static_cast( totalNumberOfGlyphs * 1.3f ); - glyphs.Resize( numberOfGlyphsReserved ); - glyphToCharacterMap.Resize( numberOfGlyphsReserved ); - - // Iterators are not valid anymore, set them again. - glyphsBuffer = glyphs.Begin(); - glyphToCharacterMapBuffer = glyphToCharacterMap.Begin(); + for( Vector::Iterator it = tmpGlyphToCharacterMap.Begin(), + endIt = tmpGlyphToCharacterMap.End(); + it != endIt; + ++it ) + { + *it += previousIndex; + } } - // Retrieve the glyphs and the glyph to character conversion map. - shaping.GetGlyphs( glyphsBuffer + glyphIndex, - glyphToCharacterMapBuffer + glyphIndex ); + totalNumberOfGlyphs += numberOfGlyphs; + numberOfNewGlyphs += numberOfGlyphs; + + glyphs.Insert( glyphs.Begin() + glyphIndex, tmpGlyphs.Begin(), tmpGlyphs.End() ); + glyphToCharacterMap.Insert( glyphToCharacterMap.Begin() + glyphIndex, tmpGlyphToCharacterMap.Begin(), tmpGlyphToCharacterMap.End() ); + glyphIndex += numberOfGlyphs; + + // Set the buffer pointers again. + glyphToCharacterMapBuffer = glyphToCharacterMap.Begin(); if( isNewParagraph ) { // Add the index of the new paragraph glyph to a vector. // Their metrics will be updated in a following step. - newParagraphGlyphs.PushBack( totalNumberOfGlyphs - 1u ); - } - - // Update indices. - if( 0u != glyphIndex ) - { - for( Length index = glyphIndex; index < glyphIndex + numberOfGlyphs; ++index ) - { - CharacterIndex& characterIndex = *( glyphToCharacterMapBuffer + index ); - characterIndex += previousIndex; - } + newParagraphGlyphs.PushBack( glyphIndex - 1u ); } // Update the iterators to get the next font or script run. @@ -188,19 +218,28 @@ void ShapeText( const Vector& text, previousIndex = currentIndex; } + // Update indices. + for( Length index = startGlyphIndex + numberOfNewGlyphs; index < totalNumberOfGlyphs; ++index ) + { + CharacterIndex& characterIndex = *( glyphToCharacterMapBuffer + index ); + characterIndex += numberOfCharacters; + } + // Add the number of characters per glyph. charactersPerGlyph.Reserve( totalNumberOfGlyphs ); - previousIndex = 0u; - for( Length index = 1u; index < totalNumberOfGlyphs; ++index ) + Length* charactersPerGlyphBuffer = charactersPerGlyph.Begin(); + + const GlyphIndex lastGlyph = startGlyphIndex + numberOfNewGlyphs; + previousIndex = startCharacterIndex; + for( Length index = startGlyphIndex + 1u; index < lastGlyph; ++index ) { const CharacterIndex characterIndex = *( glyphToCharacterMapBuffer + index ); - charactersPerGlyph.PushBack( characterIndex - previousIndex ); + charactersPerGlyph.Insert( charactersPerGlyphBuffer + index - 1u, characterIndex - previousIndex ); previousIndex = characterIndex; } - - charactersPerGlyph.PushBack( numberOfCharacters - previousIndex ); + charactersPerGlyph.Insert( charactersPerGlyphBuffer + lastGlyph - 1u, numberOfCharacters + startCharacterIndex - previousIndex ); // Resize the vectors to set the right number of items. glyphs.Resize( totalNumberOfGlyphs ); diff --git a/dali-toolkit/internal/text/shaper.h b/dali-toolkit/internal/text/shaper.h index 70e2e58..2cd47cb 100644 --- a/dali-toolkit/internal/text/shaper.h +++ b/dali-toolkit/internal/text/shaper.h @@ -44,6 +44,9 @@ class VisualModel; * @param[in] lineBreakInfo The line break info. * @param[in] scripts Vector containing the script runs for the whole text. * @param[in] fonts Vector with validated fonts. + * @param[in] startCharacterIndex The character from where the text is shaped. + * @param[in] startGlyphIndex The glyph from where the text is shaped. + * @param[in] numberOfCharacters The number of characters to be shaped. * @param[out] glyphs Vector of glyphs in the visual order. * @param[out] glyphToCharacterMap Vector containing the first character in the logical model that each glyph relates to. * @param[out] charactersPerGlyph Vector containing the number of characters per glyph. @@ -53,6 +56,9 @@ void ShapeText( const Vector& text, const Vector& lineBreakInfo, const Vector& scripts, const Vector& fonts, + CharacterIndex startCharacterIndex, + GlyphIndex startGlyphIndex, + Length numberOfCharacters, Vector& glyphs, Vector& glyphToCharacterMap, Vector& charactersPerGlyph, diff --git a/dali-toolkit/internal/text/text-controller-impl.cpp b/dali-toolkit/internal/text/text-controller-impl.cpp index 9458933..c2c2fa8 100644 --- a/dali-toolkit/internal/text/text-controller-impl.cpp +++ b/dali-toolkit/internal/text/text-controller-impl.cpp @@ -453,6 +453,7 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired ) Vector newParagraphGlyphs; newParagraphGlyphs.Reserve( numberOfParagraphs ); + GlyphIndex startGlyphIndex = 0u; if( SHAPE_TEXT & operations ) { const Vector& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters; @@ -461,21 +462,24 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired ) lineBreakInfo, scripts, validFonts, + startIndex, + startGlyphIndex, + requestedNumberOfCharacters, glyphs, glyphsToCharactersMap, charactersPerGlyph, newParagraphGlyphs ); // Create the 'number of glyphs' per character and the glyph to character conversion tables. - mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters ); - mVisualModel->CreateCharacterToGlyphTable( numberOfCharacters ); + mVisualModel->CreateGlyphsPerCharacterTable( startIndex, numberOfCharacters ); + mVisualModel->CreateCharacterToGlyphTable( startIndex, numberOfCharacters ); } const Length numberOfGlyphs = glyphs.Count(); if( GET_GLYPH_METRICS & operations ) { - GlyphInfo* glyphsBuffer = glyphs.Begin(); + GlyphInfo* glyphsBuffer = glyphs.Begin() + startGlyphIndex; mMetrics->GetGlyphMetrics( glyphsBuffer, numberOfGlyphs ); // Update the width and advance of all new paragraph characters. diff --git a/dali-toolkit/internal/text/visual-model-impl.cpp b/dali-toolkit/internal/text/visual-model-impl.cpp index 561beee..3e9c123 100644 --- a/dali-toolkit/internal/text/visual-model-impl.cpp +++ b/dali-toolkit/internal/text/visual-model-impl.cpp @@ -35,29 +35,50 @@ VisualModelPtr VisualModel::New() return VisualModelPtr( new VisualModel() ); } -void VisualModel::CreateCharacterToGlyphTable( Length numberOfCharacters ) +void VisualModel::CreateCharacterToGlyphTable( CharacterIndex startIndex, + Length numberOfCharacters ) { - // 1) Reserve some space for the characters to avoid reallocations. if( 0u == numberOfCharacters ) { - // If no number of characters is given, just set something sensible to avoid reallocations. - numberOfCharacters = static_cast ( static_cast( mGlyphs.Count() ) * 1.3f ); + // Nothing to do. + return; } - mCharactersToGlyph.Reserve( numberOfCharacters ); - DALI_ASSERT_DEBUG( mGlyphsPerCharacter.Count() != 0u || - ( 0u == numberOfCharacters ) ); + DALI_ASSERT_DEBUG( mGlyphsPerCharacter.Count() != 0u ); + + // Get the total number of characters. + const Length totalNumberOfCharacters = ( 0u == mGlyphsToCharacters.Count() ) ? 0u : *( mGlyphsToCharacters.End() - 1u ) + *( mCharactersPerGlyph.End() - 1u ); // Index to the first character + the number of characters that form the last glyph. + + // Whether the current buffer is being updated or is set from scratch. + const bool updateCurrentBuffer = numberOfCharacters < totalNumberOfCharacters; + + Vector newCharactersToGlyph; + GlyphIndex* charactersToGlyphBuffer = NULL; + + // 1) Reserve some space for the glyph indices to avoid reallocations. + if( updateCurrentBuffer ) + { + newCharactersToGlyph.Resize( numberOfCharacters ); + charactersToGlyphBuffer = newCharactersToGlyph.Begin(); + } + else + { + mCharactersToGlyph.Resize( numberOfCharacters ); + charactersToGlyphBuffer = mCharactersToGlyph.Begin() + startIndex; + } const Length* const glyphsPerCharacterBuffer = mGlyphsPerCharacter.Begin(); // 2) Traverse the glyphs and set the glyph indices per character. // Index to the glyph. - GlyphIndex glyphIndex = 0u; - CharacterIndex characterIndex = 0u; - for( Vector::ConstIterator it = mCharactersPerGlyph.Begin(), + const GlyphIndex startGlyphIndex = updateCurrentBuffer ? *( mCharactersToGlyph.Begin() + startIndex ) : 0u; + GlyphIndex glyphIndex = startGlyphIndex; + CharacterIndex characterIndex = startIndex; + const CharacterIndex lastCharacterIndexPlusOne = startIndex + numberOfCharacters; + for( Vector::ConstIterator it = mCharactersPerGlyph.Begin() + glyphIndex, endIt = mCharactersPerGlyph.End(); - it != endIt; + ( it != endIt ) && ( characterIndex < lastCharacterIndexPlusOne ); ++it ) { const Length numberOfCharactersPerGlyph = *it; @@ -66,34 +87,79 @@ void VisualModel::CreateCharacterToGlyphTable( Length numberOfCharacters ) // Set the glyph indices. for( Length index = 0u; index < numberOfCharactersPerGlyph; ++index, ++characterIndex ) { - mCharactersToGlyph.PushBack( glyphIndex ); + *charactersToGlyphBuffer = glyphIndex; numberOfGlyphs += *( glyphsPerCharacterBuffer + characterIndex ); + ++charactersToGlyphBuffer; } glyphIndex += numberOfGlyphs; } + + // If the character to glyph buffer is updated, it needs to be inserted in the model. + if( updateCurrentBuffer ) + { + // Update the indices. + const Length numberOfGlyphs = glyphIndex - startGlyphIndex; + for( Vector::Iterator it = mCharactersToGlyph.Begin() + startIndex, + endIt = mCharactersToGlyph.End(); + it != endIt; + ++it ) + { + *it += numberOfGlyphs; + } + + mCharactersToGlyph.Insert( mCharactersToGlyph.Begin() + startIndex, + newCharactersToGlyph.Begin(), + newCharactersToGlyph.End() ); + + } } -void VisualModel::CreateGlyphsPerCharacterTable( Length numberOfCharacters ) +void VisualModel::CreateGlyphsPerCharacterTable( CharacterIndex startIndex, + Length numberOfCharacters ) { - // 1) Reserve some space for the characters to avoid reallocations. if( 0u == numberOfCharacters ) { - // If no number of characters is given, just set something sensible to avoid reallocations. - numberOfCharacters = static_cast ( static_cast( mGlyphs.Count() ) * 1.3f ); + // Nothing to do. + return; + } + + // Get the total number of characters. + const Length totalNumberOfCharacters = ( 0u == mGlyphsToCharacters.Count() ) ? 0u : *( mGlyphsToCharacters.End() - 1u ) + *( mCharactersPerGlyph.End() - 1u ); // Index to the first character + the number of characters that form the last glyph. + + // Whether the current buffer is being updated or is set from scratch. + const bool updateCurrentBuffer = numberOfCharacters < totalNumberOfCharacters; + + Vector newGlyphsPerCharacter; + Length* glyphsPerCharacterBuffer = NULL; + + // 1) Reserve some space for the glyphs per character to avoid reallocations. + if( updateCurrentBuffer ) + { + newGlyphsPerCharacter.Resize( numberOfCharacters ); + glyphsPerCharacterBuffer = newGlyphsPerCharacter.Begin(); + } + else + { + mGlyphsPerCharacter.Resize( numberOfCharacters ); + glyphsPerCharacterBuffer = mGlyphsPerCharacter.Begin() + startIndex; } - mGlyphsPerCharacter.Reserve( numberOfCharacters ); // 2) Traverse the glyphs and set the number of glyphs per character. + // The glyph index. + const GlyphIndex glyphIndex = updateCurrentBuffer ? *( mCharactersToGlyph.Begin() + startIndex ) : 0u; + Length traversedCharacters = 0; + // The number of 'characters per glyph' equal to zero. Length zeroCharactersPerGlyph = 0u; - for( Vector::ConstIterator it = mCharactersPerGlyph.Begin(), + for( Vector::ConstIterator it = mCharactersPerGlyph.Begin() + glyphIndex, endIt = mCharactersPerGlyph.End(); - it != endIt; + ( it != endIt ) && ( traversedCharacters < numberOfCharacters ); ++it ) { const Length numberOfCharactersPerGlyph = *it; + traversedCharacters += numberOfCharactersPerGlyph; // Set the glyphs per character. if( 0u == numberOfCharactersPerGlyph ) @@ -103,16 +169,30 @@ void VisualModel::CreateGlyphsPerCharacterTable( Length numberOfCharacters ) else { const Length numberOfZeroGlyphsPerCharacter = ( numberOfCharactersPerGlyph - 1u ); - for( Length zeroIndex = 0u; zeroIndex < numberOfZeroGlyphsPerCharacter ; ++zeroIndex ) + for( Length zeroIndex = 0u; zeroIndex < numberOfZeroGlyphsPerCharacter; ++zeroIndex ) { - mGlyphsPerCharacter.PushBack( 0u ); + *glyphsPerCharacterBuffer = 0u; + + // Point to the next position in the buffer. + ++glyphsPerCharacterBuffer; } - mGlyphsPerCharacter.PushBack( 1u + zeroCharactersPerGlyph ); + *glyphsPerCharacterBuffer = zeroCharactersPerGlyph + 1u; zeroCharactersPerGlyph = 0u; + + // Point to the next position in the buffer. + ++glyphsPerCharacterBuffer; } } + + // If the glyphs per character buffer is updated, it needs to be inserted in the model. + if( updateCurrentBuffer ) + { + mGlyphsPerCharacter.Insert( mGlyphsPerCharacter.Begin() + startIndex, + newGlyphsPerCharacter.Begin(), + newGlyphsPerCharacter.End() ); + } } void VisualModel::GetGlyphs( GlyphInfo* glyphs, diff --git a/dali-toolkit/internal/text/visual-model-impl.h b/dali-toolkit/internal/text/visual-model-impl.h index ca579e1..eb2e5a0 100644 --- a/dali-toolkit/internal/text/visual-model-impl.h +++ b/dali-toolkit/internal/text/visual-model-impl.h @@ -66,16 +66,20 @@ public: * * @pre The glyphs per character table needs to be created first. * + * @param[in] startIndex The character from where the conversion table is created. * @param[in] numberOfCharacters The number of characters. */ - void CreateCharacterToGlyphTable( Length numberOfCharacters = 0u ); + void CreateCharacterToGlyphTable( CharacterIndex startIndex, + Length numberOfCharacters ); /** * @brief Creates an array containing the number of glyphs per character. * + * @param[in] startIndex The character from where the table is created. * @param[in] numberOfCharacters The number of characters. */ - void CreateGlyphsPerCharacterTable( Length numberOfCharacters = 0u ); + void CreateGlyphsPerCharacterTable( CharacterIndex startIndex, + Length numberOfCharacters ); /** * @brief Retrieves glyphs in the given buffer. diff --git a/dali-toolkit/public-api/dali-toolkit-version.cpp b/dali-toolkit/public-api/dali-toolkit-version.cpp index 6189b91..8b743f4 100644 --- a/dali-toolkit/public-api/dali-toolkit-version.cpp +++ b/dali-toolkit/public-api/dali-toolkit-version.cpp @@ -31,7 +31,7 @@ namespace Toolkit const unsigned int TOOLKIT_MAJOR_VERSION = 1; const unsigned int TOOLKIT_MINOR_VERSION = 1; -const unsigned int TOOLKIT_MICRO_VERSION = 24; +const unsigned int TOOLKIT_MICRO_VERSION = 25; const char * const TOOLKIT_BUILD_DATE = __DATE__ " " __TIME__; #ifdef DEBUG_ENABLED diff --git a/packaging/dali-toolkit.spec b/packaging/dali-toolkit.spec index 9e2f459..3be221d 100644 --- a/packaging/dali-toolkit.spec +++ b/packaging/dali-toolkit.spec @@ -1,6 +1,6 @@ Name: dali-toolkit Summary: The OpenGLES Canvas Core Library Toolkit -Version: 1.1.24 +Version: 1.1.25 Release: 1 Group: System/Libraries License: Apache-2.0 and BSD-2-Clause and MIT