X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fvisuals%2Ftext%2Ftext-visual.cpp;h=04f36188e246ef3337e2736c386b68a511f41a57;hp=3c6bdf3a6425076561aacbb08ce6e9c47b9b768c;hb=HEAD;hpb=a1d6238d1bb9d8ca13d9bca6a4d58b633b0eb906 diff --git a/dali-toolkit/internal/visuals/text/text-visual.cpp b/dali-toolkit/internal/visuals/text/text-visual.cpp index 3c6bdf3..5d2de15 100644 --- a/dali-toolkit/internal/visuals/text/text-visual.cpp +++ b/dali-toolkit/internal/visuals/text/text-visual.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 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. @@ -20,11 +20,11 @@ // EXTERNAL INCLUDES #include -#include #include #include #include #include +#include #include // INTERNAL HEADER @@ -51,9 +51,9 @@ namespace Internal { namespace { -const int CUSTOM_PROPERTY_COUNT(5); // anim,premul,size,offset,multicol +DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_TEXT_PERFORMANCE_MARKER, false); -const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f); +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; } @@ -256,9 +256,12 @@ TextVisual::TextVisual(VisualFactoryCache& factoryCache, TextVisualShaderFactory mTypesetter(Text::Typesetter::New(mController->GetTextModel())), mTextVisualShaderFactory(shaderFactory), mTextShaderFeatureCache(), + 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; @@ -275,6 +278,8 @@ 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)); } void TextVisual::DoSetProperties(const Property::Map& propertyMap) @@ -338,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(); } @@ -348,12 +354,13 @@ void TextVisual::DoSetOnScene(Actor& actor) UpdateRenderer(); } -void TextVisual::RemoveRenderer(Actor& actor) +void TextVisual::RemoveRenderer(Actor& actor, bool removeDefaultRenderer) { for(RendererContainer::iterator iter = mRendererList.begin(); iter != mRendererList.end(); ++iter) { Renderer renderer = (*iter); - if(renderer) + if(renderer && + (removeDefaultRenderer || (renderer != mImpl->mRenderer))) { // Removes the renderer from the actor. actor.RemoveRenderer(renderer); @@ -374,7 +381,7 @@ void TextVisual::DoSetOffScene(Actor& actor) mOpacityConstraint.Remove(); } - RemoveRenderer(actor); + RemoveRenderer(actor, true); // Resets the control handle. mControl.Reset(); @@ -500,17 +507,19 @@ 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)); - std::string text; - mController->GetText(text); + auto textLengthUtf32 = mController->GetNumberOfCharacters(); - if((fabsf(relayoutSize.width) < Math::MACHINE_EPSILON_1000) || (fabsf(relayoutSize.height) < Math::MACHINE_EPSILON_1000) || text.empty()) + if((fabsf(relayoutSize.width) < Math::MACHINE_EPSILON_1000) || (fabsf(relayoutSize.height) < Math::MACHINE_EPSILON_1000) || textLengthUtf32 == 0u) { // Remove the texture set and any renderer previously set. - RemoveRenderer(control); + RemoveRenderer(control, true); // Nothing else to do if the relayout size is zero. ResourceReady(Toolkit::Visual::ResourceStatus::READY); @@ -526,7 +535,8 @@ void TextVisual::UpdateRenderer() mRendererUpdateNeeded = false; // Remove the texture set and any renderer previously set. - RemoveRenderer(control); + // Note, we don't need to remove the mImpl->Renderer, since it will be added again after AddRenderer call. + RemoveRenderer(control, false); if((relayoutSize.width > Math::MACHINE_EPSILON_1000) && (relayoutSize.height > Math::MACHINE_EPSILON_1000)) @@ -563,16 +573,29 @@ 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(cutoutEnabled) + { + 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); @@ -644,7 +667,7 @@ void TextVisual::CreateTextureSet(TilingInfo& info, VisualRenderer& renderer, Sa // Enable the pre-multiplied alpha to improve the text quality renderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, true); - renderer.RegisterProperty(PREMULTIPLIED_ALPHA, 1.0f); + renderer.SetProperty(VisualRenderer::Property::VISUAL_PRE_MULTIPLIED_ALPHA, true); // Set size and offset for the tiling. renderer.SetProperty(VisualRenderer::Property::TRANSFORM_SIZE, Vector2(info.width, info.height)); @@ -660,6 +683,8 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple Shader shader = GetTextShader(mFactoryCache, TextVisualShaderFeature::FeatureBuilder().EnableMultiColor(hasMultipleTextColors).EnableEmoji(containsColorGlyph).EnableStyle(styleEnabled).EnableOverlay(isOverlayStyle)); mImpl->mRenderer.SetShader(shader); + DALI_TRACE_SCOPE(gTraceFilter, "DALI_TEXT_VISUAL_UPDATE_RENDERER"); + // Get the maximum size. const int maxTextureSize = Dali::GetMaxTextureSize(); @@ -671,7 +696,7 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple mImpl->mRenderer.SetTextures(textureSet); //Register transform properties mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT); - mImpl->mRenderer.RegisterProperty("uHasMultipleTextColors", static_cast(hasMultipleTextColors)); + mImpl->mRenderer.SetProperty(mHasMultipleTextColorsIndex, static_cast(hasMultipleTextColors)); mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON); mRendererList.push_back(mImpl->mRenderer); @@ -762,6 +787,7 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple Renderer renderer = (*iter); if(renderer) { + // Note, AddRenderer will ignore renderer if it is already added. @SINCE 2_3.22 actor.AddRenderer(renderer); if(renderer != mImpl->mRenderer) @@ -784,6 +810,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(); } } @@ -793,6 +820,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); @@ -800,22 +829,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; } @@ -845,10 +900,18 @@ Shader TextVisual::GetTextShader(VisualFactoryCache& factoryCache, const TextVis mTextShaderFeatureCache = featureBuilder; Shader shader = mTextVisualShaderFactory.GetShader(factoryCache, mTextShaderFeatureCache); - shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT); return shader; } +void TextVisual::SetRequireRender(bool requireRender) +{ + mTextRequireRender = requireRender; + if(mImpl->mRenderer) + { + mImpl->mRenderer.SetProperty(mTextRequireRenderPropertyIndex, mTextRequireRender); + } +} + } // namespace Internal } // namespace Toolkit