From 8fa7d052e772ebdb612e596cf06bf57bf88da12f Mon Sep 17 00:00:00 2001 From: Armin Le Grand Date: Tue, 17 Oct 2017 17:04:03 +0200 Subject: EditEngine: Enhance visualization of URLs When URLs get layouted Multi-Lined from the EditEngine, a rough 'guess' how many chars per line should be used was in place up to now. This could lead to lines being too short or being longer than the available space, also looked ugly. Layouting now using the needed space properly. Also adapted vertical (for horizontal text) space usage, with multiple lines the space was 'compressed' and wrong calculated. Change-Id: I7255e3e65c85a3a50497b771ed2ca1ef5d97c0dd Reviewed-on: https://gerrit.libreoffice.org/43464 Tested-by: Jenkins Reviewed-by: Armin Le Grand --- editeng/source/editeng/impedit3.cxx | 89 +++++++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 19 deletions(-) (limited to 'editeng') diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx index f68f2eff166a..0a5bd8490809 100644 --- a/editeng/source/editeng/impedit3.cxx +++ b/editeng/source/editeng/impedit3.cxx @@ -1045,32 +1045,77 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY ) OUString aFieldValue = cChar ? OUString(cChar) : static_cast(pNextFeature)->GetFieldValue(); if ( bCalcCharPositions || !pPortion->HasValidSize() ) { - pPortion->GetSize() = aTmpFont.QuickGetTextSize( GetRefDevice(), aFieldValue, 0, aFieldValue.getLength() ); + // get size, but also DXArray to allow length information in line breaking below + const sal_Int32 nLength(aFieldValue.getLength()); + std::unique_ptr pTmpDXArray(new long[nLength]); + pPortion->GetSize() = aTmpFont.QuickGetTextSize(GetRefDevice(), aFieldValue, 0, aFieldValue.getLength(), pTmpDXArray.get()); + // So no scrolling for oversized fields if ( pPortion->GetSize().Width() > nXWidth ) { - sal_Int32 nWidthOrg = pPortion->GetSize().Width(); - sal_Int32 nChars = aFieldValue.getLength(); - sal_Int32 nApproxWC = nXWidth / ( nWidthOrg / nChars ); - ExtraPortionInfo *pExtraInfo= pPortion->GetExtraInfos(); - if( !nApproxWC ) nApproxWC++; - if( pExtraInfo == nullptr ) + // create ExtraPortionInfo on-demand, flush lineBreaksList + ExtraPortionInfo *pExtraInfo = pPortion->GetExtraInfos(); + + if(nullptr == pExtraInfo) { pExtraInfo = new ExtraPortionInfo(); pExtraInfo->nOrgWidth = nXWidth; - pPortion->SetExtraInfos( pExtraInfo ); + pPortion->SetExtraInfos(pExtraInfo); } else { pExtraInfo->lineBreaksList.clear(); } - pPortion->GetSize().Width() = nXWidth; - - while( nChars > 0 ) + // iterate over CellBreaks using XBreakIterator to be on the + // safe side with international texts/charSets + Reference < i18n::XBreakIterator > xBreakIterator(ImplGetBreakIterator()); + const sal_Int32 nTextLength(aFieldValue.getLength()); + const lang::Locale aLocale(GetLocale(EditPaM(pNode, nPortionStart))); + sal_Int32 nDone(0); + sal_Int32 nNextCellBreak( + xBreakIterator->nextCharacters( + aFieldValue, + 0, + aLocale, + css::i18n::CharacterIteratorMode::SKIPCELL, + 0, + nDone)); + sal_Int32 nLastCellBreak(0); + sal_Int32 nLineStartX(0); + + // always add 1st line break (safe, we already know we are larger than nXWidth) + pExtraInfo->lineBreaksList.push_back(0); + + for(sal_Int32 a(0); a < nTextLength; a++) { - pExtraInfo->lineBreaksList.push_back( aFieldValue.getLength() - nChars ); - nChars -= nApproxWC; + if(a == nNextCellBreak) + { + // check width + if(pTmpDXArray[a] - nLineStartX > nXWidth) + { + // new CellBreak does not fit in current line, need to + // create a break at LastCellBreak - but do not add 1st + // line break twice for very tall frames + if(0 != a) + { + pExtraInfo->lineBreaksList.push_back(a); + } + + // moveLineStart forward in X + nLineStartX = pTmpDXArray[nLastCellBreak]; + } + + // update CellBreak iteration values + nLastCellBreak = a; + nNextCellBreak = xBreakIterator->nextCharacters( + aFieldValue, + a, + aLocale, + css::i18n::CharacterIteratorMode::SKIPCELL, + 1, + nDone); + } } } } @@ -3262,26 +3307,32 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po bParsingFields = true; itSubLines = pExtraInfo->lineBreaksList.begin(); } + if( bParsingFields ) { if( itSubLines != pExtraInfo->lineBreaksList.begin() ) { + // only use GetMaxAscent(), pLine->GetHeight() will not + // proceed as needed (see PortionKind::TEXT above and nAdvanceY) + // what will lead to a compressed look with multiple lines + const sal_uInt16 nMaxAscent(pLine->GetMaxAscent()); + if ( !IsVertical() ) { - aStartPos.Y() += pLine->GetMaxAscent(); - aTmpPos.Y() += pLine->GetHeight(); + aStartPos.Y() += nMaxAscent; + aTmpPos.Y() += nMaxAscent; } else { if (IsTopToBottom()) { - aTmpPos.X() -= pLine->GetMaxAscent(); - aStartPos.X() -= pLine->GetHeight(); + aTmpPos.X() -= nMaxAscent; + aStartPos.X() -= nMaxAscent; } else { - aTmpPos.X() += pLine->GetMaxAscent(); - aStartPos.X() += pLine->GetHeight(); + aTmpPos.X() += nMaxAscent; + aStartPos.X() += nMaxAscent; } } } -- cgit