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=291c187cf97df90713337a0f3f8beb3a65b0baf6;hp=a21078508a9cd9a2c4161643cc80f1ceb80f9834;hb=cee2831414bee408f07923a17cad74671c14d180;hpb=29a52105283ce8ced672ed92545daeacf882316a 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 a210785..291c187 100644 --- a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp +++ b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 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. @@ -24,13 +24,17 @@ #include #include #include +#include // INTERNAL INCLUDES #include #include +#include #include #include #include +#include +#include #include using namespace Dali; @@ -84,7 +88,8 @@ struct AtlasRenderer::Impl mLineThickness(0.0f), mMeshRecordIndex(0u), mUnderlineChunkId(0u), - mStrikethroughPosition(0.0f) + mStrikethroughPosition(0.0f), + mStrikethroughChunkId(0u) { } @@ -96,6 +101,7 @@ struct AtlasRenderer::Impl uint32_t mMeshRecordIndex; uint32_t mUnderlineChunkId; float mStrikethroughPosition; + uint32_t mStrikethroughChunkId; }; struct MaxBlockSize @@ -155,25 +161,31 @@ struct AtlasRenderer::Impl mQuadVertexFormat["aColor"] = Property::VECTOR4; } - bool IsGlyphUnderlined(GlyphIndex index, - const Vector& underlineRuns) + bool + doGlyphHaveStrikethrough(GlyphIndex index, + const Vector& strikethroughRuns, + Vector4& strikethroughColor) { - for(Vector::ConstIterator it = underlineRuns.Begin(), - endIt = underlineRuns.End(); + for(Vector::ConstIterator it = strikethroughRuns.Begin(), + endIt = strikethroughRuns.End(); it != endIt; ++it) { - const GlyphRun& run = *it; + const StrikethroughGlyphRun& run = *it; - if((run.glyphIndex <= index) && (index < run.glyphIndex + run.numberOfGlyphs)) + if((run.glyphRun.glyphIndex <= index) && (index < run.glyphRun.glyphIndex + run.glyphRun.numberOfGlyphs)) { + if(run.isColorSet) + { + strikethroughColor = run.color; + } + return true; } } return false; } - void CacheGlyph(const GlyphInfo& glyph, FontId lastFontId, const AtlasGlyphManager::GlyphStyle& style, AtlasManager::AtlasSlot& slot) { const Size& defaultTextAtlasSize = mFontClient.GetDefaultTextAtlasSize(); //Retrieve default size of text-atlas-block from font-client. @@ -293,7 +305,8 @@ struct AtlasRenderer::Impl Vector& newTextCache, Vector& extents, uint32_t underlineChunkId, - bool isGlyphCached) + bool isGlyphCached, + uint32_t strikethroughChunkId) { // Generate mesh data for this quad, plugging in our supplied position AtlasManager::Mesh2D newMesh; @@ -334,7 +347,8 @@ struct AtlasRenderer::Impl currentlineThickness, slot, underlineChunkId, - position.y + (glyph.height * HALF)); + position.y + (glyph.height * HALF), + strikethroughChunkId); } void CreateActors(const std::vector& meshContainer, @@ -427,25 +441,22 @@ struct AtlasRenderer::Impl 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 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(); + 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 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(); + Vector4 currentStrikethroughColor; + const float characterSpacing(view.GetCharacterSpacing()); // Elided text info. Indices according to elided text. const auto startIndexOfGlyphs = view.GetStartIndexOfElidedGlyphs(); @@ -454,23 +465,45 @@ struct AtlasRenderer::Impl const bool useDefaultColor = (NULL == colorsBuffer); + // Get a handle of the font client. Used to retrieve the bitmaps of the glyphs. + TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); + // Get the underline runs. - const Length numberOfUnderlineRuns = view.GetNumberOfUnderlineRuns(); - Vector underlineRuns; + const Length numberOfUnderlineRuns = view.GetNumberOfUnderlineRuns(); + Vector underlineRuns; underlineRuns.Resize(numberOfUnderlineRuns); view.GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns); + // Aggregate underline-style-properties from view + const UnderlineStyleProperties viewUnderlineProperties{view.GetUnderlineType(), + view.GetUnderlineColor(), + view.GetUnderlineHeight(), + view.GetDashedUnderlineGap(), + view.GetDashedUnderlineWidth(), + true, + true, + true, + true, + true}; + + float maxUnderlineHeight = viewUnderlineProperties.height; + + // Get the strikethrough runs. + const Length numberOfStrikethroughRuns = view.GetNumberOfStrikethroughRuns(); + Vector strikethroughRuns; + strikethroughRuns.Resize(numberOfStrikethroughRuns); + view.GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns); + bool thereAreUnderlinedGlyphs = false; bool strikethroughGlyphsExist = false; - float currentUnderlinePosition = ZERO; - float currentUnderlineThickness = underlineHeight; - float currentStrikethroughThickness = strikethroughHeight; - FontId lastFontId = 0; - FontId lastUnderlinedFontId = 0; - Style style = STYLE_NORMAL; + float currentUnderlinePosition = ZERO; + float currentStrikethroughHeight = strikethroughHeight; + float maxStrikethroughHeight = currentStrikethroughHeight; + FontId lastFontId = 0; + Style style = STYLE_NORMAL; if(fabsf(shadowOffset.x) > Math::MACHINE_EPSILON_1 || fabsf(shadowOffset.y) > Math::MACHINE_EPSILON_1) { @@ -487,8 +520,17 @@ struct AtlasRenderer::Impl uint32_t hyphenIndex = 0; //For septated underlined chunks. (this is for Markup case) - uint32_t underlineChunkId = 0u; // give id for each chunk. - bool isPreUnderlined = false; // status of underlined for previous glyph. + uint32_t underlineChunkId = 0u; // give id for each chunk. + bool isPreUnderlined = false; // status of underlined for previous glyph. + std::map mapUnderlineChunkIdWithProperties; // mapping underlineChunkId with UnderlineStyleProperties to get properties of underlined chunk + UnderlineStyleProperties preUnderlineProperties = viewUnderlineProperties; // the previous UnderlineStyleProperties + + uint32_t strikethroughChunkId = 0u; // give id for each chunk. + bool isPrevGlyphStrikethrough = false; // status of strikethrough for previous glyph. + const Character* textBuffer = view.GetTextBuffer(); + float calculatedAdvance = 0.f; + const Vector& glyphToCharacterMap = view.GetGlyphsToCharacters(); + const CharacterIndex* glyphToCharacterMapBuffer = glyphToCharacterMap.Begin(); //Skip hyphenIndices less than startIndexOfGlyphs or between two middle of elided text if(hyphenIndices) @@ -500,6 +542,12 @@ struct AtlasRenderer::Impl } } + //To keep the last fontMetrics of lastDecorativeLinesFontId + FontId lastDecorativeLinesFontId = 0; // DecorativeLines like Undeline and Strikethrough + FontMetrics lastDecorativeLinesFontMetrics; + fontClient.GetFontMetrics(lastDecorativeLinesFontId, lastDecorativeLinesFontMetrics); + + // Iteration on glyphs for(uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i) { GlyphInfo glyph; @@ -514,65 +562,55 @@ struct AtlasRenderer::Impl glyph = *(glyphsBuffer + i); } - const bool isGlyphUnderlined = underlineEnabled || IsGlyphUnderlined(i, underlineRuns); - thereAreUnderlinedGlyphs = thereAreUnderlinedGlyphs || isGlyphUnderlined; - strikethroughGlyphsExist = strikethroughGlyphsExist || strikethroughEnabled; + Vector::ConstIterator currentUnderlinedGlyphRunIt = underlineRuns.End(); + const bool isGlyphUnderlined = underlineEnabled || IsGlyphUnderlined(i, underlineRuns, currentUnderlinedGlyphRunIt); + const UnderlineStyleProperties currentUnderlineProperties = GetCurrentUnderlineProperties(i, isGlyphUnderlined, underlineRuns, currentUnderlinedGlyphRunIt, viewUnderlineProperties); + float currentUnderlineHeight = currentUnderlineProperties.height; + thereAreUnderlinedGlyphs = thereAreUnderlinedGlyphs || isGlyphUnderlined; + + currentStrikethroughColor = strikethroughColor; + const bool isStrikethroughGlyph = strikethroughEnabled || doGlyphHaveStrikethrough(i, strikethroughRuns, currentStrikethroughColor); + strikethroughGlyphsExist = strikethroughGlyphsExist || isStrikethroughGlyph; // No operation for white space if(glyph.width && glyph.height) { - // Are we still using the same fontId as previous - if((isGlyphUnderlined || strikethroughGlyphsExist) && (glyph.fontId != lastUnderlinedFontId)) + // Check and update decorative-lines informations + if((isGlyphUnderlined || isStrikethroughGlyph) && + ((glyph.fontId != lastDecorativeLinesFontId) || !(currentUnderlineProperties.IsHeightEqualTo(preUnderlineProperties)))) { - // We need to fetch fresh font underline metrics - FontMetrics fontMetrics; - mFontClient.GetFontMetrics(glyph.fontId, fontMetrics); - currentUnderlinePosition = ceil(fabsf(fontMetrics.underlinePosition)); - const float descender = ceil(fabsf(fontMetrics.descender)); - - if(fabsf(underlineHeight) < Math::MACHINE_EPSILON_1000) + bool isDecorativeLinesFontIdUpdated = false; + // Are we still using the same fontId as previous + if(glyph.fontId != lastDecorativeLinesFontId) { - currentUnderlineThickness = fontMetrics.underlineThickness; + // We need to fetch fresh font metrics + lastDecorativeLinesFontId = glyph.fontId; + isDecorativeLinesFontIdUpdated = true; + fontClient.GetFontMetrics(lastDecorativeLinesFontId, lastDecorativeLinesFontMetrics); - // Ensure underline will be at least a pixel high - if(currentUnderlineThickness < ONE) - { - currentUnderlineThickness = ONE; - } - else + if(isStrikethroughGlyph || isGlyphUnderlined) { - currentUnderlineThickness = ceil(currentUnderlineThickness); + //The currentUnderlinePosition will be used for both Underline and/or Strikethrough + currentUnderlinePosition = FetchUnderlinePositionFromFontMetrics(lastDecorativeLinesFontMetrics); } } - if(fabsf(strikethroughHeight) < Math::MACHINE_EPSILON_1000) + if(isGlyphUnderlined && (isDecorativeLinesFontIdUpdated || !(currentUnderlineProperties.IsHeightEqualTo(preUnderlineProperties)))) { - // Ensure strikethrough will be at least a pixel high - if(currentStrikethroughThickness < ONE) + //If the Underline Height is changed then we need to recalculate height. + if(!(currentUnderlineProperties.IsHeightEqualTo(preUnderlineProperties))) { - currentStrikethroughThickness = ONE; + maxUnderlineHeight = currentUnderlineHeight; } - 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) - { - currentUnderlinePosition = descender; + CalcualteUnderlineHeight(lastDecorativeLinesFontMetrics, currentUnderlineHeight, maxUnderlineHeight); } - if(fabsf(currentUnderlinePosition) < Math::MACHINE_EPSILON_1000) + if(isDecorativeLinesFontIdUpdated && isStrikethroughGlyph) { - // Move offset down by one ( EFL behavior ) - currentUnderlinePosition = ONE; + CalcualteStrikethroughHeight(currentStrikethroughHeight, maxStrikethroughHeight); } - - lastUnderlinedFontId = glyph.fontId; - - } // underline + } // decorative-lines AtlasGlyphManager::GlyphStyle style; style.isItalic = glyph.isItalicRequired; @@ -594,7 +632,8 @@ struct AtlasRenderer::Impl if(addHyphen) { GlyphInfo tempInfo = *(glyphsBuffer + i); - position.x = position.x + tempInfo.advance - tempInfo.xBearing + glyph.xBearing; + calculatedAdvance = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + i))), characterSpacing, tempInfo.advance); + position.x = position.x + calculatedAdvance - tempInfo.xBearing + glyph.xBearing; position.y += tempInfo.yBearing - glyph.yBearing; } @@ -614,6 +653,18 @@ struct AtlasRenderer::Impl const ColorIndex colorIndex = useDefaultColor ? 0u : *(colorIndicesBuffer + i); const Vector4& color = (useDefaultColor || (0u == colorIndex)) ? defaultColor : *(colorsBuffer + colorIndex - 1u); + //The new underlined chunk. Add new id if they are not consecutive indices (this is for Markup case) + // Examples: "Hello World Hello World", "World Hello World", " World Hello World" + if((!isPreUnderlined && isGlyphUnderlined) || (isGlyphUnderlined && (preUnderlineProperties != currentUnderlineProperties))) + { + underlineChunkId++; + mapUnderlineChunkIdWithProperties.insert(std::pair(underlineChunkId, currentUnderlineProperties)); + } + + //Keep status of underlined for previous glyph to check consecutive indices + isPreUnderlined = isGlyphUnderlined; + preUnderlineProperties = currentUnderlineProperties; + GenerateMesh(glyph, positionPlusOutlineOffset, color, @@ -621,14 +672,15 @@ struct AtlasRenderer::Impl slot, isGlyphUnderlined, currentUnderlinePosition, - currentUnderlineThickness, + maxUnderlineHeight, meshContainer, newTextCache, extents, underlineChunkId, - false); + false, + 0u); - if(strikethroughGlyphsExist) + if(isStrikethroughGlyph) { GenerateMesh(glyph, positionPlusOutlineOffset, @@ -637,12 +689,13 @@ struct AtlasRenderer::Impl slot, strikethroughGlyphsExist, 0.0f, - currentStrikethroughThickness, + maxStrikethroughHeight, meshContainer, newTextCache, strikethroughExtents, 0u, - true); + true, + strikethroughChunkId); } lastFontId = glyph.fontId; // Prevents searching for existing blocksizes when string of the same fontId. @@ -657,22 +710,21 @@ struct AtlasRenderer::Impl slotOutline, false, currentUnderlinePosition, - currentUnderlineThickness, + maxUnderlineHeight, meshContainerOutline, newTextCache, extents, 0u, - false); + false, + 0u); } - //The new underlined chunk. Add new id if they are not consecutive indices (this is for Markup case) - // Examples: "Hello World Hello World", "World Hello World", " World Hello World" - if(isPreUnderlined && (isPreUnderlined != isGlyphUnderlined)) + if(isPrevGlyphStrikethrough && !isStrikethroughGlyph) { - underlineChunkId++; + strikethroughChunkId++; } - //Keep status of underlined for previous glyph to check consecutive indices - isPreUnderlined = isGlyphUnderlined; + + isPrevGlyphStrikethrough = isStrikethroughGlyph; } if(addHyphen) @@ -688,13 +740,13 @@ struct AtlasRenderer::Impl if(thereAreUnderlinedGlyphs) { // Check to see if any of the text needs an underline - GenerateUnderlines(meshContainer, extents, underlineColor, underlineType, dashedUnderlineWidth, dashedUnderlineGap); + GenerateUnderlines(meshContainer, extents, viewUnderlineProperties, mapUnderlineChunkIdWithProperties); } if(strikethroughGlyphsExist) { // Check to see if any of the text needs a strikethrough - GenerateStrikethrough(meshContainer, strikethroughExtents, strikethroughColor); + GenerateStrikethrough(meshContainer, strikethroughExtents, currentStrikethroughColor); } // For each MeshData object, create a mesh actor and add to the renderable actor @@ -836,7 +888,8 @@ struct AtlasRenderer::Impl float lineThickness, AtlasManager::AtlasSlot& slot, uint32_t underlineChunkId, - float strikethroughPosition) + float strikethroughPosition, + uint32_t strikethroughChunkId) { if(slot.mImageId) { @@ -866,7 +919,8 @@ struct AtlasRenderer::Impl underlinePosition, lineThickness, underlineChunkId, - strikethroughPosition); + strikethroughPosition, + strikethroughChunkId); } return; @@ -891,7 +945,8 @@ struct AtlasRenderer::Impl underlinePosition, lineThickness, underlineChunkId, - strikethroughPosition); + strikethroughPosition, + strikethroughChunkId); } } } @@ -905,7 +960,8 @@ struct AtlasRenderer::Impl float underlinePosition, float lineThickness, uint32_t underlineChunkId, - float strikethroughPosition) + float strikethroughPosition, + uint32_t strikethroughChunkId) { bool foundExtent = false; for(Vector::Iterator eIt = extents.Begin(), @@ -913,7 +969,7 @@ struct AtlasRenderer::Impl eIt != eEndIt; ++eIt) { - if(Equals(baseLine, eIt->mBaseLine) && underlineChunkId == eIt->mUnderlineChunkId) + if(Equals(baseLine, eIt->mBaseLine) && underlineChunkId == eIt->mUnderlineChunkId && strikethroughChunkId == eIt->mStrikethroughChunkId) { foundExtent = true; if(left < eIt->mLeft) @@ -946,6 +1002,7 @@ struct AtlasRenderer::Impl extent.mUnderlineChunkId = underlineChunkId; extent.mLineThickness = lineThickness; extent.mStrikethroughPosition = strikethroughPosition; + extent.mStrikethroughChunkId = strikethroughChunkId; extents.PushBack(extent); } } @@ -988,15 +1045,14 @@ struct AtlasRenderer::Impl } } - void GenerateUnderlines(std::vector& meshRecords, - Vector& extents, - const Vector4& underlineColor, - const Text::Underline::Type& underlineType, - const float& dashedUnderlineWidth, - const float& dashedUnderlineGap) + void GenerateUnderlines(std::vector& meshRecords, + Vector& extents, + const UnderlineStyleProperties& viewUnderlineProperties, + const std::map& mapUnderlineChunkIdWithProperties) { AtlasManager::Mesh2D newMesh; unsigned short faceIndex = 0; + for(Vector::ConstIterator eIt = extents.Begin(), eEndIt = extents.End(); eIt != eEndIt; @@ -1006,6 +1062,17 @@ struct AtlasRenderer::Impl uint32_t index = eIt->mMeshRecordIndex; Vector2 uv = mGlyphManager.GetAtlasSize(meshRecords[index].mAtlasId); + auto pairUnderlineChunkIdWithProperties = mapUnderlineChunkIdWithProperties.find(eIt->mUnderlineChunkId); + + const UnderlineStyleProperties underlineProperties = (pairUnderlineChunkIdWithProperties == mapUnderlineChunkIdWithProperties.end()) + ? viewUnderlineProperties + : pairUnderlineChunkIdWithProperties->second; + + const Vector4& underlineColor = underlineProperties.colorDefined ? underlineProperties.color : viewUnderlineProperties.color; + const Text::Underline::Type& underlineType = underlineProperties.typeDefined ? underlineProperties.type : viewUnderlineProperties.type; + const float& dashedUnderlineGap = underlineProperties.dashGapDefined ? underlineProperties.dashGap : viewUnderlineProperties.dashGap; + const float& dashedUnderlineWidth = underlineProperties.dashWidthDefined ? underlineProperties.dashWidth : viewUnderlineProperties.dashWidth; + // 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; @@ -1019,9 +1086,7 @@ struct AtlasRenderer::Impl { float dashTlx = tlx; float dashBrx = tlx; - faceIndex = 0; - AtlasManager::Mesh2D newMesh; while((dashTlx >= tlx) && (dashTlx < brx) && ((dashTlx + dashedUnderlineWidth) <= brx)) { dashBrx = dashTlx + dashedUnderlineWidth;