From 3bd33c80f23b760eace186738f140fc3361edf00 Mon Sep 17 00:00:00 2001 From: ANZ1217 Date: Tue, 2 Apr 2024 19:49:46 +0900 Subject: [PATCH] Introduce CUTOUT Property Change-Id: I195f3cb85415ec957b600c52080c02dcaca8020a --- .../src/dali-toolkit/utc-Dali-TextLabel.cpp | 20 +++ .../controls/text-controls/text-label-devel.h | 6 + .../controls/text-controls/text-label-impl.cpp | 62 +++++++ .../text/controller/text-controller-impl.h | 4 +- .../internal/text/controller/text-controller.cpp | 37 +++++ .../internal/text/controller/text-controller.h | 40 +++++ .../internal/text/rendering/text-typesetter.cpp | 183 +++++++++++++++++++-- .../internal/text/rendering/text-typesetter.h | 55 +++++++ .../internal/text/rendering/view-model.cpp | 25 +++ dali-toolkit/internal/text/rendering/view-model.h | 25 +++ dali-toolkit/internal/text/text-model-interface.h | 35 ++++ dali-toolkit/internal/text/text-model.cpp | 25 +++ dali-toolkit/internal/text/text-model.h | 25 +++ dali-toolkit/internal/text/text-view-interface.h | 7 + dali-toolkit/internal/text/text-view.cpp | 9 + dali-toolkit/internal/text/text-view.h | 5 + dali-toolkit/internal/text/visual-model-impl.cpp | 35 +++- dali-toolkit/internal/text/visual-model-impl.h | 119 +++++++++----- dali-toolkit/internal/visuals/text/text-visual.cpp | 98 ++++++++--- dali-toolkit/internal/visuals/text/text-visual.h | 18 ++ 20 files changed, 757 insertions(+), 76 deletions(-) diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp index 576bd0f..aed1457 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp @@ -82,6 +82,7 @@ const char* const PROPERTY_NAME_ANCHOR_CLICKED_COLOR = "anchorClickedColor"; const char* const PROPERTY_NAME_REMOVE_FRONT_INSET = "removeFrontInset"; const char* const PROPERTY_NAME_REMOVE_BACK_INSET = "removeBackInset"; +const char* const PROPERTY_NAME_REMOVE_CUTOUT = "cutout"; const std::string DEFAULT_FONT_DIR("/resources/fonts"); const unsigned int EMOJI_FONT_SIZE = 3840u; // 60 * 64 @@ -365,6 +366,7 @@ int UtcDaliToolkitTextLabelGetPropertyP(void) DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_ANCHOR_CLICKED_COLOR) == DevelTextLabel::Property::ANCHOR_CLICKED_COLOR); DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_REMOVE_FRONT_INSET) == DevelTextLabel::Property::REMOVE_FRONT_INSET); DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_REMOVE_BACK_INSET) == DevelTextLabel::Property::REMOVE_BACK_INSET); + DALI_TEST_CHECK(label.GetPropertyIndex(PROPERTY_NAME_REMOVE_CUTOUT) == DevelTextLabel::Property::CUTOUT); END_TEST; } @@ -1041,6 +1043,14 @@ int UtcDaliToolkitTextLabelSetPropertyP(void) application.SendNotification(); application.Render(); + // Check cutout Property + DALI_TEST_CHECK(!label.GetProperty(DevelTextLabel::Property::CUTOUT)); + label.SetProperty(DevelTextLabel::Property::CUTOUT, true); + DALI_TEST_CHECK(label.GetProperty(DevelTextLabel::Property::CUTOUT)); + + application.SendNotification(); + application.Render(); + END_TEST; } @@ -1794,6 +1804,16 @@ int UtcDaliToolkitTextLabelColorComponents(void) DALI_TEST_EQUALS(drawTrace.FindMethod("DrawArrays"), false, TEST_LOCATION); // Rendering should be skipped + label.SetProperty(DevelTextLabel::Property::CUTOUT, true); + + drawTrace.Reset(); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(drawTrace.FindMethod("DrawArrays"), true, TEST_LOCATION); // When cutout is enabled, should not be skipped + + label.SetProperty(DevelTextLabel::Property::CUTOUT, false); label.SetProperty(TextLabel::Property::TEXT_COLOR, Color::RED); drawTrace.Reset(); diff --git a/dali-toolkit/devel-api/controls/text-controls/text-label-devel.h b/dali-toolkit/devel-api/controls/text-controls/text-label-devel.h index ed2e5d9..4c00662 100644 --- a/dali-toolkit/devel-api/controls/text-controls/text-label-devel.h +++ b/dali-toolkit/devel-api/controls/text-controls/text-label-devel.h @@ -230,6 +230,12 @@ enum Type * @details Name "removeBackInset", type Property::BOOLEAN. */ REMOVE_BACK_INSET, + + /** + * @brief Whether to make the elements transparent, such as background or outline behind the text. + * @details Name "cutout", type Property::BOOLEAN. + */ + CUTOUT, }; } // namespace Property diff --git a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp index 3063429..c125332 100644 --- a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp @@ -48,6 +48,7 @@ #include #include #include +#include // DEVEL INCLUDES #include @@ -146,6 +147,7 @@ DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "anchorColor", DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "anchorClickedColor", VECTOR4, ANCHOR_CLICKED_COLOR ) DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "removeFrontInset", BOOLEAN, REMOVE_FRONT_INSET ) DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "removeBackInset", BOOLEAN, REMOVE_BACK_INSET ) +DALI_DEVEL_PROPERTY_REGISTRATION(Toolkit, TextLabel, "cutout", BOOLEAN, CUTOUT ) DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT(Toolkit, TextLabel, "textColor", Color::BLACK, TEXT_COLOR ) DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION(Toolkit, TextLabel, "textColorRed", TEXT_COLOR_RED, TEXT_COLOR, 0) @@ -604,6 +606,19 @@ void TextLabel::SetProperty(BaseObject* object, Property::Index index, const Pro impl.mController->SetRemoveBackInset(remove); break; } + case Toolkit::DevelTextLabel::Property::CUTOUT: + { + const bool cutout = value.Get(); + + impl.mController->SetTextCutout(cutout); + + // Property doesn't affect the layout, only Visual must be updated + TextVisual::EnableRendererUpdate(impl.mVisual); + + // No need to trigger full re-layout. Instead call UpdateRenderer() directly + TextVisual::UpdateRenderer(impl.mVisual); + break; + } } // Request relayout when text update is needed. It's necessary to call it @@ -888,6 +903,11 @@ Property::Value TextLabel::GetProperty(BaseObject* object, Property::Index index value = impl.mController->IsRemoveBackInset(); break; } + case Toolkit::DevelTextLabel::Property::CUTOUT: + { + value = impl.mController->IsTextCutout(); + break; + } } } @@ -1080,6 +1100,48 @@ void TextLabel::OnPropertySet(Property::Index index, const Property::Value& prop CommonTextUtils::SynchronizeTextAnchorsInParent(Self(), mController, mAnchorActors); break; } + case Toolkit::Control::Property::BACKGROUND: + { + const Vector4 backgroundColor = propertyValue.Get(); + + if(mController->IsTextCutout()) + { + DevelControl::EnableVisual(*this, Toolkit::Control::Property::BACKGROUND, false); + mController->SetBackgroundWithCutoutEnabled(true); + mController->SetBackgroundColorWithCutout(backgroundColor); + } + + break; + } + case Toolkit::DevelTextLabel::Property::CUTOUT: + { + const bool cutoutEnabled = propertyValue.Get(); + + if(cutoutEnabled) + { + Vector4 backgroundColor = Vector4::ZERO; + + const Property::Map backgroundMap = Self().GetProperty(Toolkit::Control::Property::BACKGROUND).Get(); + Property::Value* backgroundValue = backgroundMap.Find(ColorVisual::Property::MIX_COLOR); + if(backgroundValue) + { + backgroundColor = backgroundValue->Get(); + } + + DevelControl::EnableVisual(*this, Toolkit::Control::Property::BACKGROUND, false); + mController->SetBackgroundWithCutoutEnabled(true); + mController->SetBackgroundColorWithCutout(backgroundColor); + } + else + { + DevelControl::EnableVisual(*this, Toolkit::Control::Property::BACKGROUND, true); + + Property::Map backgroundMapSet; + mController->SetBackgroundWithCutoutEnabled(false); + } + + TextVisual::SetRequireRender(mVisual, cutoutEnabled); + } default: { Control::OnPropertySet(index, propertyValue); // up call to control for non-handled properties diff --git a/dali-toolkit/internal/text/controller/text-controller-impl.h b/dali-toolkit/internal/text/controller/text-controller-impl.h index cc6a818..0b404cc 100644 --- a/dali-toolkit/internal/text/controller/text-controller-impl.h +++ b/dali-toolkit/internal/text/controller/text-controller-impl.h @@ -374,7 +374,8 @@ struct Controller::Impl mTextFitArrayEnabled(false), mIsLayoutDirectionChanged(false), mIsUserInteractionEnabled(true), - mProcessorRegistered(false) + mProcessorRegistered(false), + mTextCutout(false) { mModel = Model::New(); @@ -1108,6 +1109,7 @@ public: bool mIsLayoutDirectionChanged : 1; ///< Whether the layout has changed. bool mIsUserInteractionEnabled : 1; ///< Whether the user interaction is enabled. bool mProcessorRegistered : 1; ///< Whether the text controller registered into processor or not. + bool mTextCutout : 1; ///< Whether the text cutout enabled. private: friend ControllerImplEventHandler; diff --git a/dali-toolkit/internal/text/controller/text-controller.cpp b/dali-toolkit/internal/text/controller/text-controller.cpp index cb126dc..da697ba 100644 --- a/dali-toolkit/internal/text/controller/text-controller.cpp +++ b/dali-toolkit/internal/text/controller/text-controller.cpp @@ -325,6 +325,21 @@ void Controller::SetRemoveBackInset(bool remove) mImpl->mModel->mRemoveBackInset = remove; } +bool Controller::IsTextCutout() const +{ + return mImpl->mTextCutout; +} + +void Controller::SetTextCutout(bool cutout) +{ + if(cutout != mImpl->mTextCutout) + { + mImpl->mModel->mVisualModel->SetCutoutEnabled(cutout); + mImpl->mTextCutout = cutout; + mImpl->RequestRelayout(); + } +} + void Controller::ChangedLayoutDirection() { mImpl->mIsLayoutDirectionChanged = true; @@ -1531,6 +1546,28 @@ void Controller::SetVisualTransformOffset(Vector2 offset) mImpl->mModel->mVisualTransformOffset = offset; } +void Controller::SetBackgroundWithCutoutEnabled(bool cutout) +{ + mImpl->mModel->mVisualModel->SetBackgroundWithCutoutEnabled(cutout); + RequestRelayout(); +} + +bool Controller::IsBackgroundWithCutoutEnabled() const +{ + return mImpl->mModel->mVisualModel->IsBackgroundWithCutoutEnabled(); +} + +void Controller::SetBackgroundColorWithCutout(const Vector4& color) +{ + mImpl->mModel->mVisualModel->SetBackgroundColorWithCutout(color); + mImpl->RequestRelayout(); +} + +const Vector4 Controller::GetBackgroundColorWithCutout() const +{ + return mImpl->mModel->mVisualModel->GetBackgroundColorWithCutout(); +} + Controller::UpdateTextType Controller::Relayout(const Size& size, Dali::LayoutDirection::Type layoutDirection) { return Relayouter::Relayout(*this, size, layoutDirection); diff --git a/dali-toolkit/internal/text/controller/text-controller.h b/dali-toolkit/internal/text/controller/text-controller.h index 9acab81..20ad0f0 100644 --- a/dali-toolkit/internal/text/controller/text-controller.h +++ b/dali-toolkit/internal/text/controller/text-controller.h @@ -1676,6 +1676,34 @@ public: // Default style & Input style */ void SetVisualTransformOffset(Vector2 offset); + /** + * @brief Sets whether background color with cutout is enabled. + * + * @param[in] enable True if enabled. + */ + void SetBackgroundWithCutoutEnabled(bool enable); + + /** + * @brief Whether background color with cutout is enabled. + * + * @return True if enabled. + */ + bool IsBackgroundWithCutoutEnabled() const; + + /** + * @brief Sets whether background color with cutout. + * + * @param[in] color The color to set. + */ + void SetBackgroundColorWithCutout(const Vector4& color); + + /** + * @brief Retrieves background color with cutout. + * + * @return The color. + */ + const Vector4 GetBackgroundColorWithCutout() const; + public: // Queries & retrieves. /** * @brief Return the layout engine. @@ -1852,6 +1880,18 @@ public: // Queries & retrieves. void SetRemoveBackInset(bool remove); /** + * @brief Retrieves cutout value to model + * @return The value of cutout for the text + */ + bool IsTextCutout() const; + + /** + * @brief Sets cutout value to model + * @param[in] cutout The value of cutout for the text + */ + void SetTextCutout(bool cutout); + + /** * @brief Sets SetMatchLayoutDirection value to model * @param[in] match The value of matchLayoutDirection for the text */ diff --git a/dali-toolkit/internal/text/rendering/text-typesetter.cpp b/dali-toolkit/internal/text/rendering/text-typesetter.cpp index 7d095b4..b8eddcd 100644 --- a/dali-toolkit/internal/text/rendering/text-typesetter.cpp +++ b/dali-toolkit/internal/text/rendering/text-typesetter.cpp @@ -20,6 +20,7 @@ // EXTERNAL INCLUDES #include +#include #include #include #include @@ -584,6 +585,8 @@ Devel::PixelBuffer DrawGlyphsBackground(const ViewModel* model, Devel::PixelBuff const Vector2* const positionBuffer = model->GetLayout(); const Vector4* const backgroundColorsBuffer = model->GetBackgroundColors(); const ColorIndex* const backgroundColorIndicesBuffer = model->GetBackgroundColorIndices(); + const bool removeFrontInset = model->IsRemoveFrontInset(); + const bool removeBackInset = model->IsRemoveBackInset(); const DevelText::VerticalLineAlignment::Type verLineAlign = model->GetVerticalLineAlignment(); @@ -653,14 +656,36 @@ Devel::PixelBuffer DrawGlyphsBackground(const ViewModel* model, Devel::PixelBuff } // Calculate the positions of leftmost and rightmost glyphs in the current line - if((position->x < left) || (backgroundColorIndex != prevBackgroundColorIndex)) + if(removeFrontInset) { - left = position->x - glyphInfo->xBearing; + if((position->x < left) || (backgroundColorIndex != prevBackgroundColorIndex)) + { + left = position->x; + } + } + else + { + const float originPositionLeft = position->x - glyphInfo->xBearing; + if((originPositionLeft < left) || (backgroundColorIndex != prevBackgroundColorIndex)) + { + left = originPositionLeft; + } } - if(position->x + glyphInfo->width > right) + if(removeBackInset) { - right = position->x - glyphInfo->xBearing + glyphInfo->advance; + if(position->x + glyphInfo->width > right) + { + right = position->x - position->x + glyphInfo->width; + } + } + else + { + const float originPositionRight = position->x - glyphInfo->xBearing + glyphInfo->advance; + if(originPositionRight > right) + { + right = originPositionRight; + } } prevBackgroundColorIndex = backgroundColorIndex; @@ -896,6 +921,24 @@ ViewModel* Typesetter::GetViewModel() PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat) { + Devel::PixelBuffer result = RenderWithPixelBuffer(size, textDirection, behaviour, ignoreHorizontalAlignment, pixelFormat); + PixelData pixelData = Devel::PixelBuffer::Convert(result); + + return pixelData; +} + +PixelData Typesetter::RenderWithCutout(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, Devel::PixelBuffer mask, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, float originAlpha) +{ + Devel::PixelBuffer result = RenderWithPixelBuffer(size, textDirection, behaviour, ignoreHorizontalAlignment, pixelFormat); + SetMaskForImageBuffer(mask, result, size.width, size.height, originAlpha); + + PixelData pixelData = Devel::PixelBuffer::Convert(result); + + return pixelData; +} + +Devel::PixelBuffer Typesetter::RenderWithPixelBuffer(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat) +{ DALI_TRACE_SCOPE(gTraceFilter, "DALI_TEXT_RENDERING_TYPESETTER"); // @todo. This initial implementation for a TextLabel has only one visible page. @@ -904,12 +947,10 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect // Retrieves the layout size. const Size& layoutSize = mModel->GetLayoutSize(); - const int32_t outlineWidth = static_cast(mModel->GetOutlineWidth()); // Set the offset for the horizontal alignment according to the text direction and outline width. int32_t penX = 0; - switch(mModel->GetHorizontalAlignment()) { case HorizontalAlignment::BEGIN: @@ -931,7 +972,6 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect // Set the offset for the vertical alignment. int32_t penY = 0u; - switch(mModel->GetVerticalAlignment()) { case VerticalAlignment::TOP: @@ -1054,6 +1094,18 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect CombineImageBuffer(imageBuffer, backgroundImageBuffer, bufferWidth, bufferHeight, true); } + // Generate the background_with_mask if enabled + const bool backgroundWithCutoutEnabled = mModel->IsBackgroundWithCutoutEnabled(); + if((backgroundWithCutoutEnabled) && RENDER_OVERLAY_STYLE != behaviour) + { + Devel::PixelBuffer backgroundImageBuffer; + + backgroundImageBuffer = CreateFullBackgroundBuffer(bufferWidth, bufferHeight, mModel->GetBackgroundColorWithCutout()); + + // Combine the two buffers + CombineImageBuffer(imageBuffer, backgroundImageBuffer, bufferWidth, bufferHeight, true); + } + if(RENDER_OVERLAY_STYLE == behaviour) { if(mModel->IsUnderlineEnabled()) @@ -1090,10 +1142,30 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect } } - // Create the final PixelData for the combined image buffer - PixelData pixelData = Devel::PixelBuffer::Convert(imageBuffer); + return imageBuffer; +} - return pixelData; +Devel::PixelBuffer Typesetter::CreateFullBackgroundBuffer(const uint32_t bufferWidth, const uint32_t bufferHeight, const Vector4& backgroundColor) +{ + const uint32_t bufferSizeInt = bufferWidth * bufferHeight; + uint8_t backgroundColorAlpha = static_cast(backgroundColor.a * 255.f); + + Devel::PixelBuffer buffer = Devel::PixelBuffer::New(bufferWidth, bufferHeight, Pixel::RGBA8888); + + uint32_t* bitmapBuffer = reinterpret_cast(buffer.GetBuffer()); + + uint32_t packedBackgroundColor = 0u; + uint8_t* packedBackgroundColorBuffer = reinterpret_cast(&packedBackgroundColor); + + // Write the color to the pixel buffer + *(packedBackgroundColorBuffer + 3u) = backgroundColorAlpha; + *(packedBackgroundColorBuffer + 2u) = static_cast(backgroundColor.b * backgroundColorAlpha); + *(packedBackgroundColorBuffer + 1u) = static_cast(backgroundColor.g * backgroundColorAlpha); + *(packedBackgroundColorBuffer) = static_cast(backgroundColor.r * backgroundColorAlpha); + + std::fill(bitmapBuffer, bitmapBuffer + bufferSizeInt, packedBackgroundColor); + + return buffer; } Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t bufferWidth, const uint32_t bufferHeight, const Typesetter::Style style, const bool ignoreHorizontalAlignment, const Pixel::Format pixelFormat, const int32_t horizontalOffset, const int32_t verticalOffset, const GlyphIndex fromGlyphIndex, const GlyphIndex toGlyphIndex) @@ -1108,6 +1180,9 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t bufferWidth, con const GlyphInfo* __restrict__ hyphens = mModel->GetHyphens(); const Length* __restrict__ hyphenIndices = mModel->GetHyphenIndices(); const Length hyphensCount = mModel->GetHyphensCount(); + const bool removeFrontInset = mModel->IsRemoveFrontInset(); + const bool removeBackInset = mModel->IsRemoveBackInset(); + const bool cutoutEnabled = mModel->IsCutoutEnabled(); // Elided text info. Indices according to elided text and Ellipsis position. const auto startIndexOfGlyphs = mModel->GetStartIndexOfElidedGlyphs(); @@ -1336,14 +1411,36 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t bufferWidth, con } // Calculate the positions of leftmost and rightmost glyphs in the current line - if(position.x < lineExtentLeft) + if(removeFrontInset) + { + if(position.x < lineExtentLeft) + { + lineExtentLeft = position.x; + } + } + else { - lineExtentLeft = position.x; + const float originPositionLeft = position.x - glyphInfo->xBearing; + if(originPositionLeft < lineExtentLeft) + { + lineExtentLeft = originPositionLeft; + } } - if(position.x + glyphInfo->width > lineExtentRight) + if(removeBackInset) { - lineExtentRight = position.x + glyphInfo->width; + if(position.x + glyphInfo->width > lineExtentRight) + { + lineExtentRight = position.x + glyphInfo->width; + } + } + else + { + const float originPositionRight = position.x - glyphInfo->xBearing + glyphInfo->advance; + if(originPositionRight > lineExtentRight) + { + lineExtentRight = originPositionRight; + } } // Retrieves the glyph's color. @@ -1363,6 +1460,12 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t bufferWidth, con color = (useDefaultColor || (0u == colorIndex)) ? defaultColor : *(colorsBuffer + (colorIndex - 1u)); } + if(style == Typesetter::STYLE_NONE && cutoutEnabled) + { + // Temporarily adjust the transparency to 1.f + color.a = 1.f; + } + // Premultiply alpha color.r *= color.a; color.g *= color.a; @@ -1528,6 +1631,58 @@ Devel::PixelBuffer Typesetter::ApplyStrikethroughMarkupImageBuffer(Devel::PixelB return topPixelBuffer; } +void Typesetter::SetMaskForImageBuffer(Devel::PixelBuffer& __restrict__ topPixelBuffer, Devel::PixelBuffer& __restrict__ bottomPixelBuffer, const uint32_t bufferWidth, const uint32_t bufferHeight, float originAlpha) +{ + // Assume that we always combine two RGBA images + // Jump with 4bytes for optimize runtime. + uint32_t* topBuffer = reinterpret_cast(topPixelBuffer.GetBuffer()); + uint32_t* bottomBuffer = reinterpret_cast(bottomPixelBuffer.GetBuffer()); + + if(topBuffer == NULL || bottomBuffer == NULL) + { + // Nothing to do if one of both buffers are empty. + return; + } + + const uint32_t bufferSizeInt = bufferWidth * bufferHeight; + + for(uint32_t pixelIndex = 0; pixelIndex < bufferSizeInt; ++pixelIndex) + { + uint32_t topBufferColor = *(topBuffer); + uint32_t bottomBufferColor = *(bottomBuffer); + uint8_t* __restrict__ topBufferColorBuffer = reinterpret_cast(&topBufferColor); + uint8_t* __restrict__ bottomBufferColorBuffer = reinterpret_cast(&bottomBufferColor); + + uint8_t topAlpha = topBufferColorBuffer[3]; + uint8_t bottomAlpha = 255 - topAlpha; + + float tempTop[4], tempBottom[4]; + + // Return the transparency of the text to original. + tempTop[0] = static_cast(topBufferColorBuffer[0]) * originAlpha; + tempTop[1] = static_cast(topBufferColorBuffer[1]) * originAlpha; + tempTop[2] = static_cast(topBufferColorBuffer[2]) * originAlpha; + tempTop[3] = static_cast(topBufferColorBuffer[3]) * originAlpha; + + // Manual blending. + tempBottom[0] = static_cast(bottomBufferColorBuffer[0]) * static_cast(bottomAlpha) / 255.f; + tempBottom[1] = static_cast(bottomBufferColorBuffer[1]) * static_cast(bottomAlpha) / 255.f; + tempBottom[2] = static_cast(bottomBufferColorBuffer[2]) * static_cast(bottomAlpha) / 255.f; + tempBottom[3] = static_cast(bottomBufferColorBuffer[3]) * static_cast(bottomAlpha) / 255.f; + + bottomBufferColorBuffer[0] = static_cast(std::min(255u, static_cast(tempBottom[0] + tempTop[0]))); + bottomBufferColorBuffer[1] = static_cast(std::min(255u, static_cast(tempBottom[1] + tempTop[1]))); + bottomBufferColorBuffer[2] = static_cast(std::min(255u, static_cast(tempBottom[2] + tempTop[2]))); + bottomBufferColorBuffer[3] = static_cast(std::min(255u, static_cast(tempBottom[3] + tempTop[3]))); + + *(bottomBuffer) = bottomBufferColor; + + // Increase each buffer's pointer. + ++topBuffer; + ++bottomBuffer; + } +} + Typesetter::Typesetter(const ModelInterface* const model) : mModel(new ViewModel(model)) { diff --git a/dali-toolkit/internal/text/rendering/text-typesetter.h b/dali-toolkit/internal/text/rendering/text-typesetter.h index 296126e..7d268c9 100644 --- a/dali-toolkit/internal/text/rendering/text-typesetter.h +++ b/dali-toolkit/internal/text/rendering/text-typesetter.h @@ -110,6 +110,61 @@ public: */ PixelData Render(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour = RENDER_TEXT_AND_STYLES, bool ignoreHorizontalAlignment = false, Pixel::Format pixelFormat = Pixel::RGBA8888); + /** + * @brief After the Render, use the pixel information of the given cutoutBuffer to make the part where the pixel is drawn transparent. + * + * @param[in] size The renderer size. + * @param[in] textDirection The direction of the text. + * @param[in] cutoutBuffer The buffer to use pixel information to cutout. + * @param[in] behaviour The behaviour of how to render the text (i.e. whether to render the text only or the styles only or both). + * @param[in] ignoreHorizontalAlignment Whether to ignore the horizontal alignment (i.e. always render as if HORIZONTAL_ALIGN_BEGIN). + * @param[in] pixelFormat The format of the pixel in the image that the text is rendered as (i.e. either Pixel::BGRA8888 or Pixel::L8). + * @param[in] originAlpha The original alpha of text. + * + * @return A pixel data with the text rendered. + */ + PixelData RenderWithCutout(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, Devel::PixelBuffer cutoutBuffer, RenderBehaviour behaviour = RENDER_TEXT_AND_STYLES, bool ignoreHorizontalAlignment = false, Pixel::Format pixelFormat = Pixel::RGBA8888, float originAlpha = 1.f); + + /** + * @brief Renders the text, return as Devel::PixelBuffer. + * + * This function is used to obtain the PixelBuffer required for cutout. + * + * @param[in] size The renderer size. + * @param[in] textDirection The direction of the text. + * @param[in] cutoutBuffer The buffer to use pixel information to cutout. + * @param[in] behaviour The behaviour of how to render the text (i.e. whether to render the text only or the styles only or both). + * @param[in] ignoreHorizontalAlignment Whether to ignore the horizontal alignment (i.e. always render as if HORIZONTAL_ALIGN_BEGIN). + * @param[in] pixelFormat The format of the pixel in the image that the text is rendered as (i.e. either Pixel::BGRA8888 or Pixel::L8). + * + * @return A pixel data with the text rendered. + */ + Devel::PixelBuffer RenderWithPixelBuffer(const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour = RENDER_TEXT_AND_STYLES, bool ignoreHorizontalAlignment = false, Pixel::Format pixelFormat = Pixel::RGBA8888); + + /** + * @brief Create & draw the image buffer of single background color. + * + * @param[in] bufferWidth The width of the image buffer. + * @param[in] bufferHeight The height of the image buffer. + * @param[in] backgroundColor The backgroundColor of image buffer. + * + * @return An image buffer with the text. + */ + Devel::PixelBuffer CreateFullBackgroundBuffer(const uint32_t bufferWidth, const uint32_t bufferHeight, const Vector4& backgroundColor); + + /** + * @brief Set Mask for two pixel buffer. + * + * The alpha value of bottomPixelBuffer is decreased as the alpha value of topPixelBuffer is higher. + * + * @param[in, out] topPixelBuffer The top layer buffer. + * @param[in, out] bottomPixelBuffer The bottom layer buffer. + * @param[in] bufferWidth The width of the image buffer. + * @param[in] bufferHeight The height of the image buffer. + * @param[in] originAlpha The original alpha value of the text. + */ + void SetMaskForImageBuffer(Devel::PixelBuffer& __restrict__ topPixelBuffer, Devel::PixelBuffer& __restrict__ bottomPixelBuffer, const uint32_t bufferWidth, const uint32_t bufferHeight, float originAlpha); + private: /** * @brief Private constructor. diff --git a/dali-toolkit/internal/text/rendering/view-model.cpp b/dali-toolkit/internal/text/rendering/view-model.cpp index 3404be2..7e3a4e3 100644 --- a/dali-toolkit/internal/text/rendering/view-model.cpp +++ b/dali-toolkit/internal/text/rendering/view-model.cpp @@ -769,6 +769,31 @@ const Vector& ViewModel::GetFontDescriptionRuns() const return mModel->GetFontDescriptionRuns(); } +bool ViewModel::IsRemoveFrontInset() const +{ + return mModel->IsRemoveFrontInset(); +} + +bool ViewModel::IsRemoveBackInset() const +{ + return mModel->IsRemoveBackInset(); +} + +bool ViewModel::IsCutoutEnabled() const +{ + return mModel->IsCutoutEnabled(); +} + +const bool ViewModel::IsBackgroundWithCutoutEnabled() const +{ + return mModel->IsBackgroundWithCutoutEnabled(); +} + +const Vector4& ViewModel::GetBackgroundColorWithCutout() const +{ + return mModel->GetBackgroundColorWithCutout(); +} + } // namespace Text } // namespace Toolkit diff --git a/dali-toolkit/internal/text/rendering/view-model.h b/dali-toolkit/internal/text/rendering/view-model.h index 9adcb65..dc7363d 100644 --- a/dali-toolkit/internal/text/rendering/view-model.h +++ b/dali-toolkit/internal/text/rendering/view-model.h @@ -388,6 +388,31 @@ public: */ const Vector& GetFontDescriptionRuns() const override; + /** + * @copydoc ModelInterface::IsRemoveFrontInset() + */ + bool IsRemoveFrontInset() const override; + + /** + * @copydoc ModelInterface::IsRemoveBackInset() + */ + bool IsRemoveBackInset() const override; + + /** + * @copydoc ModelInterface::IsCutoutEnabled() + */ + bool IsCutoutEnabled() const override; + + /** + * @copydoc ModelInterface::IsBackgroundWithCutoutEnabled() + */ + const bool IsBackgroundWithCutoutEnabled() const override; + + /** + * @copydoc ModelInterface::GetBackgroundColorWithCutout() + */ + const Vector4& GetBackgroundColorWithCutout() const override; + private: const ModelInterface* const mModel; ///< Pointer to the text's model. Vector mElidedGlyphs; ///< Stores the glyphs of the elided text. diff --git a/dali-toolkit/internal/text/text-model-interface.h b/dali-toolkit/internal/text/text-model-interface.h index 212ec0d..ba9f6ca 100644 --- a/dali-toolkit/internal/text/text-model-interface.h +++ b/dali-toolkit/internal/text/text-model-interface.h @@ -508,6 +508,41 @@ public: * @return The reference for font description runs. */ virtual const Vector& GetFontDescriptionRuns() const = 0; + + /** + * @brief Retrieves the remove front inset is enabled or not. + * + * @return boolean if it is enabled. + */ + virtual bool IsRemoveFrontInset() const = 0; + + /** + * @brief Retrieves the remove back inset is enabled or not. + * + * @return boolean if it is enabled. + */ + virtual bool IsRemoveBackInset() const = 0; + + /** + * @brief Retrieves the cutout is enabled or not. + * + * @return boolean if it is enabled. + */ + virtual bool IsCutoutEnabled() const = 0; + + /** + * @brief Retrieves the background with cutout is enabled or not. + * + * @return boolean if it is enabled. + */ + virtual const bool IsBackgroundWithCutoutEnabled() const = 0; + + /** + * @brief Retrieves the color of the background with cutout. + * + * @return The color of the background with cutout. + */ + virtual const Vector4& GetBackgroundColorWithCutout() const = 0; }; } // namespace Text diff --git a/dali-toolkit/internal/text/text-model.cpp b/dali-toolkit/internal/text/text-model.cpp index 01c6f60..bbe126b 100644 --- a/dali-toolkit/internal/text/text-model.cpp +++ b/dali-toolkit/internal/text/text-model.cpp @@ -356,6 +356,31 @@ const Vector& Model::GetFontDescriptionRuns() const return mLogicalModel->mFontDescriptionRuns; } +bool Model::IsRemoveFrontInset() const +{ + return mRemoveFrontInset; +} + +bool Model::IsRemoveBackInset() const +{ + return mRemoveBackInset; +} + +bool Model::IsCutoutEnabled() const +{ + return mVisualModel->IsCutoutEnabled(); +} + +const bool Model::IsBackgroundWithCutoutEnabled() const +{ + return mVisualModel->IsBackgroundWithCutoutEnabled(); +} + +const Vector4& Model::GetBackgroundColorWithCutout() const +{ + return mVisualModel->GetBackgroundColorWithCutout(); +} + Model::Model() : mLogicalModel(), mVisualModel(), diff --git a/dali-toolkit/internal/text/text-model.h b/dali-toolkit/internal/text/text-model.h index eb0d8a6..5661035 100644 --- a/dali-toolkit/internal/text/text-model.h +++ b/dali-toolkit/internal/text/text-model.h @@ -374,6 +374,31 @@ public: */ const Vector& GetFontDescriptionRuns() const override; + /** + * @copydoc ModelInterface::IsRemoveFrontInset() + */ + bool IsRemoveFrontInset() const override; + + /** + * @copydoc ModelInterface::IsRemoveBackInset() + */ + bool IsRemoveBackInset() const override; + + /** + * @copydoc ModelInterface::IsCutoutEnabled() + */ + bool IsCutoutEnabled() const override; + + /** + * @copydoc ModelInterface::IsBackgroundWithCutoutEnabled() + */ + const bool IsBackgroundWithCutoutEnabled() const override; + + /** + * @copydoc ModelInterface::GetBackgroundColorWithCutout() + */ + const Vector4& GetBackgroundColorWithCutout() const override; + private: // Private contructors & copy operator. /** * @brief Private constructor. diff --git a/dali-toolkit/internal/text/text-view-interface.h b/dali-toolkit/internal/text/text-view-interface.h index 10ff4ff..5fbbfea 100644 --- a/dali-toolkit/internal/text/text-view-interface.h +++ b/dali-toolkit/internal/text/text-view-interface.h @@ -392,6 +392,13 @@ public: * @return GetGlyphsToCharacters. */ virtual const Vector& GetGlyphsToCharacters() const = 0; + + /** + * @brief Returns whether cutout is enabled or not. + * + * @return The cutout state. + */ + virtual bool IsCutoutEnabled() const = 0; }; } // namespace Text diff --git a/dali-toolkit/internal/text/text-view.cpp b/dali-toolkit/internal/text/text-view.cpp index 66d0af9..3b678dd 100644 --- a/dali-toolkit/internal/text/text-view.cpp +++ b/dali-toolkit/internal/text/text-view.cpp @@ -1024,4 +1024,13 @@ const Vector& View::GetGlyphsToCharacters() const return mImpl->mVisualModel->GetGlyphsToCharacters(); } +bool View::IsCutoutEnabled() const +{ + if(mImpl->mVisualModel) + { + return mImpl->mVisualModel->IsCutoutEnabled(); + } + return false; +} + } // namespace Dali::Toolkit::Text diff --git a/dali-toolkit/internal/text/text-view.h b/dali-toolkit/internal/text/text-view.h index 9b12d03..d141f4b 100644 --- a/dali-toolkit/internal/text/text-view.h +++ b/dali-toolkit/internal/text/text-view.h @@ -288,6 +288,11 @@ public: */ const Vector& GetGlyphsToCharacters() const override; + /** + * @copydoc Dali::Toolkit::Text::ViewInterface::IsCutoutEnabled() + */ + bool IsCutoutEnabled() const override; + private: // Undefined View(const View& handle); diff --git a/dali-toolkit/internal/text/visual-model-impl.cpp b/dali-toolkit/internal/text/visual-model-impl.cpp index fd6b683..3fdd6b8 100644 --- a/dali-toolkit/internal/text/visual-model-impl.cpp +++ b/dali-toolkit/internal/text/visual-model-impl.cpp @@ -665,6 +665,36 @@ const Vector& VisualModel::GetGlyphsToCharacters() const return mGlyphsToCharacters; } +void VisualModel::SetCutoutEnabled(bool enable) +{ + mCutoutEnabled = enable; +} + +bool VisualModel::IsCutoutEnabled() const +{ + return mCutoutEnabled; +} + +void VisualModel::SetBackgroundWithCutoutEnabled(bool enable) +{ + mBackgroundWithCutoutEnabled = enable; +} + +bool VisualModel::IsBackgroundWithCutoutEnabled() const +{ + return mBackgroundWithCutoutEnabled; +} + +void VisualModel::SetBackgroundColorWithCutout(const Vector4& color) +{ + mBackgroundColorWithCutout = color; +} + +const Vector4& VisualModel::GetBackgroundColorWithCutout() const +{ + return mBackgroundColorWithCutout; +} + VisualModel::~VisualModel() { } @@ -709,8 +739,9 @@ VisualModel::VisualModel() mBackgroundEnabled(false), mMarkupProcessorEnabled(false), mStrikethroughEnabled(false), - mCharacterSpacing(0.0f) - + mCharacterSpacing(0.0f), + mCutoutEnabled(false), + mBackgroundWithCutoutEnabled(false) { } diff --git a/dali-toolkit/internal/text/visual-model-impl.h b/dali-toolkit/internal/text/visual-model-impl.h index edebaf6..7ef55b5 100644 --- a/dali-toolkit/internal/text/visual-model-impl.h +++ b/dali-toolkit/internal/text/visual-model-impl.h @@ -662,6 +662,48 @@ public: */ const Vector& GetCharacterSpacingGlyphRuns() const; + /** + * @brief Sets the cutout flag. + * + * @param[in] enable true if cutouted. + */ + void SetCutoutEnabled(bool enable); + + /** + * @brief Returns whether the text is cutouted or not. + * + * @return cutout state. + */ + bool IsCutoutEnabled() const; + + /** + * @brief Sets the background with cutout flag. + * + * @param[in] enable true if background enabled. + */ + void SetBackgroundWithCutoutEnabled(bool enable); + + /** + * @brief Returns whether the text is cutouted or not. + * + * @return True if enabled. + */ + bool IsBackgroundWithCutoutEnabled() const; + + /** + * @brief Sets the Color of background with cutout. + * + * @param[in] color The color to set. + */ + void SetBackgroundColorWithCutout(const Vector4& color); + + /** + * @brief Retrieves the Color of background with cutout. + * + * @return The color. + */ + const Vector4& GetBackgroundColorWithCutout() const; + protected: /** * @brief A reference counted object may only be deleted by calling Unreference(). @@ -681,37 +723,38 @@ private: VisualModel& operator=(const VisualModel& handle); public: - Vector mGlyphs; ///< For each glyph, the font's id, glyph's index within the font and glyph's metrics. - Vector mGlyphsToCharacters; ///< For each glyph, the index of the first character. - Vector mCharactersToGlyph; ///< For each character, the index of the first glyph. - Vector mCharactersPerGlyph; ///< For each glyph, the number of characters that form the glyph. - Vector mGlyphsPerCharacter; ///< For each character, the number of glyphs that are shaped. - Vector mGlyphPositions; ///< For each glyph, the position. - Vector mLines; ///< The laid out lines. - Vector mUnderlineRuns; ///< Runs of glyphs that are underlined. - Vector mColors; ///< Colors of the glyphs. - Vector mColorIndices; ///< Indices to the vector of colors for each glyphs. - Vector mBackgroundColors; ///< Background colors of the glyphs. - Vector mBackgroundColorIndices; ///< Indices to the vector of background colors for each glyphs. - Vector4 mTextColor; ///< The text color - Vector4 mShadowColor; ///< Color of drop shadow - Vector4 mUnderlineColor; ///< Color of underline - Vector4 mOutlineColor; ///< Color of outline - Vector4 mBackgroundColor; ///< Color of text background - Vector4 mStrikethroughColor; ///< Color of text background - Size mControlSize; ///< The size of the UI control. - Vector2 mShadowOffset; ///< Offset for drop shadow, 0 indicates no shadow - Vector2 mOutlineOffset; ///< Offset for outline - float mUnderlineHeight; ///< Fixed height for underline to override font metrics. - float mStrikethroughHeight; ///< Fixed height for strikethrough to override font metrics. - Text::Underline::Type mUnderlineType; ///< The type of the underline. - float mDashedUnderlineWidth; ///< The width of the dashes of the dashed underline. - float mDashedUnderlineGap; ///< The gap between the dashes of the dashed underline. - float mShadowBlurRadius; ///< Blur radius of shadow, 0 indicates no blur. + Vector mGlyphs; ///< For each glyph, the font's id, glyph's index within the font and glyph's metrics. + Vector mGlyphsToCharacters; ///< For each glyph, the index of the first character. + Vector mCharactersToGlyph; ///< For each character, the index of the first glyph. + Vector mCharactersPerGlyph; ///< For each glyph, the number of characters that form the glyph. + Vector mGlyphsPerCharacter; ///< For each character, the number of glyphs that are shaped. + Vector mGlyphPositions; ///< For each glyph, the position. + Vector mLines; ///< The laid out lines. + Vector mUnderlineRuns; ///< Runs of glyphs that are underlined. + Vector mColors; ///< Colors of the glyphs. + Vector mColorIndices; ///< Indices to the vector of colors for each glyphs. + Vector mBackgroundColors; ///< Background colors of the glyphs. + Vector mBackgroundColorIndices; ///< Indices to the vector of background colors for each glyphs. + Vector4 mTextColor; ///< The text color + Vector4 mShadowColor; ///< Color of drop shadow + Vector4 mUnderlineColor; ///< Color of underline + Vector4 mOutlineColor; ///< Color of outline + Vector4 mBackgroundColor; ///< Color of text background + Vector4 mStrikethroughColor; ///< Color of text background + Size mControlSize; ///< The size of the UI control. + Vector2 mShadowOffset; ///< Offset for drop shadow, 0 indicates no shadow + Vector2 mOutlineOffset; ///< Offset for outline + float mUnderlineHeight; ///< Fixed height for underline to override font metrics. + float mStrikethroughHeight; ///< Fixed height for strikethrough to override font metrics. + Text::Underline::Type mUnderlineType; ///< The type of the underline. + float mDashedUnderlineWidth; ///< The width of the dashes of the dashed underline. + float mDashedUnderlineGap; ///< The gap between the dashes of the dashed underline. + float mShadowBlurRadius; ///< Blur radius of shadow, 0 indicates no blur. float mOutlineBlurRadius; ///< Blur radius of outline, 0 indicates no blur. - uint16_t mOutlineWidth; ///< Width of outline. - Vector mStrikethroughRuns; ///< Runs of glyphs that have strikethrough. - Vector mCharacterSpacingRuns; ///< Runs of glyphs that have character-spacing. + uint16_t mOutlineWidth; ///< Width of outline. + Vector mStrikethroughRuns; ///< Runs of glyphs that have strikethrough. + Vector mCharacterSpacingRuns; ///< Runs of glyphs that have character-spacing. + Vector4 mBackgroundColorWithCutout; ///< Background color with cutout. private: Size mNaturalSize; ///< Size of the text with no line wrapping. @@ -729,13 +772,15 @@ private: bool mTextElideEnabled : 1; ///< Whether the text's elide is enabled. public: - bool mUnderlineEnabled : 1; ///< Underline enabled flag - bool mUnderlineColorSet : 1; ///< Has the underline color been explicitly set? - bool mBackgroundEnabled : 1; ///< Background enabled flag - bool mMarkupProcessorEnabled : 1; ///< Markup-processor enabled flag - HyphenInfo mHyphen; ///< Contains hyphen glyph info & the character index to draw hyphen after. - bool mStrikethroughEnabled : 1; ///< Strikethrough enabled flag - float mCharacterSpacing; ///< Contains the value of the character spacing. + bool mUnderlineEnabled : 1; ///< Underline enabled flag + bool mUnderlineColorSet : 1; ///< Has the underline color been explicitly set? + bool mBackgroundEnabled : 1; ///< Background enabled flag + bool mMarkupProcessorEnabled : 1; ///< Markup-processor enabled flag + HyphenInfo mHyphen; ///< Contains hyphen glyph info & the character index to draw hyphen after. + bool mStrikethroughEnabled : 1; ///< Strikethrough enabled flag + float mCharacterSpacing; ///< Contains the value of the character spacing. + bool mCutoutEnabled : 1; ///< Cutout enabled flag + bool mBackgroundWithCutoutEnabled : 1; ///< Background with cutout enabled flag. }; } // namespace Text diff --git a/dali-toolkit/internal/visuals/text/text-visual.cpp b/dali-toolkit/internal/visuals/text/text-visual.cpp index 02bd921..8e01eac 100644 --- a/dali-toolkit/internal/visuals/text/text-visual.cpp +++ b/dali-toolkit/internal/visuals/text/text-visual.cpp @@ -53,7 +53,7 @@ namespace { DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_TEXT_PERFORMANCE_MARKER, false); -const int CUSTOM_PROPERTY_COUNT(2); // uTextColorAnimatable, uHasMultipleTextColors +const int CUSTOM_PROPERTY_COUNT(3); // uTextColorAnimatable, uHasMultipleTextColors, requireRender /** * Return Property index for the given string key @@ -137,7 +137,7 @@ void TextColorConstraint(Vector4& current, const PropertyInputContainer& inputs) void OpacityConstraint(float& current, const PropertyInputContainer& inputs) { // Make zero if the alpha value of text color is zero to skip rendering text - if(EqualsZero(inputs[0]->GetVector4().a)) + if(EqualsZero(inputs[0]->GetVector4().a) && !inputs[1]->GetBoolean()) { current = 0.0f; } @@ -259,7 +259,9 @@ TextVisual::TextVisual(VisualFactoryCache& factoryCache, TextVisualShaderFactory mHasMultipleTextColorsIndex(Property::INVALID_INDEX), mAnimatableTextColorPropertyIndex(Property::INVALID_INDEX), mTextColorAnimatableIndex(Property::INVALID_INDEX), - mRendererUpdateNeeded(false) + mTextRequireRenderPropertyIndex(Property::INVALID_INDEX), + mRendererUpdateNeeded(false), + mTextRequireRender(false) { // Enable the pre-multiplied alpha to improve the text quality mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA; @@ -276,6 +278,7 @@ void TextVisual::OnInitialize() mImpl->mRenderer = VisualRenderer::New(geometry, shader); mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT); + mTextRequireRenderPropertyIndex = mImpl->mRenderer.RegisterUniqueProperty("requireRender", mTextRequireRender); mHasMultipleTextColorsIndex = mImpl->mRenderer.RegisterUniqueProperty("uHasMultipleTextColors", static_cast(false)); } @@ -340,6 +343,7 @@ void TextVisual::DoSetOnScene(Actor& actor) // VisualRenderer::Property::OPACITY uses same animatable property internally. mOpacityConstraint = Constraint::New(mImpl->mRenderer, Dali::DevelRenderer::Property::OPACITY, OpacityConstraint); mOpacityConstraint.AddSource(Source(actor, mAnimatableTextColorPropertyIndex)); + mOpacityConstraint.AddSource(Source(mImpl->mRenderer, mTextRequireRenderPropertyIndex)); } mOpacityConstraint.Apply(); } @@ -503,9 +507,12 @@ void TextVisual::UpdateRenderer() const bool isWidthRelative = fabsf(mImpl->mTransform.mOffsetSizeMode.z) < Math::MACHINE_EPSILON_1000; const bool isHeightRelative = fabsf(mImpl->mTransform.mOffsetSizeMode.w) < Math::MACHINE_EPSILON_1000; + const float controlWidth = mImpl->mControlSize.width; + const float controlHeight = mImpl->mControlSize.height; + // Round the size and offset to avoid pixel alignement issues. - relayoutSize.width = floorf(0.5f + (isWidthRelative ? mImpl->mControlSize.width * mImpl->mTransform.mSize.x : mImpl->mTransform.mSize.width)); - relayoutSize.height = floorf(0.5f + (isHeightRelative ? mImpl->mControlSize.height * mImpl->mTransform.mSize.y : mImpl->mTransform.mSize.height)); + relayoutSize.width = floorf(0.5f + (isWidthRelative ? controlWidth * mImpl->mTransform.mSize.x : mImpl->mTransform.mSize.width)); + relayoutSize.height = floorf(0.5f + (isHeightRelative ? controlHeight * mImpl->mTransform.mSize.y : mImpl->mTransform.mSize.height)); auto textLengthUtf32 = mController->GetNumberOfCharacters(); @@ -566,16 +573,28 @@ void TextVisual::UpdateRenderer() shadowEnabled = true; } - const bool outlineEnabled = (mController->GetTextModel()->GetOutlineWidth() > Math::MACHINE_EPSILON_1); - const bool backgroundEnabled = mController->GetTextModel()->IsBackgroundEnabled(); - const bool markupOrSpannedText = mController->IsMarkupProcessorEnabled() || mController->GetTextModel()->IsSpannedTextPlaced(); - const bool markupUnderlineEnabled = markupOrSpannedText && mController->GetTextModel()->IsMarkupUnderlineSet(); - const bool markupStrikethroughEnabled = markupOrSpannedText && mController->GetTextModel()->IsMarkupStrikethroughSet(); - const bool underlineEnabled = mController->GetTextModel()->IsUnderlineEnabled() || markupUnderlineEnabled; - const bool strikethroughEnabled = mController->GetTextModel()->IsStrikethroughEnabled() || markupStrikethroughEnabled; - const bool backgroundMarkupSet = mController->GetTextModel()->IsMarkupBackgroundColorSet(); - const bool styleEnabled = (shadowEnabled || outlineEnabled || backgroundEnabled || markupOrSpannedText || backgroundMarkupSet); - const bool isOverlayStyle = underlineEnabled || strikethroughEnabled; + const bool outlineEnabled = (mController->GetTextModel()->GetOutlineWidth() > Math::MACHINE_EPSILON_1); + const bool backgroundEnabled = mController->GetTextModel()->IsBackgroundEnabled(); + const bool markupOrSpannedText = mController->IsMarkupProcessorEnabled() || mController->GetTextModel()->IsSpannedTextPlaced(); + const bool markupUnderlineEnabled = markupOrSpannedText && mController->GetTextModel()->IsMarkupUnderlineSet(); + const bool markupStrikethroughEnabled = markupOrSpannedText && mController->GetTextModel()->IsMarkupStrikethroughSet(); + const bool underlineEnabled = mController->GetTextModel()->IsUnderlineEnabled() || markupUnderlineEnabled; + const bool strikethroughEnabled = mController->GetTextModel()->IsStrikethroughEnabled() || markupStrikethroughEnabled; + const bool backgroundMarkupSet = mController->GetTextModel()->IsMarkupBackgroundColorSet(); + const bool cutoutEnabled = mController->IsTextCutout(); + const bool backgroundWithCutoutEnabled = mController->GetTextModel()->IsBackgroundWithCutoutEnabled(); + const bool styleEnabled = (shadowEnabled || outlineEnabled || backgroundEnabled || markupOrSpannedText || backgroundMarkupSet || cutoutEnabled || backgroundWithCutoutEnabled); + const bool isOverlayStyle = underlineEnabled || strikethroughEnabled; + + // if background with cutout is enabled, This text visual must render the entire control size. + if(backgroundWithCutoutEnabled) + { + relayoutSize = Vector2(controlWidth, controlHeight); + mImpl->mTransform.mSize.width = controlWidth; + mImpl->mTransform.mSize.height = controlHeight; + mImpl->mTransform.mOffset.x = 0; + mImpl->mTransform.mOffset.y = 0; + } AddRenderer(control, relayoutSize, hasMultipleTextColors, containsColorGlyph, styleEnabled, isOverlayStyle); @@ -790,6 +809,7 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple // VisualRenderer::Property::OPACITY uses same animatable property internally. Constraint opacityConstraint = Constraint::New(renderer, Dali::DevelRenderer::Property::OPACITY, OpacityConstraint); opacityConstraint.AddSource(Source(actor, mAnimatableTextColorPropertyIndex)); + opacityConstraint.AddSource(Source(mImpl->mRenderer, mTextRequireRenderPropertyIndex)); opacityConstraint.Apply(); } } @@ -799,6 +819,8 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple TextureSet TextVisual::GetTextTexture(const Vector2& size) { + const bool cutoutEnabled = mController->IsTextCutout(); + // Filter mode needs to be set to linear to produce better quality while scaling. Sampler sampler = Sampler::New(); sampler.SetFilterMode(FilterMode::LINEAR, FilterMode::LINEAR); @@ -806,22 +828,48 @@ TextureSet TextVisual::GetTextTexture(const Vector2& size) TextureSet textureSet = TextureSet::New(); // Create RGBA texture if the text contains emojis or multiple text colors, otherwise L8 texture - Pixel::Format textPixelFormat = (mTextShaderFeatureCache.IsEnabledEmoji() || mTextShaderFeatureCache.IsEnabledMultiColor()) ? Pixel::RGBA8888 : Pixel::L8; + Pixel::Format textPixelFormat = (mTextShaderFeatureCache.IsEnabledEmoji() || mTextShaderFeatureCache.IsEnabledMultiColor() || cutoutEnabled) ? Pixel::RGBA8888 : Pixel::L8; // Check the text direction Toolkit::DevelText::TextDirection::Type textDirection = mController->GetTextDirection(); - + uint32_t textureSetIndex = 0u; // Create a texture for the text without any styles - PixelData data = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat); - uint32_t textureSetIndex = 0u; - AddTexture(textureSet, data, sampler, textureSetIndex); - ++textureSetIndex; + Devel::PixelBuffer cutoutData; + float cutoutAlpha = mController->GetTextModel()->GetDefaultColor().a; + if(cutoutEnabled) + { + cutoutData = mTypesetter->RenderWithPixelBuffer(size, textDirection, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat); + + // Make transparent buffer. + // If the cutout is enabled, a separate texture is not used for the text. + Devel::PixelBuffer buffer = mTypesetter->CreateFullBackgroundBuffer(1, 1, Vector4(0.f, 0.f ,0.f ,0.f)); + PixelData data = Devel::PixelBuffer::Convert(buffer); + AddTexture(textureSet, data, sampler, textureSetIndex); + ++textureSetIndex; + } + else + { + PixelData data = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat); + AddTexture(textureSet, data, sampler, textureSetIndex); + ++textureSetIndex; + } + if(mTextShaderFeatureCache.IsEnabledStyle()) { // Create RGBA texture for all the text styles that render in the background (without the text itself) - PixelData styleData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888); + PixelData styleData; + + if(cutoutEnabled && cutoutData) + { + styleData = mTypesetter->RenderWithCutout(size, textDirection, cutoutData, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888, cutoutAlpha); + } + else + { + styleData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888); + } + AddTexture(textureSet, styleData, sampler, textureSetIndex); ++textureSetIndex; } @@ -854,6 +902,12 @@ Shader TextVisual::GetTextShader(VisualFactoryCache& factoryCache, const TextVis return shader; } +void TextVisual::SetRequireRender(bool requireRender) +{ + mTextRequireRender = requireRender; + mImpl->mRenderer.SetProperty(mTextRequireRenderPropertyIndex, mTextRequireRender); +} + } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/visuals/text/text-visual.h b/dali-toolkit/internal/visuals/text/text-visual.h index 1376184..0d5e5f8 100644 --- a/dali-toolkit/internal/visuals/text/text-visual.h +++ b/dali-toolkit/internal/visuals/text/text-visual.h @@ -116,6 +116,16 @@ public: }; /** + * @brief Set the text to be always rendered + * @param[in] visual The text visual. + * @param[in] requireRender Whether to text always rendered. + */ + static void SetRequireRender(Toolkit::Visual::Base visual, bool requireRender) + { + GetVisualObject(visual).SetRequireRender(requireRender); + }; + + /** * @brief Instantly updates the renderer * @param[in] visual The text visual. */ @@ -293,6 +303,12 @@ private: Shader GetTextShader(VisualFactoryCache& factoryCache, const TextVisualShaderFeature::FeatureBuilder& featureBuilder); /** + * @brief Set the text to be always rendered + * @param[in] requireRender Whether to text always rendered. + */ + void SetRequireRender(bool requireRender); + + /** * @brief Retrieve the TextVisual object. * @param[in] visual A handle to the TextVisual * @return The TextVisual object @@ -318,7 +334,9 @@ private: Property::Index mHasMultipleTextColorsIndex; ///< The index of uHasMultipleTextColors proeprty. Property::Index mAnimatableTextColorPropertyIndex; ///< The index of animatable text color property registered by the control. Property::Index mTextColorAnimatableIndex; ///< The index of uTextColorAnimatable property. + Property::Index mTextRequireRenderPropertyIndex; ///< The index of requireRender property. bool mRendererUpdateNeeded : 1; ///< The flag to indicate whether the renderer needs to be updated. + bool mTextRequireRender : 1; ///< The flag to indicate whether the text needs to be rendered. RendererContainer mRendererList; }; -- 2.7.4