From fe3c31e7c1d047a8b0679c8ba580e19545cf9664 Mon Sep 17 00:00:00 2001 From: ssabah Date: Mon, 7 Mar 2022 01:37:43 +0300 Subject: [PATCH] Resolve cases for strikethrough when using multiple tags 1- Last color is applied for all tags when using multiple tags 2- Draw strikethrough on text between two tags 3- Standardize strikethrough code. Make strikethrough code similar to underline code. Change-Id: I6d6c7c7435423083ca788686b04b97ff554bdb88 --- .../utc-Dali-TextEditor-internal.cpp | 4 +- .../utc-Dali-TextField-internal.cpp | 4 +- .../utc-Dali-TextLabel-internal.cpp | 16 +-- .../text/markup-processor-strikethrough.cpp | 10 +- .../internal/text/markup-processor-strikethrough.h | 9 ++ dali-toolkit/internal/text/markup-processor.cpp | 2 +- .../text/rendering/atlas/text-atlas-renderer.cpp | 123 +++++++++++---------- .../styles/strikethrough-helper-functions.cpp | 46 +++++++- .../styles/strikethrough-helper-functions.h | 45 +++++++- .../internal/text/rendering/text-typesetter.cpp | 83 ++++++-------- .../internal/text/strikethrough-character-run.h | 15 ++- .../internal/text/strikethrough-glyph-run.h | 15 ++- .../internal/text/strikethrough-style-properties.h | 93 ++++++++++++++++ .../internal/text/text-controller-impl.cpp | 3 +- 14 files changed, 333 insertions(+), 135 deletions(-) create mode 100644 dali-toolkit/internal/text/strikethrough-style-properties.h diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextEditor-internal.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextEditor-internal.cpp index c75f754..48f44a6 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextEditor-internal.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextEditor-internal.cpp @@ -857,12 +857,12 @@ int UtcDaliTextEditorMarkupStrikethrough(void) //ABC have strikethrough DALI_TEST_EQUALS(strikethroughRuns[0u].glyphRun.glyphIndex, 0u, TEST_LOCATION); DALI_TEST_EQUALS(strikethroughRuns[0u].glyphRun.numberOfGlyphs, 3u, TEST_LOCATION); - DALI_TEST_CHECK(!strikethroughRuns[0u].isColorSet); + DALI_TEST_CHECK(!strikethroughRuns[0u].properties.colorDefined); //GH have strikethrough DALI_TEST_EQUALS(strikethroughRuns[1u].glyphRun.glyphIndex, 5u, TEST_LOCATION); DALI_TEST_EQUALS(strikethroughRuns[1u].glyphRun.numberOfGlyphs, 2u, TEST_LOCATION); - DALI_TEST_CHECK(strikethroughRuns[1u].isColorSet); + DALI_TEST_CHECK(strikethroughRuns[1u].properties.colorDefined); END_TEST; } diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextField-internal.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextField-internal.cpp index b73142a..07b097b 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextField-internal.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextField-internal.cpp @@ -933,12 +933,12 @@ int UtcDaliTextFieldMarkupStrikethrough(void) //ABC have strikethrough DALI_TEST_EQUALS(strikethroughRuns[0u].glyphRun.glyphIndex, 0u, TEST_LOCATION); DALI_TEST_EQUALS(strikethroughRuns[0u].glyphRun.numberOfGlyphs, 3u, TEST_LOCATION); - DALI_TEST_CHECK(!strikethroughRuns[0u].isColorSet); + DALI_TEST_CHECK(!strikethroughRuns[0u].properties.colorDefined); //GH have strikethrough DALI_TEST_EQUALS(strikethroughRuns[1u].glyphRun.glyphIndex, 5u, TEST_LOCATION); DALI_TEST_EQUALS(strikethroughRuns[1u].glyphRun.numberOfGlyphs, 2u, TEST_LOCATION); - DALI_TEST_CHECK(strikethroughRuns[1u].isColorSet); + DALI_TEST_CHECK(strikethroughRuns[1u].properties.colorDefined); END_TEST; } diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextLabel-internal.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextLabel-internal.cpp index dd460f2..5fa2eaf 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextLabel-internal.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextLabel-internal.cpp @@ -739,18 +739,18 @@ int UtcDaliTextLabelMarkupStrikethrough(void) //ABC have strikethrough DALI_TEST_EQUALS(strikethroughRuns[0u].glyphRun.glyphIndex, 0u, TEST_LOCATION); DALI_TEST_EQUALS(strikethroughRuns[0u].glyphRun.numberOfGlyphs, 3u, TEST_LOCATION); - DALI_TEST_CHECK(strikethroughRuns[0u].isColorSet); - DALI_TEST_EQUALS(strikethroughRuns[0u].color.r, 1u, TEST_LOCATION); - DALI_TEST_EQUALS(strikethroughRuns[0u].color.g, 0u, TEST_LOCATION); - DALI_TEST_EQUALS(strikethroughRuns[0u].color.b, 0u, TEST_LOCATION); + DALI_TEST_CHECK(strikethroughRuns[0u].properties.colorDefined); + DALI_TEST_EQUALS(strikethroughRuns[0u].properties.color.r, 1u, TEST_LOCATION); + DALI_TEST_EQUALS(strikethroughRuns[0u].properties.color.g, 0u, TEST_LOCATION); + DALI_TEST_EQUALS(strikethroughRuns[0u].properties.color.b, 0u, TEST_LOCATION); //GH have strikethrough DALI_TEST_EQUALS(strikethroughRuns[1u].glyphRun.glyphIndex, 5u, TEST_LOCATION); DALI_TEST_EQUALS(strikethroughRuns[1u].glyphRun.numberOfGlyphs, 2u, TEST_LOCATION); - DALI_TEST_CHECK(strikethroughRuns[1u].isColorSet); - DALI_TEST_EQUALS(strikethroughRuns[1u].color.r, 0u, TEST_LOCATION); - DALI_TEST_EQUALS(strikethroughRuns[1u].color.g, 1u, TEST_LOCATION); - DALI_TEST_EQUALS(strikethroughRuns[1u].color.b, 0u, TEST_LOCATION); + DALI_TEST_CHECK(strikethroughRuns[1u].properties.colorDefined); + DALI_TEST_EQUALS(strikethroughRuns[1u].properties.color.r, 0u, TEST_LOCATION); + DALI_TEST_EQUALS(strikethroughRuns[1u].properties.color.g, 1u, TEST_LOCATION); + DALI_TEST_EQUALS(strikethroughRuns[1u].properties.color.b, 0u, TEST_LOCATION); END_TEST; } diff --git a/dali-toolkit/internal/text/markup-processor-strikethrough.cpp b/dali-toolkit/internal/text/markup-processor-strikethrough.cpp index 9282121..3612461 100644 --- a/dali-toolkit/internal/text/markup-processor-strikethrough.cpp +++ b/dali-toolkit/internal/text/markup-processor-strikethrough.cpp @@ -36,6 +36,13 @@ namespace const std::string XHTML_COLOR_ATTRIBUTE("color"); } +void ProcessColorAttribute(const Attribute& attribute, StrikethroughCharacterRun& strikethroughRun) + +{ + ColorStringToVector4(attribute.valueBuffer, attribute.valueLength, strikethroughRun.properties.color); + strikethroughRun.properties.colorDefined = true; +} + void ProcessStrikethroughTag(const Tag& tag, StrikethroughCharacterRun& strikethroughRun) { for(Vector::ConstIterator it = tag.attributes.Begin(), @@ -46,8 +53,7 @@ void ProcessStrikethroughTag(const Tag& tag, StrikethroughCharacterRun& striketh const Attribute& attribute(*it); if(TokenComparison(XHTML_COLOR_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength)) { - strikethroughRun.isColorSet = true; - ColorStringToVector4(attribute.valueBuffer, attribute.valueLength, strikethroughRun.color); + ProcessColorAttribute(attribute, strikethroughRun); } } } diff --git a/dali-toolkit/internal/text/markup-processor-strikethrough.h b/dali-toolkit/internal/text/markup-processor-strikethrough.h index 6c0a520..44bfab9 100644 --- a/dali-toolkit/internal/text/markup-processor-strikethrough.h +++ b/dali-toolkit/internal/text/markup-processor-strikethrough.h @@ -25,9 +25,18 @@ namespace Toolkit namespace Text { struct Tag; +struct Attribute; struct StrikethroughCharacterRun; /** + * @brief Fill the strikethrough character run with the color attribute value. + * + * @param[in] attribute the color attribute. + * @param[out] strikethroughCharacterRun The strikethrough character run + */ +void ProcessColorAttribute(const Attribute& attribute, StrikethroughCharacterRun& strikethroughCharacterRun); + +/** * @brief Retrieves the strikethrough run info from the tag and sets it to the strikethrough run. * * @param[in] tag The strikethrough tag and its attributes. diff --git a/dali-toolkit/internal/text/markup-processor.cpp b/dali-toolkit/internal/text/markup-processor.cpp index 197dff1..e44fbde 100644 --- a/dali-toolkit/internal/text/markup-processor.cpp +++ b/dali-toolkit/internal/text/markup-processor.cpp @@ -214,7 +214,7 @@ void Initialize(StrikethroughCharacterRun& strikethroughCharacterRun) { strikethroughCharacterRun.characterRun.characterIndex = 0u; strikethroughCharacterRun.characterRun.numberOfCharacters = 0u; - strikethroughCharacterRun.isColorSet = false; + strikethroughCharacterRun.properties.colorDefined = false; } /** 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 291c187..d9c4c86 100644 --- a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp +++ b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp @@ -161,31 +161,6 @@ struct AtlasRenderer::Impl mQuadVertexFormat["aColor"] = Property::VECTOR4; } - bool - doGlyphHaveStrikethrough(GlyphIndex index, - const Vector& strikethroughRuns, - Vector4& strikethroughColor) - { - for(Vector::ConstIterator it = strikethroughRuns.Begin(), - endIt = strikethroughRuns.End(); - it != endIt; - ++it) - { - const StrikethroughGlyphRun& run = *it; - - 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. @@ -337,6 +312,10 @@ struct AtlasRenderer::Impl vertex.mColor = color; } + // Since Free Type font doesn't contain the strikethrough-position property, + // strikethrough position will be calculated by moving the underline position upwards by half the value of the line height. + float strikethroughStartingYPosition = (position.y + glyph.yBearing + currentUnderlinePosition) - ((glyph.height) * HALF); + // Find an existing mesh data object to attach to ( or create a new one, if we can't find one using the same atlas) StitchTextMesh(meshContainer, newMesh, @@ -347,7 +326,7 @@ struct AtlasRenderer::Impl currentlineThickness, slot, underlineChunkId, - position.y + (glyph.height * HALF), + strikethroughStartingYPosition, strikethroughChunkId); } @@ -453,9 +432,6 @@ struct AtlasRenderer::Impl 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. @@ -496,14 +472,18 @@ struct AtlasRenderer::Impl strikethroughRuns.Resize(numberOfStrikethroughRuns); view.GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns); - bool thereAreUnderlinedGlyphs = false; - bool strikethroughGlyphsExist = false; + const StrikethroughStyleProperties viewStrikethroughProperties{view.GetStrikethroughColor(), + view.GetStrikethroughHeight(), + true, + true}; + + float maxStrikethroughHeight = viewStrikethroughProperties.height; - float currentUnderlinePosition = ZERO; - float currentStrikethroughHeight = strikethroughHeight; - float maxStrikethroughHeight = currentStrikethroughHeight; - FontId lastFontId = 0; - Style style = STYLE_NORMAL; + FontId lastFontId = 0; + Style style = STYLE_NORMAL; + float currentUnderlinePosition = ZERO; + bool thereAreUnderlinedGlyphs = false; + bool thereAreStrikethroughGlyphs = false; if(fabsf(shadowOffset.x) > Math::MACHINE_EPSILON_1 || fabsf(shadowOffset.y) > Math::MACHINE_EPSILON_1) { @@ -525,8 +505,12 @@ struct AtlasRenderer::Impl 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. + //For septated strikethrough chunks. (this is for Markup case) + uint32_t strikethroughChunkId = 0u; // give id for each chunk. + bool isPreStrikethrough = false; // status of strikethrough for previous glyph. + std::map mapStrikethroughChunkIdWithProperties; // mapping strikethroughChunkId with StrikethroughStyleProperties to get properties of strikethrough chunk + StrikethroughStyleProperties preStrikethroughProperties = viewStrikethroughProperties; // the previous StrikethroughStyleProperties + const Character* textBuffer = view.GetTextBuffer(); float calculatedAdvance = 0.f; const Vector& glyphToCharacterMap = view.GetGlyphsToCharacters(); @@ -568,16 +552,17 @@ struct AtlasRenderer::Impl float currentUnderlineHeight = currentUnderlineProperties.height; thereAreUnderlinedGlyphs = thereAreUnderlinedGlyphs || isGlyphUnderlined; - currentStrikethroughColor = strikethroughColor; - const bool isStrikethroughGlyph = strikethroughEnabled || doGlyphHaveStrikethrough(i, strikethroughRuns, currentStrikethroughColor); - strikethroughGlyphsExist = strikethroughGlyphsExist || isStrikethroughGlyph; + Vector::ConstIterator currentStrikethroughGlyphRunIt = strikethroughRuns.End(); + const bool isGlyphStrikethrough = strikethroughEnabled || IsGlyphStrikethrough(i, strikethroughRuns, currentStrikethroughGlyphRunIt); + const StrikethroughStyleProperties currentStrikethroughProperties = GetCurrentStrikethroughProperties(isGlyphStrikethrough, strikethroughRuns, currentStrikethroughGlyphRunIt, viewStrikethroughProperties); + float currentStrikethroughHeight = GetCurrentStrikethroughHeight(strikethroughRuns, currentStrikethroughGlyphRunIt, viewStrikethroughProperties.height); + thereAreStrikethroughGlyphs = thereAreStrikethroughGlyphs || isGlyphStrikethrough; // No operation for white space if(glyph.width && glyph.height) { // Check and update decorative-lines informations - if((isGlyphUnderlined || isStrikethroughGlyph) && - ((glyph.fontId != lastDecorativeLinesFontId) || !(currentUnderlineProperties.IsHeightEqualTo(preUnderlineProperties)))) + if(isGlyphUnderlined || isGlyphStrikethrough) { bool isDecorativeLinesFontIdUpdated = false; // Are we still using the same fontId as previous @@ -588,7 +573,7 @@ struct AtlasRenderer::Impl isDecorativeLinesFontIdUpdated = true; fontClient.GetFontMetrics(lastDecorativeLinesFontId, lastDecorativeLinesFontMetrics); - if(isStrikethroughGlyph || isGlyphUnderlined) + if(isGlyphStrikethrough || isGlyphUnderlined) { //The currentUnderlinePosition will be used for both Underline and/or Strikethrough currentUnderlinePosition = FetchUnderlinePositionFromFontMetrics(lastDecorativeLinesFontMetrics); @@ -606,8 +591,14 @@ struct AtlasRenderer::Impl CalcualteUnderlineHeight(lastDecorativeLinesFontMetrics, currentUnderlineHeight, maxUnderlineHeight); } - if(isDecorativeLinesFontIdUpdated && isStrikethroughGlyph) + if(isGlyphStrikethrough && (isDecorativeLinesFontIdUpdated || !(currentStrikethroughProperties.IsHeightEqualTo(preStrikethroughProperties)))) { + //If the Strikethrough Height is changed then we need to recalculate height. + if(!(currentStrikethroughProperties.IsHeightEqualTo(preStrikethroughProperties))) + { + maxStrikethroughHeight = currentStrikethroughHeight; + } + CalcualteStrikethroughHeight(currentStrikethroughHeight, maxStrikethroughHeight); } } // decorative-lines @@ -680,14 +671,22 @@ struct AtlasRenderer::Impl false, 0u); - if(isStrikethroughGlyph) + if(isGlyphStrikethrough) { + //The new strikethrough 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((!isPreStrikethrough) || (preStrikethroughProperties != currentStrikethroughProperties)) + { + strikethroughChunkId++; + mapStrikethroughChunkIdWithProperties.insert(std::pair(strikethroughChunkId, currentStrikethroughProperties)); + } + GenerateMesh(glyph, positionPlusOutlineOffset, color, NO_OUTLINE, slot, - strikethroughGlyphsExist, + isGlyphStrikethrough, 0.0f, maxStrikethroughHeight, meshContainer, @@ -698,6 +697,10 @@ struct AtlasRenderer::Impl strikethroughChunkId); } + //Keep status of Strikethrough for previous glyph to check consecutive indices + isPreStrikethrough = isGlyphStrikethrough; + preStrikethroughProperties = currentStrikethroughProperties; + lastFontId = glyph.fontId; // Prevents searching for existing blocksizes when string of the same fontId. } @@ -718,13 +721,6 @@ struct AtlasRenderer::Impl false, 0u); } - - if(isPrevGlyphStrikethrough && !isStrikethroughGlyph) - { - strikethroughChunkId++; - } - - isPrevGlyphStrikethrough = isStrikethroughGlyph; } if(addHyphen) @@ -743,10 +739,10 @@ struct AtlasRenderer::Impl GenerateUnderlines(meshContainer, extents, viewUnderlineProperties, mapUnderlineChunkIdWithProperties); } - if(strikethroughGlyphsExist) + if(thereAreStrikethroughGlyphs) { // Check to see if any of the text needs a strikethrough - GenerateStrikethrough(meshContainer, strikethroughExtents, currentStrikethroughColor); + GenerateStrikethrough(meshContainer, strikethroughExtents, viewStrikethroughProperties, mapStrikethroughChunkIdWithProperties); } // For each MeshData object, create a mesh actor and add to the renderable actor @@ -1226,9 +1222,10 @@ struct AtlasRenderer::Impl } } - void GenerateStrikethrough(std::vector& meshRecords, - Vector& extents, - const Vector4& strikethroughColor) + void GenerateStrikethrough(std::vector& meshRecords, + Vector& extents, + const StrikethroughStyleProperties& viewStrikethroughProperties, + const std::map& mapStrikethroughChunkIdWithProperties) { AtlasManager::Mesh2D newMesh; unsigned short faceIndex = 0; @@ -1241,6 +1238,14 @@ struct AtlasRenderer::Impl uint32_t index = eIt->mMeshRecordIndex; Vector2 uv = mGlyphManager.GetAtlasSize(meshRecords[index].mAtlasId); + auto pairStrikethroughChunkIdWithProperties = mapStrikethroughChunkIdWithProperties.find(eIt->mStrikethroughChunkId); + + const StrikethroughStyleProperties strikethroughProperties = (pairStrikethroughChunkIdWithProperties == mapStrikethroughChunkIdWithProperties.end()) + ? viewStrikethroughProperties + : pairStrikethroughChunkIdWithProperties->second; + + const Vector4& strikethroughColor = strikethroughProperties.colorDefined ? strikethroughProperties.color : viewStrikethroughProperties.color; + // 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; diff --git a/dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.cpp b/dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.cpp index c87fe88..b28f90f 100644 --- a/dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.cpp +++ b/dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.cpp @@ -24,7 +24,51 @@ namespace Toolkit { namespace Text { -/// Helper method to fetch the underline metrics for the specified font glyph +bool IsGlyphStrikethrough(GlyphIndex index, + const Vector& strikethroughRuns, + Vector::ConstIterator& currentStrikethroughGlyphRunIt) +{ + for(Vector::ConstIterator it = strikethroughRuns.Begin(), + endIt = strikethroughRuns.End(); + it != endIt; + ++it) + { + const StrikethroughGlyphRun& run = *it; + + if((run.glyphRun.glyphIndex <= index) && (index < run.glyphRun.glyphIndex + run.glyphRun.numberOfGlyphs)) + { + currentStrikethroughGlyphRunIt = it; + return true; + } + } + + return false; +} + +float GetCurrentStrikethroughHeight(const Vector& strikethroughRuns, + Vector::ConstIterator currentStrikethroughGlyphRunIt, + const float strikethroughHeight) +{ + if(currentStrikethroughGlyphRunIt == strikethroughRuns.End()) + { + return strikethroughHeight; + } + + const StrikethroughGlyphRun& strikethroughGlyphRun = *currentStrikethroughGlyphRunIt; + return (strikethroughGlyphRun.properties.heightDefined ? strikethroughGlyphRun.properties.height : strikethroughHeight); +} + +StrikethroughStyleProperties GetCurrentStrikethroughProperties(const bool& isGlyphStrikethrough, + const Vector& strikethroughRuns, + Vector::ConstIterator currentStrikethroughGlyphRunIt, + const StrikethroughStyleProperties& commonStrikethroughProperties) +{ + return (isGlyphStrikethrough && (currentStrikethroughGlyphRunIt != strikethroughRuns.End())) + ? currentStrikethroughGlyphRunIt->properties + : commonStrikethroughProperties; +} + +/// Helper method to fetch the strikethrough metrics for the specified font glyph void CalcualteStrikethroughHeight(float& currentStrikethroughHeight, float& maxStrikethroughHeight) { //Height of strikethrough represents the thickness of line. diff --git a/dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.h b/dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.h index b3df7ef..c5c5141 100644 --- a/dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.h +++ b/dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.h @@ -23,7 +23,7 @@ #include // INTERNAL INCLUDES -#include +#include #include namespace Dali @@ -33,7 +33,48 @@ namespace Toolkit namespace Text { /** - * @brief Calculate the current underline height and update maximum underline height + * @brief Whether the glyph at index is strikethrough or not. If true then return iterator to the run containes index. + * + * @param[in] index the index of glyph. + * @param[in] strikethroughRuns the strikethrough runs. + * @param[out] currentStrikethroughGlyphRunIt the iterator of current strikethrough glyph run. + * + * @return true if glyph at index is strikethrough + */ +bool IsGlyphStrikethrough(GlyphIndex index, + const Vector& strikethroughRuns, + Vector::ConstIterator& currentStrikethroughGlyphRunIt); + +/** + * @brief Check the current strikethrough glyph run iterator if not empty and its height is defined then return ts height. Otherwise return the common strikethrough height. + * + * @param[in] strikethroughRuns the strikethrough runs. + * @param[in] currentStrikethroughGlyphRunIt the iterator of current strikethrough glyph run. + * @param[in] strikethroughHeight the common strikethrough height. + * + * @return the determined strikethrough height + */ +float GetCurrentStrikethroughHeight(const Vector& strikethroughRuns, + Vector::ConstIterator currentStrikethroughGlyphRunIt, + const float strikethroughHeight); + +/** + * @brief Check the current strikethrough glyph run iterator if not empty and isGlyphStrikethrough is true then return its StrikethroughProperties. Otherwise return the common strikethrough properties. + * + * @param[in] isGlyphStrikethrough whether the glyph is strikethrough. + * @param[in] strikethroughRuns the strikethrough runs. + * @param[in] currentStrikethroughGlyphRunIt the iterator of current strikethrough glyph run. + * @param[in] commonStrikethroughProperties the common strikethrough properties. + * + * @return the determined strikethrough properties + */ +StrikethroughStyleProperties GetCurrentStrikethroughProperties(const bool& isGlyphStrikethrough, + const Vector& strikethroughRuns, + Vector::ConstIterator currentStrikethroughGlyphRunIt, + const StrikethroughStyleProperties& commonStrikethroughProperties); + +/** + * @brief Calculate the current strikethrough height and update maximum strikethrough height * * @param[inout] currentStrikethroughHeight the current strikethrough height. * @param[inout] maxStrikethroughHeight the maximum strikethrough height. diff --git a/dali-toolkit/internal/text/rendering/text-typesetter.cpp b/dali-toolkit/internal/text/rendering/text-typesetter.cpp index 4dc9775..afb279e 100644 --- a/dali-toolkit/internal/text/rendering/text-typesetter.cpp +++ b/dali-toolkit/internal/text/rendering/text-typesetter.cpp @@ -260,31 +260,6 @@ void TypesetGlyph(GlyphData& data, } } -bool doGlyphHaveStrikethrough(GlyphIndex index, - const Vector& strikethroughRuns, - Vector4& strikethroughColor) -{ - for(Vector::ConstIterator it = strikethroughRuns.Begin(), - endIt = strikethroughRuns.End(); - it != endIt; - ++it) - { - const StrikethroughGlyphRun& run = *it; - - if((run.glyphRun.glyphIndex <= index) && (index < run.glyphRun.glyphIndex + run.glyphRun.numberOfGlyphs)) - { - if(run.isColorSet) - { - strikethroughColor = run.color; - } - - return true; - } - } - - return false; -} - /// Draws the specified color to the pixel buffer void WriteColorToPixelBuffer( GlyphData& glyphData, @@ -546,18 +521,20 @@ Devel::PixelBuffer DrawGlyphsBackground(const ViewModel* model, Devel::PixelBuff } /// Draws the specified strikethrough color to the buffer -void DrawStrikethrough( - const Vector4& strikethroughColor, - const unsigned int bufferWidth, - const unsigned int bufferHeight, - GlyphData& glyphData, - const float baseline, - const LineRun& line, - const float maxStrikethroughHeight, - const float lineExtentLeft, - const float lineExtentRight, - float strikethroughStartingYPosition) +void DrawStrikethrough(const unsigned int bufferWidth, + const unsigned int bufferHeight, + GlyphData& glyphData, + const float baseline, + const float strikethroughStartingYPosition, + const float maxStrikethroughHeight, + const float lineExtentLeft, + const float lineExtentRight, + const StrikethroughStyleProperties& commonStrikethroughProperties, + const StrikethroughStyleProperties& currentStrikethroughProperties, + const LineRun& line) { + const Vector4& strikethroughColor = currentStrikethroughProperties.colorDefined ? currentStrikethroughProperties.color : commonStrikethroughProperties.color; + uint32_t* bitmapBuffer = reinterpret_cast(glyphData.bitmapBuffer.GetBuffer()); for(unsigned int y = strikethroughStartingYPosition; y < strikethroughStartingYPosition + maxStrikethroughHeight; y++) @@ -840,7 +817,6 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth, // Whether to use the default color. const bool useDefaultColor = (NULL == colorsBuffer); const Vector4& defaultColor = mModel->GetDefaultColor(); - Vector4 currentStrikethroughColor; // Create and initialize the pixel buffer. GlyphData glyphData; @@ -901,11 +877,9 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth, } } - const bool underlineEnabled = mModel->IsUnderlineEnabled(); - const bool strikethroughEnabled = mModel->IsStrikethroughEnabled(); - const Vector4& strikethroughColor = mModel->GetStrikethroughColor(); - const float strikethroughHeight = mModel->GetStrikethroughHeight(); - const float characterSpacing = mModel->GetCharacterSpacing(); + const bool underlineEnabled = mModel->IsUnderlineEnabled(); + const bool strikethroughEnabled = mModel->IsStrikethroughEnabled(); + const float characterSpacing = mModel->GetCharacterSpacing(); // Aggregate underline-style-properties from mModel const UnderlineStyleProperties modelUnderlineProperties{mModel->GetUnderlineType(), @@ -919,6 +893,12 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth, true, true}; + // Aggregate strikethrough-style-properties from mModel + const StrikethroughStyleProperties modelStrikethroughProperties{mModel->GetStrikethroughColor(), + mModel->GetStrikethroughHeight(), + true, + true}; + // Get the underline runs. const Length numberOfUnderlineRuns = mModel->GetNumberOfUnderlineRuns(); Vector underlineRuns; @@ -931,16 +911,17 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth, strikethroughRuns.Resize(numberOfStrikethroughRuns); mModel->GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns); - bool thereAreUnderlinedGlyphs = false; - bool strikethroughGlyphsExist = false; + bool thereAreUnderlinedGlyphs = false; + bool thereAreStrikethroughGlyphs = false; float currentUnderlinePosition = 0.0f; float currentUnderlineHeight = modelUnderlineProperties.height; float maxUnderlineHeight = currentUnderlineHeight; auto currentUnderlineProperties = modelUnderlineProperties; - float currentStrikethroughHeight = strikethroughHeight; + float currentStrikethroughHeight = modelStrikethroughProperties.height; float maxStrikethroughHeight = currentStrikethroughHeight; + auto currentStrikethroughProperties = modelStrikethroughProperties; float strikethroughStartingYPosition = 0.0f; FontId lastFontId = 0; @@ -1008,9 +989,11 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth, currentUnderlineHeight = currentUnderlineProperties.height; thereAreUnderlinedGlyphs = thereAreUnderlinedGlyphs || underlineGlyph; - currentStrikethroughColor = strikethroughColor; - const bool strikethroughGlyph = strikethroughEnabled || doGlyphHaveStrikethrough(glyphIndex, strikethroughRuns, currentStrikethroughColor); - strikethroughGlyphsExist = strikethroughGlyphsExist || strikethroughGlyph; + Vector::ConstIterator currentStrikethroughGlyphRunIt = strikethroughRuns.End(); + const bool strikethroughGlyph = strikethroughEnabled || IsGlyphStrikethrough(glyphIndex, strikethroughRuns, currentStrikethroughGlyphRunIt); + currentStrikethroughProperties = GetCurrentStrikethroughProperties(strikethroughGlyph, strikethroughRuns, currentStrikethroughGlyphRunIt, modelStrikethroughProperties); + currentStrikethroughHeight = GetCurrentStrikethroughHeight(strikethroughRuns, currentStrikethroughGlyphRunIt, modelStrikethroughProperties.height); + thereAreStrikethroughGlyphs = thereAreStrikethroughGlyphs || strikethroughGlyph; // Are we still using the same fontId as previous if((glyphInfo->fontId != lastFontId) && (strikethroughGlyph || underlineGlyph)) @@ -1163,11 +1146,11 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth, } // Draw the strikethrough from the leftmost glyph to the rightmost glyph - if(strikethroughGlyphsExist && style == Typesetter::STYLE_STRIKETHROUGH) + if(thereAreStrikethroughGlyphs && style == Typesetter::STYLE_STRIKETHROUGH) { //TODO : The currently implemented strikethrough creates a strikethrough on the line level. We need to create different strikethroughs the case of glyphs with different sizes. strikethroughStartingYPosition = (glyphData.verticalOffset + baseline + currentUnderlinePosition) - ((line.ascender) * HALF); // Since Free Type font doesn't contain the strikethrough-position property, strikethrough position will be calculated by moving the underline position upwards by half the value of the line height. - DrawStrikethrough(currentStrikethroughColor, bufferWidth, bufferHeight, glyphData, baseline, line, maxStrikethroughHeight, lineExtentLeft, lineExtentRight, strikethroughStartingYPosition); + DrawStrikethrough(bufferWidth, bufferHeight, glyphData, baseline, strikethroughStartingYPosition, maxStrikethroughHeight, lineExtentLeft, lineExtentRight, modelStrikethroughProperties, currentStrikethroughProperties, line); } // Increases the vertical offset with the line's descender. diff --git a/dali-toolkit/internal/text/strikethrough-character-run.h b/dali-toolkit/internal/text/strikethrough-character-run.h index 3f0e1f4..66214b7 100644 --- a/dali-toolkit/internal/text/strikethrough-character-run.h +++ b/dali-toolkit/internal/text/strikethrough-character-run.h @@ -23,6 +23,7 @@ // INTERNAL INCLUDES #include +#include namespace Dali { @@ -35,9 +36,17 @@ namespace Text */ struct StrikethroughCharacterRun { - CharacterRun characterRun; ///< The initial character index and the number of characters of the run. - Vector4 color; ///< The color of strikethrough. - bool isColorSet; ///< If the color of strikethrough is set. + /** + * Default constructor to set the default values of bitfields + */ + StrikethroughCharacterRun() + : characterRun{}, + properties{} + { + } + + CharacterRun characterRun; ///< The initial character index and the number of characters of the run. + StrikethroughStyleProperties properties; /// The properties of strikethrough style }; } // namespace Text diff --git a/dali-toolkit/internal/text/strikethrough-glyph-run.h b/dali-toolkit/internal/text/strikethrough-glyph-run.h index 34be0af..61536bc 100644 --- a/dali-toolkit/internal/text/strikethrough-glyph-run.h +++ b/dali-toolkit/internal/text/strikethrough-glyph-run.h @@ -23,6 +23,7 @@ // INTERNAL INCLUDES #include +#include namespace Dali { @@ -35,9 +36,17 @@ namespace Text */ struct StrikethroughGlyphRun { - GlyphRun glyphRun; ///< The initial glyph index and the number of glyphs in the run. - Vector4 color; ///< The color of strikethrough. - bool isColorSet; ///< If the color of strikethrough is set. + /** + * Default constructor to set the default values of bitfields + */ + StrikethroughGlyphRun() + : glyphRun{}, + properties{} + { + } + + GlyphRun glyphRun; ///< The initial glyph index and the number of glyphs in the run. + StrikethroughStyleProperties properties; /// The properties of strikethrough style }; } // namespace Text diff --git a/dali-toolkit/internal/text/strikethrough-style-properties.h b/dali-toolkit/internal/text/strikethrough-style-properties.h new file mode 100644 index 0000000..a92f4c2 --- /dev/null +++ b/dali-toolkit/internal/text/strikethrough-style-properties.h @@ -0,0 +1,93 @@ +#ifndef DALI_TOOLKIT_TEXT_STRIKETHROUGH_STYLE_PROPERTIES_H +#define DALI_TOOLKIT_TEXT_STRIKETHROUGH_STYLE_PROPERTIES_H + +/* + * 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. + * 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. + * + */ + +// EXTERNAL INCLUDES +#include + +namespace Dali +{ +namespace Toolkit +{ +namespace Text +{ +/** + * @brief Properties of strikethrough style. + */ +struct StrikethroughStyleProperties +{ + // Constructors + + /** + * Default constructor to set the default values of bitfields + */ + StrikethroughStyleProperties() + : color{Color::BLACK}, + height{0u}, + colorDefined{false}, + heightDefined{false} + { + } + + StrikethroughStyleProperties(Vector4 color, + float height, + bool colorDefined, + bool heightDefined) + : color{color}, + height{height}, + colorDefined{colorDefined}, + heightDefined{heightDefined} + + { + } + + // Overloading operators + + bool operator==(const StrikethroughStyleProperties& other) const + { + //The property is similar when both are not defined or when both are defined and have the same value. + return ((!colorDefined && !other.colorDefined) || ((colorDefined && other.colorDefined) && (color == other.color))) && + ((!heightDefined && !other.heightDefined) || ((heightDefined && other.heightDefined) && (height == other.height))); + } + + bool operator!=(const StrikethroughStyleProperties& other) const + { + return !(*this == other); + } + + bool IsHeightEqualTo(const StrikethroughStyleProperties& other) const + { + return ((!heightDefined && !other.heightDefined) || ((heightDefined && other.heightDefined) && (height == other.height))); + } + + //Attributes + Vector4 color; ///< The color of strikethrough. + float height; ///< The height of strikethrough. + + bool colorDefined : 1; ///< Whether the color is defined. + bool heightDefined : 1; ///< Whether the height is defined. +}; + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // DALI_TOOLKIT_TEXT_STRIKETHROUGH_STYLE_PROPERTIES_H diff --git a/dali-toolkit/internal/text/text-controller-impl.cpp b/dali-toolkit/internal/text/text-controller-impl.cpp index cf49df5..e97535c 100644 --- a/dali-toolkit/internal/text/text-controller-impl.cpp +++ b/dali-toolkit/internal/text/text-controller-impl.cpp @@ -1679,8 +1679,7 @@ void Controller::Impl::CopyStrikethroughFromLogicalToVisualModels() } StrikethroughGlyphRun strikethroughGlyphRun; - strikethroughGlyphRun.color = it->color; - strikethroughGlyphRun.isColorSet = it->isColorSet; + strikethroughGlyphRun.properties = it->properties; strikethroughGlyphRun.glyphRun.glyphIndex = charactersToGlyph[characterIndex]; strikethroughGlyphRun.glyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex]; -- 2.7.4