diff --git a/sw/qa/extras/layout/data/tdf167326.fodt b/sw/qa/extras/layout/data/tdf167326.fodt new file mode 100644 index 000000000000..5004f9ed9cbf --- /dev/null +++ b/sw/qa/extras/layout/data/tdf167326.fodt @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + In this cell, below, there is a section with a shape: + + + + + + + + + + + \ No newline at end of file diff --git a/sw/qa/extras/layout/layout4.cxx b/sw/qa/extras/layout/layout4.cxx index 421ddfd93521..7fb98e772d11 100644 --- a/sw/qa/extras/layout/layout4.cxx +++ b/sw/qa/extras/layout/layout4.cxx @@ -1443,6 +1443,33 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf160958_orphans) assertXPath(pExportDump, "//page[2]/body/txt[1]/SwParaPortion/SwLineLayout", 1); } +CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf167326) +{ + // A document with a table with a section with a to-char no-wrap keep-inside-boundaries shape + createSwDoc("tdf167326.fodt"); + auto pExportDump = parseLayoutDump(); + assertXPath(pExportDump, "//tab", 1); + OUString height = getXPath(pExportDump, "//tab/infos/bounds", "height"); + // Expected height: ~3388 = shape 2836 + 2 * text ~276 + CPPUNIT_ASSERT_GREATER(sal_Int32(3000), height.toInt32()); + + // Hide the section + auto xTextSectionsSupplier = mxComponent.queryThrow(); + auto xSections = xTextSectionsSupplier->getTextSections(); + CPPUNIT_ASSERT(xSections); + auto xSection = xSections->getByName(u"Sect1"_ustr).queryThrow(); + xSection->setPropertyValue(u"IsVisible"_ustr, css::uno::Any(false)); + + calcLayout(); + pExportDump = parseLayoutDump(); + assertXPath(pExportDump, "//tab", 1); + height = getXPath(pExportDump, "//tab/infos/bounds", "height"); + // Expected height: ~276 = 1 * text ~276 + // Without the fix, this was ~3111, because calculation of table cell's height considered + // height of section's shape, not taking its visibility into account. + CPPUNIT_ASSERT_LESS(sal_Int32(500), height.toInt32()); +} + CPPUNIT_TEST_FIXTURE(SwLayoutWriter4, testTdf161368) { // Given a document with a text body width of 116 mm, greater than 65535 twips (115.6 mm) diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx index d79568dcf44e..a08ce1af68e2 100644 --- a/sw/source/core/layout/tabfrm.cxx +++ b/sw/source/core/layout/tabfrm.cxx @@ -4789,125 +4789,139 @@ void SwRowFrame::dumpAsXml(xmlTextWriterPtr writer) const (void)xmlTextWriterEndElement(writer); } +static tools::Long CalcHeightWithFlys_Impl(const SwFrame* pTmp, const SwFrame* pFrame, + const SwRectFnSet& aRectFnSet) +{ + if (pFrame->IsHiddenNow()) + return 0; + tools::Long nHeight = 0; + // #i26945# - consider follow text frames + const SwSortedObjs* pObjs( nullptr ); + bool bIsFollow( false ); + if ( pTmp->IsTextFrame() && static_cast(pTmp)->IsFollow() ) + { + const SwFrame* pMaster; + // #i46450# Master does not necessarily have + // to exist if this function is called from JoinFrame() -> + // Cut() -> Shrink() + const SwTextFrame* pTmpFrame = static_cast(pTmp); + if ( pTmpFrame->GetPrev() && pTmpFrame->GetPrev()->IsTextFrame() && + static_cast(pTmpFrame->GetPrev())->GetFollow() && + static_cast(pTmpFrame->GetPrev())->GetFollow() != pTmp ) + pMaster = nullptr; + else + pMaster = pTmpFrame->FindMaster(); + + if ( pMaster ) + { + pObjs = static_cast(pTmp)->FindMaster()->GetDrawObjs(); + bIsFollow = true; + } + } + else + { + pObjs = pTmp->GetDrawObjs(); + } + if ( pObjs ) + { + for (SwAnchoredObject* pAnchoredObj : *pObjs) + { + // #i26945# - if is follow, the + // anchor character frame has to be . + if ( bIsFollow && + pAnchoredObj->FindAnchorCharFrame() != pTmp ) + { + continue; + } + // #i26945# - consider also drawing objects + { + // OD 30.09.2003 #i18732# - only objects, which follow + // the text flow have to be considered. + const SwFrameFormat* pFrameFormat = pAnchoredObj->GetFrameFormat(); + bool bFollowTextFlow = pFrameFormat->GetFollowTextFlow().GetValue(); + bool bIsFarAway = pAnchoredObj->GetObjRect().Top() != FAR_AWAY; + const SwPageFrame* pPageFrm = pTmp->FindPageFrame(); + bool bIsAnchoredToTmpFrm = false; + if ( pPageFrm && pPageFrm->IsPageFrame() && pAnchoredObj->GetPageFrame()) + bIsAnchoredToTmpFrm = pAnchoredObj->GetPageFrame() == pPageFrm || + (pPageFrm->GetFormatPage().GetPhyPageNum() == pAnchoredObj->GetPageFrame()->GetFormatPage().GetPhyPageNum() + 1); + const bool bConsiderObj = + (pFrameFormat->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR) && + bIsFarAway && + bFollowTextFlow && bIsAnchoredToTmpFrm; + bool bWrapThrough = pFrameFormat->GetSurround().GetValue() == text::WrapTextMode_THROUGH; + bool bInBackground = !pFrameFormat->GetOpaque().GetValue(); + // Legacy render requires in-background setting, the new mode does not. + bool bConsiderFollowTextFlow = bInBackground + || !pFrameFormat->getIDocumentSettingAccess().get( + DocumentSettingId::USE_FORMER_TEXT_WRAPPING); + if (pFrame->IsInTab() && bFollowTextFlow && bWrapThrough && bConsiderFollowTextFlow) + { + // Ignore wrap-through objects when determining the cell height. + // Normally FollowTextFlow requires a resize of the cell, but not in case of + // wrap-through. + continue; + } + + if ( bConsiderObj ) + { + const SwFormatFrameSize &rSz = pFrameFormat->GetFrameSize(); + if( !rSz.GetHeightPercent() ) + { + const SwTwips nDistOfFlyBottomToAnchorTop = + aRectFnSet.GetHeight(pAnchoredObj->GetObjRect()) + + ( aRectFnSet.IsVert() ? + pAnchoredObj->GetCurrRelPos().X() : + pAnchoredObj->GetCurrRelPos().Y() ); + + const SwTwips nFrameDiff = + aRectFnSet.YDiff( + aRectFnSet.GetTop(pTmp->getFrameArea()), + aRectFnSet.GetTop(pFrame->getFrameArea()) ); + + nHeight = std::max( nHeight, nDistOfFlyBottomToAnchorTop + nFrameDiff - + aRectFnSet.GetHeight(pFrame->getFrameArea()) ); + + // #i56115# The first height calculation + // gives wrong results if pFrame->getFramePrintArea().Y() > 0. We do + // a second calculation based on the actual rectangles of + // pFrame and pAnchoredObj, and use the maximum of the results. + // I do not want to remove the first calculation because + // if clipping has been applied, using the GetCurrRelPos + // might be the better option to calculate nHeight. + const SwTwips nDistOfFlyBottomToAnchorTop2 = aRectFnSet.YDiff( + aRectFnSet.GetBottom(pAnchoredObj->GetObjRect()), + aRectFnSet.GetBottom(pFrame->getFrameArea()) ); + + nHeight = std::max( nHeight, tools::Long(nDistOfFlyBottomToAnchorTop2 )); + } + } + } + } + } + return nHeight; +} + tools::Long CalcHeightWithFlys( const SwFrame *pFrame ) { SwRectFnSet aRectFnSet(pFrame); - tools::Long nHeight = 0; - const SwFrame* pTmp = pFrame->IsSctFrame() ? - static_cast(pFrame)->ContainsContent() : pFrame; - while( pTmp ) + if (pFrame->IsSctFrame()) { - // #i26945# - consider follow text frames - const SwSortedObjs* pObjs( nullptr ); - bool bIsFollow( false ); - if ( pTmp->IsTextFrame() && static_cast(pTmp)->IsFollow() ) + if (pFrame->IsHiddenNow()) + return 0; + tools::Long nHeight = 0; + const SwFrame* pTmp = static_cast(pFrame)->ContainsContent(); + while (pTmp) { - const SwFrame* pMaster; - // #i46450# Master does not necessarily have - // to exist if this function is called from JoinFrame() -> - // Cut() -> Shrink() - const SwTextFrame* pTmpFrame = static_cast(pTmp); - if ( pTmpFrame->GetPrev() && pTmpFrame->GetPrev()->IsTextFrame() && - static_cast(pTmpFrame->GetPrev())->GetFollow() && - static_cast(pTmpFrame->GetPrev())->GetFollow() != pTmp ) - pMaster = nullptr; - else - pMaster = pTmpFrame->FindMaster(); - - if ( pMaster ) - { - pObjs = static_cast(pTmp)->FindMaster()->GetDrawObjs(); - bIsFollow = true; - } + nHeight += CalcHeightWithFlys_Impl(pTmp, pFrame, aRectFnSet); + pTmp = pTmp->FindNextCnt(); + if (!static_cast(pFrame)->IsAnLower(pTmp)) + break; } - else - { - pObjs = pTmp->GetDrawObjs(); - } - if ( pObjs ) - { - for (SwAnchoredObject* pAnchoredObj : *pObjs) - { - // #i26945# - if is follow, the - // anchor character frame has to be . - if ( bIsFollow && - pAnchoredObj->FindAnchorCharFrame() != pTmp ) - { - continue; - } - // #i26945# - consider also drawing objects - { - // OD 30.09.2003 #i18732# - only objects, which follow - // the text flow have to be considered. - const SwFrameFormat* pFrameFormat = pAnchoredObj->GetFrameFormat(); - bool bFollowTextFlow = pFrameFormat->GetFollowTextFlow().GetValue(); - bool bIsFarAway = pAnchoredObj->GetObjRect().Top() != FAR_AWAY; - const SwPageFrame* pPageFrm = pTmp->FindPageFrame(); - bool bIsAnchoredToTmpFrm = false; - if ( pPageFrm && pPageFrm->IsPageFrame() && pAnchoredObj->GetPageFrame()) - bIsAnchoredToTmpFrm = pAnchoredObj->GetPageFrame() == pPageFrm || - (pPageFrm->GetFormatPage().GetPhyPageNum() == pAnchoredObj->GetPageFrame()->GetFormatPage().GetPhyPageNum() + 1); - const bool bConsiderObj = - (pFrameFormat->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR) && - bIsFarAway && - bFollowTextFlow && bIsAnchoredToTmpFrm; - bool bWrapThrough = pFrameFormat->GetSurround().GetValue() == text::WrapTextMode_THROUGH; - bool bInBackground = !pFrameFormat->GetOpaque().GetValue(); - // Legacy render requires in-background setting, the new mode does not. - bool bConsiderFollowTextFlow = bInBackground - || !pFrameFormat->getIDocumentSettingAccess().get( - DocumentSettingId::USE_FORMER_TEXT_WRAPPING); - if (pFrame->IsInTab() && bFollowTextFlow && bWrapThrough && bConsiderFollowTextFlow) - { - // Ignore wrap-through objects when determining the cell height. - // Normally FollowTextFlow requires a resize of the cell, but not in case of - // wrap-through. - continue; - } - - if ( bConsiderObj ) - { - const SwFormatFrameSize &rSz = pFrameFormat->GetFrameSize(); - if( !rSz.GetHeightPercent() ) - { - const SwTwips nDistOfFlyBottomToAnchorTop = - aRectFnSet.GetHeight(pAnchoredObj->GetObjRect()) + - ( aRectFnSet.IsVert() ? - pAnchoredObj->GetCurrRelPos().X() : - pAnchoredObj->GetCurrRelPos().Y() ); - - const SwTwips nFrameDiff = - aRectFnSet.YDiff( - aRectFnSet.GetTop(pTmp->getFrameArea()), - aRectFnSet.GetTop(pFrame->getFrameArea()) ); - - nHeight = std::max( nHeight, nDistOfFlyBottomToAnchorTop + nFrameDiff - - aRectFnSet.GetHeight(pFrame->getFrameArea()) ); - - // #i56115# The first height calculation - // gives wrong results if pFrame->getFramePrintArea().Y() > 0. We do - // a second calculation based on the actual rectangles of - // pFrame and pAnchoredObj, and use the maximum of the results. - // I do not want to remove the first calculation because - // if clipping has been applied, using the GetCurrRelPos - // might be the better option to calculate nHeight. - const SwTwips nDistOfFlyBottomToAnchorTop2 = aRectFnSet.YDiff( - aRectFnSet.GetBottom(pAnchoredObj->GetObjRect()), - aRectFnSet.GetBottom(pFrame->getFrameArea()) ); - - nHeight = std::max( nHeight, tools::Long(nDistOfFlyBottomToAnchorTop2 )); - } - } - } - } - } - if( !pFrame->IsSctFrame() ) - break; - pTmp = pTmp->FindNextCnt(); - if( !static_cast(pFrame)->IsAnLower( pTmp ) ) - break; + return nHeight; } - return nHeight; + // Not a section frame + return CalcHeightWithFlys_Impl(pFrame, pFrame, aRectFnSet); } static SwTwips lcl_CalcTopAndBottomMargin( const SwLayoutFrame& rCell, const SwBorderAttrs& rAttrs )