const Toolkit::AtlasManager::Mesh2D& second,
bool optimize )
{
- uint32_t vc = first.mVertices.Size();
+ const uint32_t verticesCount = first.mVertices.Size();
+ first.mVertices.Insert( first.mVertices.End(),
+ second.mVertices.Begin(),
+ second.mVertices.End() );
- for ( uint32_t v = 0; v < second.mVertices.Size(); ++v )
- {
- first.mVertices.PushBack( second.mVertices[ v ] );
- }
+ const uint32_t indicesCount = first.mIndices.Size();
+ first.mIndices.Insert( first.mIndices.End(),
+ second.mIndices.Begin(),
+ second.mIndices.End() );
- for ( uint32_t i = 0; i < second.mIndices.Size(); ++i )
+ for( Vector<unsigned int>::Iterator it = first.mIndices.Begin() + indicesCount,
+ endIt = first.mIndices.End();
+ it != endIt;
+ ++it )
{
- first.mIndices.PushBack( second.mIndices[ i ] + vc );
+ *it += verticesCount;
}
if ( optimize )
}
}
-void AtlasManager::StitchMesh( const Toolkit::AtlasManager::Mesh2D& first,
- const Toolkit::AtlasManager::Mesh2D& second,
- Toolkit::AtlasManager::Mesh2D& out,
- bool optimize )
-{
- uint32_t vc = first.mVertices.Size();
-
- for ( uint32_t v = 0; v < vc; ++v )
- {
- out.mVertices.PushBack( first.mVertices[ v ] );
- }
-
- for ( uint32_t v = 0; v < second.mVertices.Size(); ++v )
- {
- out.mVertices.PushBack( second.mVertices[ v ] );
- }
-
- for ( uint32_t i = 0; i < first.mIndices.Size(); ++i )
- {
- out.mIndices.PushBack( first.mIndices[ i ] );
- }
-
- for ( uint32_t i = 0; i < second.mIndices.Size(); ++i )
- {
- out.mIndices.PushBack( second.mIndices[ i ] + vc );
- }
-
- if ( optimize )
- {
- Toolkit::AtlasManager::Mesh2D optimizedMesh;
- OptimizeMesh( out, optimizedMesh );
- out = optimizedMesh;
- }
-}
-
void AtlasManager::UploadImage( const BufferImage& image,
const AtlasSlotDescriptor& desc )
{
bool optimize );
/**
- * @copydoc Toolkit::AtlasManager::StitchMesh
- */
- void StitchMesh( const Toolkit::AtlasManager::Mesh2D& first,
- const Toolkit::AtlasManager::Mesh2D& second,
- Toolkit::AtlasManager::Mesh2D& out,
- bool optimize );
-
- /**
* @copydoc Toolkit::AtlasManager::Remove
*/
bool Remove( ImageId id );
} // namespace Dali
- #endif // __DALI_TOOLKIT_ATLAS_MANAGER_IMPL_H__
\ No newline at end of file
+ #endif // __DALI_TOOLKIT_ATLAS_MANAGER_IMPL_H__
GetImplementation(*this).StitchMesh( first, second, optimize );
}
-void AtlasManager::StitchMesh( const Mesh2D& first,
- const Mesh2D& second,
- Mesh2D& out,
- bool optimize )
-{
- GetImplementation(*this).StitchMesh( first, second, out, optimize );
-}
-
Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
{
return GetImplementation(*this).GetAtlasContainer( atlas );
bool optimize = false );
/**
- * @brief Combine two meshes, outputting the result into a new mesh
- *
- * @param[in] first First mesh
- * @param[in] second Second mesh
- * @param[in] optimize should we optimize vertex data
- * @param[out] out resulting mesh
- */
- void StitchMesh( const Mesh2D& first,
- const Mesh2D& second,
- Mesh2D& out,
- bool optimize = false );
-
- /**
* @brief Get the BufferImage containing an atlas
*
* @param[in] atlas AtlasId returned when atlas was created
--- /dev/null
+#ifndef __DALI_TOOLKIT_TEXT_GLYPH_RUN_H__
+#define __DALI_TOOLKIT_TEXT_GLYPH_RUN_H__
+
+/*
+ * Copyright (c) 2015 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief A run of consecutive glyphs.
+ */
+struct GlyphRun
+{
+ GlyphIndex glyphIndex; ///< Index to the first glyph.
+ Length numberOfGlyphs; ///< Number of glyphs in the run.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // __DALI_TOOLKIT_TEXT_GLYPH_RUN_H__
penY -= layout.ascender - lineRun.descender;
- ellipsisLayout.glyphIndex = lineRun.glyphIndex;
+ ellipsisLayout.glyphIndex = lineRun.glyphRun.glyphIndex;
}
else
{
- lineRun.glyphIndex = 0u;
+ lineRun.glyphRun.glyphIndex = 0u;
ellipsisLayout.glyphIndex = 0u;
}
currentParagraphDirection,
true );
- lineRun.numberOfGlyphs = ellipsisLayout.numberOfGlyphs;
+ lineRun.glyphRun.numberOfGlyphs = ellipsisLayout.numberOfGlyphs;
lineRun.characterRun.characterIndex = ellipsisLayout.characterIndex;
lineRun.characterRun.numberOfCharacters = ellipsisLayout.numberOfCharacters;
lineRun.width = ellipsisLayout.length;
actualSize.width = layoutParameters.boundingBox.width;
actualSize.height += ( lineRun.ascender + -lineRun.descender );
- SetGlyphPositions( layoutParameters.glyphsBuffer + lineRun.glyphIndex,
+ SetGlyphPositions( layoutParameters.glyphsBuffer + lineRun.glyphRun.glyphIndex,
ellipsisLayout.numberOfGlyphs,
penY,
- glyphPositions.Begin() + lineRun.glyphIndex );
+ glyphPositions.Begin() + lineRun.glyphRun.glyphIndex );
if( 0u != numberOfLines )
{
const bool isLastLine = index + layout.numberOfGlyphs == layoutParameters.totalNumberOfGlyphs;
LineRun lineRun;
- lineRun.glyphIndex = index;
- lineRun.numberOfGlyphs = layout.numberOfGlyphs;
+ lineRun.glyphRun.glyphIndex = index;
+ lineRun.glyphRun.numberOfGlyphs = layout.numberOfGlyphs;
lineRun.characterRun.characterIndex = layout.characterIndex;
lineRun.characterRun.numberOfCharacters = layout.numberOfCharacters;
if( isLastLine && !layoutParameters.isLastNewParagraph )
mFontClient.GetFontMetrics( glyphInfo.fontId, fontMetrics );
LineRun lineRun;
- lineRun.glyphIndex = 0u;
- lineRun.numberOfGlyphs = 0u;
+ lineRun.glyphRun.glyphIndex = 0u;
+ lineRun.glyphRun.numberOfGlyphs = 0u;
lineRun.characterRun.characterIndex = 0u;
lineRun.characterRun.numberOfCharacters = 0u;
lineRun.width = 0.f;
// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/character-run.h>
+#include <dali-toolkit/internal/text/glyph-run.h>
namespace Dali
{
*/
struct LineRun
{
- GlyphIndex glyphIndex; ///< The initial glyph index.
- Length numberOfGlyphs; ///< The number of glyphs of the run.
- CharacterRun characterRun; ///< The initial character and the number of characters.
+ GlyphRun glyphRun; ///< The initial glyph index and the number of glyphs of the run.
+ CharacterRun characterRun; ///< The initial character index and the number of characters of the run.
float width; ///< The line's width.
float ascender; ///< The line's ascender.
float descender; ///< The line's descender.
-
#ifndef __DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_IMPL_H__
#define __DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_IMPL_H__
} // namespace Dali
-
- #endif // __DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_IMPL_H__
+#endif // __DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_IMPL_H__
// INTERNAL INCLUDES
#include <dali-toolkit/public-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/internal/text/glyph-run.h>
#include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
#include <dali-toolkit/internal/text/text-view.h>
FrameBufferImage mBuffer;
};
+ /**
+ * brief Struct used to generate the underline mesh.
+ * There is one Extent per line of text.
+ */
struct Extent
{
Extent()
mQuadIndexFormat[ "indices" ] = Property::INTEGER;
}
+ bool IsGlyphUnderlined( GlyphIndex index,
+ const Vector<GlyphRun>& underlineRuns )
+ {
+ // TODO: At the moment it works because we always traverse the glyphs starting from the beginning
+ // and there is only one glyph run! If there are more they should be ordered.
+
+ for( Vector<GlyphRun>::ConstIterator it = underlineRuns.Begin(),
+ endIt = underlineRuns.End();
+ it != endIt;
+ ++it )
+ {
+ const GlyphRun& run = *it;
+
+ if( ( run.glyphIndex <= index ) && ( index < run.glyphIndex + run.numberOfGlyphs ) )
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
void AddGlyphs( Text::ViewInterface& view,
- const std::vector<Vector2>& positions,
+ const Vector<Vector2>& positions,
const Vector<GlyphInfo>& glyphs,
int depth )
{
mDepth = depth;
const Vector2& actorSize( view.GetControlSize() );
- Vector2 halfActorSize( actorSize * 0.5f );
+ const Vector2 halfActorSize( actorSize * 0.5f );
const Vector4& textColor( view.GetTextColor() );
const Vector2& shadowOffset( view.GetShadowOffset() );
const Vector4& shadowColor( view.GetShadowColor() );
- bool underlineEnabled( view.IsUnderlineEnabled() );
+ const bool underlineEnabled( view.IsUnderlineEnabled() );
const Vector4& underlineColor( view.GetUnderlineColor() );
- float underlineHeight( view.GetUnderlineHeight() );
+ const float underlineHeight( view.GetUnderlineHeight() );
+
+ // Get the underline runs.
+ const Length numberOfUnderlineRuns = view.GetNumberOfUnderlineRuns();
+ Vector<GlyphRun> underlineRuns;
+ underlineRuns.Resize( numberOfUnderlineRuns );
+ view.GetUnderlineRuns( underlineRuns.Begin(),
+ 0u,
+ numberOfUnderlineRuns );
+
+ bool thereAreUnderlinedGlyphs = false;
float currentUnderlinePosition = ZERO;
float currentUnderlineThickness = underlineHeight;
uint32_t currentBlockSize = 0;
FontId lastFontId = 0;
+ FontId lastUnderlinedFontId = 0;
Style style = STYLE_NORMAL;
if ( fabsf( shadowOffset.x ) > Math::MACHINE_EPSILON_1 || fabsf( shadowOffset.y ) > Math::MACHINE_EPSILON_1 )
// Avoid emptying mTextCache (& removing references) until after incremented references for the new text
Vector< TextCacheEntry > newTextCache;
const GlyphInfo* const glyphsBuffer = glyphs.Begin();
+ const Vector2* const positionsBuffer = positions.Begin();
for( uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i )
{
const GlyphInfo& glyph = *( glyphsBuffer + i );
+ const bool underlineGlyph = underlineEnabled || IsGlyphUnderlined( i, underlineRuns );
+ thereAreUnderlinedGlyphs = thereAreUnderlinedGlyphs || underlineGlyph;
+
// No operation for white space
if ( glyph.width && glyph.height )
{
// Are we still using the same fontId as previous
- if ( glyph.fontId != lastFontId )
+ if ( underlineGlyph && ( glyph.fontId != lastUnderlinedFontId ) )
{
// We need to fetch fresh font underline metrics
FontMetrics fontMetrics;
// Move offset down by one ( EFL behavior )
currentUnderlinePosition = ONE;
}
- }
+
+ lastUnderlinedFontId = glyph.fontId;
+ } // underline
if ( !mGlyphManager.Cached( glyph.fontId, glyph.index, slot ) )
{
}
// Move the origin (0,0) of the mesh to the center of the actor
- Vector2 position = positions[ i ] - halfActorSize;
+ Vector2 position = *( positionsBuffer + i ) - halfActorSize;
// Generate mesh data for this quad, plugging in our supplied position
AtlasManager::Mesh2D newMesh;
extents,
textColor,
position.y + glyph.yBearing,
+ underlineGlyph,
currentUnderlinePosition,
currentUnderlineThickness,
slot );
RemoveText();
mTextCache.Swap( newTextCache );
- if ( underlineEnabled )
+ if( thereAreUnderlinedGlyphs )
{
// Check to see if any of the text needs an underline
GenerateUnderlines( meshContainer, extents, underlineColor, textColor );
Vector< Extent >& extents,
const Vector4& color,
float baseLine,
+ bool underlineGlyph,
float underlinePosition,
float underlineThickness,
AtlasManager::AtlasSlot& slot )
{
// Stitch the mesh to the existing mesh and adjust any extents
mGlyphManager.StitchMesh( mIt->mMesh, newMesh );
- AdjustExtents( extents,
- meshContainer,
- index,
- left,
- right,
- baseLine,
- underlinePosition,
- underlineThickness );
+
+ if( underlineGlyph )
+ {
+ AdjustExtents( extents,
+ meshContainer,
+ index,
+ left,
+ right,
+ baseLine,
+ underlinePosition,
+ underlineThickness );
+ }
+
return;
}
}
meshRecord.mColor = color;
meshContainer.push_back( meshRecord );
- // Adjust extents for this new meshrecord
- AdjustExtents( extents,
- meshContainer,
- meshContainer.size() - 1u,
- left,
- right,
- baseLine,
- underlinePosition,
- underlineThickness );
-
+ if( underlineGlyph )
+ {
+ // Adjust extents for this new meshrecord
+ AdjustExtents( extents,
+ meshContainer,
+ meshContainer.size() - 1u,
+ left,
+ right,
+ baseLine,
+ underlinePosition,
+ underlineThickness );
+ }
}
}
Vector<GlyphInfo> glyphs;
glyphs.Resize( numberOfGlyphs );
- std::vector<Vector2> positions;
- positions.resize( numberOfGlyphs );
+ Vector<Vector2> positions;
+ positions.Resize( numberOfGlyphs );
numberOfGlyphs = view.GetGlyphs( glyphs.Begin(),
- &positions[0],
+ positions.Begin(),
0u,
numberOfGlyphs );
glyphs.Resize( numberOfGlyphs );
- positions.resize( numberOfGlyphs );
+ positions.Resize( numberOfGlyphs );
mImpl->AddGlyphs( view,
positions,
this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
+ // TODO: At the moment the underline runs are only for pre-edit.
+ mImpl->mVisualModel->mUnderlineRuns.Clear();
+
Vector<Character> utf32Characters;
Length characterCount( 0u );
}
else // PRE_EDIT
{
- if( ! mImpl->mEventData->mPreEditFlag )
+ if( !mImpl->mEventData->mPreEditFlag )
{
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state" );
mImpl->mEventData->mPreEditLength = utf32Characters.Count();
mImpl->mEventData->mPreEditFlag = true;
+ // Add the underline for the pre-edit text.
+ const GlyphIndex* const charactersToGlyphBuffer = mImpl->mVisualModel->mCharactersToGlyph.Begin();
+ const Length* const glyphsPerCharacterBuffer = mImpl->mVisualModel->mGlyphsPerCharacter.Begin();
+
+ const GlyphIndex glyphStart = *( charactersToGlyphBuffer + mImpl->mEventData->mPreEditStartPosition );
+ const CharacterIndex lastPreEditCharacter = mImpl->mEventData->mPreEditStartPosition + ( ( mImpl->mEventData->mPreEditLength > 0u ) ? mImpl->mEventData->mPreEditLength - 1u : 0u );
+ const Length numberOfGlyphsLastCharacter = *( glyphsPerCharacterBuffer + lastPreEditCharacter );
+ const GlyphIndex glyphEnd = *( charactersToGlyphBuffer + lastPreEditCharacter ) + ( numberOfGlyphsLastCharacter > 1u ? numberOfGlyphsLastCharacter - 1u : 0u );
+
+ GlyphRun underlineRun;
+ underlineRun.glyphIndex = glyphStart;
+ underlineRun.numberOfGlyphs = 1u + glyphEnd - glyphStart;
+
+ // TODO: At the moment the underline runs are only for pre-edit.
+ mImpl->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
+
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
}
}
typedef uint32_t GlyphIndex; ///< An index into an array of glyphs.
typedef uint32_t ScriptRunIndex; ///< An index into an array of script runs.
typedef uint32_t FontRunIndex; ///< An index into an array of font runs.
+typedef uint32_t UnderlineRunIndex; ///< An index into an array of underline runs.
typedef uint32_t BidirectionalRunIndex; ///< An index into an array of font runs.
typedef uint32_t LineIndex; ///< An index into an array of lines.
for( unsigned int i=0; i<lineRuns.Count(); ++i )
{
// e.g. Print "Line 0 Glyphs: 0->9 Characters: 0->9 (10)" for a ten character run staring from beginning of the model
- o << "Line " << i << " Glyphs: " << lineRuns[i].glyphIndex << "->" << (lineRuns[i].glyphIndex + lineRuns[i].numberOfGlyphs );
+ o << "Line " << i << " Glyphs: " << lineRuns[i].glyphRun.glyphIndex << "->" << (lineRuns[i].glyphRun.glyphIndex + lineRuns[i].glyphRun.numberOfGlyphs );
o << " Characters: " << lineRuns[i].characterRun.characterIndex << "->" << (lineRuns[i].characterRun.characterIndex + lineRuns[i].characterRun.numberOfCharacters );
o << " Width: " << lineRuns[i].width;
o << " Ascender: " << lineRuns[i].ascender;
namespace Text
{
+struct GlyphRun;
+
/**
* @brief Abstract interface to provide the information necessary displaying text.
*
*/
virtual float GetUnderlineHeight() const = 0;
+ /**
+ * @brief Retrieves the number of underline runs.
+ *
+ * @return The number of underline runs.
+ */
+ virtual Length GetNumberOfUnderlineRuns() const = 0;
+
+ /**
+ * @brief Retrieves the underline runs.
+ *
+ * @param[out] underlineRuns Pointer to a buffer where the underline runs are copied.
+ * @param[in] index Index of the first underline run to be copied.
+ * @param[in] numberOfRuns Number of underline runs to be copied.
+ */
+ virtual void GetUnderlineRuns( GlyphRun* underlineRuns,
+ UnderlineRunIndex index,
+ Length numberOfRuns ) const = 0;
};
} // namespace Text
// Otherwise use the given number of glyphs.
if( lastLine.ellipsis )
{
- numberOfLaidOutGlyphs = lastLine.glyphIndex + lastLine.numberOfGlyphs;
+ numberOfLaidOutGlyphs = lastLine.glyphRun.glyphIndex + lastLine.glyphRun.numberOfGlyphs;
}
else
{
LineRun* line = lineBuffer + lineIndex;
// Index of the last glyph of the line.
- GlyphIndex lastGlyphIndexOfLine = line->glyphIndex + line->numberOfGlyphs - 1u;
+ GlyphIndex lastGlyphIndexOfLine = line->glyphRun.glyphIndex + line->glyphRun.numberOfGlyphs - 1u;
// Add the alignment offset to the glyph's position.
for( Length index = 0u; index < numberOfLaidOutGlyphs; ++index )
if( lineIndex < numberOfLines )
{
line = lineBuffer + lineIndex;
- lastGlyphIndexOfLine = line->glyphIndex + line->numberOfGlyphs - 1u;
+ lastGlyphIndexOfLine = line->glyphRun.glyphIndex + line->glyphRun.numberOfGlyphs - 1u;
}
}
}
return 0.0f;
}
+Length View::GetNumberOfUnderlineRuns() const
+{
+ if( mImpl->mVisualModel )
+ {
+ return mImpl->mVisualModel->mUnderlineRuns.Count();
+ }
+
+ return 0u;
+}
+
+void View::GetUnderlineRuns( GlyphRun* underlineRuns,
+ UnderlineRunIndex index,
+ Length numberOfRuns ) const
+{
+ if( mImpl->mVisualModel )
+ {
+ mImpl->mVisualModel->GetUnderlineRuns( underlineRuns,
+ index,
+ numberOfRuns );
+ }
+}
} // namespace Text
*/
virtual float GetUnderlineHeight() const;
+ /**
+ * @copydoc Dali::Toolkit::Text::ViewInterface::GetNumberOfUnderlineRuns()
+ */
+ virtual Length GetNumberOfUnderlineRuns() const;
+
+ /**
+ * @copydoc Dali::Toolkit::Text::ViewInterface::GetUnderlineRuns()
+ */
+ virtual void GetUnderlineRuns( GlyphRun* underlineRuns,
+ UnderlineRunIndex index,
+ Length numberOfRuns ) const;
+
private:
// Undefined
{
const LineRun& line = *it;
- if( ( line.glyphIndex + line.numberOfGlyphs > glyphIndex ) &&
- ( lastGlyphIndex > line.glyphIndex ) )
+ if( ( line.glyphRun.glyphIndex + line.glyphRun.numberOfGlyphs > glyphIndex ) &&
+ ( lastGlyphIndex > line.glyphRun.glyphIndex ) )
{
firstLineFound = true;
++numberOfLines;
}
- else if( lastGlyphIndex <= line.glyphIndex )
+ else if( lastGlyphIndex <= line.glyphRun.glyphIndex )
{
// nothing else to do.
break;
return index;
}
+void VisualModel::GetUnderlineRuns( GlyphRun* underlineRuns,
+ UnderlineRunIndex index,
+ Length numberOfRuns ) const
+{
+ memcpy( underlineRuns,
+ mUnderlineRuns.Begin() + index,
+ numberOfRuns * sizeof( GlyphRun ) );
+}
+
void VisualModel::SetNaturalSize( const Vector2& size )
{
mNaturalSize = size;
*/
LineIndex GetLineOfCharacter( CharacterIndex characterIndex );
+ // Underline runs
+
+ /**
+ * @brief Retrieves the underline runs.
+ *
+ * @param[out] underlineRuns Pointer to a buffer where the underline runs are copied.
+ * @param[in] index Index of the first underline run to be copied.
+ * @param[in] numberOfRuns Number of underline runs to be copied.
+ */
+ void GetUnderlineRuns( GlyphRun* underlineRuns,
+ UnderlineRunIndex index,
+ Length numberOfRuns ) const;
+
// Size interface
/**
Vector<Length> mGlyphsPerCharacter; ///< For each character, the number of glyphs that are shaped.
Vector<Vector2> mGlyphPositions; ///< For each glyph, the position.
Vector<LineRun> mLines; ///< The laid out lines.
+ Vector<GlyphRun> mUnderlineRuns; ///< Runs of glyphs that are underlined.
Vector2 mControlSize; ///< The size of the UI control the decorator is adding it's decorations to.
Vector4 mTextColor; ///< The text color