From 7b747a323f0bdb3487d4e4e86b0a111fae891400 Mon Sep 17 00:00:00 2001 From: "Eunki, Hong" Date: Fri, 18 Nov 2022 22:47:19 +0900 Subject: [PATCH] TextFit check without candidate listup Previous code required O((maxPointSize - minPointSize) / pointInterval) memory. Now we make to pick valid pointsize without listup. Also, make binary search as overflow-safety. Change-Id: I6542c1692e94395fdab07a91fd7322b718a510e1 Signed-off-by: Eunki, Hong --- .../src/dali-toolkit/utc-Dali-TextLabel.cpp | 44 +++++++++++++++-- .../text/controller/text-controller-relayouter.cpp | 57 ++++++++++++++-------- 2 files changed, 78 insertions(+), 23 deletions(-) diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp index 27a14a9..41783dc 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp @@ -1508,7 +1508,6 @@ int UtcDaliToolkitTextlabelScrollingN(void) const bool enabled = label.GetProperty(TextLabel::Property::ENABLE_AUTO_SCROLL).Get(); DALI_TEST_CHECK(!enabled); - label.SetProperty(TextLabel::Property::MULTI_LINE, false); label.SetProperty(TextLabel::Property::AUTO_SCROLL_LOOP_COUNT, 1); label.SetProperty(TextLabel::Property::AUTO_SCROLL_SPEED, 9999.0f); @@ -2038,6 +2037,47 @@ int UtcDaliToolkitTextlabelTextFit(void) END_TEST; } +int UtcDaliToolkitTextlabelTextFitStressTest(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliToolkitTextlabelTextFitStressTest"); + TextLabel label = TextLabel::New(); + Vector2 size(460.0f, 100.0f); + label.SetProperty(Actor::Property::SIZE, size); + label.SetProperty(TextLabel::Property::TEXT, "Hello world"); + + // connect to the text git changed signal. + ConnectionTracker* testTracker = new ConnectionTracker(); + DevelTextLabel::TextFitChangedSignal(label).Connect(&TestTextFitChangedCallback); + bool textFitChangedSignal = false; + label.ConnectSignal(testTracker, "textFitChanged", CallbackFunctor(&textFitChangedSignal)); + gTextFitChangedCallBackCalled = false; + + // check point size with veryvery big range + Property::Map textFitMapSet; + textFitMapSet["enable"] = true; + textFitMapSet["minSize"] = 10.f; + textFitMapSet["maxSize"] = 10000.f; + textFitMapSet["stepSize"] = -1.0f; + textFitMapSet["fontSizeType"] = "pointSize"; + + label.SetProperty(Toolkit::DevelTextLabel::Property::TEXT_FIT, textFitMapSet); + label.SetProperty(TextLabel::Property::POINT_SIZE, 120.f); + + application.GetScene().Add(label); + + application.SendNotification(); + application.Render(); + + const Vector3 EXPECTED_NATURAL_SIZE(450.0f, 96.0f, 0.0f); + DALI_TEST_EQUALS(EXPECTED_NATURAL_SIZE, label.GetNaturalSize(), TEST_LOCATION); + + DALI_TEST_CHECK(gTextFitChangedCallBackCalled); + DALI_TEST_CHECK(textFitChangedSignal); + + END_TEST; +} + int UtcDaliToolkitTextlabelMaxTextureSet(void) { ToolkitTestApplication application; @@ -2138,7 +2178,6 @@ int UtcDaliToolkitTextlabelMaxTextureSet(void) application.SendNotification(); application.Render(); - END_TEST; } @@ -2687,7 +2726,6 @@ int utcDaliTextLabelGeometryOneGlyph(void) END_TEST; } - int utcDaliTextLabelGeometryNullPtr(void) { ToolkitTestApplication application; diff --git a/dali-toolkit/internal/text/controller/text-controller-relayouter.cpp b/dali-toolkit/internal/text/controller/text-controller-relayouter.cpp index c759051..f95019a 100644 --- a/dali-toolkit/internal/text/controller/text-controller-relayouter.cpp +++ b/dali-toolkit/internal/text/controller/text-controller-relayouter.cpp @@ -23,9 +23,9 @@ #include // INTERNAL INCLUDES -#include #include #include +#include namespace { @@ -253,48 +253,65 @@ void Controller::Relayouter::FitPointSizeforLayout(Controller& controller, const float currentFitPointSize = impl.mFontDefaults->mFitPointSize; model->mElideEnabled = false; - Vector pointSizeArray; // check zero value if(pointInterval < 1.f) { impl.mTextFitStepSize = pointInterval = 1.0f; } + uint32_t pointSizeRange = static_cast(ceil((maxPointSize - minPointSize) / pointInterval)); - pointSizeArray.Reserve(static_cast(ceil((maxPointSize - minPointSize) / pointInterval))); - - for(float i = minPointSize; i < maxPointSize; i += pointInterval) + // Ensure minPointSize + pointSizeRange * pointInverval >= maxPointSize + while(minPointSize + static_cast(pointSizeRange) * pointInterval < maxPointSize) { - pointSizeArray.PushBack(i); + ++pointSizeRange; } - pointSizeArray.PushBack(maxPointSize); - - int bestSizeIndex = 0; - int min = bestSizeIndex + 1; - int max = pointSizeArray.Size() - 1; - while(min <= max) + uint32_t bestSizeIndex = 0; + uint32_t minIndex = bestSizeIndex + 1u; + uint32_t maxIndex = pointSizeRange + 1u; + + bool bestSizeUpdatedLatest = false; + // Find best size as binary search. + // Range format as [l r). (left closed, right opened) + // It mean, we already check all i < l is valid, and r <= i is invalid. + // Below binary search will check m = (l+r)/2 point. + // Search area sperate as [l m) or [m+1 r) + // + // Basically, we can assume that 0 (minPointSize) is always valid. + // Now, we will check [1 pointSizeRange] range s.t. pointSizeRange mean the maxPointSize + while(minIndex < maxIndex) { - int destI = (min + max) / 2; + uint32_t testIndex = minIndex + ((maxIndex - minIndex) >> 1u); + const float testPointSize = std::min(maxPointSize, minPointSize + static_cast(testIndex) * pointInterval); - if(CheckForTextFit(controller, pointSizeArray[destI], layoutSize)) + if(CheckForTextFit(controller, testPointSize, layoutSize)) { - bestSizeIndex = min; - min = destI + 1; + bestSizeUpdatedLatest = true; + + bestSizeIndex = testIndex; + minIndex = testIndex + 1u; } else { - max = destI - 1; - bestSizeIndex = max; + bestSizeUpdatedLatest = false; + maxIndex = testIndex; } } + const float bestPointSize = std::min(maxPointSize, minPointSize + static_cast(bestSizeIndex) * pointInterval); + + // Best point size was not updated. re-run so the TextFit should be fitted really. + if(!bestSizeUpdatedLatest) + { + CheckForTextFit(controller, bestPointSize, layoutSize); + } model->mElideEnabled = actualellipsis; - if(currentFitPointSize != pointSizeArray[bestSizeIndex]) + if(currentFitPointSize != bestPointSize) { impl.mTextFitChanged = true; } - impl.mFontDefaults->mFitPointSize = pointSizeArray[bestSizeIndex]; + impl.mFontDefaults->mFitPointSize = bestPointSize; impl.mFontDefaults->sizeDefined = true; impl.ClearFontData(); } -- 2.7.4