X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fvisuals%2Ftext%2Ftext-visual.cpp;h=02bd92104e3fb9dbf70bf45f7445a022428923ae;hb=HEAD;hp=5b12a349f4429691486cc116aeaf1b4e6b4dde45;hpb=7946b5a1a7188e31803ac8de5c4a8ea3cbc560cc;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-toolkit/internal/visuals/text/text-visual.cpp b/dali-toolkit/internal/visuals/text/text-visual.cpp index 5b12a34..aab56ea 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,9 +20,12 @@ // EXTERNAL INCLUDES #include -#include #include +#include #include +#include +#include +#include #include // INTERNAL HEADER @@ -34,7 +37,7 @@ #include #include #include -#include +#include #include #include #include @@ -49,9 +52,28 @@ namespace Internal { namespace { -const int CUSTOM_PROPERTY_COUNT(10); // 5 transform properties + anim,premul,size,offset,multicol +DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_TEXT_PERFORMANCE_MARKER, false); +DALI_INIT_TRACE_FILTER(gTraceFilter2, DALI_TRACE_TEXT_ASYNC, false); -const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f); +const int CUSTOM_PROPERTY_COUNT(3); // uTextColorAnimatable, uHasMultipleTextColors, requireRender + +const float VERTICAL_ALIGNMENT_TABLE[Text::VerticalAlignment::BOTTOM + 1] = + { + 0.0f, // VerticalAlignment::TOP + 0.5f, // VerticalAlignment::CENTER + 1.0f // VerticalAlignment::BOTTOM +}; + +#ifdef TRACE_ENABLED +const char* GetRequestTypeName(Text::Async::RequestType type) +{ + if(type < Text::Async::RENDER_FIXED_SIZE || type > Text::Async::COMPUTE_HEIGHT_FOR_WIDTH) + { + return "INVALID_REQUEST_TYPE"; + } + return Text::Async::RequestTypeName[type]; +} +#endif /** * Return Property index for the given string key @@ -135,7 +157,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; } @@ -147,9 +169,9 @@ void OpacityConstraint(float& current, const PropertyInputContainer& inputs) } // unnamed namespace -TextVisualPtr TextVisual::New(VisualFactoryCache& factoryCache, const Property::Map& properties) +TextVisualPtr TextVisual::New(VisualFactoryCache& factoryCache, TextVisualShaderFactory& shaderFactory, const Property::Map& properties) { - TextVisualPtr textVisualPtr(new TextVisual(factoryCache)); + TextVisualPtr textVisualPtr(new TextVisual(factoryCache, shaderFactory)); textVisualPtr->SetProperties(properties); textVisualPtr->Initialize(); return textVisualPtr; @@ -239,14 +261,37 @@ void TextVisual::DoCreateInstancePropertyMap(Property::Map& map) const map.Insert(Toolkit::TextVisual::Property::TEXT, text); } -TextVisual::TextVisual(VisualFactoryCache& factoryCache) -: Visual::Base(factoryCache, Visual::FittingMode::FIT_KEEP_ASPECT_RATIO, Toolkit::Visual::TEXT), +void TextVisual::EnablePreMultipliedAlpha(bool preMultiplied) +{ + // Make always enable pre multiplied alpha whether preMultiplied value is false. + if(!preMultiplied) + { + DALI_LOG_WARNING("Note : TextVisual cannot disable PreMultipliedAlpha\n"); + } +} + +TextVisual::TextVisual(VisualFactoryCache& factoryCache, TextVisualShaderFactory& shaderFactory) +: Visual::Base(factoryCache, Visual::FittingMode::DONT_CARE, Toolkit::Visual::TEXT), mController(Text::Controller::New()), mTypesetter(Text::Typesetter::New(mController->GetTextModel())), + mAsyncTextInterface(nullptr), + 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), + mTextLoadingTaskId(0u), + mNaturalSizeTaskId(0u), + mHeightForWidthTaskId(0u), + mIsTextLoadingTaskRunning(false), + mIsNaturalSizeTaskRunning(false), + mIsHeightForWidthTaskRunning(false) { + // Enable the pre-multiplied alpha to improve the text quality + mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA; } TextVisual::~TextVisual() @@ -255,11 +300,14 @@ TextVisual::~TextVisual() void TextVisual::OnInitialize() { - Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY); - Shader shader = GetTextShader(mFactoryCache, TextType::SINGLE_COLOR_TEXT, TextType::NO_EMOJI, TextType::NO_STYLES); + Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY); + auto featureBuilder = TextVisualShaderFeature::FeatureBuilder(); + Shader shader = GetTextShader(mFactoryCache, featureBuilder); - mImpl->mRenderer = Renderer::New(geometry, shader); + 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) @@ -294,9 +342,6 @@ void TextVisual::DoSetOnScene(Actor& actor) mImpl->mRenderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, Toolkit::DepthIndex::CONTENT); - // Enable the pre-multiplied alpha to improve the text quality - EnablePreMultipliedAlpha(true); - const Vector4& defaultColor = mController->GetTextModel()->GetDefaultColor(); if(mTextColorAnimatableIndex == Property::INVALID_INDEX) { @@ -323,8 +368,10 @@ void TextVisual::DoSetOnScene(Actor& actor) // Make zero if the alpha value of text color is zero to skip rendering text if(!mOpacityConstraint) { + // 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(); } @@ -332,17 +379,16 @@ void TextVisual::DoSetOnScene(Actor& actor) // Renderer needs textures and to be added to control mRendererUpdateNeeded = true; - mRendererList.push_back(mImpl->mRenderer); - 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); @@ -354,6 +400,11 @@ void TextVisual::RemoveRenderer(Actor& actor) void TextVisual::DoSetOffScene(Actor& actor) { + if(mController->GetRenderMode() != DevelTextLabel::Render::SYNC && mIsTextLoadingTaskRunning) + { + Text::AsyncTextManager::Get().RequestCancel(mTextLoadingTaskId); + mIsTextLoadingTaskRunning = false; + } if(mColorConstraint) { mColorConstraint.Remove(); @@ -363,7 +414,7 @@ void TextVisual::DoSetOffScene(Actor& actor) mOpacityConstraint.Remove(); } - RemoveRenderer(actor); + RemoveRenderer(actor, true); // Resets the control handle. mControl.Reset(); @@ -476,6 +527,11 @@ void TextVisual::DoSetProperty(Dali::Property::Index index, const Dali::Property void TextVisual::UpdateRenderer() { + if(mController->GetRenderMode() != DevelTextLabel::Render::SYNC) + { + return; + } + Actor control = mControl.GetHandle(); if(!control) { @@ -489,17 +545,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); @@ -515,7 +573,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)) @@ -552,14 +611,39 @@ void TextVisual::UpdateRenderer() shadowEnabled = true; } - const bool underlineEnabled = mController->GetTextModel()->IsUnderlineEnabled(); - const bool outlineEnabled = (mController->GetTextModel()->GetOutlineWidth() > Math::MACHINE_EPSILON_1); - const bool backgroundEnabled = mController->GetTextModel()->IsBackgroundEnabled(); - const bool markupProcessorEnabled = mController->IsMarkupProcessorEnabled(); - const bool strikethroughEnabled = mController->GetTextModel()->IsStrikethroughEnabled(); + 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) + { + // mTransform stores the size and offset of the current visual. + // padding and alignment information is stored in mOffset. + // When Cutout Enabled, the current visual must draw the entire control. + // so set the size to controlSize and offset to 0. + + relayoutSize = Vector2(controlWidth, controlHeight); + mImpl->mTransform.mSize.width = controlWidth; + mImpl->mTransform.mSize.height = controlHeight; + + // Relayout to the original size has been completed, so save only the offset information and use it in typesetter. - const bool styleEnabled = (shadowEnabled || underlineEnabled || outlineEnabled || backgroundEnabled || markupProcessorEnabled || strikethroughEnabled); - const bool isOverlayStyle = underlineEnabled || strikethroughEnabled; + Vector2 originOffset = Vector2(mImpl->mTransform.mOffset.x, mImpl->mTransform.mOffset.y); + mController->SetOffsetWithCutout(originOffset); + mImpl->mTransform.mOffset.x = 0; + mImpl->mTransform.mOffset.y = 0; + } AddRenderer(control, relayoutSize, hasMultipleTextColors, containsColorGlyph, styleEnabled, isOverlayStyle); @@ -581,90 +665,509 @@ void TextVisual::AddTexture(TextureSet& textureSet, PixelData& data, Sampler& sa textureSet.SetSampler(textureSetIndex, sampler); } -PixelData TextVisual::ConvertToPixelData(unsigned char* buffer, int width, int height, int offsetPosition, const Pixel::Format textPixelFormat) +void TextVisual::AddTilingTexture(TextureSet& textureSet, TilingInfo& tilingInfo, PixelData& data, Sampler& sampler, unsigned int textureSetIndex) { - int bpp = Pixel::GetBytesPerPixel(textPixelFormat); - unsigned int bufferSize = width * height * bpp; - unsigned char* dstBuffer = static_cast(malloc(bufferSize)); - memcpy(dstBuffer, buffer + offsetPosition * bpp, bufferSize); - PixelData pixelData = Dali::PixelData::New(dstBuffer, - bufferSize, - width, - height, - textPixelFormat, - Dali::PixelData::FREE); - return pixelData; + Texture texture = Texture::New(Dali::TextureType::TEXTURE_2D, + data.GetPixelFormat(), + tilingInfo.width, + tilingInfo.height); + DevelTexture::UploadSubPixelData(texture, data, 0u, tilingInfo.offsetHeight, tilingInfo.width, tilingInfo.height); + + textureSet.SetTexture(textureSetIndex, texture); + textureSet.SetSampler(textureSetIndex, sampler); } -void TextVisual::CreateTextureSet(TilingInfo& info, Renderer& renderer, Sampler& sampler, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled, bool isOverlayStyle) +void TextVisual::CreateTextureSet(TilingInfo& info, VisualRenderer& renderer, Sampler& sampler) { - TextureSet textureSet = TextureSet::New(); - unsigned int textureSetIndex = 0u; + TextureSet textureSet = TextureSet::New(); + uint32_t textureSetIndex = 0u; // Convert the buffer to pixel data to make it a texture. - if(info.textBuffer) + if(info.textPixelData) { - PixelData data = ConvertToPixelData(info.textBuffer, info.width, info.height, info.offsetPosition, info.textPixelFormat); - AddTexture(textureSet, data, sampler, textureSetIndex); + AddTilingTexture(textureSet, info, info.textPixelData, sampler, textureSetIndex); ++textureSetIndex; } - if(styleEnabled && info.styleBuffer) + if(mTextShaderFeatureCache.IsEnabledStyle() && info.stylePixelData) { - PixelData styleData = ConvertToPixelData(info.styleBuffer, info.width, info.height, info.offsetPosition, Pixel::RGBA8888); - AddTexture(textureSet, styleData, sampler, textureSetIndex); + AddTilingTexture(textureSet, info, info.stylePixelData, sampler, textureSetIndex); ++textureSetIndex; } - if(styleEnabled && isOverlayStyle && info.styleBuffer) + if(mTextShaderFeatureCache.IsEnabledOverlay() && info.overlayStylePixelData) { - PixelData overlayStyleData = ConvertToPixelData(info.styleBuffer, info.width, info.height, info.offsetPosition, Pixel::RGBA8888); - AddTexture(textureSet, overlayStyleData, sampler, textureSetIndex); + AddTilingTexture(textureSet, info, info.overlayStylePixelData, sampler, textureSetIndex); ++textureSetIndex; } - if(containsColorGlyph && !hasMultipleTextColors && info.maskBuffer) + if(mTextShaderFeatureCache.IsEnabledEmoji() && !mTextShaderFeatureCache.IsEnabledMultiColor() && info.maskPixelData) { - PixelData maskData = ConvertToPixelData(info.maskBuffer, info.width, info.height, info.offsetPosition, Pixel::L8); - AddTexture(textureSet, maskData, sampler, textureSetIndex); + AddTilingTexture(textureSet, info, info.maskPixelData, sampler, textureSetIndex); + ++textureSetIndex; } renderer.SetTextures(textureSet); - //Register transform properties - mImpl->mTransform.RegisterUniforms(renderer, Direction::LEFT_TO_RIGHT); + // Register transform properties + mImpl->mTransform.SetUniforms(renderer, Direction::LEFT_TO_RIGHT); // 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); // Set size and offset for the tiling. - renderer.RegisterProperty(SIZE, Vector2(info.width, info.height)); - renderer.RegisterProperty(OFFSET, Vector2(info.offSet.x, info.offSet.y)); - renderer.RegisterProperty("uHasMultipleTextColors", static_cast(hasMultipleTextColors)); + renderer.SetProperty(VisualRenderer::Property::TRANSFORM_SIZE, Vector2(static_cast(info.width), static_cast(info.height))); + renderer.SetProperty(VisualRenderer::Property::TRANSFORM_OFFSET, info.transformOffset); renderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON); + renderer.RegisterProperty("uHasMultipleTextColors", static_cast(mTextShaderFeatureCache.IsEnabledMultiColor())); mRendererList.push_back(renderer); } +// From async text manager +void TextVisual::LoadComplete(bool loadingSuccess, const TextInformation& textInformation) +{ + Text::AsyncTextParameters parameters = textInformation.parameters; + +#ifdef TRACE_ENABLED + if(gTraceFilter2 && gTraceFilter2->IsTraceEnabled()) + { + DALI_LOG_RELEASE_INFO("LoadComplete, success:%d, type:%s\n", loadingSuccess, GetRequestTypeName(parameters.requestType)); + } +#endif + + switch(parameters.requestType) + { + case Text::Async::RENDER_FIXED_SIZE: + case Text::Async::RENDER_FIXED_WIDTH: + case Text::Async::RENDER_CONSTRAINT: + { + mIsTextLoadingTaskRunning = false; + break; + } + case Text::Async::COMPUTE_NATURAL_SIZE: + { + mIsNaturalSizeTaskRunning = false; + break; + } + case Text::Async::COMPUTE_HEIGHT_FOR_WIDTH: + { + mIsHeightForWidthTaskRunning = false; + break; + } + default: + { + DALI_LOG_ERROR("Unexpected request type : %d\n", parameters.requestType); + break; + } + } + + Toolkit::Visual::ResourceStatus resourceStatus; + + if(loadingSuccess) + { + resourceStatus = Toolkit::Visual::ResourceStatus::READY; + + Text::AsyncTextRenderInfo renderInfo = textInformation.renderInfo; + + if(parameters.requestType == Text::Async::COMPUTE_NATURAL_SIZE || parameters.requestType == Text::Async::COMPUTE_HEIGHT_FOR_WIDTH) + { + if(mAsyncTextInterface) + { + mAsyncTextInterface->AsyncSizeComputed(renderInfo); + return; + } + } + + Actor control = mControl.GetHandle(); + if(!control) + { + // Nothing to do. + ResourceReady(Toolkit::Visual::ResourceStatus::READY); + return; + } + + // Calculate the size of the visual that can fit the text. + // The size of the text after it has been laid-out, size of pixel data buffer. + Size layoutSize(static_cast(renderInfo.width), static_cast(renderInfo.height)); + + // Calculate the offset for vertical alignment only, as the layout engine will do the horizontal alignment. + Vector2 alignmentOffset; + alignmentOffset.x = 0.0f; + alignmentOffset.y = (parameters.textHeight - layoutSize.y) * VERTICAL_ALIGNMENT_TABLE[parameters.verticalAlignment]; + + // Size of the text control including padding. + Vector2 textControlSize(parameters.textWidth + (parameters.padding.start + parameters.padding.end), parameters.textHeight + (parameters.padding.top + parameters.padding.bottom)); + + if(parameters.isAutoScrollEnabled) + { + // In case of auto scroll, the layout width (renderInfo's width) is the natural size of the text. + // Since the layout size is the size of the visual transform, it should be reset to the text area excluding padding. + layoutSize.width = parameters.textWidth; + } + + 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); + } + + SetRequireRender(renderInfo.isCutout); + + // Transform offset is used for subpixel data upload in text tiling. + // We should set the transform before creating a tiling texture. + Property::Map visualTransform; + visualTransform.Add(Toolkit::Visual::Transform::Property::SIZE, layoutSize) + .Add(Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE)) + .Add(Toolkit::Visual::Transform::Property::OFFSET, visualTransformOffset) + .Add(Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE)) + .Add(Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN) + .Add(Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN); + SetTransformAndSize(visualTransform, textControlSize); + + Shader shader = GetTextShader(mFactoryCache, TextVisualShaderFeature::FeatureBuilder().EnableMultiColor(renderInfo.hasMultipleTextColors).EnableEmoji(renderInfo.containsColorGlyph).EnableStyle(renderInfo.styleEnabled).EnableOverlay(renderInfo.isOverlayStyle)); + mImpl->mRenderer.SetShader(shader); + + // Remove the texture set and any renderer previously set. + RemoveRenderer(control, false); + + // Get the maximum texture size. + const int maxTextureSize = Dali::GetMaxTextureSize(); + + // No tiling required. Use the default renderer. + if(renderInfo.height < static_cast(maxTextureSize)) + { + // Filter mode needs to be set to linear to produce better quality while scaling. + Sampler sampler = Sampler::New(); + sampler.SetFilterMode(FilterMode::LINEAR, FilterMode::LINEAR); + + TextureSet textureSet = TextureSet::New(); + + uint32_t textureSetIndex = 0u; + AddTexture(textureSet, renderInfo.textPixelData, sampler, textureSetIndex); + ++textureSetIndex; + + if(mTextShaderFeatureCache.IsEnabledStyle()) + { + // Create RGBA texture for all the text styles that render in the background (without the text itself) + AddTexture(textureSet, renderInfo.stylePixelData, sampler, textureSetIndex); + ++textureSetIndex; + } + if(mTextShaderFeatureCache.IsEnabledOverlay()) + { + // Create RGBA texture for overlay styles such as underline and strikethrough (without the text itself) + AddTexture(textureSet, renderInfo.overlayStylePixelData, sampler, textureSetIndex); + ++textureSetIndex; + } + + if(mTextShaderFeatureCache.IsEnabledEmoji() && !mTextShaderFeatureCache.IsEnabledMultiColor()) + { + // Create a L8 texture as a mask to avoid color glyphs (e.g. emojis) to be affected by text color animation + AddTexture(textureSet, renderInfo.maskPixelData, sampler, textureSetIndex); + } + + mImpl->mRenderer.SetTextures(textureSet); + // Register transform properties + mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT); + mImpl->mRenderer.SetProperty(mHasMultipleTextColorsIndex, static_cast(mTextShaderFeatureCache.IsEnabledMultiColor())); + mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON); + + mRendererList.push_back(mImpl->mRenderer); + } + else + { + // Filter mode needs to be set to linear to produce better quality while scaling. + Sampler sampler = Sampler::New(); + sampler.SetFilterMode(FilterMode::LINEAR, FilterMode::LINEAR); + + int verifiedWidth = static_cast(renderInfo.width); + int verifiedHeight = static_cast(renderInfo.height); + + // Set information for creating textures. + TilingInfo info(verifiedWidth, maxTextureSize); + + // Get the pixel data of text. + info.textPixelData = renderInfo.textPixelData; + + if(mTextShaderFeatureCache.IsEnabledStyle()) + { + info.stylePixelData = renderInfo.stylePixelData; + } + + if(mTextShaderFeatureCache.IsEnabledOverlay()) + { + info.overlayStylePixelData = renderInfo.overlayStylePixelData; + } + + if(mTextShaderFeatureCache.IsEnabledEmoji() && !mTextShaderFeatureCache.IsEnabledMultiColor()) + { + info.maskPixelData = renderInfo.maskPixelData; + } + + // Get the current offset for recalculate the offset when tiling. + Property::Map retMap; + mImpl->mTransform.GetPropertyMap(retMap); + Property::Value* offsetValue = retMap.Find(Dali::Toolkit::Visual::Transform::Property::OFFSET); + if(offsetValue) + { + offsetValue->Get(info.transformOffset); + } + + // Create a textureset in the default renderer. + CreateTextureSet(info, mImpl->mRenderer, sampler); + + verifiedHeight -= maxTextureSize; + + Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY); + + // Create a renderer by cutting maxTextureSize. + while(verifiedHeight > 0) + { + VisualRenderer tilingRenderer = VisualRenderer::New(geometry, shader); + tilingRenderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, Toolkit::DepthIndex::CONTENT); + // New offset position of buffer for tiling. + info.offsetHeight += static_cast(maxTextureSize); + // New height for tiling. + info.height = (verifiedHeight - maxTextureSize) > 0 ? maxTextureSize : verifiedHeight; + // New offset for tiling. + info.transformOffset.y += static_cast(maxTextureSize); + + // Create a textureset int the new tiling renderer. + CreateTextureSet(info, tilingRenderer, sampler); + + verifiedHeight -= maxTextureSize; + } + } + + mImpl->mFlags &= ~Visual::Base::Impl::IS_ATLASING_APPLIED; + + const Vector4& defaultColor = parameters.textColor; + + for(RendererContainer::iterator iter = mRendererList.begin(); iter != mRendererList.end(); ++iter) + { + Renderer renderer = (*iter); + if(renderer) + { + control.AddRenderer(renderer); + + if(renderer != mImpl->mRenderer) + { + // Set constraint for text label's color for non-default renderers. + if(mAnimatableTextColorPropertyIndex != Property::INVALID_INDEX) + { + // Register unique property, or get property for default renderer. + Property::Index index = renderer.RegisterUniqueProperty("uTextColorAnimatable", defaultColor); + + // Create constraint for the animatable text's color Property with uTextColorAnimatable in the renderer. + if(index != Property::INVALID_INDEX) + { + Constraint colorConstraint = Constraint::New(renderer, index, TextColorConstraint); + colorConstraint.AddSource(Source(control, mAnimatableTextColorPropertyIndex)); + colorConstraint.Apply(); + } + + // Make zero if the alpha value of text color is zero to skip rendering text + // VisualRenderer::Property::OPACITY uses same animatable property internally. + Constraint opacityConstraint = Constraint::New(renderer, Dali::DevelRenderer::Property::OPACITY, OpacityConstraint); + opacityConstraint.AddSource(Source(control, mAnimatableTextColorPropertyIndex)); + opacityConstraint.AddSource(Source(mImpl->mRenderer, mTextRequireRenderPropertyIndex)); + opacityConstraint.Apply(); + } + } + } + } + + if(mAsyncTextInterface && parameters.isAutoScrollEnabled) + { + mAsyncTextInterface->AsyncSetupAutoScroll(renderInfo); + } + + if(mAsyncTextInterface && parameters.isTextFitEnabled) + { + mAsyncTextInterface->AsyncTextFitChanged(parameters.fontSize); + } + + if(mAsyncTextInterface) + { + mAsyncTextInterface->AsyncLoadComplete(renderInfo); + } + + // Ignore current result when user re-request async load during load complete callback. + if(mIsTextLoadingTaskRunning) + { + // Remove the texture set and any renderer previously set. + RemoveRenderer(control, true); + return; + } + } + else + { + resourceStatus = Toolkit::Visual::ResourceStatus::FAILED; + } + + // Signal to observers ( control ) that resources are ready. Must be all resources. + ResourceReady(resourceStatus); +} + +void TextVisual::SetAsyncTextInterface(Text::AsyncTextInterface* asyncTextInterface) +{ + mAsyncTextInterface = asyncTextInterface; +} + +void TextVisual::RequestAsyncSizeComputation(Text::AsyncTextParameters& parameters) +{ +#ifdef TRACE_ENABLED + if(gTraceFilter2 && gTraceFilter2->IsTraceEnabled()) + { + DALI_LOG_RELEASE_INFO("Request size computation, type:%s\n", GetRequestTypeName(parameters.requestType)); + } +#endif + + switch(parameters.requestType) + { + case Text::Async::COMPUTE_NATURAL_SIZE: + { + if(mIsNaturalSizeTaskRunning) + { + Text::AsyncTextManager::Get().RequestCancel(mNaturalSizeTaskId); + } + mIsNaturalSizeTaskRunning = true; + + TextLoadObserver* textLoadObserver = this; + mNaturalSizeTaskId = Text::AsyncTextManager::Get().RequestLoad(parameters, textLoadObserver); + break; + } + case Text::Async::COMPUTE_HEIGHT_FOR_WIDTH: + { + if(mIsHeightForWidthTaskRunning) + { + Text::AsyncTextManager::Get().RequestCancel(mHeightForWidthTaskId); + } + mIsHeightForWidthTaskRunning = true; + + TextLoadObserver* textLoadObserver = this; + mHeightForWidthTaskId = Text::AsyncTextManager::Get().RequestLoad(parameters, textLoadObserver); + break; + } + default: + { + DALI_LOG_ERROR("Unexpected request type : %d\n", parameters.requestType); + break; + } + } +} + +bool TextVisual::UpdateAsyncRenderer(Text::AsyncTextParameters& parameters) +{ + Actor control = mControl.GetHandle(); + if(!control) + { + // Nothing to do. + ResourceReady(Toolkit::Visual::ResourceStatus::READY); + return false; + } + + if((fabsf(parameters.textWidth) < Math::MACHINE_EPSILON_1000) || (fabsf(parameters.textHeight) < Math::MACHINE_EPSILON_1000) || + parameters.text.empty()) + { + if(mIsTextLoadingTaskRunning) + { + Text::AsyncTextManager::Get().RequestCancel(mTextLoadingTaskId); + mIsTextLoadingTaskRunning = false; + } + + // Remove the texture set and any renderer previously set. + RemoveRenderer(control, true); + + // Nothing else to do if the relayout size is zero. + ResourceReady(Toolkit::Visual::ResourceStatus::READY); + + if(mAsyncTextInterface) + { + Text::AsyncTextRenderInfo renderInfo; + if(parameters.requestType == Text::Async::RENDER_FIXED_SIZE) + { + renderInfo.renderedSize = Size(parameters.textWidth, parameters.textHeight); + } + else if(parameters.requestType == Text::Async::RENDER_FIXED_WIDTH) + { + renderInfo.renderedSize = Size(parameters.textWidth, 0.0f); + } + else + { + renderInfo.renderedSize = Size::ZERO; + } + + renderInfo.manualRendered = parameters.manualRender; + mAsyncTextInterface->AsyncLoadComplete(renderInfo); + } + + return true; + } + + // Get the maximum texture size. + const int maxTextureSize = Dali::GetMaxTextureSize(); + + if(parameters.textWidth > maxTextureSize) + { + DALI_LOG_WARNING("layoutSize(%f) > maxTextureSize(%d): To guarantee the behavior of Texture::New, layoutSize must not be bigger than maxTextureSize\n", parameters.textWidth, maxTextureSize); + parameters.textWidth = maxTextureSize; + } + + // This does not mean whether task is actually running or waiting. + // It is whether text visual received a completion callback after requesting a task. + if(mIsTextLoadingTaskRunning) + { + Text::AsyncTextManager::Get().RequestCancel(mTextLoadingTaskId); + } + +#ifdef TRACE_ENABLED + if(gTraceFilter2 && gTraceFilter2->IsTraceEnabled()) + { + DALI_LOG_RELEASE_INFO("Request render, type:%s\n", GetRequestTypeName(parameters.requestType)); + } +#endif + + mIsTextLoadingTaskRunning = true; + TextLoadObserver* textLoadObserver = this; + mTextLoadingTaskId = Text::AsyncTextManager::Get().RequestLoad(parameters, textLoadObserver); + + return true; +} + void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled, bool isOverlayStyle) { - Shader shader = GetTextShader(mFactoryCache, hasMultipleTextColors, containsColorGlyph, styleEnabled); + 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(); // No tiling required. Use the default renderer. if(size.height < maxTextureSize) { - TextureSet textureSet = GetTextTexture(size, hasMultipleTextColors, containsColorGlyph, styleEnabled, isOverlayStyle); + TextureSet textureSet = GetTextTexture(size); mImpl->mRenderer.SetTextures(textureSet); - //Register transform properties - mImpl->mTransform.RegisterUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT); - mImpl->mRenderer.RegisterProperty("uHasMultipleTextColors", static_cast(hasMultipleTextColors)); + // Register transform properties + mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT); + mImpl->mRenderer.SetProperty(mHasMultipleTextColorsIndex, static_cast(hasMultipleTextColors)); mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON); mRendererList.push_back(mImpl->mRenderer); @@ -689,26 +1192,27 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple int verifiedHeight = data.GetHeight(); // Set information for creating textures. - TilingInfo info(verifiedWidth, maxTextureSize, textPixelFormat); + TilingInfo info(verifiedWidth, maxTextureSize); - // Get the buffer of text. - Dali::DevelPixelData::PixelDataBuffer textPixelData = Dali::DevelPixelData::ReleasePixelDataBuffer(data); - info.textBuffer = textPixelData.buffer; + // Get the pixel data of text. + info.textPixelData = data; - if(styleEnabled) + if(mTextShaderFeatureCache.IsEnabledStyle()) { // Create RGBA texture for all the text styles (without the text itself) - PixelData styleData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888); - Dali::DevelPixelData::PixelDataBuffer stylePixelData = Dali::DevelPixelData::ReleasePixelDataBuffer(styleData); - info.styleBuffer = stylePixelData.buffer; + info.stylePixelData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888); } - if(containsColorGlyph && !hasMultipleTextColors) + if(mTextShaderFeatureCache.IsEnabledOverlay()) + { + // Create RGBA texture for all the overlay styles + info.overlayStylePixelData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_OVERLAY_STYLE, false, Pixel::RGBA8888); + } + + if(mTextShaderFeatureCache.IsEnabledEmoji() && !mTextShaderFeatureCache.IsEnabledMultiColor()) { // Create a L8 texture as a mask to avoid color glyphs (e.g. emojis) to be affected by text color animation - PixelData maskData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_MASK, false, Pixel::L8); - Dali::DevelPixelData::PixelDataBuffer maskPixelData = Dali::DevelPixelData::ReleasePixelDataBuffer(maskData); - info.maskBuffer = maskPixelData.buffer; + info.maskPixelData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_MASK, false, Pixel::L8); } // Get the current offset for recalculate the offset when tiling. @@ -717,30 +1221,29 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple Property::Value* offsetValue = retMap.Find(Dali::Toolkit::Visual::Transform::Property::OFFSET); if(offsetValue) { - offsetValue->Get(info.offSet); + offsetValue->Get(info.transformOffset); } // Create a textureset in the default renderer. - CreateTextureSet(info, mImpl->mRenderer, sampler, hasMultipleTextColors, containsColorGlyph, styleEnabled, isOverlayStyle); + CreateTextureSet(info, mImpl->mRenderer, sampler); verifiedHeight -= maxTextureSize; Geometry geometry = mFactoryCache.GetGeometry(VisualFactoryCache::QUAD_GEOMETRY); - int offsetPosition = verifiedWidth * maxTextureSize; // Create a renderer by cutting maxTextureSize. while(verifiedHeight > 0) { - Renderer tilingRenderer = Renderer::New(geometry, shader); + VisualRenderer tilingRenderer = VisualRenderer::New(geometry, shader); tilingRenderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, Toolkit::DepthIndex::CONTENT); // New offset position of buffer for tiling. - info.offsetPosition += offsetPosition; + info.offsetHeight += maxTextureSize; // New height for tiling. info.height = (verifiedHeight - maxTextureSize) > 0 ? maxTextureSize : verifiedHeight; // New offset for tiling. - info.offSet.y += maxTextureSize; + info.transformOffset.y += maxTextureSize; // Create a textureset int the new tiling renderer. - CreateTextureSet(info, tilingRenderer, sampler, hasMultipleTextColors, containsColorGlyph, styleEnabled, isOverlayStyle); + CreateTextureSet(info, tilingRenderer, sampler); verifiedHeight -= maxTextureSize; } @@ -748,18 +1251,48 @@ void TextVisual::AddRenderer(Actor& actor, const Vector2& size, bool hasMultiple mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED; + const Vector4& defaultColor = mController->GetTextModel()->GetDefaultColor(); + for(RendererContainer::iterator iter = mRendererList.begin(); iter != mRendererList.end(); ++iter) { 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) + { + // Set constraint for text label's color for non-default renderers. + if(mAnimatableTextColorPropertyIndex != Property::INVALID_INDEX) + { + // Register unique property, or get property for default renderer. + Property::Index index = renderer.RegisterUniqueProperty("uTextColorAnimatable", defaultColor); + + // Create constraint for the animatable text's color Property with uTextColorAnimatable in the renderer. + if(index != Property::INVALID_INDEX) + { + Constraint colorConstraint = Constraint::New(renderer, index, TextColorConstraint); + colorConstraint.AddSource(Source(actor, mAnimatableTextColorPropertyIndex)); + colorConstraint.Apply(); + } + + // Make zero if the alpha value of text color is zero to skip rendering text + // 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(); + } + } } } } -TextureSet TextVisual::GetTextTexture(const Vector2& size, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled, bool isOverlayStyle) +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); @@ -767,33 +1300,60 @@ TextureSet TextVisual::GetTextTexture(const Vector2& size, bool hasMultipleTextC TextureSet textureSet = TextureSet::New(); // 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 = (mTextShaderFeatureCache.IsEnabledEmoji() || mTextShaderFeatureCache.IsEnabledMultiColor() || cutoutEnabled) ? Pixel::RGBA8888 : Pixel::L8; // Check the text direction - Toolkit::DevelText::TextDirection::Type textDirection = mController->GetTextDirection(); - + 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); - // It may happen the image atlas can't handle a pixel data it exceeds the maximum size. - // In that case, create a texture. TODO: should tile the text. - unsigned int 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(styleEnabled) + 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; + } + + if(mTextShaderFeatureCache.IsEnabledOverlay()) + { // Create RGBA texture for overlay styles such as underline and strikethrough (without the text itself) PixelData overlayStyleData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_OVERLAY_STYLE, false, Pixel::RGBA8888); AddTexture(textureSet, overlayStyleData, sampler, textureSetIndex); ++textureSetIndex; } - if(containsColorGlyph && !hasMultipleTextColors) + if(mTextShaderFeatureCache.IsEnabledEmoji() && !mTextShaderFeatureCache.IsEnabledMultiColor()) { // Create a L8 texture as a mask to avoid color glyphs (e.g. emojis) to be affected by text color animation PixelData maskData = mTypesetter->Render(size, textDirection, Text::Typesetter::RENDER_MASK, false, Pixel::L8); @@ -804,74 +1364,26 @@ TextureSet TextVisual::GetTextTexture(const Vector2& size, bool hasMultipleTextC return textureSet; } -Shader TextVisual::GetTextShader(VisualFactoryCache& factoryCache, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled) +Shader TextVisual::GetTextShader(VisualFactoryCache& factoryCache, TextVisualShaderFeature::FeatureBuilder& featureBuilder) { - Shader shader; + // Cache feature builder informations. + mTextShaderFeatureCache = featureBuilder; - if(hasMultipleTextColors && !styleEnabled) - { - // We don't animate text color if the text contains multiple colors - shader = factoryCache.GetShader(VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT); - if(!shader) - { - shader = Shader::New(SHADER_TEXT_VISUAL_SHADER_VERT, SHADER_TEXT_VISUAL_MULTI_COLOR_TEXT_SHADER_FRAG); - shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT); - factoryCache.SaveShader(VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT, shader); - } - } - else if(hasMultipleTextColors && styleEnabled) - { - // We don't animate text color if the text contains multiple colors - shader = factoryCache.GetShader(VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE); - if(!shader) - { - shader = Shader::New(SHADER_TEXT_VISUAL_SHADER_VERT, SHADER_TEXT_VISUAL_MULTI_COLOR_TEXT_WITH_STYLE_SHADER_FRAG); - shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT); - factoryCache.SaveShader(VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE, shader); - } - } - else if(!hasMultipleTextColors && !containsColorGlyph && !styleEnabled) - { - shader = factoryCache.GetShader(VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT); - if(!shader) - { - shader = Shader::New(SHADER_TEXT_VISUAL_SHADER_VERT, SHADER_TEXT_VISUAL_SINGLE_COLOR_TEXT_SHADER_FRAG); - shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT); - factoryCache.SaveShader(VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT, shader); - } - } - else if(!hasMultipleTextColors && !containsColorGlyph && styleEnabled) - { - shader = factoryCache.GetShader(VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE); - if(!shader) - { - shader = Shader::New(SHADER_TEXT_VISUAL_SHADER_VERT, SHADER_TEXT_VISUAL_SINGLE_COLOR_TEXT_WITH_STYLE_SHADER_FRAG); - shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT); - factoryCache.SaveShader(VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE, shader); - } - } - else if(!hasMultipleTextColors && containsColorGlyph && !styleEnabled) - { - shader = factoryCache.GetShader(VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI); - if(!shader) - { - shader = Shader::New(SHADER_TEXT_VISUAL_SHADER_VERT, SHADER_TEXT_VISUAL_SINGLE_COLOR_TEXT_WITH_EMOJI_SHADER_FRAG); - shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT); - factoryCache.SaveShader(VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI, shader); - } - } - else // if( !hasMultipleTextColors && containsColorGlyph && styleEnabled ) + Shader shader = mTextVisualShaderFactory.GetShader(factoryCache, mTextShaderFeatureCache); + return shader; +} + +void TextVisual::SetRequireRender(bool requireRender) +{ + // Avoid function calls if there is no change. + if(mTextRequireRender != requireRender) { - shader = factoryCache.GetShader(VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI); - if(!shader) + mTextRequireRender = requireRender; + if(mImpl->mRenderer) { - shader = Shader::New(SHADER_TEXT_VISUAL_SHADER_VERT, SHADER_TEXT_VISUAL_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI_SHADER_FRAG); - shader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT); - factoryCache.SaveShader(VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI, shader); + mImpl->mRenderer.SetProperty(mTextRequireRenderPropertyIndex, mTextRequireRender); } } - - return shader; } } // namespace Internal