Add cutout to async text
authorBowon Ryu <bowon.ryu@samsung.com>
Tue, 18 Jun 2024 02:18:50 +0000 (11:18 +0900)
committerBowon Ryu <bowon.ryu@samsung.com>
Tue, 18 Jun 2024 02:18:50 +0000 (11:18 +0900)
Change-Id: I20b52cdd4b20580e4b1bcde4dea778a2439f1012
Signed-off-by: Bowon Ryu <bowon.ryu@samsung.com>
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
dali-toolkit/internal/text/async-text/async-text-loader-impl.cpp
dali-toolkit/internal/text/async-text/async-text-loader.h
dali-toolkit/internal/visuals/text/text-visual.cpp

index 64b4cb2..8acea27 100644 (file)
@@ -1383,6 +1383,9 @@ AsyncTextParameters TextLabel::GetAsyncTextParameters(const Vector2& contentSize
     parameters.autoScrollLoopDelay = mTextScroller->GetLoopDelay();
     parameters.autoScrollGap       = mTextScroller->GetGap();
   }
+  parameters.cutout                      = mController->IsTextCutout();
+  parameters.backgroundWithCutoutEnabled = mController->IsBackgroundWithCutoutEnabled();
+  parameters.backgroundColorWithCutout   = mController->GetBackgroundColorWithCutout();
 
   return parameters;
 }
index 101ad73..9bf9f69 100644 (file)
@@ -42,6 +42,12 @@ namespace Toolkit
 namespace
 {
 constexpr uint32_t MAX_UINT32 = std::numeric_limits<uint32_t>::max();
+const float VERTICAL_ALIGNMENT_TABLE[Text::VerticalAlignment::BOTTOM + 1] =
+{
+    0.0f, // VerticalAlignment::TOP
+    0.5f, // VerticalAlignment::CENTER
+    1.0f  // VerticalAlignment::BOTTOM
+};
 } // namespace
 
 namespace Text
@@ -387,6 +393,10 @@ void AsyncTextLoader::Update(AsyncTextParameters& parameters)
     mTextModel->mVisualModel->SetOutlineOffset(parameters.outlineOffset);
   }
 
+  mTextModel->mVisualModel->SetCutoutEnabled(parameters.cutout);
+  mTextModel->mVisualModel->SetBackgroundWithCutoutEnabled(parameters.backgroundWithCutoutEnabled);
+  mTextModel->mVisualModel->SetBackgroundColorWithCutout(parameters.backgroundColorWithCutout);
+
   mTextModel->mRemoveFrontInset = parameters.removeFrontInset;
   mTextModel->mRemoveBackInset  = parameters.removeBackInset;
 
@@ -969,19 +979,21 @@ AsyncTextRenderInfo AsyncTextLoader::Render(AsyncTextParameters& parameters)
     shadowEnabled = true;
   }
 
-  const bool outlineEnabled             = mTextModel->GetOutlineWidth() > Math::MACHINE_EPSILON_1;
-  const bool backgroundEnabled          = mTextModel->IsBackgroundEnabled();
-  const bool markupOrSpannedText        = parameters.enableMarkup || mTextModel->IsSpannedTextPlaced();
-  const bool markupUnderlineEnabled     = markupOrSpannedText && mTextModel->IsMarkupUnderlineSet();
-  const bool markupStrikethroughEnabled = markupOrSpannedText && mTextModel->IsMarkupStrikethroughSet();
-  const bool underlineEnabled           = mTextModel->IsUnderlineEnabled() || markupUnderlineEnabled;
-  const bool strikethroughEnabled       = mTextModel->IsStrikethroughEnabled() || markupStrikethroughEnabled;
-  const bool backgroundMarkupSet        = mTextModel->IsMarkupBackgroundColorSet();
-  const bool styleEnabled               = (shadowEnabled || outlineEnabled || backgroundEnabled || markupOrSpannedText || backgroundMarkupSet);
-  const bool isOverlayStyle             = underlineEnabled || strikethroughEnabled;
+  const bool outlineEnabled              = mTextModel->GetOutlineWidth() > Math::MACHINE_EPSILON_1;
+  const bool backgroundEnabled           = mTextModel->IsBackgroundEnabled();
+  const bool markupOrSpannedText         = parameters.enableMarkup || mTextModel->IsSpannedTextPlaced();
+  const bool markupUnderlineEnabled      = markupOrSpannedText && mTextModel->IsMarkupUnderlineSet();
+  const bool markupStrikethroughEnabled  = markupOrSpannedText && mTextModel->IsMarkupStrikethroughSet();
+  const bool underlineEnabled            = mTextModel->IsUnderlineEnabled() || markupUnderlineEnabled;
+  const bool strikethroughEnabled        = mTextModel->IsStrikethroughEnabled() || markupStrikethroughEnabled;
+  const bool backgroundMarkupSet         = mTextModel->IsMarkupBackgroundColorSet();
+  const bool cutoutEnabled               = mTextModel->IsCutoutEnabled();
+  const bool backgroundWithCutoutEnabled = mTextModel->IsBackgroundWithCutoutEnabled();
+  const bool styleEnabled                = (shadowEnabled || outlineEnabled || backgroundEnabled || markupOrSpannedText || backgroundMarkupSet || cutoutEnabled || backgroundWithCutoutEnabled);
+  const bool isOverlayStyle              = underlineEnabled || strikethroughEnabled;
 
   // Create RGBA texture if the text contains emojis or multiple text colors, otherwise L8 texture
-  Pixel::Format textPixelFormat = (containsColorGlyph || hasMultipleTextColors) ? Pixel::RGBA8888 : Pixel::L8;
+  Pixel::Format textPixelFormat = (containsColorGlyph || hasMultipleTextColors || cutoutEnabled) ? Pixel::RGBA8888 : Pixel::L8;
 
   // The width is the control's width, height is the minimum height of the text.
   // This calculated layout size determines the size of the pixel data buffer.
@@ -997,29 +1009,62 @@ AsyncTextRenderInfo AsyncTextLoader::Render(AsyncTextParameters& parameters)
   layoutSize.y += outlineWidth * 2.0f;
   layoutSize.y = std::min(layoutSize.y, static_cast<float>(parameters.textHeight));
 
+  if(cutoutEnabled)
+  {
+    // We need to store the offset including padding and vertical alignment.
+    float xOffset = parameters.padding.start;
+    float yOffset = parameters.padding.top + std::round((static_cast<float>(parameters.textHeight) - layoutSize.y) * VERTICAL_ALIGNMENT_TABLE[parameters.verticalAlignment]);
+    mTextModel->mVisualModel->SetOffsetWithCutout(Vector2(xOffset, yOffset));
+
+    // The layout size is set to the text control size including padding.
+    layoutSize.x = static_cast<float>(parameters.textWidth) + (parameters.padding.start + parameters.padding.end);
+    layoutSize.y = static_cast<float>(parameters.textHeight) + (parameters.padding.top + parameters.padding.bottom);
+  }
+
   DALI_LOG_RELEASE_INFO("-->AsyncTextLoader::Render ControlSize : %f, %f, LayoutSize : %f, %f\n", static_cast<float>(parameters.textWidth), static_cast<float>(parameters.textHeight), layoutSize.x, layoutSize.y);
 
   // Check the text direction
   Toolkit::DevelText::TextDirection::Type textDirection = mIsTextDirectionRTL ? Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT : Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
 
-  // Create a pixel data for the text without any styles
-  PixelData data = mTypesetter->Render(layoutSize, textDirection, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat);
-
   // Set information for creating pixel datas.
   AsyncTextRenderInfo renderInfo;
   renderInfo.width  = static_cast<uint32_t>(layoutSize.x);
   renderInfo.height = static_cast<uint32_t>(layoutSize.y);
 
-  // Get the pixel data of text.
-  renderInfo.textPixelData = data;
-
   // Set the direction of text.
   renderInfo.isTextDirectionRTL = mIsTextDirectionRTL;
 
+  Devel::PixelBuffer cutoutData;
+  if(cutoutEnabled)
+  {
+    cutoutData = mTypesetter->RenderWithPixelBuffer(layoutSize, 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, Color::TRANSPARENT);
+    renderInfo.textPixelData = Devel::PixelBuffer::Convert(buffer);
+
+    // Set the flag of cutout.
+    renderInfo.isCutout = cutoutEnabled && (cutoutData != nullptr);
+  }
+  else
+  {
+    // Create a pixel data for the text without any styles
+    renderInfo.textPixelData = mTypesetter->Render(layoutSize, textDirection, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat);
+  }
+
   if(styleEnabled)
   {
-    // Create RGBA pixel data for all the text styles (without the text itself)
-    renderInfo.stylePixelData = mTypesetter->Render(layoutSize, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888);
+    if(renderInfo.isCutout)
+    {
+      float cutoutAlpha = mTextModel->GetDefaultColor().a;
+      renderInfo.stylePixelData = mTypesetter->RenderWithCutout(layoutSize, textDirection, cutoutData, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888, cutoutAlpha);
+    }
+    else
+    {
+      // Create RGBA pixel data for all the text styles (without the text itself)
+      renderInfo.stylePixelData = mTypesetter->Render(layoutSize, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888);
+    }
   }
   if(isOverlayStyle)
   {
index 6a363c9..992c3c2 100644 (file)
@@ -102,7 +102,10 @@ struct AsyncTextParameters
     autoScrollLoopCount{1},
     autoScrollLoopDelay{0.0f},
     autoScrollGap{0},
-    isAutoScrollMaxTextureExceeded{false}
+    isAutoScrollMaxTextureExceeded{false},
+    cutout{false},
+    backgroundWithCutoutEnabled{false},
+    backgroundColorWithCutout{Color::TRANSPARENT}
   {
   }
 
@@ -181,6 +184,10 @@ struct AsyncTextParameters
   float                               autoScrollLoopDelay;
   int                                 autoScrollGap;
   bool                                isAutoScrollMaxTextureExceeded : 1;
+
+  bool cutout : 1;                      ///< Cutout enabled flag
+  bool backgroundWithCutoutEnabled : 1; ///< Background with cutout enabled flag.
+  Vector4 backgroundColorWithCutout;    ///< Background color with cutout.
 };
 
 struct AsyncTextRenderInfo
@@ -199,7 +206,8 @@ struct AsyncTextRenderInfo
     containsColorGlyph(false),
     styleEnabled(false),
     isOverlayStyle(false),
-    isTextDirectionRTL(false)
+    isTextDirectionRTL(false),
+    isCutout(false)
   {
   }
 
@@ -221,6 +229,7 @@ struct AsyncTextRenderInfo
   bool          styleEnabled;
   bool          isOverlayStyle;
   bool          isTextDirectionRTL;
+  bool          isCutout;
 };
 
 /**
index cd5a27c..219b18c 100644 (file)
@@ -738,15 +738,28 @@ void TextVisual::LoadComplete(bool loadingSuccess, TextInformation textInformati
     alignmentOffset.x = 0.0f;
     alignmentOffset.y = (static_cast<float>(parameters.textHeight) - layoutSize.y) * VERTICAL_ALIGNMENT_TABLE[parameters.verticalAlignment];
 
-    // This affects font rendering quality.
-    // It need to be integerized.
-    Vector2 visualTransformOffset;
-    visualTransformOffset.x = roundf(parameters.padding.start + alignmentOffset.x);
-    visualTransformOffset.y = roundf(parameters.padding.top + alignmentOffset.y);
-
     // Size of the text control including padding.
     Vector2 textControlSize(static_cast<float>(parameters.textWidth) + (parameters.padding.start + parameters.padding.end), static_cast<float>(parameters.textHeight) + (parameters.padding.top + parameters.padding.bottom));
 
+    Vector2 visualTransformOffset;
+    if(renderInfo.isCutout)
+    {
+      // When Cutout Enabled, the current visual must draw the entire control.
+      // so set the size to controlSize and offset to 0.
+      visualTransformOffset.x = 0.0f;
+      visualTransformOffset.y = 0.0f;
+
+      // The layout size is set to the text control size including padding.
+      layoutSize = textControlSize;
+    }
+    else
+    {
+      // This affects font rendering quality.
+      // It need to be integerized.
+      visualTransformOffset.x = roundf(parameters.padding.start + alignmentOffset.x);
+      visualTransformOffset.y = roundf(parameters.padding.top + alignmentOffset.y);
+    }
+
     // Transform offset is used for subpixel data upload in text tiling.
     // We should set the transform before creating a tiling texture.
     Property::Map visualTransform;