Rebased ref, commits from common ancestor:
commit d8f6e78fdc047e77d362a029dd2d1c46c5e5c092
Author: Samuel Mehrbrodt <[email protected]>
AuthorDate: Tue Feb 15 17:17:54 2022 +0100
Commit: Samuel Mehrbrodt <[email protected]>
CommitDate: Wed Feb 23 11:04:08 2022 +0100
Try to fix .bau files being ignored
Change-Id: I4248fb283d4399a8501a979cae7e6bcc6d8e8a2d
diff --git a/sw/source/uibase/utlui/gloslst.cxx
b/sw/source/uibase/utlui/gloslst.cxx
index 0d80082fd21c..7d4e183efbfd 100644
--- a/sw/source/uibase/utlui/gloslst.cxx
+++ b/sw/source/uibase/utlui/gloslst.cxx
@@ -299,7 +299,7 @@ void SwGlossaryList::Update()
aGroupArr.push_back(std::unique_ptr<AutoTextGroup>(pFound));
}
- else if( pFound->aDateModified < rDT )
+ else if( pFound->aDateModified != rDT )
{
FillGroup(pFound, pGlossaries);
pFound->aDateModified = rDT;
commit b6fb3c0a9dcc699dff033d1fe11471302251de15
Author: Samuel Mehrbrodt <[email protected]>
AuthorDate: Tue Feb 15 17:16:37 2022 +0100
Commit: Samuel Mehrbrodt <[email protected]>
CommitDate: Wed Feb 23 11:04:08 2022 +0100
Add logging to auotext functions
Change-Id: Id7e69e764664978cc97016803773c1077cd15979
diff --git a/include/sal/log-areas.dox b/include/sal/log-areas.dox
index 904ba74b4425..9a0c43587bc9 100644
--- a/include/sal/log-areas.dox
+++ b/include/sal/log-areas.dox
@@ -514,6 +514,7 @@ certain functionality.
@li @c sw
@li @c sw.a11y - accessibility
+@li @c sw.autotext - Autotext
@li @c sw.calc - formula calculation
@li @c sw.core - Writer core
@li @c sw.createcopy
diff --git a/sw/source/uibase/dochdl/gloshdl.cxx
b/sw/source/uibase/dochdl/gloshdl.cxx
index fc1f13dae296..30353d27f00c 100644
--- a/sw/source/uibase/dochdl/gloshdl.cxx
+++ b/sw/source/uibase/dochdl/gloshdl.cxx
@@ -349,12 +349,15 @@ bool SwGlossaryHdl::DelGlossary(const OUString
&rShortName)
// expand short name
bool SwGlossaryHdl::ExpandGlossary(weld::Window* pParent)
{
+ SAL_INFO("sw.autotext", "SwGlossaryHdl::ExpandGlossary");
OSL_ENSURE(pWrtShell->CanInsert(), "illegal");
SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
::GlossaryGetCurrGroup fnGetCurrGroup = pFact->GetGlossaryCurrGroupFunc();
OUString sGroupName( (*fnGetCurrGroup)() );
+ SAL_INFO("sw.autotext", "current group name: " << sGroupName);
if (sGroupName.indexOf(GLOS_DELIM)<0)
FindGroupName(sGroupName);
+ SAL_INFO("sw.autotext", "new group name: " << sGroupName);
std::unique_ptr<SwTextBlocks> pGlossary =
rStatGlossaries.GetGroupDoc(sGroupName);
OUString aShortName;
@@ -378,6 +381,7 @@ bool SwGlossaryHdl::ExpandGlossary(weld::Window* pParent)
if(pWrtShell->IsSelection())
aShortName = pWrtShell->GetSelText();
}
+ SAL_INFO("sw.autotext", "END SwGlossaryHdl::ExpandGlossary");
return pGlossary && Expand(pParent, aShortName, &rStatGlossaries,
std::move(pGlossary));
}
@@ -385,16 +389,19 @@ bool SwGlossaryHdl::Expand(weld::Window* pParent, const
OUString& rShortName,
SwGlossaries *pGlossaries,
std::unique_ptr<SwTextBlocks> pGlossary)
{
+ SAL_INFO("sw.autotext", "SwGlossaryHdl::Expand rShortName: " <<
rShortName);
std::vector<TextBlockInfo_Impl> aFoundArr;
OUString aShortName( rShortName );
bool bCancel = false;
// search for text block
// - don't prefer current group depending on configuration setting
const SvxAutoCorrCfg& rCfg = SvxAutoCorrCfg::Get();
+ SAL_INFO("sw.autotext", "rCfg.IsSearchInAllCategories(): " <<
rCfg.IsSearchInAllCategories());
sal_uInt16 nFound = !rCfg.IsSearchInAllCategories() ? pGlossary->GetIndex(
aShortName ) : -1;
// if not found then search in all groups
if( nFound == sal_uInt16(-1) )
{
+ SAL_INFO("sw.autotext", "not found");
const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore();
SwGlossaryList* pGlossaryList = ::GetGlossaryList();
const size_t nGroupCount = pGlossaryList->GetGroupCount();
@@ -402,11 +409,14 @@ bool SwGlossaryHdl::Expand(weld::Window* pParent, const
OUString& rShortName,
{
// get group name with path-extension
const OUString sGroupName = pGlossaryList->GetGroupName(i);
+ SAL_INFO("sw.autotext", "checking group " << sGroupName);
if(sGroupName == pGlossary->GetName())
continue;
+ SAL_INFO("sw.autotext", "found group " << sGroupName);
const sal_uInt16 nBlockCount = pGlossaryList->GetBlockCount(i);
if(nBlockCount)
{
+ SAL_INFO("sw.autotext", "found block");
const OUString sTitle = pGlossaryList->GetGroupTitle(i);
for(sal_uInt16 j = 0; j < nBlockCount; j++)
{
@@ -414,6 +424,7 @@ bool SwGlossaryHdl::Expand(weld::Window* pParent, const
OUString& rShortName,
const OUString
sShortName(pGlossaryList->GetBlockShortName(i, j));
if( rSCmp.isEqual( rShortName, sShortName ))
{
+ SAL_INFO("sw.autotext", "found: sTitle: " << sTitle <<
" sLongName" << sLongName << " sGroupName " << sGroupName );
aFoundArr.emplace_back(sTitle, sLongName, sGroupName);
}
}
@@ -421,9 +432,11 @@ bool SwGlossaryHdl::Expand(weld::Window* pParent, const
OUString& rShortName,
}
if( !aFoundArr.empty() ) // one was found
{
+ SAL_INFO("sw.autotext", "one was found");
pGlossary.reset();
if (1 == aFoundArr.size())
{
+ SAL_INFO("sw.autotext", "aFoundArr.size() == 1");
TextBlockInfo_Impl& rData = aFoundArr.front();
pGlossary = pGlossaries->GetGroupDoc(rData.sGroupName);
nFound = pGlossary->GetIndex( aShortName );
@@ -459,6 +472,7 @@ bool SwGlossaryHdl::Expand(weld::Window* pParent, const
OUString& rShortName,
// not found
if( nFound == sal_uInt16(-1) )
{
+ SAL_INFO("sw.autotext", "not found.");
if( !bCancel )
{
pGlossary.reset();
@@ -480,6 +494,7 @@ bool SwGlossaryHdl::Expand(weld::Window* pParent, const
OUString& rShortName,
}
else
{
+ SAL_INFO("sw.autotext", "inserting glossary.");
SvxMacro aStartMacro(OUString(), OUString(), STARBASIC);
SvxMacro aEndMacro(OUString(), OUString(), STARBASIC);
GetMacros( aShortName, aStartMacro, aEndMacro, pGlossary.get() );
@@ -510,6 +525,7 @@ bool SwGlossaryHdl::Expand(weld::Window* pParent, const
OUString& rShortName,
if( aFieldLst.BuildSortLst() )
pWrtShell->UpdateInputFields( &aFieldLst );
}
+ SAL_INFO("sw.autotext", "END SwGlossaryHdl::Expand");
return true;
}
diff --git a/sw/source/uibase/misc/glosdoc.cxx
b/sw/source/uibase/misc/glosdoc.cxx
index 08cab28a4304..1666cfac5905 100644
--- a/sw/source/uibase/misc/glosdoc.cxx
+++ b/sw/source/uibase/misc/glosdoc.cxx
@@ -347,11 +347,13 @@ static OUString lcl_makePath(const std::vector<OUString>&
rPaths)
void SwGlossaries::UpdateGlosPath(bool bFull)
{
+ SAL_INFO("sw.autotext", "SwGlossaries::UpdateGlosPath bFull: " << true);
SvtPathOptions aPathOpt;
const OUString& aNewPath( aPathOpt.GetAutoTextPath() );
bool bPathChanged = m_aPath != aNewPath;
if (bFull || bPathChanged)
{
+ SAL_INFO("sw.autotext", "if (bFull || bPathChanged)");
m_aPath = aNewPath;
m_PathArr.clear();
@@ -360,6 +362,7 @@ void SwGlossaries::UpdateGlosPath(bool bFull)
std::vector<OUString> aInvalidPaths;
if (!m_aPath.isEmpty())
{
+ SAL_INFO("sw.autotext", "if (!m_aPath.isEmpty())");
sal_Int32 nIndex = 0;
do
{
@@ -374,19 +377,27 @@ void SwGlossaries::UpdateGlosPath(bool bFull)
}
aDirArr.push_back(sPth);
if( !FStatHelper::IsFolder( sPth ) )
+ {
aInvalidPaths.push_back(sPth);
+ SAL_INFO("sw.autotext", "invalid path: " << sPth);
+ }
else
+ {
m_PathArr.push_back(sPth);
+ SAL_INFO("sw.autotext", "valid path: " << sPth);
+ }
}
while (nIndex>=0);
}
if (m_aPath.isEmpty() || !aInvalidPaths.empty())
{
+ SAL_INFO("sw.autotext", "if (m_aPath.isEmpty() ||
!aInvalidPaths.empty())");
std::sort(aInvalidPaths.begin(), aInvalidPaths.end());
aInvalidPaths.erase(std::unique(aInvalidPaths.begin(),
aInvalidPaths.end()), aInvalidPaths.end());
if (bPathChanged || (m_aInvalidPaths != aInvalidPaths))
{
+ SAL_INFO("sw.autotext", "err condition!");
m_aInvalidPaths = aInvalidPaths;
// wrong path, that means AutoText directory doesn't exist
@@ -403,10 +414,12 @@ void SwGlossaries::UpdateGlosPath(bool bFull)
if (!m_GlosArr.empty())
{
+ SAL_INFO("sw.autotext", "if (!m_GlosArr.empty())");
m_GlosArr.clear();
GetNameList();
}
}
+ SAL_INFO("sw.autotext", "END SwGlossaries::UpdateGlosPath");
}
void SwGlossaries::ShowError()
@@ -591,16 +604,23 @@ Reference< text::XAutoTextEntry >
SwGlossaries::GetAutoTextEntry(
const OUString& rGroupName,
const OUString& rEntryName )
{
+ SAL_INFO("sw.autotext", "SwGlossaries::GetAutoTextEntry
rCompleteGroupName: " << rCompleteGroupName << " rGroupName: " << rGroupName
<< " rEntryName: " << rEntryName);
//standard must be created
bool bCreate = ( rCompleteGroupName == GetDefName() );
std::unique_ptr< SwTextBlocks > pGlosGroup( GetGroupDoc(
rCompleteGroupName, bCreate ) );
if (!pGlosGroup || pGlosGroup->GetError())
+ {
+ SAL_INFO("sw.autotext", "pGlosGroup empty!");
throw lang::WrappedTargetException();
+ }
sal_uInt16 nIdx = pGlosGroup->GetIndex( rEntryName );
if ( USHRT_MAX == nIdx )
+ {
+ SAL_INFO("sw.autotext", "rEntryName not found!");
throw container::NoSuchElementException();
+ }
Reference< text::XAutoTextEntry > xReturn;
diff --git a/sw/source/uibase/utlui/gloslst.cxx
b/sw/source/uibase/utlui/gloslst.cxx
index 6041dbd881d8..0d80082fd21c 100644
--- a/sw/source/uibase/utlui/gloslst.cxx
+++ b/sw/source/uibase/utlui/gloslst.cxx
@@ -82,6 +82,7 @@ IMPL_LINK_NOARG(SwGlossDecideDlg, SelectHdl, weld::TreeView&,
void)
SwGlossaryList::SwGlossaryList() :
bFilled(false)
{
+ SAL_INFO("sw.autotext", "SwGlossaryList::SwGlossaryList");
SvtPathOptions aPathOpt;
sPath = aPathOpt.GetAutoTextPath();
SetTimeout(GLOS_TIMEOUT);
@@ -89,6 +90,7 @@ SwGlossaryList::SwGlossaryList() :
SwGlossaryList::~SwGlossaryList()
{
+ SAL_INFO("sw.autotext", "SwGlossaryList::~SwGlossaryList");
ClearGroups();
}
@@ -225,6 +227,7 @@ OUString SwGlossaryList::GetBlockShortName(size_t nGroup,
sal_uInt16 nBlock)
void SwGlossaryList::Update()
{
+ SAL_INFO("sw.autotext", "SwGlossaryList::Update");
if(!IsActive())
Start();
@@ -232,6 +235,7 @@ void SwGlossaryList::Update()
const OUString& sTemp( aPathOpt.GetAutoTextPath() );
if(sTemp != sPath)
{
+ SAL_INFO("sw.autotext", "sTemp != sPath");
sPath = sTemp;
bFilled = false;
ClearGroups();
@@ -241,6 +245,7 @@ void SwGlossaryList::Update()
const OUString sExt( SwGlossaries::GetExtension() );
if(!bFilled)
{
+ SAL_INFO("sw.autotext", "!bFilled");
const size_t nGroupCount = pGlossaries->GetGroupCnt();
for(size_t i = 0; i < nGroupCount; ++i)
{
@@ -266,6 +271,7 @@ void SwGlossaryList::Update()
}
else
{
+ SAL_INFO("sw.autotext", "bFilled");
for( size_t nPath = 0; nPath < rPathArr.size(); nPath++ )
{
std::vector<OUString> aFoundGroupNames;
@@ -323,10 +329,12 @@ void SwGlossaryList::Update()
}
}
}
+ SAL_INFO("sw.autotext", "END SwGlossaryList::Update");
}
void SwGlossaryList::Invoke()
{
+ SAL_INFO("sw.autotext", "SwGlossaryList::Invoke");
// Only update automatically if a SwView has the focus.
if(::GetActiveView())
Update();
@@ -350,6 +358,7 @@ void SwGlossaryList::FillGroup(AutoTextGroup* pGroup,
SwGlossaries* pGlossaries)
pGroup->sShortNames.clear();
if(pBlock)
pGroup->sTitle = pBlock->GetName();
+ SAL_INFO("sw.autotext", "SwGlossaryList::FillGroup " << pGroup->sTitle);
for(sal_uInt16 j = 0; j < pGroup->nCount; j++)
{
@@ -358,6 +367,7 @@ void SwGlossaryList::FillGroup(AutoTextGroup* pGroup,
SwGlossaries* pGlossaries)
pGroup->sShortNames += pBlock->GetShortName(j)
+ OUStringLiteral1(STRING_DELIM);
}
+ SAL_INFO("sw.autotext", "END SwGlossaryList::FillGroup");
}
// Give back all (not exceeding FIND_MAX_GLOS) found modules
commit 081520aabe12475fb1b760ab3cbd63de03479591
Author: Stephan Bergmann <[email protected]>
AuthorDate: Mon May 31 13:30:37 2021 +0200
Commit: Samuel Mehrbrodt <[email protected]>
CommitDate: Wed Feb 23 11:04:08 2022 +0100
Adapt to hamcrest-2.2-3.fc35.noarch.rpm
Change-Id: Ibddfc30a5f0828ab77235ec1155f1c2e1eef24ee
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116506
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <[email protected]>
(cherry picked from commit e6c25186c8584f68b5f8074004556bd855200fff)
diff --git a/configure.ac b/configure.ac
index d5841860c1c0..dcdd9c5f6fd2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -12064,6 +12064,8 @@ if test "$ENABLE_JAVA" != "" -a "$with_junit" != "no";
then
HAMCREST_JAR=/usr/share/lib/java/hamcrest.jar
elif test -e /usr/share/java/hamcrest/core.jar; then
HAMCREST_JAR=/usr/share/java/hamcrest/core.jar
+ elif test -e /usr/share/java/hamcrest/hamcrest.jar; then
+ HAMCREST_JAR=/usr/share/java/hamcrest/hamcrest.jar
else
HAMCREST_JAR=/usr/share/java/hamcrest.jar
fi
commit 9d4674b99da973a8b4be6e30ae8cd8ae2e86e316
Author: Michael Stahl <[email protected]>
AuthorDate: Fri Feb 11 18:28:42 2022 +0100
Commit: Samuel Mehrbrodt <[email protected]>
CommitDate: Mon Feb 21 11:39:28 2022 +0100
sw: layout: fix overlapped table rows in --convert-to pdf
If the document is loaded via UI, the first layout action is triggered
from resizing the Window and the table is positioned properly on the
first try.
If the document is loaded via --convert-to, only getRendererCount()
formats the content of the table, and positioning goes wrong.
Somehow the 2 rows of the table in the fly end up on the same Y
position, because when the text frame in the 1st row is formatted
and grows from 0 to 230, the already-valid position of the cell
frame in the 2nd row is not invalidated.
This happens since the earliest version checked, OOo 3.4 beta.
This fix is somewhat similar to commit
068c133ac41c97652909b88c432e3b73010efc3e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129851
Tested-by: Jenkins
Reviewed-by: Michael Stahl <[email protected]>
(cherry picked from commit e7874c936dd1ff9b3423eb7477cbee2494535176)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129845
Reviewed-by: Thorsten Behrens <[email protected]>
(cherry picked from commit 06bb600ce3445abe095b8011ec7e66b33badb4ef)
Change-Id: I3259c440265cfe40dc7731cb4830bfe2487acf38
diff --git a/sw/qa/extras/layout/data/table_cell_overlap.fodt
b/sw/qa/extras/layout/data/table_cell_overlap.fodt
new file mode 100644
index 000000000000..e9565054de88
--- /dev/null
+++ b/sw/qa/extras/layout/data/table_cell_overlap.fodt
@@ -0,0 +1,161 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<office:document xmlns:officeooo="http://openoffice.org/2009/office"
xmlns:css3t="http://www.w3.org/TR/css3-text/"
xmlns:grddl="http://www.w3.org/2003/g/data-view#"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
xmlns:rpt="http://openoffice.org/2005/report"
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0"
xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2"
xmlns:dc="http://purl.org/dc/eleme
nts/1.1/" xmlns:ooo="http://openoffice.org/2004/office"
xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0"
xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0"
xmlns:drawooo="http://openoffice.org/2010/draw"
xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0"
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"
xmlns:ooow="http://openoffice.org/2004/writer"
xmlns:oooc="http://openoffice.org/2004/calc"
xmlns:tableooo="http://openoffice.org/2009/table"
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"
xmlns:math="http://www.w3.org/1998/Math/MathML"
xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0"
xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0
" xmlns:dom="http://www.w3.org/2001/xml-events"
xmlns:xforms="http://www.w3.org/2002/xforms" office:version="1.2"
office:mimetype="application/vnd.oasis.opendocument.text">
+
<office:meta><meta:creation-date>2022-02-11T15:45:44.525015226</meta:creation-date><dc:date>2022-02-11T15:51:17.840027874</dc:date><meta:editing-duration>PT5M32S</meta:editing-duration><meta:editing-cycles>4</meta:editing-cycles><meta:generator>LibreOfficeDev/6.3.6.11$Linux_X86_64
LibreOffice_project/798c41960be08155f4f9734c6307615ab45c134e</meta:generator><meta:document-statistic
meta:table-count="1" meta:image-count="0" meta:object-count="0"
meta:page-count="1" meta:paragraph-count="2" meta:word-count="2"
meta:character-count="8" meta:non-whitespace-character-count="8"/></office:meta>
+ <office:font-face-decls>
+ <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation
Serif'" style:font-family-generic="roman" style:font-pitch="variable"/>
+ <style:font-face style:name="Lohit Devanagari" svg:font-family="'Lohit
Devanagari'" style:font-family-generic="system" style:font-pitch="variable"/>
+ <style:font-face style:name="Source Han Serif CN" svg:font-family="'Source
Han Serif CN'" style:font-family-generic="system" style:font-pitch="variable"/>
+ </office:font-face-decls>
+ <office:styles>
+ <style:default-style style:family="graphic">
+ <style:graphic-properties svg:stroke-color="#3465a4"
draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.3cm"
draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm"
draw:start-line-spacing-vertical="0.283cm"
draw:end-line-spacing-horizontal="0.283cm"
draw:end-line-spacing-vertical="0.283cm" style:flow-with-text="false"/>
+ <style:paragraph-properties style:text-autospace="ideograph-alpha"
style:line-break="strict" style:writing-mode="lr-tb"
style:font-independent-line-spacing="false">
+ <style:tab-stops/>
+ </style:paragraph-properties>
+ <style:text-properties style:use-window-font-color="true"
style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="de"
fo:country="DE" style:letter-kerning="true" style:font-name-asian="Source Han
Serif CN" style:font-size-asian="10.5pt" style:language-asian="zh"
style:country-asian="CN" style:font-name-complex="Lohit Devanagari"
style:font-size-complex="12pt" style:language-complex="hi"
style:country-complex="IN"/>
+ </style:default-style>
+ <style:default-style style:family="paragraph">
+ <style:paragraph-properties fo:orphans="2" fo:widows="2"
fo:hyphenation-ladder-count="no-limit" style:text-autospace="ideograph-alpha"
style:punctuation-wrap="hanging" style:line-break="strict"
style:tab-stop-distance="1.251cm" style:writing-mode="page"/>
+ <style:text-properties style:use-window-font-color="true"
style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="de"
fo:country="DE" style:letter-kerning="true" style:font-name-asian="Source Han
Serif CN" style:font-size-asian="10.5pt" style:language-asian="zh"
style:country-asian="CN" style:font-name-complex="Lohit Devanagari"
style:font-size-complex="12pt" style:language-complex="hi"
style:country-complex="IN" fo:hyphenate="false"
fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2"/>
+ </style:default-style>
+ <style:default-style style:family="table">
+ <style:table-properties table:border-model="collapsing"/>
+ </style:default-style>
+ <style:default-style style:family="table-row">
+ <style:table-row-properties fo:keep-together="auto"/>
+ </style:default-style>
+ <style:style style:name="Standard" style:family="paragraph"
style:class="text"/>
+ <style:style style:name="Boooo" style:family="paragraph"
style:parent-style-name="Standard" style:master-page-name="">
+ <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm"
loext:contextual-spacing="false" fo:line-height="100%" fo:text-align="start"
style:justify-single-word="false" style:page-number="auto">
+ <style:tab-stops/>
+ </style:paragraph-properties>
+ <style:text-properties fo:font-size="10pt"/>
+ </style:style>
+ <style:style style:name="Frame" style:family="graphic">
+ <style:graphic-properties text:anchor-type="paragraph" svg:x="0cm"
svg:y="0cm" fo:margin-left="0.201cm" fo:margin-right="0.201cm"
fo:margin-top="0.201cm" fo:margin-bottom="0.201cm" style:wrap="parallel"
style:number-wrapped-paragraphs="no-limit" style:wrap-contour="false"
style:vertical-pos="top" style:vertical-rel="paragraph-content"
style:horizontal-pos="center" style:horizontal-rel="paragraph-content"
fo:padding="0.15cm" fo:border="0.06pt solid #000000"/>
+ </style:style>
+ <text:outline-style style:name="Outline">
+ <text:outline-level-style text:level="1" style:num-format="">
+ <style:list-level-properties
text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="2" style:num-format="">
+ <style:list-level-properties
text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="3" style:num-format="">
+ <style:list-level-properties
text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="4" style:num-format="">
+ <style:list-level-properties
text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="5" style:num-format="">
+ <style:list-level-properties
text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="6" style:num-format="">
+ <style:list-level-properties
text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="7" style:num-format="">
+ <style:list-level-properties
text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="8" style:num-format="">
+ <style:list-level-properties
text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="9" style:num-format="">
+ <style:list-level-properties
text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="10" style:num-format="">
+ <style:list-level-properties
text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ </text:outline-style>
+ <text:notes-configuration text:note-class="footnote" style:num-format="1"
text:start-value="0" text:footnotes-position="page"
text:start-numbering-at="document"/>
+ <text:notes-configuration text:note-class="endnote" style:num-format="i"
text:start-value="0"/>
+ <text:linenumbering-configuration text:number-lines="false"
text:offset="0.499cm" style:num-format="1" text:number-position="left"
text:increment="5"/>
+ </office:styles>
+ <office:automatic-styles>
+ <style:style style:name="Table1" style:family="table">
+ <style:table-properties style:width="16.198cm" table:align="margins"/>
+ </style:style>
+ <style:style style:name="Table1.A" style:family="table-column">
+ <style:table-column-properties style:column-width="16.198cm"
style:rel-column-width="65535*"/>
+ </style:style>
+ <style:style style:name="Table1.A1" style:family="table-cell">
+ <style:table-cell-properties fo:background-color="transparent"
fo:padding="0cm" fo:border="none">
+ <style:background-image/>
+ </style:table-cell-properties>
+ </style:style>
+ <style:style style:name="P1" style:family="paragraph"
style:parent-style-name="Boooo">
+ <style:text-properties fo:font-size="11pt" style:font-size-asian="11pt"
style:font-size-complex="11pt"/>
+ </style:style>
+ <style:style style:name="T3" style:family="text">
+ <style:text-properties fo:font-weight="bold" style:font-weight-asian="bold"
style:font-weight-complex="bold"/>
+ </style:style>
+ <style:style style:name="T4" style:family="text">
+ <style:text-properties fo:font-weight="bold" style:font-weight-asian="bold"
style:font-weight-complex="bold"/>
+ </style:style>
+ <style:style style:name="T5" style:family="text">
+ <style:text-properties fo:font-size="10pt" fo:font-weight="bold"
style:font-weight-asian="bold" style:font-weight-complex="bold"/>
+ </style:style>
+ <style:style style:name="fr1" style:family="graphic"
style:parent-style-name="Frame">
+ <style:graphic-properties fo:margin-left="0cm" fo:margin-right="0cm"
fo:margin-top="0cm" fo:margin-bottom="0cm" style:protect="position"
style:vertical-pos="from-top" style:vertical-rel="page"
style:horizontal-pos="from-left" style:horizontal-rel="page"
fo:background-color="#e6e6e6" style:background-transparency="0%"
draw:fill="solid" draw:fill-color="#e6e6e6" draw:opacity="100%"
fo:padding="0.199cm" fo:border="0.06pt solid #ffffff" style:shadow="none"
draw:shadow-opacity="100%"/>
+ </style:style>
+ <style:page-layout style:name="pm1">
+ <style:page-layout-properties fo:page-width="21.001cm"
fo:page-height="29.7cm" style:num-format="1" style:print-orientation="portrait"
fo:margin-top="2cm" fo:margin-bottom="2cm" fo:margin-left="2cm"
fo:margin-right="2cm" style:writing-mode="lr-tb"
style:footnote-max-height="0cm">
+ <style:footnote-sep style:width="0.018cm"
style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm"
style:line-style="solid" style:adjustment="left" style:rel-width="25%"
style:color="#000000"/>
+ </style:page-layout-properties>
+ <style:header-style/>
+ <style:footer-style/>
+ </style:page-layout>
+ </office:automatic-styles>
+ <office:master-styles>
+ <style:master-page style:name="Standard" style:page-layout-name="pm1"/>
+ </office:master-styles>
+ <office:body>
+ <office:text>
+ <office:forms form:automatic-focus="false" form:apply-design-mode="false"/>
+ <text:sequence-decls>
+ <text:sequence-decl text:display-outline-level="0"
text:name="Illustration"/>
+ <text:sequence-decl text:display-outline-level="0" text:name="Table"/>
+ <text:sequence-decl text:display-outline-level="0" text:name="Text"/>
+ <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/>
+ <text:sequence-decl text:display-outline-level="0" text:name="Figure"/>
+ </text:sequence-decls><draw:frame draw:style-name="fr1" draw:name="Boooo"
text:anchor-type="page" text:anchor-page-number="1" svg:x="2.2cm"
svg:y="11.591cm" svg:width="16.6cm" draw:z-index="0">
+ <draw:text-box fo:min-height="2.147cm">
+ <table:table table:name="Table1" table:style-name="Table1">
+ <table:table-column table:style-name="Table1.A"/>
+ <table:table-row>
+ <table:table-cell table:style-name="Table1.A1"
office:value-type="string">
+ <text:p text:style-name="Boooo"><text:span
text:style-name="T5">ONE</text:span><text:span
text:style-name="T3">:</text:span></text:p>
+ </table:table-cell>
+ </table:table-row>
+ <table:table-row>
+ <table:table-cell table:style-name="Table1.A1"
office:value-type="string">
+ <text:p text:style-name="Boooo"><text:span
text:style-name="T5">TWO</text:span><text:span
text:style-name="T4">:</text:span></text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table>
+ <text:p text:style-name="P1"/>
+ </draw:text-box>
+ </draw:frame>
+ <text:p text:style-name="Standard"/>
+ </office:text>
+ </office:body>
+</office:document>
diff --git a/sw/qa/extras/layout/layout.cxx b/sw/qa/extras/layout/layout.cxx
index 0bd25d45b4b6..8f6ca8a92580 100644
--- a/sw/qa/extras/layout/layout.cxx
+++ b/sw/qa/extras/layout/layout.cxx
@@ -3017,6 +3017,62 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf122607)
"Portion", "Fax:");
}
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTableCellInvalidate)
+{
+ discardDumpedLayout();
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ OUString const pName("table_cell_overlap.fodt");
+
+ OUString const url(m_directories.getURLFromSrc(DATA_DIRECTORY) + pName);
+
+ // note: must set Hidden property, so that
SfxFrameViewWindow_Impl::Resize()
+ // does *not* forward initial VCL Window Resize and thereby triggers a
+ // layout which does not happen on soffice --convert-to pdf.
+ std::vector<beans::PropertyValue> aFilterOptions = {
+ { beans::PropertyValue("Hidden", -1, uno::Any(true),
beans::PropertyState_DIRECT_VALUE) },
+ };
+
+ std::cout << pName << ":\n";
+
+ // inline the loading because currently properties can't be passed...
+ mxComponent = loadFromDesktop(url, "com.sun.star.text.TextDocument",
+
comphelper::containerToSequence(aFilterOptions));
+ uno::Sequence<beans::PropertyValue>
props(comphelper::InitPropertySequence({
+ { "FilterName", uno::Any(OUString("writer_pdf_Export")) },
+ }));
+ utl::TempFile aTempFile;
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ xStorable->storeToURL(aTempFile.GetURL(), props);
+
+ xmlDocPtr pXmlDoc = parseLayoutDump();
+ // somehow these 2 rows overlapped in the PDF unless CalcLayout() runs
+ assertXPath(pXmlDoc,
"/root/page[1]/anchored/fly/tab[1]/row[1]/infos/bounds", "top", "6969");
+ assertXPath(pXmlDoc,
"/root/page[1]/anchored/fly/tab[1]/row[1]/infos/bounds", "height", "231");
+ assertXPath(pXmlDoc,
"/root/page[1]/anchored/fly/tab[1]/row[1]/cell[1]/infos/bounds", "top",
+ "6969");
+ assertXPath(pXmlDoc,
"/root/page[1]/anchored/fly/tab[1]/row[1]/cell[1]/infos/bounds", "height",
+ "231");
+ assertXPath(pXmlDoc,
"/root/page[1]/anchored/fly/tab[1]/row[1]/cell[1]/txt[1]/infos/bounds",
+ "top", "6969");
+ assertXPath(pXmlDoc,
"/root/page[1]/anchored/fly/tab[1]/row[1]/cell[1]/txt[1]/infos/bounds",
+ "height", "231");
+ assertXPath(pXmlDoc,
"/root/page[1]/anchored/fly/tab[1]/row[2]/infos/bounds", "top", "7200");
+ assertXPath(pXmlDoc,
"/root/page[1]/anchored/fly/tab[1]/row[2]/infos/bounds", "height", "231");
+ // this was 6969, causing the overlap
+ assertXPath(pXmlDoc,
"/root/page[1]/anchored/fly/tab[1]/row[2]/cell[1]/infos/bounds", "top",
+ "7200");
+ assertXPath(pXmlDoc,
"/root/page[1]/anchored/fly/tab[1]/row[2]/cell[1]/infos/bounds", "height",
+ "231");
+ assertXPath(pXmlDoc,
"/root/page[1]/anchored/fly/tab[1]/row[2]/cell[1]/txt[1]/infos/bounds",
+ "top", "7200");
+ assertXPath(pXmlDoc,
"/root/page[1]/anchored/fly/tab[1]/row[2]/cell[1]/txt[1]/infos/bounds",
+ "height", "231");
+
+ aTempFile.EnableKillingFile();
+}
+
CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf122607_regression)
{
discardDumpedLayout();
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index b396b4f0f407..b7e5e3149403 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -2736,6 +2736,10 @@ SwTwips SwLayoutFrame::GrowFrame( SwTwips nDist, bool
bTst, bool bInfo )
if ( GetNext() )
{
GetNext()->InvalidatePos_();
+ if (GetNext()->IsRowFrame())
+ { // also invalidate first cell
+
static_cast<SwLayoutFrame*>(GetNext())->Lower()->InvalidatePos_();
+ }
if ( GetNext()->IsContentFrame() )
GetNext()->InvalidatePage( pPage );
}
commit 21cbd2cb9c1bf86728edf351f5e350d923eb15b2
Author: Michael Stahl <[email protected]>
AuthorDate: Thu Feb 10 19:43:08 2022 +0100
Commit: Samuel Mehrbrodt <[email protected]>
CommitDate: Mon Feb 21 11:39:15 2022 +0100
sw: fix layout loop on soffice --convert-to pdf ooo95698-1.odt
For unknown reasons, this loops since commit
32902f66e7749b2d06d13f50416be5323a0c0ea9a
"sw_redlinehide: make layout based Show/Hide mode the default"
The problem is that when page 1 is layouted for the first time, it
splits into 6 pages, and then the SwTabFrame 47 decides that it wants
to move its follow flow line because it fits onto page 1.
Then splitting the SwTabFrame again fails, but for this
RemoveFollowFlowLine() was called a 2nd time and removed the one on
page 3.
The result is a layout with content on page 1, nothing on page 2, 3
and again content on page 4. This seems to reoccur every time page 1
is formatted.
But the first RemoveFollowFlowLine() was wrong because
CalcHeightOfFirstContentLine() returns 0 because
lcl_CalcHeightOfFirstContentLine() didn't handle the case of
SwSectionFrame containing SwTabFrame.
This is similar to commit e024cad7c1365da6a198656c3ca0c32b28938e87
doing the same thing for text frames in section.
Change-Id: I23fb4d1d56622039f461bb2d357a9c88db140605
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129800
Tested-by: Jenkins
Reviewed-by: Michael Stahl <[email protected]>
(cherry picked from commit b4271e028686d729189afc5e42a9c310f81144f3)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129828
Reviewed-by: Xisco Fauli <[email protected]>
(cherry picked from commit 60811f97c753360393f52aa747837db15a722162)
diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx
index c00a7294e8c3..4f2c504cc8e5 100644
--- a/sw/source/core/layout/tabfrm.cxx
+++ b/sw/source/core/layout/tabfrm.cxx
@@ -5581,9 +5581,12 @@ static SwTwips lcl_CalcHeightOfFirstContentLine( const
SwRowFrame& rSourceLine )
const SwRowFrame* pTmpSourceRow = static_cast<const
SwRowFrame*>(pCurrSourceCell->Lower());
nTmpHeight = lcl_CalcHeightOfFirstContentLine( *pTmpSourceRow
);
}
- else if ( pTmp->IsTabFrame() )
+ else if (pTmp->IsTabFrame() || (pTmp->IsSctFrame() &&
pTmp->GetLower() && pTmp->GetLower()->IsTabFrame()))
{
- nTmpHeight = static_cast<const
SwTabFrame*>(pTmp)->CalcHeightOfFirstContentLine();
+ SwTabFrame const*const pTabFrame(pTmp->IsTabFrame()
+ ? static_cast<SwTabFrame const*>(pTmp)
+ : static_cast<SwTabFrame const*>(pTmp->GetLower()));
+ nTmpHeight = pTabFrame->CalcHeightOfFirstContentLine();
}
else if (pTmp->IsTextFrame() || (pTmp->IsSctFrame() &&
pTmp->GetLower() && pTmp->GetLower()->IsTextFrame()))
{
commit d2f374ea109f818c45c4e8f73df4c33710455431
Author: Samuel Mehrbrodt <[email protected]>
AuthorDate: Thu Jan 20 15:57:51 2022 +0100
Commit: Samuel Mehrbrodt <[email protected]>
CommitDate: Fri Jan 21 09:15:17 2022 +0100
Release 6.3.6.14
Change-Id: I3ea3698f6e8473dad3211a1b18788a9a49c039e7
diff --git a/configure.ac b/configure.ac
index fb26c107376c..d5841860c1c0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -9,7 +9,7 @@ dnl in order to create a configure script.
# several non-alphanumeric characters, those are split off and used only for
the
# ABOUTBOXPRODUCTVERSIONSUFFIX in openoffice.lst. Why that is necessary, no
idea.
-AC_INIT([LibreOffice],[6.3.6.13],[],[],[http://documentfoundation.org/])
+AC_INIT([LibreOffice],[6.3.6.14],[],[],[http://documentfoundation.org/])
dnl libnumbertext needs autoconf 2.68, but that can pick up autoconf268 just
fine if it is installed
dnl whereas aclocal (as run by autogen.sh) insists on using autoconf and fails
hard
commit 74d6225836b910b7b71d552c433352c9de5db329
Author: Luke Deller <[email protected]>
AuthorDate: Fri Apr 9 09:08:37 2021 +1000
Commit: Samuel Mehrbrodt <[email protected]>
CommitDate: Fri Jan 21 09:15:09 2022 +0100
tdf#141556 Fix 100% CPU usage in Writer idle loop
Do not interrupt the idle layout processing unnecessarily, because if it
is continually interrupted before making enough progress then it will
keep resuming at the same page, never finishing, constantly using CPU.
This is achieved with two changes:
- Revert "tdf#123583 use TaskStopwatch for Writer Idle loop"
(commit 383032c50a3e3354f04200ce984a47ab9d2c5c67) which
introduced a stopwatch timer to interrupt idle processing every 50ms.
This reversion restores the previous behaviour where idle processing
is interrupted only when there is an input event.
- Filter out TIMER events so that they do not interrupt the idle loop;
this fixes both tdf#123583 and tdf#141556
Conflicts:
sw/source/core/inc/layact.hxx
sw/source/core/layout/layact.cxx
Change-Id: Ic989631e5f32199209d64b66b72059253fc0167a
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113825
Tested-by: Jenkins
Reviewed-by: Jan-Marek Glogowski <[email protected]>
Reviewed-by: Miklos Vajna <[email protected]>
(cherry picked from commit 0fedac18214a6025401c4c426466a5166553e8ec)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114944
(cherry picked from commit b33148071ae6256845352f8625e58b1ab95be41c)
diff --git a/sw/source/core/inc/layact.hxx b/sw/source/core/inc/layact.hxx
index 1707383b62d7..bac0a23da163 100644
--- a/sw/source/core/inc/layact.hxx
+++ b/sw/source/core/inc/layact.hxx
@@ -22,7 +22,6 @@
#include <sal/config.h>
#include <vcl/inputtypes.hxx>
-#include <vcl/TaskStopwatch.hxx>
#include <tools/color.hxx>
#include <ctime>
@@ -57,7 +56,6 @@ class SwLayAction
{
SwRootFrame *m_pRoot;
SwViewShellImp *m_pImp; // here the action logs in and off
- TaskStopwatch* m_pWatch;
// For the sake of optimization, so that the tables stick a bit better to
// the Cursor when hitting return/backspace in front of one.
@@ -76,6 +74,7 @@ class SwLayAction
std::clock_t m_nStartTicks; // The Action's starting time; if too
much time passes the
// WaitCursor can be enabled via
CheckWaitCursor()
+ VclInputFlags m_nInputType; // Which input should terminate processing
sal_uInt16 m_nEndPage; // StatBar control
sal_uInt16 m_nCheckPageNum; // CheckPageDesc() was delayed if !=
USHRT_MAX
// check from this page onwards
@@ -85,8 +84,9 @@ class SwLayAction
bool m_bCalcLayout; // Complete reformatting?
bool m_bAgain; // For the automatically repeated Action if Pages
are deleted
bool m_bNextCycle; // Reset on the first invalid Page
+ bool m_bInput; // For terminating processing on input
+ bool m_bIdle; // True if the LayAction was triggered by the Idler
bool m_bReschedule; // Call Reschedule depending on Progress?
- bool m_bInterrupt; // For termination the layouting
bool m_bCheckPages; // Run CheckPageDescs() or delay it
bool m_bUpdateExpFields; // Is set if, after Formatting, we need to do
another round for ExpField
bool m_bBrowseActionStop; // Terminate Action early (as per bInput) and
leave the rest to the Idler
@@ -119,26 +119,33 @@ class SwLayAction
bool RemoveEmptyBrowserPages();
+ inline void CheckIdleEnd();
+
public:
- SwLayAction(SwRootFrame *pRt, SwViewShellImp *pImp, TaskStopwatch* pWatch
= nullptr);
+ SwLayAction( SwRootFrame *pRt, SwViewShellImp *pImp );
~SwLayAction();
+ void SetIdle ( bool bNew ) { m_bIdle = bNew; }
void SetCheckPages ( bool bNew ) { m_bCheckPages = bNew; }
void SetBrowseActionStop( bool bNew ) { m_bBrowseActionStop = bNew; }
void SetNextCycle ( bool bNew ) { m_bNextCycle = bNew; }
bool IsWaitAllowed() const { return m_bWaitAllowed; }
bool IsNextCycle() const { return m_bNextCycle; }
+ bool IsInput() const { return m_bInput; }
bool IsPaint() const { return m_bPaint; }
+ bool IsIdle() const { return m_bIdle; }
bool IsReschedule() const { return m_bReschedule; }
- bool IsIdle() const { return m_pWatch != nullptr; }
- bool IsPaintExtraData() const { return m_bPaintExtraData; }
- bool IsInterrupt();
+ bool IsPaintExtraData() const { return m_bPaintExtraData;}
+ bool IsInterrupt() const { return IsInput(); }
+
+ VclInputFlags GetInputType() const { return m_nInputType; }
// adjusting Action to the wanted behaviour
void SetPaint ( bool bNew ) { m_bPaint = bNew; }
void SetComplete ( bool bNew ) { m_bComplete = bNew; }
void SetStatBar ( bool bNew );
+ void SetInputType ( VclInputFlags nNew ) { m_nInputType = nNew; }
void SetCalcLayout ( bool bNew ) { m_bCalcLayout = bNew; }
void SetReschedule ( bool bNew ) { m_bReschedule = bNew; }
void SetWaitAllowed ( bool bNew ) { m_bWaitAllowed = bNew; }
@@ -175,7 +182,6 @@ public:
class SwLayIdle
{
- TaskStopwatch m_aWatch;
SwRootFrame *pRoot;
SwViewShellImp *pImp; // The Idler registers and deregisters
here
SwContentNode *pContentNode; // The current cursor position is saved
here
@@ -187,7 +193,6 @@ class SwLayIdle
void ShowIdle( Color eName );
#endif
- bool IsInterrupt();
enum IdleJobType{ ONLINE_SPELLING, AUTOCOMPLETE_WORDS, WORD_COUNT,
SMART_TAGS };
bool DoIdleJob_( const SwContentFrame*, IdleJobType );
bool DoIdleJob( IdleJobType, bool bVisAreaOnly );
diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx
index abac3364efd2..d5efa7680fd6 100644
--- a/sw/source/core/layout/layact.cxx
+++ b/sw/source/core/layout/layact.cxx
@@ -89,6 +89,13 @@ void SwLayAction::CheckWaitCursor()
}
}
+// Time over already?
+inline void SwLayAction::CheckIdleEnd()
+{
+ if ( !IsInput() )
+ m_bInput = bool(GetInputType()) && Application::AnyInput(
GetInputType() );
+}
+
void SwLayAction::SetStatBar( bool bNew )
{
if ( bNew )
@@ -246,19 +253,19 @@ void SwLayAction::PaintContent( const SwContentFrame
*pCnt,
}
}
-SwLayAction::SwLayAction(SwRootFrame *pRt, SwViewShellImp *pI, TaskStopwatch*
pWatch)
- : m_pRoot(pRt),
+SwLayAction::SwLayAction( SwRootFrame *pRt, SwViewShellImp *pI ) :
+ m_pRoot( pRt ),
m_pImp( pI ),
- m_pWatch(pWatch),
m_pOptTab( nullptr ),
m_nPreInvaPage( USHRT_MAX ),
m_nStartTicks( std::clock() ),
+ m_nInputType( VclInputFlags::NONE ),
m_nEndPage( USHRT_MAX ),
m_nCheckPageNum( USHRT_MAX )
{
m_bPaintExtraData = ::IsExtraData( m_pImp->GetShell()->GetDoc() );
m_bPaint = m_bComplete = m_bWaitAllowed = m_bCheckPages = true;
- m_bInterrupt = m_bAgain = m_bNextCycle = m_bCalcLayout = m_bReschedule =
+ m_bInput = m_bAgain = m_bNextCycle = m_bCalcLayout = m_bIdle =
m_bReschedule =
m_bUpdateExpFields = m_bBrowseActionStop = m_bActionInProgress = false;
// init new flag <mbFormatContentOnInterrupt>.
mbFormatContentOnInterrupt = false;
@@ -273,18 +280,14 @@ SwLayAction::~SwLayAction()
m_pImp->m_pLayAction = nullptr; // unregister
}
-bool SwLayAction::IsInterrupt()
-{
- return m_bInterrupt || (m_pWatch && m_pWatch->exceededRuntime());
-}
-
void SwLayAction::Reset()
{
m_pOptTab = nullptr;
m_nStartTicks = std::clock();
+ m_nInputType = VclInputFlags::NONE;
m_nEndPage = m_nPreInvaPage = m_nCheckPageNum = USHRT_MAX;
m_bPaint = m_bComplete = m_bWaitAllowed = m_bCheckPages = true;
- m_bInterrupt = m_bAgain = m_bNextCycle = m_bCalcLayout = m_bReschedule =
+ m_bInput = m_bAgain = m_bNextCycle = m_bCalcLayout = m_bIdle =
m_bReschedule =
m_bUpdateExpFields = m_bBrowseActionStop = false;
}
@@ -443,7 +446,7 @@ void SwLayAction::InternalAction(OutputDevice*
pRenderContext)
IDocumentLayoutAccess& rLayoutAccess =
m_pRoot->GetFormat()->getIDocumentLayoutAccess();
bool bNoLoop = pPage && SwLayouter::StartLoopControl(
m_pRoot->GetFormat()->GetDoc(), pPage );
sal_uInt16 nPercentPageNum = 0;
- while ((!IsInterrupt() && pPage) || (m_nCheckPageNum != USHRT_MAX))
+ while ( (pPage && !IsInterrupt()) || m_nCheckPageNum != USHRT_MAX )
{
// note: this is the only place that consumes and resets
m_nCheckPageNum
if ((IsInterrupt() || !pPage) && m_nCheckPageNum != USHRT_MAX)
@@ -567,7 +570,7 @@ void SwLayAction::InternalAction(OutputDevice*
pRenderContext)
pPage->InvalidateFlyLayout();
pPage->InvalidateFlyContent();
if ( IsBrowseActionStop() )
- m_bInterrupt = true;
+ m_bInput = true;
}
}
if( bNoLoop )
@@ -585,8 +588,7 @@ void SwLayAction::InternalAction(OutputDevice*
pRenderContext)
pPage->ValidateFlyLayout();
pPage->ValidateFlyContent();
}
-
- if (!IsInterrupt())
+ if ( !IsInterrupt() )
{
SetNextCycle( false );
@@ -627,8 +629,8 @@ void SwLayAction::InternalAction(OutputDevice*
pRenderContext)
if( bNoLoop )
rLayoutAccess.GetLayouter()->LoopControl( pPage );
}
+ CheckIdleEnd();
}
-
if ( !pPage && !IsInterrupt() &&
(m_pRoot->IsSuperfluous() || m_pRoot->IsAssertFlyPages()) )
{
@@ -654,7 +656,6 @@ void SwLayAction::InternalAction(OutputDevice*
pRenderContext)
pPage = static_cast<SwPageFrame*>(pPage->GetNext());
}
}
-
if ( IsInterrupt() && pPage )
{
// If we have input, we don't want to format content anymore, but
@@ -683,7 +684,7 @@ void SwLayAction::InternalAction(OutputDevice*
pRenderContext)
pPg = pPg ? static_cast<SwPageFrame*>(pPg->GetPrev()) : pPage;
// set flag for interrupt content formatting
- mbFormatContentOnInterrupt = IsInterrupt();
+ mbFormatContentOnInterrupt = IsInput();
long nBottom = rVis.Bottom();
// #i42586# - format current page, if idle action is active
// This is an optimization for the case that the interrupt is created
by
@@ -777,6 +778,7 @@ void SwLayAction::InternalAction(OutputDevice*
pRenderContext)
bool SwLayAction::TurboAction_( const SwContentFrame *pCnt )
{
+
const SwPageFrame *pPage = nullptr;
if ( !pCnt->isFrameAreaDefinitionValid() || pCnt->IsCompletePaint() ||
pCnt->IsRetouche() )
{
@@ -837,7 +839,10 @@ bool SwLayAction::TurboAction()
if ( m_pRoot->GetTurbo() )
{
if ( !TurboAction_( m_pRoot->GetTurbo() ) )
+ {
+ CheckIdleEnd();
bRet = false;
+ }
m_pRoot->ResetTurbo();
}
else
@@ -1683,6 +1688,7 @@ bool SwLayAction::FormatContent(SwPageFrame *const pPage)
// paragraph has been processed.
if (!pTab || !bInValid)
{
+ CheckIdleEnd();
// consider interrupt formatting.
if ( ( IsInterrupt() && !mbFormatContentOnInterrupt ) ||
( !bBrowse && pPage->IsInvalidLayout() ) ||
@@ -1775,6 +1781,7 @@ bool SwLayAction::FormatContent(SwPageFrame *const pPage)
PaintContent( pContent, pPage, pContent->getFrameArea(),
pContent->getFrameArea().Bottom());
if ( IsIdle() )
{
+ CheckIdleEnd();
// consider interrupt formatting.
if ( IsInterrupt() && !mbFormatContentOnInterrupt )
return false;
@@ -1870,6 +1877,7 @@ void SwLayAction::FormatFlyContent( const SwFlyFrame
*pFly )
// If there's input, we interrupt processing.
if ( !pFly->IsFlyInContentFrame() )
{
+ CheckIdleEnd();
// consider interrupt formatting.
if ( IsInterrupt() && !mbFormatContentOnInterrupt )
return;
@@ -1879,11 +1887,6 @@ void SwLayAction::FormatFlyContent( const SwFlyFrame
*pFly )
CheckWaitCursor();
}
-bool SwLayIdle::IsInterrupt()
-{
- return m_aWatch.exceededRuntime();
-}
-
bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob )
{
OSL_ENSURE( pCnt->IsTextFrame(), "NoText neighbour of Text" );
@@ -1967,7 +1970,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt,
IdleJobType eJob )
bPageValid = bPageValid && (SwTextNode::WrongState::TODO !=
pTextNode->GetWrongDirty());
if ( aRepaint.HasArea() )
pImp->GetShell()->InvalidateWindows( aRepaint );
- if (IsInterrupt())
+ if (Application::AnyInput(VCL_INPUT_ANY &
VclInputFlags(~VclInputFlags::TIMER)))
return true;
break;
}
@@ -1975,7 +1978,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt,
IdleJobType eJob )
const_cast<SwTextFrame*>(pTextFrame)->CollectAutoCmplWrds(*pTextNode, nPos);
// note: bPageValid remains true here even if the cursor
// position is skipped, so no PENDING state needed currently
- if (IsInterrupt())
+ if (Application::AnyInput(VCL_INPUT_ANY &
VclInputFlags(~VclInputFlags::TIMER)))
return true;
break;
case WORD_COUNT :
@@ -1983,7 +1986,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt,
IdleJobType eJob )
const sal_Int32 nEnd = pTextNode->GetText().getLength();
SwDocStat aStat;
pTextNode->CountWords( aStat, 0, nEnd );
- if (IsInterrupt())
+ if ( Application::AnyInput() )
return true;
break;
}
@@ -1998,7 +2001,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt,
IdleJobType eJob )
// handle smarttag problems gracefully and provide
diagnostics
SAL_WARN( "sw.core", "SMART_TAGS: " << e);
}
- if (IsInterrupt())
+ if (Application::AnyInput(VCL_INPUT_ANY &
VclInputFlags(~VclInputFlags::TIMER)))
return true;
break;
}
@@ -2190,7 +2193,9 @@ SwLayIdle::SwLayIdle( SwRootFrame *pRt, SwViewShellImp
*pI ) :
bool bInterrupt(false);
{
- SwLayAction aAction(pRoot, pImp, &m_aWatch);
+ SwLayAction aAction( pRoot, pImp );
+ aAction.SetInputType( VCL_INPUT_ANY &
VclInputFlags(~VclInputFlags::TIMER) );
+ aAction.SetIdle( true );
aAction.SetWaitAllowed( false );
aAction.Action(pImp->GetShell()->GetOut());
bInterrupt = aAction.IsInterrupt();
diff --git a/sw/source/core/view/viewsh.cxx b/sw/source/core/view/viewsh.cxx
index 0095d134ba6d..66775b933a8d 100644
--- a/sw/source/core/view/viewsh.cxx
+++ b/sw/source/core/view/viewsh.cxx
@@ -291,6 +291,7 @@ void SwViewShell::ImplEndAction( const bool bIdleEnd )
aAction.SetComplete( false );
if ( mnLockPaint )
aAction.SetPaint( false );
+ aAction.SetInputType( VclInputFlags::KEYBOARD );
aAction.Action(GetWin());
}
commit 73b9318dd60b191984ee6e9fa12afb25773ad11b
Author: Samuel Mehrbrodt <[email protected]>
AuthorDate: Tue Jan 18 10:08:24 2022 +0100
Commit: Samuel Mehrbrodt <[email protected]>
CommitDate: Tue Jan 18 10:08:24 2022 +0100
Update .gitreview
Change-Id: I360c95365dbe553dc589a0a7da99189f1148a754
diff --git a/.gitreview b/.gitreview
index c4d492adf26d..79f1e7ad3fbf 100644
--- a/.gitreview
+++ b/.gitreview
@@ -3,5 +3,5 @@ host=gerrit.libreoffice.org
port=29418
project=core
defaultremote=logerrit
-defaultbranch=feature/cib_contract57d
+defaultbranch=feature/cib_contract57l
commit de28100fe351ded5e0724b98e2ebb398ee21825c
Author: Jan-Marek Glogowski <[email protected]>
AuthorDate: Tue Aug 6 17:09:51 2019 +0200
Commit: Samuel Mehrbrodt <[email protected]>
CommitDate: Tue Jan 18 09:58:02 2022 +0100
tdf#123583 use TaskStopwatch for Writer Idle loop
I don't see much of a point in the extra CheckIdleEnd() function.
We already check IsInterrupt() almost everywhere, so move that
check in there.
An other strange thing is the Idle job, which should just be
interrupted by keyboard events (using SetInputType(, which this
patch removes). Unlucky for me this code was there in the initial
import. I can just say that othing obvious breaks...
Change-Id: Ia5955d1eaf2ab612f2c4b63b0e458ed92507b75c
Reviewed-on: https://gerrit.libreoffice.org/77040
Tested-by: Jenkins
Reviewed-by: Jan-Marek Glogowski <[email protected]>
(cherry picked from commit 383032c50a3e3354f04200ce984a47ab9d2c5c67)
diff --git a/sw/source/core/inc/layact.hxx b/sw/source/core/inc/layact.hxx
index 50335077694c..1707383b62d7 100644
--- a/sw/source/core/inc/layact.hxx
+++ b/sw/source/core/inc/layact.hxx
@@ -22,6 +22,7 @@
#include <sal/config.h>
#include <vcl/inputtypes.hxx>
+#include <vcl/TaskStopwatch.hxx>
#include <tools/color.hxx>
#include <ctime>
@@ -56,6 +57,7 @@ class SwLayAction
{
SwRootFrame *m_pRoot;
SwViewShellImp *m_pImp; // here the action logs in and off
+ TaskStopwatch* m_pWatch;
// For the sake of optimization, so that the tables stick a bit better to
// the Cursor when hitting return/backspace in front of one.
@@ -74,7 +76,6 @@ class SwLayAction
std::clock_t m_nStartTicks; // The Action's starting time; if too
much time passes the
// WaitCursor can be enabled via
CheckWaitCursor()
- VclInputFlags m_nInputType; // Which input should terminate processing
sal_uInt16 m_nEndPage; // StatBar control
sal_uInt16 m_nCheckPageNum; // CheckPageDesc() was delayed if !=
USHRT_MAX
// check from this page onwards
@@ -84,9 +85,8 @@ class SwLayAction
bool m_bCalcLayout; // Complete reformatting?
bool m_bAgain; // For the automatically repeated Action if Pages
are deleted
bool m_bNextCycle; // Reset on the first invalid Page
- bool m_bInput; // For terminating processing on input
- bool m_bIdle; // True if the LayAction was triggered by the Idler
bool m_bReschedule; // Call Reschedule depending on Progress?
+ bool m_bInterrupt; // For termination the layouting
bool m_bCheckPages; // Run CheckPageDescs() or delay it
bool m_bUpdateExpFields; // Is set if, after Formatting, we need to do
another round for ExpField
bool m_bBrowseActionStop; // Terminate Action early (as per bInput) and
leave the rest to the Idler
@@ -119,33 +119,26 @@ class SwLayAction
bool RemoveEmptyBrowserPages();
- inline void CheckIdleEnd();
-
public:
- SwLayAction( SwRootFrame *pRt, SwViewShellImp *pImp );
+ SwLayAction(SwRootFrame *pRt, SwViewShellImp *pImp, TaskStopwatch* pWatch
= nullptr);
~SwLayAction();
- void SetIdle ( bool bNew ) { m_bIdle = bNew; }
void SetCheckPages ( bool bNew ) { m_bCheckPages = bNew; }
void SetBrowseActionStop( bool bNew ) { m_bBrowseActionStop = bNew; }
void SetNextCycle ( bool bNew ) { m_bNextCycle = bNew; }
bool IsWaitAllowed() const { return m_bWaitAllowed; }
bool IsNextCycle() const { return m_bNextCycle; }
- bool IsInput() const { return m_bInput; }
bool IsPaint() const { return m_bPaint; }
- bool IsIdle() const { return m_bIdle; }
bool IsReschedule() const { return m_bReschedule; }
- bool IsPaintExtraData() const { return m_bPaintExtraData;}
- bool IsInterrupt() const { return IsInput(); }
-
- VclInputFlags GetInputType() const { return m_nInputType; }
+ bool IsIdle() const { return m_pWatch != nullptr; }
+ bool IsPaintExtraData() const { return m_bPaintExtraData; }
+ bool IsInterrupt();
// adjusting Action to the wanted behaviour
void SetPaint ( bool bNew ) { m_bPaint = bNew; }
void SetComplete ( bool bNew ) { m_bComplete = bNew; }
void SetStatBar ( bool bNew );
- void SetInputType ( VclInputFlags nNew ) { m_nInputType = nNew; }
void SetCalcLayout ( bool bNew ) { m_bCalcLayout = bNew; }
void SetReschedule ( bool bNew ) { m_bReschedule = bNew; }
void SetWaitAllowed ( bool bNew ) { m_bWaitAllowed = bNew; }
@@ -182,21 +175,19 @@ public:
class SwLayIdle
{
-
+ TaskStopwatch m_aWatch;
SwRootFrame *pRoot;
SwViewShellImp *pImp; // The Idler registers and deregisters
here
SwContentNode *pContentNode; // The current cursor position is saved
here
sal_Int32 nTextPos;
bool bPageValid; // Were we able to evaluate everything on the
whole page?
-
#ifdef DBG_UTIL
bool m_bIndicator;
-#endif
-#ifdef DBG_UTIL
void ShowIdle( Color eName );
#endif
+ bool IsInterrupt();
enum IdleJobType{ ONLINE_SPELLING, AUTOCOMPLETE_WORDS, WORD_COUNT,
SMART_TAGS };
bool DoIdleJob_( const SwContentFrame*, IdleJobType );
bool DoIdleJob( IdleJobType, bool bVisAreaOnly );
diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx
index 96796cca4662..abac3364efd2 100644
--- a/sw/source/core/layout/layact.cxx
+++ b/sw/source/core/layout/layact.cxx
@@ -89,13 +89,6 @@ void SwLayAction::CheckWaitCursor()
}
}
-// Time over already?
-inline void SwLayAction::CheckIdleEnd()
-{
- if ( !IsInput() )
- m_bInput = bool(GetInputType()) && Application::AnyInput(
GetInputType() );
-}
-
void SwLayAction::SetStatBar( bool bNew )
{
if ( bNew )
@@ -253,19 +246,19 @@ void SwLayAction::PaintContent( const SwContentFrame
*pCnt,
}
}
-SwLayAction::SwLayAction( SwRootFrame *pRt, SwViewShellImp *pI ) :
- m_pRoot( pRt ),
+SwLayAction::SwLayAction(SwRootFrame *pRt, SwViewShellImp *pI, TaskStopwatch*
pWatch)
+ : m_pRoot(pRt),
m_pImp( pI ),
+ m_pWatch(pWatch),
m_pOptTab( nullptr ),
m_nPreInvaPage( USHRT_MAX ),
m_nStartTicks( std::clock() ),
- m_nInputType( VclInputFlags::NONE ),
m_nEndPage( USHRT_MAX ),
m_nCheckPageNum( USHRT_MAX )
{
m_bPaintExtraData = ::IsExtraData( m_pImp->GetShell()->GetDoc() );
m_bPaint = m_bComplete = m_bWaitAllowed = m_bCheckPages = true;
- m_bInput = m_bAgain = m_bNextCycle = m_bCalcLayout = m_bIdle =
m_bReschedule =
+ m_bInterrupt = m_bAgain = m_bNextCycle = m_bCalcLayout = m_bReschedule =
m_bUpdateExpFields = m_bBrowseActionStop = m_bActionInProgress = false;
// init new flag <mbFormatContentOnInterrupt>.
mbFormatContentOnInterrupt = false;
@@ -280,14 +273,18 @@ SwLayAction::~SwLayAction()
m_pImp->m_pLayAction = nullptr; // unregister
}
+bool SwLayAction::IsInterrupt()
+{
+ return m_bInterrupt || (m_pWatch && m_pWatch->exceededRuntime());
+}
+
void SwLayAction::Reset()
{
m_pOptTab = nullptr;
m_nStartTicks = std::clock();
- m_nInputType = VclInputFlags::NONE;
m_nEndPage = m_nPreInvaPage = m_nCheckPageNum = USHRT_MAX;
m_bPaint = m_bComplete = m_bWaitAllowed = m_bCheckPages = true;
- m_bInput = m_bAgain = m_bNextCycle = m_bCalcLayout = m_bIdle =
m_bReschedule =
+ m_bInterrupt = m_bAgain = m_bNextCycle = m_bCalcLayout = m_bReschedule =
m_bUpdateExpFields = m_bBrowseActionStop = false;
}
@@ -446,7 +443,7 @@ void SwLayAction::InternalAction(OutputDevice*
pRenderContext)
IDocumentLayoutAccess& rLayoutAccess =
m_pRoot->GetFormat()->getIDocumentLayoutAccess();
bool bNoLoop = pPage && SwLayouter::StartLoopControl(
m_pRoot->GetFormat()->GetDoc(), pPage );
sal_uInt16 nPercentPageNum = 0;
- while ( (pPage && !IsInterrupt()) || m_nCheckPageNum != USHRT_MAX )
+ while ((!IsInterrupt() && pPage) || (m_nCheckPageNum != USHRT_MAX))
{
// note: this is the only place that consumes and resets
m_nCheckPageNum
if ((IsInterrupt() || !pPage) && m_nCheckPageNum != USHRT_MAX)
@@ -570,7 +567,7 @@ void SwLayAction::InternalAction(OutputDevice*
pRenderContext)
pPage->InvalidateFlyLayout();
pPage->InvalidateFlyContent();
if ( IsBrowseActionStop() )
- m_bInput = true;
+ m_bInterrupt = true;
}
}
if( bNoLoop )
@@ -588,7 +585,8 @@ void SwLayAction::InternalAction(OutputDevice*
pRenderContext)
pPage->ValidateFlyLayout();
pPage->ValidateFlyContent();
}
- if ( !IsInterrupt() )
+
+ if (!IsInterrupt())
{
SetNextCycle( false );
@@ -629,8 +627,8 @@ void SwLayAction::InternalAction(OutputDevice*
pRenderContext)
if( bNoLoop )
rLayoutAccess.GetLayouter()->LoopControl( pPage );
}
- CheckIdleEnd();
}
+
if ( !pPage && !IsInterrupt() &&
(m_pRoot->IsSuperfluous() || m_pRoot->IsAssertFlyPages()) )
{
@@ -656,6 +654,7 @@ void SwLayAction::InternalAction(OutputDevice*
pRenderContext)
pPage = static_cast<SwPageFrame*>(pPage->GetNext());
}
}
+
if ( IsInterrupt() && pPage )
{
// If we have input, we don't want to format content anymore, but
@@ -684,7 +683,7 @@ void SwLayAction::InternalAction(OutputDevice*
pRenderContext)
pPg = pPg ? static_cast<SwPageFrame*>(pPg->GetPrev()) : pPage;
// set flag for interrupt content formatting
- mbFormatContentOnInterrupt = IsInput();
+ mbFormatContentOnInterrupt = IsInterrupt();
long nBottom = rVis.Bottom();
// #i42586# - format current page, if idle action is active
// This is an optimization for the case that the interrupt is created
by
@@ -778,7 +777,6 @@ void SwLayAction::InternalAction(OutputDevice*
pRenderContext)
bool SwLayAction::TurboAction_( const SwContentFrame *pCnt )
{
-
const SwPageFrame *pPage = nullptr;
if ( !pCnt->isFrameAreaDefinitionValid() || pCnt->IsCompletePaint() ||
pCnt->IsRetouche() )
{
@@ -839,10 +837,7 @@ bool SwLayAction::TurboAction()
if ( m_pRoot->GetTurbo() )
{
if ( !TurboAction_( m_pRoot->GetTurbo() ) )
- {
- CheckIdleEnd();
bRet = false;
- }
m_pRoot->ResetTurbo();
}
else
@@ -1688,7 +1683,6 @@ bool SwLayAction::FormatContent(SwPageFrame *const pPage)
// paragraph has been processed.
if (!pTab || !bInValid)
{
- CheckIdleEnd();
// consider interrupt formatting.
if ( ( IsInterrupt() && !mbFormatContentOnInterrupt ) ||
( !bBrowse && pPage->IsInvalidLayout() ) ||
@@ -1781,7 +1775,6 @@ bool SwLayAction::FormatContent(SwPageFrame *const pPage)
PaintContent( pContent, pPage, pContent->getFrameArea(),
pContent->getFrameArea().Bottom());
if ( IsIdle() )
{
- CheckIdleEnd();
// consider interrupt formatting.
if ( IsInterrupt() && !mbFormatContentOnInterrupt )
return false;
@@ -1877,7 +1870,6 @@ void SwLayAction::FormatFlyContent( const SwFlyFrame
*pFly )
// If there's input, we interrupt processing.
if ( !pFly->IsFlyInContentFrame() )
{
- CheckIdleEnd();
// consider interrupt formatting.
if ( IsInterrupt() && !mbFormatContentOnInterrupt )
return;
@@ -1887,6 +1879,11 @@ void SwLayAction::FormatFlyContent( const SwFlyFrame
*pFly )
CheckWaitCursor();
}
+bool SwLayIdle::IsInterrupt()
+{
+ return m_aWatch.exceededRuntime();
+}
+
bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob )
{
OSL_ENSURE( pCnt->IsTextFrame(), "NoText neighbour of Text" );
@@ -1970,7 +1967,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt,
IdleJobType eJob )
bPageValid = bPageValid && (SwTextNode::WrongState::TODO !=
pTextNode->GetWrongDirty());
if ( aRepaint.HasArea() )
pImp->GetShell()->InvalidateWindows( aRepaint );
- if (Application::AnyInput(VCL_INPUT_ANY &
VclInputFlags(~VclInputFlags::TIMER)))
+ if (IsInterrupt())
return true;
break;
}
@@ -1978,7 +1975,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt,
IdleJobType eJob )
const_cast<SwTextFrame*>(pTextFrame)->CollectAutoCmplWrds(*pTextNode, nPos);
// note: bPageValid remains true here even if the cursor
// position is skipped, so no PENDING state needed currently
- if (Application::AnyInput(VCL_INPUT_ANY &
VclInputFlags(~VclInputFlags::TIMER)))
+ if (IsInterrupt())
return true;
break;
case WORD_COUNT :
@@ -1986,7 +1983,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt,
IdleJobType eJob )
const sal_Int32 nEnd = pTextNode->GetText().getLength();
SwDocStat aStat;
pTextNode->CountWords( aStat, 0, nEnd );
- if ( Application::AnyInput() )
+ if (IsInterrupt())
return true;
break;
}
@@ -2001,7 +1998,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt,
IdleJobType eJob )
// handle smarttag problems gracefully and provide
diagnostics
SAL_WARN( "sw.core", "SMART_TAGS: " << e);
}
- if (Application::AnyInput(VCL_INPUT_ANY &
VclInputFlags(~VclInputFlags::TIMER)))
+ if (IsInterrupt())
return true;
break;
}
@@ -2193,9 +2190,7 @@ SwLayIdle::SwLayIdle( SwRootFrame *pRt, SwViewShellImp
*pI ) :
bool bInterrupt(false);
{
- SwLayAction aAction( pRoot, pImp );
- aAction.SetInputType( VCL_INPUT_ANY );
- aAction.SetIdle( true );
+ SwLayAction aAction(pRoot, pImp, &m_aWatch);
aAction.SetWaitAllowed( false );
aAction.Action(pImp->GetShell()->GetOut());
bInterrupt = aAction.IsInterrupt();
diff --git a/sw/source/core/view/viewsh.cxx b/sw/source/core/view/viewsh.cxx
index 66775b933a8d..0095d134ba6d 100644
--- a/sw/source/core/view/viewsh.cxx
+++ b/sw/source/core/view/viewsh.cxx
@@ -291,7 +291,6 @@ void SwViewShell::ImplEndAction( const bool bIdleEnd )
aAction.SetComplete( false );
if ( mnLockPaint )
aAction.SetPaint( false );
- aAction.SetInputType( VclInputFlags::KEYBOARD );
aAction.Action(GetWin());
}
commit 95a422aa7105a94f6b0b78246d83df3180a74ecc
Author: Stephan Bergmann <[email protected]>
AuthorDate: Fri Aug 16 09:56:29 2019 +0200
Commit: Samuel Mehrbrodt <[email protected]>
CommitDate: Tue Jan 18 09:57:59 2022 +0100
Drop bogus check from TimerTest::testStopwatch
(that had been added with 6e13585508ca3c9b66c6571ad1eb42bfcb66ef0b "Add a
TaskStopwatch to interrupt idle loops"). For each StopwatchIdle, m_nIters
counts the calls to Invoke before it calls Stop (which it calls based on
tools::Time::GetSystemTicks calculations). But the number of such
GetSystemTicks() spent in each Invoke is nondeterministic (it can e.g. be
affected by the overall system load), so a2Idle may Stop prior to a1Idle and
thus have a lower nIter2 than nIter1.
Change-Id: I416eee9774c3605be25e9832b24dec7d9dcb00c2
Reviewed-on: https://gerrit.libreoffice.org/77561
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <[email protected]>
(cherry picked from commit 92e42a0fde32e3f2dbe2c786a0e41547e4912b4b)
diff --git a/vcl/qa/cppunit/timer.cxx b/vcl/qa/cppunit/timer.cxx
index 0531c0c7f99c..5154c1947a75 100644
--- a/vcl/qa/cppunit/timer.cxx
+++ b/vcl/qa/cppunit/timer.cxx
@@ -603,7 +603,6 @@ void TimerTest::testStopwatch()
bool b1Done = a1Idle.isDone(n1Iter);
bool b2Done = a2Idle.isDone(n2Iter);
- CPPUNIT_ASSERT(n1Iter >= n2Iter);
if (b1Done && b2Done)
break;
commit 7ab267ef5e2d86a2bdb0d67f2ab6294e0ee6fc95
Author: Jan-Marek Glogowski <[email protected]>
AuthorDate: Sun Jul 7 23:09:15 2019 +0200
Commit: Samuel Mehrbrodt <[email protected]>
CommitDate: Tue Jan 18 09:57:47 2022 +0100
Add a TaskStopwatch to interrupt idle loops
If we have multiple pending Idles, they will interrupt / starve
each other, because there will be an instant pending timeout for
the next Idle.
This patch introduces a time slice to tasks, so long running events
can use a TaskStopwatch to do the real interrupt after running out
of their time slice. Apart from the time, this breaks when AnyInput
is available, except for the timer event.
This class just helps to track the time, as the scheduler is coop,
not preemptive.
Change-Id: I9d0b4a5aa388ebdf496b355d100152d890224524
Reviewed-on: https://gerrit.libreoffice.org/75568
Tested-by: Jenkins
Reviewed-by: Jan-Marek Glogowski <[email protected]>
(cherry picked from commit 6e13585508ca3c9b66c6571ad1eb42bfcb66ef0b)
diff --git a/include/vcl/TaskStopwatch.hxx b/include/vcl/TaskStopwatch.hxx
new file mode 100644
index 000000000000..c98dcc6f5527
--- /dev/null
+++ b/include/vcl/TaskStopwatch.hxx
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_VCL_TASK_STOPWATCH_HXX
+#define INCLUDED_VCL_TASK_STOPWATCH_HXX
+
+#include <tools/time.hxx>
+#include <vcl/dllapi.h>
+#include <vcl/inputtypes.hxx>
+#include <vcl/svapp.hxx>
+
+/**
+ * Helper class primary used to track time of long running iterating tasks.
+ *
+ * Normally it should be sufficiant to instanciate the watch object before
+ * starting the iteration and query continueIter() at the end of each.
+ *
+ * Called Stopwatch, because there is already a Timer class in the Scheduler.
+ *
+ * TODO: merge into the general Scheduler, so this can also be used to track
+ * Task runtimes in a more general way.
+ * TODO: handle fast iterations, where continueIter is called multiple times
+ * per tick, by counting the iterations per tick and use that for appoximation.
+ **/
+class VCL_DLLPUBLIC TaskStopwatch
+{
+ static constexpr VclInputFlags eDefaultInputStop = VCL_INPUT_ANY &
~VclInputFlags::TIMER;
+ static constexpr unsigned int nDefaultTimeSlice = 50;
+ static unsigned int m_nTimeSlice;
+
+ sal_uInt64 m_nStartTicks;
+ sal_uInt64 m_nIterStartTicks;
+ bool m_bConsiderLastIterTime;
+ VclInputFlags m_eInputStop;
+
+ bool nextIter(bool bQueryOnly)
+ {
+ sal_uInt64 nCurTicks = tools::Time::GetSystemTicks();
+ // handle system ticks wrap as exceeded time slice
+ if (nCurTicks < m_nStartTicks)
+ return false;
+
+ if (!bQueryOnly && m_bConsiderLastIterTime)
+ {
+ // based on the last iter runtime, we don't expect to finish in
time
+ // m_nTimeSlice < (nCurTicks - m_nStartTicks) + (nCurTicks -
m_nIterStartTicks)
+ if (m_nTimeSlice < 2 * nCurTicks - m_nIterStartTicks -
m_nStartTicks)
+ return false;
+ }
+ // time slice exceeded
+ else if (m_nTimeSlice < nCurTicks - m_nStartTicks)
+ return false;
+
+ if (!bQueryOnly)
+ m_nIterStartTicks = nCurTicks;
+
+ return !Application::AnyInput(m_eInputStop);
+ }
+
+public:
+ /**
+ * Per default the watch consideres the last iter time when asking for an
+ * other iteration, so considers Scheduler::acceptableTaskTime as a
+ * maximum value.
+ *
+ * If you already know your iter time vary in a large range, consider
+ * setting bConciderLastIterTime to false, so Scheduler::acceptableTaskTime
+ * will be used as a mimimum time slot.
+ **/
+ TaskStopwatch(bool bConciderLastIterTime = true)
+ : m_nStartTicks(tools::Time::GetSystemTicks())
+ , m_nIterStartTicks(m_nStartTicks)
+ , m_bConsiderLastIterTime(bConciderLastIterTime)
+ , m_eInputStop(eDefaultInputStop)
+ {
+ }
+
+ /**
+ * Returns true, if the time slot is already exceeded
+ **/
+ bool exceededRuntime() { return !nextIter(true); }
+
+ /**
+ * Returns true, if an other iteration will probably pass in the time slot
+ **/
+ bool continueIter() { return nextIter(false); }
+
+ /**
+ * Reset the stopwatch
+ **/
+ void reset()
+ {
+ m_nStartTicks = tools::Time::GetSystemTicks();
+ m_nIterStartTicks = m_nStartTicks;
+ }
+
+ /**
+ * Sets the input events, which should also "exceed" the stopwatch.
+ *
+ * Per default this ignores the VclInputFlags::TIMER.
+ */
+ void setInputStop(VclInputFlags eInputStop = eDefaultInputStop) {
m_eInputStop = eInputStop; }
+ VclInputFlags inputStop() const { return m_eInputStop; }
+
+ /**
+ * Sets the time considered the acceptable maximum for a task to run
+ *
+ * This is an orientation for long time background jobs to yield to
+ * the scheduler, so Idle task don't starve each other too much.
+ **/
+ static unsigned int timeSlice() { return m_nTimeSlice; }
+ static void setTimeSlice(unsigned int nTimeSlice) { m_nTimeSlice =
nTimeSlice; }
+};
+
+#endif // INCLUDED_VCL_TASK_STOPWATCH_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/CppunitTest_vcl_timer.mk b/vcl/CppunitTest_vcl_timer.mk
index b17bfc3a27f6..a89e4e070ec8 100644
--- a/vcl/CppunitTest_vcl_timer.mk
+++ b/vcl/CppunitTest_vcl_timer.mk
@@ -27,6 +27,7 @@ $(eval $(call gb_CppunitTest_use_libraries,vcl_timer, \
sal \
salhelper \
test \
+ tl \
unotest \
vcl \
))
diff --git a/vcl/README.scheduler b/vcl/README.scheduler
index 23decf3b7ec2..ebbd7c3682d1 100644
--- a/vcl/README.scheduler
+++ b/vcl/README.scheduler
@@ -26,8 +26,7 @@ C.2. Tasks should be split into sensible blocks
C.3. This is not an OS scheduler
There is no real way to "fix" B.2. and B.3.
If you need to do a preemptive task, use a thread!
- Otherwise make your task suspendable and check SalInstance::AnyInput
- or call Application::Reschedule regularly.
+ Otherwise make your task suspendable.
= Driving the scheduler AKA the system timer =
@@ -43,8 +42,7 @@ Every time a task is started, the scheduler timer is
adjusted. When the timer
fires, it posts an event to the system message queue. If the next most
important task is an Idle (AKA instant, 0ms timeout), the event is pushed to
the back of the queue, so we don't starve system messages, otherwise to the
-front. This is especially important to get a correct SalInstance::AnyInput
-handling, as this is used to suspend long background Idle tasks.
+front.
Every time the scheduler is invoked it searches for the next task to process,
restarts the timer with the timeout for the next event and then invokes the
@@ -120,7 +118,7 @@ bool DoYield( bool bWait, bool bAllCurrent )
== General: main thread deferral ==
-Currently for Mac and Windows, we run main thread deferrals by disabling the
+In almost all VCL backends, we run main thread deferrals by disabling the
SolarMutex using a boolean. In the case of the redirect, this makes
tryToAcquire and doAcquire return true or 1, while a release is ignored.
Also the IsCurrentThread() mutex check function will act accordingly, so all
@@ -176,6 +174,52 @@ To prevent these problems, we don't even try to remove
these events, but
invalidate them by versioning the timer events. Timer events with invalid
versions are processed but simply don't run the scheduler.
+== General: track time of long running tasks ==
+
+There is TaskStopwatch class. It'll track the time and report a timout either
+when the tasks time slice is finished or some system event did occur.
+
+Eventually it will be merged into the main scheduler, so each invoked task can
+easily track it's runtime and eventually this can be used to "blame" / find
+other long running tasks, so interactivity can be improved.
+
+There were some questions coming up when implementing it:
+
+=== Why does the scheduler not detect that we only have idle tasks pending,
+and skip the instant timeout? ===
+
+You never know how long a task will run. Currently the scheduler simply asks
+each task when it'll be ready to run, until two runable tasks are found.
+Normally this is very quick, as LO has a lot of one-shot instant tasks / Idles
+and just a very few long term pending Timers.
+
+Especially UNO calls add a lot of Idles to the task list, which just need to
+be processed in order.
+
+=== Why not use things like Linux timer wheels? ===
+
+LO has relatively few timers and a lot one-shot Idles. 99% of time the search
+for the next task is quick, because there are just ~5 long term timers per
+document (cache invalidation, cursor blinking etc.).
+
+This might become a problem, if you have a lot of open documents, so the long
+term timer list increases AKA for highly loaded LOOL instances.
+
+But the Linux timer wheel mainly relies on the facts that the OS timers are
+expected to not expire, as they are use to catch "error" timeouts, which rarely
+happen, so this definitly not matches LO's usage.
+
+=== Not really usable to find misbehaving tasks ===
+
+The TaskStopwatch class is just a little time keeper + detecting of input
+events. This is not about misbehaving Tasks, but long running tasks, which
+have to yield to the Scheduler, so other Tasks and System events can be
+processed.
+
+There is the TODO to merge the functionality into the Scheduler itself, at
+which point we can think about profiling individual Tasks to improve
+interactivity.
+
== macOS implementation details ==
Generally the Scheduler is handled as expected, except on resize, which is
@@ -343,3 +387,8 @@ A few layers of indirection make this code hard to follow.
The SalXLib::Yield
and SalX11Display::Yield architecture makes it impossible to process just the
current events. This really needs a refactoring and rearchitecture step, which
will also affect the Gtk+ and KDE backend for the user event handling.
+
+== Merge TaskStopwatch functionality into the Scheduler ==
+
+This way it can be easier used to profile Tasks, eventually to improve LO's
+interactivity.
diff --git a/vcl/qa/cppunit/timer.cxx b/vcl/qa/cppunit/timer.cxx
index 01eef078fae8..0531c0c7f99c 100644
--- a/vcl/qa/cppunit/timer.cxx
+++ b/vcl/qa/cppunit/timer.cxx
@@ -16,6 +16,7 @@
#include <salhelper/thread.hxx>
#include <chrono>
+#include <vcl/TaskStopwatch.hxx>
#include <vcl/timer.hxx>
#include <vcl/idle.hxx>
#include <vcl/svapp.hxx>
@@ -75,6 +76,8 @@ public:
void testPriority();
void testRoundRobin();
+ void testStopwatch();
+
CPPUNIT_TEST_SUITE(TimerTest);
CPPUNIT_TEST(testIdle);
#ifndef _WIN32
@@ -96,6 +99,8 @@ public:
CPPUNIT_TEST(testPriority);
CPPUNIT_TEST(testRoundRobin);
+ CPPUNIT_TEST(testStopwatch);
+
CPPUNIT_TEST_SUITE_END();
};
@@ -535,6 +540,79 @@ void TimerTest::testRoundRobin()
CPPUNIT_ASSERT( 3 == nCount1 && 3 == nCount2 );
}
+class StopwatchIdle : public AutoIdle
+{
+ sal_uInt32 m_nIters;
+ sal_uInt64 m_nBusyTicks;
+
+public:
+ StopwatchIdle(sal_uInt64 nBusyTicks)
+ : AutoIdle("StopwatchIdle")
+ , m_nIters(0)
+ , m_nBusyTicks(nBusyTicks)
+ {
+ if (m_nBusyTicks > 0)
+ Start();
+ }
+
+ virtual void Invoke() override
+ {
+ TaskStopwatch aWatch;
+ // ignore all system events
+ aWatch.setInputStop(VclInputFlags::NONE);
+
+ sal_uInt64 nStartTicks = tools::Time::GetSystemTicks();
+ sal_uInt64 nCurTicks = nStartTicks;
+
+ while (!aWatch.exceededRuntime())
+ {
+ nCurTicks = tools::Time::GetSystemTicks();
+ if (nCurTicks - nStartTicks >= m_nBusyTicks)
+ {
+ nCurTicks = nStartTicks + m_nBusyTicks;
+ break;
+ }
+ }
+
+ assert(m_nBusyTicks >= (nCurTicks - nStartTicks));
+ m_nBusyTicks -= (nCurTicks - nStartTicks);
+ m_nIters++;
+
+ if (m_nBusyTicks == 0)
+ Stop();
+ }
+
+ bool isDone(sal_uInt32 &nIters)
+ {
+ nIters = m_nIters;
+ return (m_nBusyTicks == 0);
+ }
+};
+
+void TimerTest::testStopwatch()
+{
+ TaskStopwatch::setTimeSlice(10);
+
+ StopwatchIdle a1Idle(100);
+ StopwatchIdle a2Idle(100);
+
+ sal_uInt32 n1Iter, n2Iter;
+ while (true)
+ {
+ Application::Reschedule();
+
+ bool b1Done = a1Idle.isDone(n1Iter);
+ bool b2Done = a2Idle.isDone(n2Iter);
+ CPPUNIT_ASSERT(n1Iter >= n2Iter);
+
+ if (b1Done && b2Done)
+ break;
+ }
+
+ CPPUNIT_ASSERT_EQUAL(sal_uInt32(10), n1Iter);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt32(10), n2Iter);
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(TimerTest);
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx
index 23bba5d7a25e..09480a6a05e3 100644
--- a/vcl/source/app/scheduler.cxx
+++ b/vcl/source/app/scheduler.cxx
@@ -33,6 +33,7 @@
#include <tools/debug.hxx>
#include <tools/diagnose_ex.h>
#include <unotools/configmgr.hxx>
+#include <vcl/TaskStopwatch.hxx>
#include <vcl/scheduler.hxx>
#include <vcl/idle.hxx>
#include <saltimer.hxx>
@@ -96,6 +97,8 @@ std::basic_ostream<charT, traits> & operator <<(
} // end anonymous namespace
+unsigned int TaskStopwatch::m_nTimeSlice = TaskStopwatch::nDefaultTimeSlice;
+
void Scheduler::ImplDeInitScheduler()
{
ImplSVData* pSVData = ImplGetSVData();
commit d148326ca8dfe8f152801eb341940c69a150c7ee
Author: Michael Stahl <[email protected]>
AuthorDate: Fri Jun 18 19:49:46 2021 +0200
Commit: Samuel Mehrbrodt <[email protected]>
CommitDate: Mon Jan 17 16:16:06 2022 +0100
tdf#116501 sw: layout: check for flys in SwTabFrame::ShouldBwdMoved()
On loading, this hits loop control
warn:legacy.osl:580715:580715:sw/source/core/layout/layact.cxx:543:
LoopControl_1 in SwLayAction::InternalAction
This is because there's a fly frame 404 anchored at the last text
frame 353 on page 2 inside the nested table 347.
ShouldBwdMoved() sees that there is space on the bottom of page 2 and
hence the follow flow row joined, but then it immediately splits again
in the same way as before due to the fly with WrapTextMode_NONE.
But then the outer table's cell 273 (upper of 347) is invalidated
again, hence the loop.
Try to check for overlapping flys in SwTabFrame::ShouldBwdMoved()
by reusing CalcFlyOffsets(), which is ... not quite ideal, but perhaps
better than copy-pasting half of it to a new function.
This should have less side effects than the previous fix, but a problem
remains that clicking on the shape on bottom of page 2 causes the layout
to go wonky, but that was also the case with previous fix.
Note there's a check of SwLayouter::DoesRowContainMovedFwdFrame() there
already, but that doesn't help because it will only detect when the fly
itself was moved forward, but in this case the fly remains on the page.
Also likely it wouldn't be a good idea to move a text frame forward if
the only thing of it that fits on a page is an anchored fly (i.e. its
follow has mnOffset=0) because that can be intentional.
Change-Id: I0376f7dcb784c006990336233c97f5093aaccb77
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/117473
Tested-by: Jenkins
Tested-by: László Németh <[email protected]>
Reviewed-by: László Németh <[email protected]>
(cherry picked from commit f1439db62eb36ef5fbc9111b87dc4e0f24b3cb86)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/117602
Reviewed-by: Xisco Fauli <[email protected]>
(cherry picked from commit 35a0bfa7bf52ca713ea8e57cd982d16723be920d)
diff --git a/sw/source/core/doc/htmltbl.cxx b/sw/source/core/doc/htmltbl.cxx
index 346c67c552fe..5482a984238a 100644
--- a/sw/source/core/doc/htmltbl.cxx
+++ b/sw/source/core/doc/htmltbl.cxx
@@ -363,7 +363,7 @@ sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByTabFrame(
SwTwips nUpperDummy = 0;
long nRightOffset = 0,
nLeftOffset = 0;
- rTabFrame.CalcFlyOffsets( nUpperDummy, nLeftOffset, nRightOffset );
+ rTabFrame.CalcFlyOffsets(nUpperDummy, nLeftOffset, nRightOffset, nullptr);
nWidth -= (nLeftOffset + nRightOffset);
return static_cast<sal_uInt16>(std::min(nWidth, SwTwips(SAL_MAX_UINT16)));
diff --git a/sw/source/core/inc/tabfrm.hxx b/sw/source/core/inc/tabfrm.hxx
index 176396c6667a..73768558ac10 100644
--- a/sw/source/core/inc/tabfrm.hxx
+++ b/sw/source/core/inc/tabfrm.hxx
@@ -201,7 +201,8 @@ public:
bool CalcFlyOffsets(
SwTwips& rUpper,
long& rLeftOffset,
- long& rRightOffset ) const;
+ long& rRightOffset,
+ SwTwips * pSpaceBelowBottom) const;
SwTwips CalcHeightOfFirstContentLine() const;
diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx
index ba85082edcaf..c00a7294e8c3 100644
--- a/sw/source/core/layout/tabfrm.cxx
+++ b/sw/source/core/layout/tabfrm.cxx
@@ -2740,7 +2740,8 @@ static bool IsNextOnSamePage(SwPageFrame const& rPage,
/// Calculate the offsets arising because of FlyFrames
bool SwTabFrame::CalcFlyOffsets( SwTwips& rUpper,
long& rLeftOffset,
- long& rRightOffset ) const
+ long& rRightOffset,
+ SwTwips *const pSpaceBelowBottom) const
{
bool bInvalidatePrtArea = false;
const SwPageFrame *pPage = FindPageFrame();
@@ -2760,9 +2761,17 @@ bool SwTabFrame::CalcFlyOffsets( SwTwips& rUpper,
long nPrtPos = aRectFnSet.GetTop(getFrameArea());
nPrtPos = aRectFnSet.YInc( nPrtPos, rUpper );
SwRect aRect( getFrameArea() );
- long nYDiff = aRectFnSet.YDiff(
aRectFnSet.GetTop(getFramePrintArea()), rUpper );
- if( nYDiff > 0 )
- aRectFnSet.AddBottom( aRect, -nYDiff );
+ if (pSpaceBelowBottom)
+ { // set to space below table frame
+ aRectFnSet.SetTopAndHeight(aRect, aRectFnSet.GetBottom(aRect),
*pSpaceBelowBottom);
+ }
+ else
+ {
+ long nYDiff = aRectFnSet.YDiff(
aRectFnSet.GetTop(getFramePrintArea()), rUpper );
+ if (nYDiff > 0)
+ aRectFnSet.AddBottom( aRect, -nYDiff );
+ }
+
for ( size_t i = 0; i < pPage->GetSortedObjs()->size(); ++i )
{
SwAnchoredObject* pAnchoredObj = (*pPage->GetSortedObjs())[i];
@@ -2797,8 +2806,9 @@ bool SwTabFrame::CalcFlyOffsets( SwTwips& rUpper,
aFlyRect.IsOver( aRect ) &&
// fly isn't lower of table and
// anchor character frame of fly isn't lower of table
- ( !IsAnLower( pFly ) &&
- ( !pAnchorCharFrame || !IsAnLower( pAnchorCharFrame ) )
) &&
+ (pSpaceBelowBottom // not if in ShouldBwdMoved
+ || (!IsAnLower( pFly ) &&
+ (!pAnchorCharFrame ||
!IsAnLower(pAnchorCharFrame)))) &&
// table isn't lower of fly
!pFly->IsAnLower( this ) &&
// fly is lower of fly, the table is in
@@ -2853,6 +2863,20 @@ bool SwTabFrame::CalcFlyOffsets( SwTwips& rUpper,
{
if (aRectFnSet.YDiff( nPrtPos, nBottom ) < 0)
nPrtPos = nBottom;
+ // tdf#116501 subtract flys blocking space from
below
+ // TODO this may not work ideally for multiple flys
+ if (pSpaceBelowBottom
+ &&
aRectFnSet.YDiff(aRectFnSet.GetBottom(aRect), nBottom) < 0)
+ {
+ if (aRectFnSet.YDiff(aRectFnSet.GetTop(aRect),
aRectFnSet.GetTop(aFlyRect)) < 0)
+ {
+ aRectFnSet.SetBottom(aRect,
aRectFnSet.GetTop(aFlyRect));
+ }
+ else
+ {
+ aRectFnSet.SetHeight(aRect, 0);
+ }
+ }
bInvalidatePrtArea = true;
}
}
@@ -2880,6 +2904,10 @@ bool SwTabFrame::CalcFlyOffsets( SwTwips& rUpper,
}
}
rUpper = aRectFnSet.YDiff( nPrtPos, aRectFnSet.GetTop(getFrameArea())
);
+ if (pSpaceBelowBottom)
+ {
+ *pSpaceBelowBottom = aRectFnSet.GetHeight(aRect);
+ }
}
return bInvalidatePrtArea;
@@ -2915,7 +2943,7 @@ void SwTabFrame::Format( vcl::RenderContext*
/*pRenderContext*/, const SwBorderA
// are right or left aligned, those set the minimum for the borders.
long nTmpRight = -1000000,
nLeftOffset = 0;
- if( CalcFlyOffsets( nUpper, nLeftOffset, nTmpRight ) )
+ if (CalcFlyOffsets(nUpper, nLeftOffset, nTmpRight, nullptr))
{
setFramePrintAreaValid(false);
}
@@ -3549,6 +3577,14 @@ bool SwTabFrame::ShouldBwdMoved( SwLayoutFrame
*pNewUpper, bool, bool &rReformat
const SwViewShell *pSh = getRootFrame()->GetCurrShell();
if( pSh && pSh->GetViewOptions()->getBrowseMode() )
nSpace += pNewUpper->Grow( LONG_MAX, true );
+ if (0 < nSpace && GetPrecede())
+ {
+ SwTwips nUpperDummy(0);
+ long nLeftOffsetDummy(0), nRightOffsetDummy(0);
+ // tdf#116501 check for no-wrap fly overlap
+ static_cast<const
SwTabFrame*>(GetPrecede())->CalcFlyOffsets(
+ nUpperDummy, nLeftOffsetDummy, nRightOffsetDummy,
&nSpace);
+ }
}
}
else if (!m_bLockBackMove)
commit 3857705b16a5cc2ae5c67a3b0501d922e6c70d6b
Author: Michael Stahl <[email protected]>
AuthorDate: Mon Jun 21 14:44:29 2021 +0200
Commit: Samuel Mehrbrodt <[email protected]>
CommitDate: Mon Jan 17 16:04:51 2022 +0100
sw: add BIRT layout test document
This nested table is an example that was broken by commit
91b2239783dc716bd71ce7962bfd7e341dfe4175 - if loaded with a wide window,
it goes into layout loop; if loaded with a tall window size where page
2 is visible, strangely it doesn't loop.
Change-Id: I5e73cfcd928ff1a321667c1a75b0ba7f348d4b77
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/117587
Tested-by: Jenkins
Reviewed-by: Michael Stahl <[email protected]>
(cherry picked from commit a41c71838d4662adf1ada9d46ec6e070cae7e695)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/117603
Reviewed-by: Xisco Fauli <[email protected]>
(cherry picked from commit 5e658c91a5d1e69e34384dd50ac8ada358ebd8ba)
diff --git a/sw/qa/extras/layout/data/birt_min.odt
b/sw/qa/extras/layout/data/birt_min.odt
new file mode 100644
index 000000000000..44bcecb976ff
Binary files /dev/null and b/sw/qa/extras/layout/data/birt_min.odt differ
diff --git a/sw/qa/extras/layout/layout.cxx b/sw/qa/extras/layout/layout.cxx
index 8d9f2a476f2a..0bd25d45b4b6 100644
--- a/sw/qa/extras/layout/layout.cxx
+++ b/sw/qa/extras/layout/layout.cxx
@@ -3437,6 +3437,12 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter,
testBtlrTableRowSpan)
assertXPathContent(pXmlDoc, "//textarray[1]/text", "USA");
}
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testBIRT)
+{
+ // this looped
+ load(DATA_DIRECTORY, "birt_min.odt");
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 38b51b53f025b1d76399b33ecf39746b820363d4
Author: Michael Stahl <[email protected]>
AuthorDate: Wed Jun 16 15:34:40 2021 +0200
Commit: Samuel Mehrbrodt <[email protected]>
CommitDate: Mon Jan 17 15:48:48 2022 +0100
Revert "tdf#116501 fix freezing at embedded text tables"
This reverts commit 91b2239783dc716bd71ce7962bfd7e341dfe4175.
This breaks documents that have many nested tables.
For example Eclipse BIRT generates reports with tables nested 8 levels
deep, they run into the counter in no time and, ironically, one goes
into a layout loop because of this counter.
Change-Id: I7451d01787903bbc60b305da3dc72f8259175e97
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/117472
Tested-by: Jenkins
Reviewed-by: Michael Stahl <[email protected]>
(cherry picked from commit ee042a371e98cdcc59848f0b953f1ce545e18e31)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/117601
Reviewed-by: Xisco Fauli <[email protected]>
(cherry picked from commit 0f026c6e7186ef57e5806348a320f8383dfb7dc7)
diff --git a/sw/source/core/inc/layact.hxx b/sw/source/core/inc/layact.hxx
index 2b1b17a4afd2..50335077694c 100644
--- a/sw/source/core/inc/layact.hxx
+++ b/sw/source/core/inc/layact.hxx
@@ -97,11 +97,6 @@ class SwLayAction
// OD 14.04.2003 #106346# - new flag for content formatting on interrupt.
bool mbFormatContentOnInterrupt;
- // for loop control by disabling in-row splitting within embedded tables
- const SwPageFrame *m_pCurPage;
- sal_uInt16 m_nTabLevel; // embedding level
- sal_uInt32 m_nCallCount; // calling FormatLayoutTab on the same page
-
void PaintContent( const SwContentFrame *, const SwPageFrame *,
const SwRect &rOldRect, long nOldBottom );
bool PaintWithoutFlys( const SwRect &, const SwContentFrame *,
diff --git a/sw/source/core/inc/tabfrm.hxx b/sw/source/core/inc/tabfrm.hxx
index cc57d46d8492..176396c6667a 100644
--- a/sw/source/core/inc/tabfrm.hxx
+++ b/sw/source/core/inc/tabfrm.hxx
@@ -84,8 +84,6 @@ class SwTabFrame: public SwLayoutFrame, public SwFlowFrame
bool m_bInRecalcLowerRow : 1;
- bool m_bSplitRowDisabled : 1; // loop control
-
/**
* Split() splits the Frame at the specified position: a Follow is
* created and constructed and inserted directly after this.
@@ -175,14 +173,6 @@ public:
{
m_bInRecalcLowerRow = bNew;
}
- bool IsSplitRowDisabled() const
- {
- return m_bSplitRowDisabled;
- }
- void SetSplitRowDisabled()
- {
- m_bSplitRowDisabled = true;
- }
// #i26945#
bool IsConsiderObjsForMinCellHeight() const
diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx
index 74fe4e85bcfd..96796cca4662 100644
--- a/sw/source/core/layout/layact.cxx
+++ b/sw/source/core/layout/layact.cxx
@@ -261,10 +261,7 @@ SwLayAction::SwLayAction( SwRootFrame *pRt, SwViewShellImp
*pI ) :
m_nStartTicks( std::clock() ),
m_nInputType( VclInputFlags::NONE ),
m_nEndPage( USHRT_MAX ),
- m_nCheckPageNum( USHRT_MAX ),
- m_pCurPage( nullptr ),
... etc. - the rest is truncated