X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ftext%2Fcontroller%2Ftext-controller-relayouter.cpp;h=de4c776ecb78842fe1368558c5a6cce5769e6904;hb=HEAD;hp=6b3bba714f79c397dbaddc1bf469baf814617a64;hpb=ff906b7bf470b3ba229fc75a533857311edb3355;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-toolkit/internal/text/controller/text-controller-relayouter.cpp b/dali-toolkit/internal/text/controller/text-controller-relayouter.cpp index 6b3bba7..de4c776 100644 --- a/dali-toolkit/internal/text/controller/text-controller-relayouter.cpp +++ b/dali-toolkit/internal/text/controller/text-controller-relayouter.cpp @@ -19,8 +19,10 @@ #include // EXTERNAL INCLUDES +#include #include #include +#include #include #include @@ -234,16 +236,18 @@ bool Controller::Relayouter::CheckForTextFit(Controller& controller, float point // Make sure the model is up-to-date before layouting impl.UpdateModel(onlyOnceOperations); + bool layoutTooSmall = false; DoRelayout(impl, Size(layoutSize.width, MAX_FLOAT), static_cast(onlyOnceOperations | LAYOUT), - textSize); + textSize, + layoutTooSmall); // Clear the update info. This info will be set the next time the text is updated. textUpdateInfo.Clear(); textUpdateInfo.mClearAll = true; - if(textSize.width > layoutSize.width || textSize.height > layoutSize.height) + if(layoutTooSmall || textSize.width > layoutSize.width || textSize.height > layoutSize.height) { return false; } @@ -377,61 +381,142 @@ void Controller::Relayouter::FitPointSizeforLayout(Controller& controller, const float pointInterval = impl.mTextFitStepSize; float currentFitPointSize = impl.mFontDefaults->mFitPointSize; float currentDefaultLineSize = impl.mLayoutEngine.GetDefaultLineSize(); + bool isMultiLine = impl.mLayoutEngine.GetLayout() == Layout::Engine::MULTI_LINE_BOX; // Instead of using the LineSize of the current TextLabel, the LineSize set in TextFit is used. + impl.SetDefaultLineSize(impl.mTextFitLineSize); model->mElideEnabled = false; + float bestPointSize = minPointSize; // check zero value if(pointInterval < 1.f) { impl.mTextFitStepSize = pointInterval = 1.0f; } - uint32_t pointSizeRange = static_cast(ceil((maxPointSize - minPointSize) / pointInterval)); - // Ensure minPointSize + pointSizeRange * pointInverval >= maxPointSize - while(minPointSize + static_cast(pointSizeRange) * pointInterval < maxPointSize) - { - ++pointSizeRange; - } + uint32_t pointSizeRange = static_cast(ceil((maxPointSize - minPointSize) / pointInterval)); - 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) + if(isMultiLine || pointSizeRange < 3) { - uint32_t testIndex = minIndex + ((maxIndex - minIndex) >> 1u); - const float testPointSize = std::min(maxPointSize, minPointSize + static_cast(testIndex) * pointInterval); + // Ensure minPointSize + pointSizeRange * pointInverval >= maxPointSize + while(minPointSize + static_cast(pointSizeRange) * pointInterval < maxPointSize) + { + ++pointSizeRange; + } - if(CheckForTextFit(controller, testPointSize, layoutSize)) + 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) { - bestSizeUpdatedLatest = true; + uint32_t testIndex = minIndex + ((maxIndex - minIndex) >> 1u); + const float testPointSize = std::min(maxPointSize, minPointSize + static_cast(testIndex) * pointInterval); + + if(CheckForTextFit(controller, testPointSize, layoutSize)) + { + bestSizeUpdatedLatest = true; - bestSizeIndex = testIndex; - minIndex = testIndex + 1u; + bestSizeIndex = testIndex; + minIndex = testIndex + 1u; + } + else + { + bestSizeUpdatedLatest = false; + maxIndex = testIndex; + } } - else + 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) { - bestSizeUpdatedLatest = false; - maxIndex = testIndex; + CheckForTextFit(controller, bestPointSize, layoutSize); } } - 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) + else { - CheckForTextFit(controller, bestPointSize, layoutSize); + // assume textSize = a * pointSize + b, finding a and b. + Size textSize; + TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo; + const OperationsMask onlyOnceOperations = static_cast(CONVERT_TO_UTF32 | + GET_SCRIPTS | + VALIDATE_FONTS | + GET_LINE_BREAKS | + BIDI_INFO | + SHAPE_TEXT | + GET_GLYPH_METRICS); + + float resultBasedX[2]; + float resultBasedY[2]; + float tmpPointSize[2] = {minPointSize, maxPointSize}; + + // Calculate a and b by creating simultaneous equations with two calculations. + for(int i=0;i<2;i++) + { + impl.mFontDefaults->mFitPointSize = tmpPointSize[i]; + impl.mFontDefaults->sizeDefined = true; + impl.ClearFontData(); + + textUpdateInfo.mParagraphCharacterIndex = 0u; + textUpdateInfo.mRequestedNumberOfCharacters = impl.mModel->mLogicalModel->mText.Count(); + + + // Make sure the model is up-to-date before layouting + impl.UpdateModel(onlyOnceOperations); + + DoRelayout(impl, + Size(layoutSize.width, MAX_FLOAT), + static_cast(onlyOnceOperations | LAYOUT), + textSize); + + // Clear the update info. This info will be set the next time the text is updated. + textUpdateInfo.Clear(); + textUpdateInfo.mClearAll = true; + + resultBasedX[i] = textSize.x; + resultBasedY[i] = textSize.y; + } + + float aBasedX = (resultBasedX[1] - resultBasedX[0]) / (tmpPointSize[1] - tmpPointSize[0]); + float bBasedX = resultBasedX[1] - aBasedX * tmpPointSize[1]; + aBasedX = std::max(aBasedX, Dali::Math::MACHINE_EPSILON_1000); + + float aBasedY = (resultBasedY[1] - resultBasedY[0]) / (tmpPointSize[1] - tmpPointSize[0]); + float bBasedY = resultBasedY[1] - aBasedY * tmpPointSize[1]; + aBasedY = std::max(aBasedY, Dali::Math::MACHINE_EPSILON_1000); + + float bestPointSizeBasedX = (layoutSize.x - bBasedX) / aBasedX; + float bestPointSizeBasedY = (layoutSize.y - bBasedY) / aBasedY; + + bestPointSize = std::min(bestPointSizeBasedX, bestPointSizeBasedY); + bestPointSize = std::min(std::max(bestPointSize, minPointSize), maxPointSize); + bestPointSize = std::floor((bestPointSize - minPointSize) / pointInterval) * pointInterval + minPointSize; + + if(CheckForTextFit(controller, bestPointSize, layoutSize)) + { + while(bestPointSize + pointInterval <= maxPointSize && CheckForTextFit(controller, bestPointSize + pointInterval, layoutSize)) + { + bestPointSize += pointInterval; + } + } + else if(bestPointSize - pointInterval >= minPointSize) + { + do + { + bestPointSize -= pointInterval; + } while(bestPointSize - pointInterval >= minPointSize && !CheckForTextFit(controller, bestPointSize, layoutSize)); + } } model->mElideEnabled = actualellipsis; @@ -673,6 +758,12 @@ Controller::UpdateTextType Controller::Relayouter::Relayout(Controller& controll bool Controller::Relayouter::DoRelayout(Controller::Impl& impl, const Size& size, OperationsMask operationsRequired, Size& layoutSize) { + bool layoutTooSmall = false; + return DoRelayout(impl, size, operationsRequired, layoutSize, layoutTooSmall); +} + +bool Controller::Relayouter::DoRelayout(Controller::Impl& impl, const Size& size, OperationsMask operationsRequired, Size& layoutSize, bool& layoutTooSmall) +{ DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::Relayouter::DoRelayout %p size %f,%f\n", &impl, size.width, size.height); DALI_TRACE_SCOPE(gTraceFilter2, "DALI_TEXT_DORELAYOUT"); bool viewUpdated(false); @@ -794,6 +885,7 @@ bool Controller::Relayouter::DoRelayout(Controller::Impl& impl, const Size& size isHiddenInputEnabled, ellipsisPosition); impl.mIsAutoScrollEnabled = isAutoScrollEnabled; + layoutTooSmall = !viewUpdated; viewUpdated = viewUpdated || (newLayoutSize != layoutSize); @@ -830,6 +922,7 @@ bool Controller::Relayouter::DoRelayout(Controller::Impl& impl, const Size& size DALI_LOG_INFO(gLogFilter, Debug::Concise, "Controller::Relayouter::DoRelayout [%p] mImpl->mIsTextDirectionRTL[%s] [%s]\n", &impl, (impl.mIsTextDirectionRTL) ? "true" : "false", currentText.c_str()); #endif DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::Relayouter::DoRelayout, view updated %s\n", (viewUpdated ? "true" : "false")); + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::Relayouter::DoRelayout, layout too small %s\n", (layoutTooSmall ? "true" : "false")); return viewUpdated; }