X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ftext%2Frendering%2Fatlas%2Ftext-atlas-renderer.cpp;h=a21078508a9cd9a2c4161643cc80f1ceb80f9834;hp=ef80844e755c04ac69bf393a7638d95536426fe1;hb=29a52105283ce8ced672ed92545daeacf882316a;hpb=22fd3cd73ef12d4ef88f12eed11a2d6665a34c5a diff --git a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp index ef80844..a210785 100644 --- a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp +++ b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp @@ -46,6 +46,7 @@ Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT const float ZERO(0.0f); const float HALF(0.5f); const float ONE(1.0f); +const float ONE_AND_A_HALF(1.5f); const uint32_t DOUBLE_PIXEL_PADDING = 4u; //Padding will be added twice to Atlas const uint16_t NO_OUTLINE = 0u; } // namespace @@ -70,7 +71,7 @@ struct AtlasRenderer::Impl }; /** - * brief Struct used to generate the underline mesh. + * brief Struct used to generate the underline/striketthrough mesh. * There is one Extent per line of text. */ struct Extent @@ -80,9 +81,10 @@ struct AtlasRenderer::Impl mLeft(0.0f), mRight(0.0f), mUnderlinePosition(0.0f), - mUnderlineThickness(0.0f), + mLineThickness(0.0f), mMeshRecordIndex(0u), - mUnderlineChunkId(0u) + mUnderlineChunkId(0u), + mStrikethroughPosition(0.0f) { } @@ -90,9 +92,10 @@ struct AtlasRenderer::Impl float mLeft; float mRight; float mUnderlinePosition; - float mUnderlineThickness; + float mLineThickness; uint32_t mMeshRecordIndex; uint32_t mUnderlineChunkId; + float mStrikethroughPosition; }; struct MaxBlockSize @@ -283,27 +286,31 @@ struct AtlasRenderer::Impl const Vector4& color, uint16_t outline, AtlasManager::AtlasSlot& slot, - bool underlineGlyph, + bool decorationlineGlyph, float currentUnderlinePosition, - float currentUnderlineThickness, + float currentlineThickness, std::vector& meshContainer, Vector& newTextCache, Vector& extents, - uint32_t underlineChunkId) + uint32_t underlineChunkId, + bool isGlyphCached) { // Generate mesh data for this quad, plugging in our supplied position AtlasManager::Mesh2D newMesh; mGlyphManager.GenerateMeshData(slot.mImageId, position, newMesh); - TextCacheEntry textCacheEntry; - textCacheEntry.mFontId = glyph.fontId; - textCacheEntry.mImageId = slot.mImageId; - textCacheEntry.mIndex = glyph.index; - textCacheEntry.mOutlineWidth = outline; - textCacheEntry.isItalic = glyph.isItalicRequired; - textCacheEntry.isBold = glyph.isBoldRequired; - - newTextCache.PushBack(textCacheEntry); + if(!isGlyphCached) + { + TextCacheEntry textCacheEntry; + textCacheEntry.mFontId = glyph.fontId; + textCacheEntry.mImageId = slot.mImageId; + textCacheEntry.mIndex = glyph.index; + textCacheEntry.mOutlineWidth = outline; + textCacheEntry.isItalic = glyph.isItalicRequired; + textCacheEntry.isBold = glyph.isBoldRequired; + + newTextCache.PushBack(textCacheEntry); + } AtlasManager::Vertex2D* verticesBuffer = newMesh.mVertices.Begin(); @@ -322,11 +329,12 @@ struct AtlasRenderer::Impl newMesh, extents, position.y + glyph.yBearing, - underlineGlyph, + decorationlineGlyph, currentUnderlinePosition, - currentUnderlineThickness, + currentlineThickness, slot, - underlineChunkId); + underlineChunkId, + position.y + (glyph.height * HALF)); } void CreateActors(const std::vector& meshContainer, @@ -416,21 +424,28 @@ struct AtlasRenderer::Impl std::vector meshContainer; std::vector meshContainerOutline; Vector extents; + Vector strikethroughExtents; mDepth = depth; - const Vector2& textSize(view.GetLayoutSize()); - const Vector2 halfTextSize(textSize * 0.5f); - const Vector2& shadowOffset(view.GetShadowOffset()); - const Vector4& shadowColor(view.GetShadowColor()); - const bool underlineEnabled = view.IsUnderlineEnabled(); - const Vector4& underlineColor(view.GetUnderlineColor()); - const float underlineHeight = view.GetUnderlineHeight(); - const uint16_t outlineWidth = view.GetOutlineWidth(); - const Vector4& outlineColor(view.GetOutlineColor()); - const bool isOutline = 0u != outlineWidth; - const GlyphInfo* hyphens = view.GetHyphens(); - const Length* hyphenIndices = view.GetHyphenIndices(); - const Length hyphensCount = view.GetHyphensCount(); + const Vector2& textSize(view.GetLayoutSize()); + const Vector2 halfTextSize(textSize * 0.5f); + const Vector2& shadowOffset(view.GetShadowOffset()); + const Vector4& shadowColor(view.GetShadowColor()); + const bool underlineEnabled = view.IsUnderlineEnabled(); + const Vector4& underlineColor(view.GetUnderlineColor()); + const float underlineHeight = view.GetUnderlineHeight(); + const Text::Underline::Type underlineType = view.GetUnderlineType(); + const float dashedUnderlineWidth = view.GetDashedUnderlineWidth(); + const float dashedUnderlineGap = view.GetDashedUnderlineGap(); + const uint16_t outlineWidth = view.GetOutlineWidth(); + const Vector4& outlineColor(view.GetOutlineColor()); + const bool isOutline = 0u != outlineWidth; + const GlyphInfo* hyphens = view.GetHyphens(); + const Length* hyphenIndices = view.GetHyphenIndices(); + const Length hyphensCount = view.GetHyphensCount(); + const bool strikethroughEnabled = view.IsStrikethroughEnabled(); + const Vector4& strikethroughColor(view.GetStrikethroughColor()); + const float strikethroughHeight = view.GetStrikethroughHeight(); // Elided text info. Indices according to elided text. const auto startIndexOfGlyphs = view.GetStartIndexOfElidedGlyphs(); @@ -448,12 +463,14 @@ struct AtlasRenderer::Impl numberOfUnderlineRuns); bool thereAreUnderlinedGlyphs = false; + bool strikethroughGlyphsExist = false; - float currentUnderlinePosition = ZERO; - float currentUnderlineThickness = underlineHeight; - FontId lastFontId = 0; - FontId lastUnderlinedFontId = 0; - Style style = STYLE_NORMAL; + float currentUnderlinePosition = ZERO; + float currentUnderlineThickness = underlineHeight; + float currentStrikethroughThickness = strikethroughHeight; + 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) { @@ -499,12 +516,13 @@ struct AtlasRenderer::Impl const bool isGlyphUnderlined = underlineEnabled || IsGlyphUnderlined(i, underlineRuns); thereAreUnderlinedGlyphs = thereAreUnderlinedGlyphs || isGlyphUnderlined; + strikethroughGlyphsExist = strikethroughGlyphsExist || strikethroughEnabled; // No operation for white space if(glyph.width && glyph.height) { // Are we still using the same fontId as previous - if(isGlyphUnderlined && (glyph.fontId != lastUnderlinedFontId)) + if((isGlyphUnderlined || strikethroughGlyphsExist) && (glyph.fontId != lastUnderlinedFontId)) { // We need to fetch fresh font underline metrics FontMetrics fontMetrics; @@ -527,6 +545,19 @@ struct AtlasRenderer::Impl } } + if(fabsf(strikethroughHeight) < Math::MACHINE_EPSILON_1000) + { + // Ensure strikethrough will be at least a pixel high + if(currentStrikethroughThickness < ONE) + { + currentStrikethroughThickness = ONE; + } + else + { + currentStrikethroughThickness = ceil(currentStrikethroughThickness); + } + } + // Clamp the underline position at the font descender and check for ( as EFL describes it ) a broken font if(currentUnderlinePosition > descender) { @@ -594,7 +625,25 @@ struct AtlasRenderer::Impl meshContainer, newTextCache, extents, - underlineChunkId); + underlineChunkId, + false); + + if(strikethroughGlyphsExist) + { + GenerateMesh(glyph, + positionPlusOutlineOffset, + color, + NO_OUTLINE, + slot, + strikethroughGlyphsExist, + 0.0f, + currentStrikethroughThickness, + meshContainer, + newTextCache, + strikethroughExtents, + 0u, + true); + } lastFontId = glyph.fontId; // Prevents searching for existing blocksizes when string of the same fontId. } @@ -612,7 +661,8 @@ struct AtlasRenderer::Impl meshContainerOutline, newTextCache, extents, - 0u); + 0u, + false); } //The new underlined chunk. Add new id if they are not consecutive indices (this is for Markup case) @@ -638,7 +688,13 @@ struct AtlasRenderer::Impl if(thereAreUnderlinedGlyphs) { // Check to see if any of the text needs an underline - GenerateUnderlines(meshContainer, extents, underlineColor); + GenerateUnderlines(meshContainer, extents, underlineColor, underlineType, dashedUnderlineWidth, dashedUnderlineGap); + } + + if(strikethroughGlyphsExist) + { + // Check to see if any of the text needs a strikethrough + GenerateStrikethrough(meshContainer, strikethroughExtents, strikethroughColor); } // For each MeshData object, create a mesh actor and add to the renderable actor @@ -775,11 +831,12 @@ struct AtlasRenderer::Impl AtlasManager::Mesh2D& newMesh, Vector& extents, float baseLine, - bool underlineGlyph, + bool decorationlineGlyph, float underlinePosition, - float underlineThickness, + float lineThickness, AtlasManager::AtlasSlot& slot, - uint32_t underlineChunkId) + uint32_t underlineChunkId, + float strikethroughPosition) { if(slot.mImageId) { @@ -798,7 +855,7 @@ struct AtlasRenderer::Impl // Append the mesh to the existing mesh and adjust any extents Toolkit::Internal::AtlasMeshFactory::AppendMesh(mIt->mMesh, newMesh); - if(underlineGlyph) + if(decorationlineGlyph) { AdjustExtents(extents, meshContainer, @@ -807,8 +864,9 @@ struct AtlasRenderer::Impl right, baseLine, underlinePosition, - underlineThickness, - underlineChunkId); + lineThickness, + underlineChunkId, + strikethroughPosition); } return; @@ -821,7 +879,7 @@ struct AtlasRenderer::Impl meshRecord.mMesh = newMesh; meshContainer.push_back(meshRecord); - if(underlineGlyph) + if(decorationlineGlyph) { // Adjust extents for this new meshrecord AdjustExtents(extents, @@ -831,8 +889,9 @@ struct AtlasRenderer::Impl right, baseLine, underlinePosition, - underlineThickness, - underlineChunkId); + lineThickness, + underlineChunkId, + strikethroughPosition); } } } @@ -844,8 +903,9 @@ struct AtlasRenderer::Impl float right, float baseLine, float underlinePosition, - float underlineThickness, - uint32_t underlineChunkId) + float lineThickness, + uint32_t underlineChunkId, + float strikethroughPosition) { bool foundExtent = false; for(Vector::Iterator eIt = extents.Begin(), @@ -869,22 +929,23 @@ struct AtlasRenderer::Impl { eIt->mUnderlinePosition = underlinePosition; } - if(underlineThickness > eIt->mUnderlineThickness) + if(lineThickness > eIt->mLineThickness) { - eIt->mUnderlineThickness = underlineThickness; + eIt->mLineThickness = lineThickness; } } } if(!foundExtent) { Extent extent; - extent.mLeft = left; - extent.mRight = right; - extent.mBaseLine = baseLine; - extent.mUnderlinePosition = underlinePosition; - extent.mUnderlineThickness = underlineThickness; - extent.mMeshRecordIndex = index; - extent.mUnderlineChunkId = underlineChunkId; + extent.mLeft = left; + extent.mRight = right; + extent.mBaseLine = baseLine; + extent.mUnderlinePosition = underlinePosition; + extent.mMeshRecordIndex = index; + extent.mUnderlineChunkId = underlineChunkId; + extent.mLineThickness = lineThickness; + extent.mStrikethroughPosition = strikethroughPosition; extents.PushBack(extent); } } @@ -927,9 +988,182 @@ struct AtlasRenderer::Impl } } - void GenerateUnderlines(std::vector& meshRecords, - Vector& extents, - const Vector4& underlineColor) + void GenerateUnderlines(std::vector& meshRecords, + Vector& extents, + const Vector4& underlineColor, + const Text::Underline::Type& underlineType, + const float& dashedUnderlineWidth, + const float& dashedUnderlineGap) + { + AtlasManager::Mesh2D newMesh; + unsigned short faceIndex = 0; + for(Vector::ConstIterator eIt = extents.Begin(), + eEndIt = extents.End(); + eIt != eEndIt; + ++eIt) + { + AtlasManager::Vertex2D vert; + uint32_t index = eIt->mMeshRecordIndex; + Vector2 uv = mGlyphManager.GetAtlasSize(meshRecords[index].mAtlasId); + + // Make sure we don't hit texture edge for single pixel texture ( filled pixel is in top left of every atlas ) + float u = HALF / uv.x; + float v = HALF / uv.y; + float thickness = eIt->mLineThickness; + float ShiftLineBy = (underlineType == Text::Underline::Type::DOUBLE) ? (thickness * ONE_AND_A_HALF) : (thickness * HALF); + float baseLine = eIt->mBaseLine + eIt->mUnderlinePosition - ShiftLineBy; + float tlx = eIt->mLeft; + float brx = eIt->mRight; + + if(underlineType == Text::Underline::Type::DASHED) + { + float dashTlx = tlx; + float dashBrx = tlx; + faceIndex = 0; + + AtlasManager::Mesh2D newMesh; + while((dashTlx >= tlx) && (dashTlx < brx) && ((dashTlx + dashedUnderlineWidth) <= brx)) + { + dashBrx = dashTlx + dashedUnderlineWidth; + + //The top left edge of the underline + vert.mPosition.x = dashTlx; + vert.mPosition.y = baseLine; + vert.mTexCoords.x = ZERO; + vert.mTexCoords.y = ZERO; + vert.mColor = underlineColor; + newMesh.mVertices.PushBack(vert); + + //The top right edge of the underline + vert.mPosition.x = dashBrx; + vert.mPosition.y = baseLine; + vert.mTexCoords.x = u; + vert.mColor = underlineColor; + newMesh.mVertices.PushBack(vert); + + //The bottom left edge of the underline + vert.mPosition.x = dashTlx; + vert.mPosition.y = baseLine + thickness; + vert.mTexCoords.x = ZERO; + vert.mTexCoords.y = v; + vert.mColor = underlineColor; + newMesh.mVertices.PushBack(vert); + + //The bottom right edge of the underline + vert.mPosition.x = dashBrx; + vert.mPosition.y = baseLine + thickness; + vert.mTexCoords.x = u; + vert.mColor = underlineColor; + newMesh.mVertices.PushBack(vert); + + dashTlx = dashBrx + dashedUnderlineGap; // The next dash will start at the right of the current dash plus the gap + + // Six indices in counter clockwise winding + newMesh.mIndices.PushBack(faceIndex + 1u); + newMesh.mIndices.PushBack(faceIndex); + newMesh.mIndices.PushBack(faceIndex + 2u); + newMesh.mIndices.PushBack(faceIndex + 2u); + newMesh.mIndices.PushBack(faceIndex + 3u); + newMesh.mIndices.PushBack(faceIndex + 1u); + + faceIndex += 4; + + Toolkit::Internal::AtlasMeshFactory::AppendMesh(meshRecords[index].mMesh, newMesh); + } + } + else + { + // It's either SOLID or DOUBLE so we need to generate the first solid underline anyway. + vert.mPosition.x = tlx; + vert.mPosition.y = baseLine; + vert.mTexCoords.x = ZERO; + vert.mTexCoords.y = ZERO; + vert.mColor = underlineColor; + newMesh.mVertices.PushBack(vert); + + vert.mPosition.x = brx; + vert.mPosition.y = baseLine; + vert.mTexCoords.x = u; + vert.mColor = underlineColor; + newMesh.mVertices.PushBack(vert); + + vert.mPosition.x = tlx; + vert.mPosition.y = baseLine + thickness; + vert.mTexCoords.x = ZERO; + vert.mTexCoords.y = v; + vert.mColor = underlineColor; + newMesh.mVertices.PushBack(vert); + + vert.mPosition.x = brx; + vert.mPosition.y = baseLine + thickness; + vert.mTexCoords.x = u; + vert.mColor = underlineColor; + newMesh.mVertices.PushBack(vert); + + // Six indices in counter clockwise winding + newMesh.mIndices.PushBack(faceIndex + 1u); + newMesh.mIndices.PushBack(faceIndex); + newMesh.mIndices.PushBack(faceIndex + 2u); + newMesh.mIndices.PushBack(faceIndex + 2u); + newMesh.mIndices.PushBack(faceIndex + 3u); + newMesh.mIndices.PushBack(faceIndex + 1u); + faceIndex += 4; + + Toolkit::Internal::AtlasMeshFactory::AppendMesh(meshRecords[index].mMesh, newMesh); + + if(underlineType == Text::Underline::Type::DOUBLE) + { + baseLine += 2 * thickness; + + //The top left edge of the underline + vert.mPosition.x = tlx; + vert.mPosition.y = baseLine; // Vertical start of the second underline + vert.mTexCoords.x = ZERO; + vert.mTexCoords.y = ZERO; + vert.mColor = underlineColor; + newMesh.mVertices.PushBack(vert); + + //The top right edge of the underline + vert.mPosition.x = brx; + vert.mPosition.y = baseLine; + vert.mTexCoords.x = u; + vert.mColor = underlineColor; + newMesh.mVertices.PushBack(vert); + + //The bottom left edge of the underline + vert.mPosition.x = tlx; + vert.mPosition.y = baseLine + thickness; // Vertical End of the second underline + vert.mTexCoords.x = ZERO; + vert.mTexCoords.y = v; + vert.mColor = underlineColor; + newMesh.mVertices.PushBack(vert); + + //The bottom right edge of the underline + vert.mPosition.x = brx; + vert.mPosition.y = baseLine + thickness; + vert.mTexCoords.x = u; + vert.mColor = underlineColor; + newMesh.mVertices.PushBack(vert); + + // Six indices in counter clockwise winding + newMesh.mIndices.PushBack(faceIndex + 1u); + newMesh.mIndices.PushBack(faceIndex); + newMesh.mIndices.PushBack(faceIndex + 2u); + newMesh.mIndices.PushBack(faceIndex + 2u); + newMesh.mIndices.PushBack(faceIndex + 3u); + newMesh.mIndices.PushBack(faceIndex + 1u); + + faceIndex += 4; + + Toolkit::Internal::AtlasMeshFactory::AppendMesh(meshRecords[index].mMesh, newMesh); + } + } + } + } + + void GenerateStrikethrough(std::vector& meshRecords, + Vector& extents, + const Vector4& strikethroughColor) { AtlasManager::Mesh2D newMesh; unsigned short faceIndex = 0; @@ -943,37 +1177,37 @@ struct AtlasRenderer::Impl Vector2 uv = mGlyphManager.GetAtlasSize(meshRecords[index].mAtlasId); // Make sure we don't hit texture edge for single pixel texture ( filled pixel is in top left of every atlas ) - float u = HALF / uv.x; - float v = HALF / uv.y; - float thickness = eIt->mUnderlineThickness; - float baseLine = eIt->mBaseLine + eIt->mUnderlinePosition - (thickness * HALF); - float tlx = eIt->mLeft; - float brx = eIt->mRight; + float u = HALF / uv.x; + float v = HALF / uv.y; + float thickness = eIt->mLineThickness; + float tlx = eIt->mLeft; + float brx = eIt->mRight; + float strikethroughPosition = eIt->mStrikethroughPosition; vert.mPosition.x = tlx; - vert.mPosition.y = baseLine; + vert.mPosition.y = strikethroughPosition; vert.mTexCoords.x = ZERO; vert.mTexCoords.y = ZERO; - vert.mColor = underlineColor; + vert.mColor = strikethroughColor; newMesh.mVertices.PushBack(vert); vert.mPosition.x = brx; - vert.mPosition.y = baseLine; + vert.mPosition.y = strikethroughPosition; vert.mTexCoords.x = u; - vert.mColor = underlineColor; + vert.mColor = strikethroughColor; newMesh.mVertices.PushBack(vert); vert.mPosition.x = tlx; - vert.mPosition.y = baseLine + thickness; + vert.mPosition.y = strikethroughPosition + thickness; vert.mTexCoords.x = ZERO; vert.mTexCoords.y = v; - vert.mColor = underlineColor; + vert.mColor = strikethroughColor; newMesh.mVertices.PushBack(vert); vert.mPosition.x = brx; - vert.mPosition.y = baseLine + thickness; + vert.mPosition.y = strikethroughPosition + thickness; vert.mTexCoords.x = u; - vert.mColor = underlineColor; + vert.mColor = strikethroughColor; newMesh.mVertices.PushBack(vert); // Six indices in counter clockwise winding