/* -*- 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/.
*/
namespace
{ /// Test to assert layout / rendering result of Writer. class SwLayoutWriter3 : public SwModelTestBase
{ public:
SwLayoutWriter3()
: SwModelTestBase(u"/sw/qa/extras/layout/data/"_ustr)
{
}
};
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf134463)
{
createSwDoc("tdf134463.docx");
xmlDocUniquePtr pXmlDoc = parseLayoutDump(); // This was 621. The previous paragraph must have zero bottom border.
assertXPath(pXmlDoc, "/root/page/body/txt[3]/infos/prtBounds", "top", u"21");
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf117188)
{
createSwDoc("tdf117188.docx");
saveAndReload(u"writer8"_ustr);
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
OUString sWidth = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/bounds", "width");
OUString sHeight = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/bounds", "height"); // The text box must have zero border distances
assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/prtBounds", "left", u"0");
assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/prtBounds", "top", u"0");
assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/prtBounds", "width", sWidth);
assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/prtBounds", "height", sHeight);
}
// there should be no fly portions
assertXPath(
pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout/child::*[@nType='PortionType::Fly']", 0);
} #ifdefined _WIN32 && defined _ARM64_ // skip for windows arm64 build #else
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf119875)
{
createSwDoc("tdf119875.odt");
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
assertXPath(pXmlDoc, "//page[2]/body/section[1]", "formatName", u"S10");
assertXPath(pXmlDoc, "//page[2]/body/section[2]", "formatName", u"S11");
assertXPath(pXmlDoc, "//page[2]/body/section[3]", "formatName", u"S13");
assertXPath(pXmlDoc, "//page[2]/body/section[4]", "formatName", u"S14"); // Sections "S10" and "S13" are hidden -> their frames are zero-height
assertXPath(pXmlDoc, "//page[2]/body/section[1]/infos/bounds", "height", u"0");
assertXPath(pXmlDoc, "//page[2]/body/section[3]/infos/bounds", "height", u"0");
// Section "S11" had the same top value as section "S14", so they overlapped.
CPPUNIT_ASSERT_LESS(S14Top.toInt32(), S11Top.toInt32());
} #endif
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf137523)
{
createSwDoc("tdf137523-1-min.fodt");
xmlDocUniquePtr pXmlDoc = parseLayoutDump(); // the problem was that in the footer, the text frames below the table // had wrong height and were not visible
assertXPath(pXmlDoc, "/root/page/footer/txt[1]/infos/bounds", "height", u"304");
assertXPath(pXmlDoc, "/root/page/footer/txt[2]/infos/bounds", "height", u"191");
assertXPath(pXmlDoc, "/root/page/footer/txt[3]/infos/bounds", "height", u"219");
assertXPath(pXmlDoc, "/root/page/footer/tab/infos/bounds", "height", u"1378");
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf120287)
{
createSwDoc("tdf120287.fodt");
xmlDocUniquePtr pXmlDoc = parseLayoutDump(); // This was 2, TabOverMargin Word-specific compat flag did not imply // default-in-Word printer-independent layout, resulting in an additional // line break.
assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout", 1);
}
auto getXPathIntAttributeValue(xmlXPathContextPtr pXmlXpathCtx, charconst* const pXPath)
-> sal_Int32
{
xmlXPathObjectPtr pXmlXpathObj = xmlXPathEvalExpression(BAD_CAST(pXPath), pXmlXpathCtx);
CPPUNIT_ASSERT(pXmlXpathObj->nodesetval);
CPPUNIT_ASSERT_EQUAL(1, xmlXPathNodeSetGetLength(pXmlXpathObj->nodesetval)); auto ret
= sal_Int32(xmlXPathCastNodeToNumber(xmlXPathNodeSetItem(pXmlXpathObj->nodesetval, 0)));
xmlXPathFreeObject(pXmlXpathObj); return ret;
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf119908)
{
createSwDoc("tdf130088.docx"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump(); // Keep real width of the exceeding line portions to calculate shrinking
sal_Int32 nPortionWidth
= getXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[2]/SwLinePortion[2]", "width")
.toInt32(); // This was 5806 (not real portion width, but stripped to the line width)
CPPUNIT_ASSERT_GREATER(sal_Int32(5840), nPortionWidth);
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf158333)
{
createSwDoc("tdf130088.docx"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// shrink line 2
assertXPath(
pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[2]", "portion",
u"viverra odio. Donec auctor molestie sem, sit amet tristique lectus hendrerit sed. ");
// shrink line 7
assertXPath(
pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[7]", "portion", // This was "...diam ", not "...diam tempor "
u"laoreet vel leo nec, volutpat facilisis eros. Donec consequat arcu ut diam tempor ");
// shrink line 2 of paragraph 2
assertXPath(
pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout[2]", "portion", // This was "...Cras ", not "...Cras sodales "
u"Donec auctor molestie sem, sit amet tristique lectus hendrerit sed. Cras sodales ");
// shrink line 2 of paragraph 4
assertXPath(pXmlDoc, "/root/page/body/txt[4]/SwParaPortion/SwLineLayout[2]", "portion", // This was "...et ", not "...et magnis "
u"consequat arcu ut diam tempor luctus. Cum sociis natoque penatibus et magnis ");
// tdf#158776 don't shrink line 11 of paragraph 4
assertXPath(pXmlDoc, "/root/page/body/txt[4]/SwParaPortion/SwLineLayout[11]", "portion", // This was "...quis curcus ", not "...quis "
u"venenatis, quis commodo dolor posuere. Curabitur dignissim sapien quis ");
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf159085)
{
createSwDoc("tdf159085.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// This was "... cursus" instead of breaking the word at soft hyphen
assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[1]", "portion",
u"venenatis, quis commodo dolor posuere. Curabitur dignissim sapien quis cur");
// This was "... cursus" instead of breaking the word at soft hyphen
assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout[1]", "portion",
u"venenatis, quis commodo dolor posuere. Curabitur dignissim sapien quis cur");
}
// Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
// click at the end of the second line of the second paragraph // (a line shrunk by the new justification)
aPoint.setX(nSecondParaLeft + nSecondParaWidth);
aPoint.setY(nSecondParaTop + (nSecondParaHeight / 6) * 1.5);
SwCursorMoveState aState(CursorMoveState::NONE);
pLayout->GetModelPositionForViewPoint(&aPosition, aPoint, &aState); // Without the accompanying fix in place, this test would have failed: character position was 155, // i.e. cursor was before the end of the paragraph.
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(156), aPosition.GetContentIndex());
}
// Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
// click before the last but one character of the paragraph // (in a line shrunk by the new space shrinking justification)
aPoint.setX(nParaLeft + nParaWidth - 2 * nParaWidth / 160);
aPoint.setY(nParaTop + nParaHeight * 0.5);
SwCursorMoveState aState(CursorMoveState::NONE);
pLayout->GetModelPositionForViewPoint(&aPosition, aPoint, &aState); // Without the accompanying fix in place, this test would have failed: character position was 160, // i.e. cursor was at the end of the paragraph instead of the last but one character
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(158), aPosition.GetContentIndex());
}
// Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// There is only a single shrunk line 1, without breaking the last word // before the last text portion "i"
// This ends in "dolorsi" (not "dolors", as before)
assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[1]", "portion",
u"Quis pretium semper. Proin luctus orci a neque venenatis, quis commodo dolorsi");
// no second line (there was a second line with the text portion "i").
assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout", 1);
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf162109)
{
createSwDoc("tdf162109.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump(); // There was no SwGluePortion, because of missing justification of the last paragraph line, // despite it is a full line with shrunk spaces
assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[1]/SwGluePortion");
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf162220)
{
createSwDoc("tdf162220.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump(); // There was no SwGluePortion, because of missing justification of the last paragraph line, // despite it is a full line with shrunk spaces
assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[1]/SwGluePortion");
}
// Find the first text array action for (size_t nAction = 0; nAction < xMetaFile->GetActionSize(); nAction++)
{ auto pAction = xMetaFile->GetAction(nAction); if (pAction->GetType() == MetaActionType::TEXTARRAY)
{ auto pTextArrayAction = static_cast<MetaTextArrayAction*>(pAction); auto pDXArray = pTextArrayAction->GetDXArray();
// There should be 101 chars on the first line
CPPUNIT_ASSERT_EQUAL(size_t(101), pDXArray.size());
// Assert we are using the expected position for the last char // This was 10093, now 10003, according to the less shrinking, // than needed for the extra hyphen glyph at hyphenation
CPPUNIT_ASSERT_LESS(sal_Int32(10010), sal_Int32(pDXArray[100])); break;
}
}
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf162725)
{
createSwDoc("tdf162725.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump(); // There was no SwGluePortion, because of missing justification of the last paragraph line, // despite it is a full line with shrunk spaces
assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[1]/SwGluePortion");
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf161810)
{
createSwDoc("tdf161810.fodt"); // Ensure that all text portions are calculated before testing.
SwDocShell* pShell = getSwDocShell();
// Dump the rendering of the first page as an XML file.
std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
MetafileXmlDump dumper;
// Find the first text array action for (size_t nAction = 0; nAction < xMetaFile->GetActionSize(); nAction++)
{ auto pAction = xMetaFile->GetAction(nAction); if (pAction->GetType() == MetaActionType::TEXTARRAY)
{ auto pTextArrayAction = static_cast<MetaTextArrayAction*>(pAction); auto pDXArray = pTextArrayAction->GetDXArray();
// There should be 70 chars on the first line // (tdf#164499 no space shrinking in lines with tabulation)
CPPUNIT_ASSERT_EQUAL(size_t(70), pDXArray.size());
break;
}
}
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf164905)
{
createSwDoc("tdf164905.docx"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump(); // This was 9 (resulting broken ToC layout)
assertXPath(pXmlDoc, "//SwGluePortion", 3); // For example, it was an unnecessary glue portion here
assertXPath(pXmlDoc, "/root/page/body/section[2]/txt[1]/SwParaPortion/SwLineLayout/SwGluePortion", 0);
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf163149)
{
createSwDoc("tdf163149.docx"); // Ensure that all text portions are calculated before testing.
SwDocShell* pShell = getSwDocShell();
// Dump the rendering of the first page as an XML file.
std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
MetafileXmlDump dumper;
// Find the text array action for the second non-empty (shrunk) line bool bFirst = true; for (size_t nAction = 0; nAction < xMetaFile->GetActionSize(); nAction++)
{ auto pAction = xMetaFile->GetAction(nAction); if (pAction->GetType() == MetaActionType::TEXTARRAY)
{ auto pTextArrayAction = static_cast<MetaTextArrayAction*>(pAction); auto pDXArray = pTextArrayAction->GetDXArray();
// skip empty paragraphs if (pDXArray.size() <= 1) continue;
// skip first non-empty line if (bFirst)
{
bFirst = false; continue;
}
// There should be 46 chars on the second line
CPPUNIT_ASSERT_EQUAL(size_t(46), pDXArray.size());
// Assert we are using the expected position for the last char // This was 4673, now 4163, according to the fixed space shrinking
CPPUNIT_ASSERT_LESS(sal_Int32(4200), sal_Int32(pDXArray[45])); break;
}
}
}
// Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// no shrinking in tabulated text lines
// This was 1 (no line break in heading 2.5.5)
assertXPath(pXmlDoc, "/root/page[1]/body/section/txt[18]/SwParaPortion/SwLineLayout", 2); // line break in heading 2.5.5: the second line contains only the page number
assertXPath(pXmlDoc, "/root/page[1]/body/section/txt[18]/SwParaPortion/SwLineLayout[2]", "portion", u"*1");
}
createSwDoc("tdf132599_always.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// 2nd paragraph: hyphenated last full line
assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout[2]", "portion",
u"ent to any other celes");
// hyphenation-keep-type='always' // 3rd paragraph: not hyphenated last full line of the hyphenated paragraph
assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout[2]", "portion",
u"ent to any other ");
}
createSwDoc("tdf132599_frames_on_same_page_no_hyphenation.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// loext:hyphenation-keep-type="column" // 2nd frame: shifted hyphenated line (no hyphenation at the end of the first frame)
assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly[2]/txt/SwParaPortion/SwLineLayout[1]", "portion", u"space, ex");
}
createSwDoc("tdf132599_frames_on_same_page_hyphenation.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// loext:hyphenation-keep-type="page" // 2nd frame: not shifted hyphenated line (hyphenation at the end of the first frame), // This was "space, ex" (bad shifting)
assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly[2]/txt/SwParaPortion/SwLineLayout[1]", "portion", u"cept that it ");
}
createSwDoc("tdf132599_frames_on_right_pages_no_hyphenation.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// loext:hyphenation-keep-type="spread" // 2nd frame: shifted hyphenated line // This was "cept that it" (missing shifting)
assertXPath(pXmlDoc, "/root/page[3]/body/txt/anchored/fly/txt/SwParaPortion/SwLineLayout[1]", "portion", u"space, ex");
}
createSwDoc("tdf132599_frames_on_spread_hyphenation.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// loext:hyphenation-keep-type="spread" // 2nd frame on left page and 3rd frame on right page -> not shifted hyphenated line // 2nd frame: not shifted hyphenated line (hyphenation at the end of the first frame),
assertXPath(pXmlDoc, "/root/page[3]/body/txt/anchored/fly/txt/SwParaPortion/SwLineLayout[1]", "portion", u"cept that it ");
}
createSwDoc("tdf165354_page.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// loext:hyphenation-keep-line="true" // first: shifted hyphenated word
assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/SwParaPortion/SwLineLayout[9]", "portion",
u"except that it has an ");
}
createSwDoc("tdf165354_spread.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// loext:hyphenation-keep-line="true" // first: shifted hyphenated word at end of the spread (right page)
assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/SwParaPortion/SwLineLayout[9]", "portion",
u"except that it has an ");
}
createSwDoc("tdf165354_spread-left-page.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// loext:hyphenation-keep-line="true" // first: no shifted hyphenated word at the end of the first page of the spread (left page)
assertXPath(pXmlDoc, "/root/page[2]/body/txt[2]/SwParaPortion/SwLineLayout[9]", "portion",
u"except that it has an at");
}
createSwDoc("tdf165354_column.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// loext:hyphenation-keep-type="column" hyphenation-keep-line="true" // 2nd frame: shifted hyphenated word (no hyphenation at the end of the first column)
assertXPath(pXmlDoc, "/root/page[1]/body/section/column[2]/body/txt/SwParaPortion/SwLineLayout[1]", "portion", u"iner");
}
createSwDoc("tdf165354_page_in_last_column.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// loext:hyphenation-keep-type="page" hyphenation-keep-line="true" // the end line of the first page is a column boundary, // but at the page boundary, too, so disable its hyphenation // 2nd frame: shifted hyphenated word (no hyphenation at the end of the first column)
assertXPath(pXmlDoc, "/root/page[2]/body/section/column[1]/body/txt/SwParaPortion/SwLineLayout[1]", "portion", u"iner");
}
createSwDoc("tdf165354_page_in_not_last_column.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// loext:hyphenation-keep-type="page" hyphenation-keep-line="true" // 2nd frame: no shifted hyphenated word (hyphenation at the end of the first column)
assertXPath(pXmlDoc, "/root/page[1]/body/section/column[2]/body/txt/SwParaPortion/SwLineLayout[1]", "portion", u"tially. ");
}
createSwDoc("tdf165354_page_in_table.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// loext:hyphenation-keep-type="page" hyphenation-keep-line="true" // 2nd frame: no shifted hyphenated word (hyphenation at the end of the first column)
assertXPath(pXmlDoc, "/root/page[2]/body/tab/row/cell/txt/SwParaPortion/SwLineLayout[1]", "portion", u"atmosphere. The Earth ");
}
createSwDoc("tdf165354_frames_on_same_page_no_hyphenation.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// loext:hyphenation-keep-type="column" hyphenation-keep-line="true" // 2nd frame: shifted hyphenated word (no hyphenation at the end of the first frame)
assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly[2]/txt/SwParaPortion/SwLineLayout[1]", "portion", u"except that ");
}
createSwDoc("tdf165354_frames_on_same_page_hyphenation.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// loext:hyphenation-keep-type="page" hyphenation-keep-line="true" // 2nd frame: not shifted hyphenated word (hyphenation at the end of the first frame),
assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly[2]/txt/SwParaPortion/SwLineLayout[1]", "portion", u"cept that it ");
}
createSwDoc("tdf165354_frames_on_spread_hyphenation.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// loext:hyphenation-keep-type="spread" hyphenation-keep-line="true" // 2nd frame on left page and 3rd frame on right page -> not shifted hyphenated word // 2nd frame: not shifted hyphenated word (hyphenation at the end of the first frame),
assertXPath(pXmlDoc, "/root/page[3]/body/txt/anchored/fly/txt/SwParaPortion/SwLineLayout[1]", "portion", u"cept that it ");
}
createSwDoc("tdf165354_frames_on_right_pages_no_hyphenation.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// loext:hyphenation-keep-line="true" // It was "space, ex": missing layout update of the last line with disabled hyphenation
assertXPath(pXmlDoc, "/root/page[1]/body/txt/anchored/fly/txt/SwParaPortion/SwLineLayout[12]", "portion", u"space, ");
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf165354_long_paragraph)
{ // disabled hyphenation on page 1 (no hyphenation at all on page 2, // only in first line of page 3, which resulted broken layout)
uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator(); if (!xHyphenator->hasLocale(lang::Locale(u"en"_ustr, u"US"_ustr, OUString()))) return;
createSwDoc("tdf165354_long_paragraph.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// 3-page paragraph, loext:hyphenation-keep-line="true" // This started with "tially" (not disabled hyphenation, because of // the first hyphenated line on the third page)
assertXPath(pXmlDoc, "/root/page[2]/body/txt/SwParaPortion/SwLineLayout[1]", "portion",
u"inertially. Even just one ");
assertXPath(pXmlDoc, "/root/page[2]/body/txt/SwParaPortion/SwLineLayout[12]", "portion",
u"of the Earth is space, ");
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf165354_long_paragraph_2)
{ // disabled hyphenation on page 1 and page 2
uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator(); if (!xHyphenator->hasLocale(lang::Locale(u"en"_ustr, u"US"_ustr, OUString()))) return;
createSwDoc("tdf165354_long_paragraph_2.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// 3-page paragraph, loext:hyphenation-keep-line="true" // This started with "tially" (not disabled hyphenation, because of // the first hyphenated line on the third page)
assertXPath(pXmlDoc, "/root/page[2]/body/txt/SwParaPortion/SwLineLayout[1]", "portion",
u"inertially. Even just one ");
// disabled hyphenation by loext:hyphenation-keep-type="page"
assertXPath(pXmlDoc, "/root/page[2]/body/txt/SwParaPortion/SwLineLayout[12]", "portion",
u"of the Earth is space ");
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf165354_long_paragraph_3)
{ // disabled hyphenation on page 1, enabled on page 2
uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator(); if (!xHyphenator->hasLocale(lang::Locale(u"en"_ustr, u"US"_ustr, OUString()))) return;
createSwDoc("tdf165354_long_paragraph_3.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// 3-page paragraph, loext:hyphenation-keep-line="true" // This started with "tially" (not disabled hyphenation, because of // the first hyphenated line on the third page)
assertXPath(pXmlDoc, "/root/page[2]/body/txt/SwParaPortion/SwLineLayout[1]", "portion",
u"inertially. Even just one ");
// not disabled hyphenation by loext:hyphenation-keep-type="spread"
assertXPath(pXmlDoc, "/root/page[2]/body/txt/SwParaPortion/SwLineLayout[12]", "portion",
u"of the Earth is space ex");
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf165984)
{ // enabled hyphenation on page 1, disabled on page 2 by hyphenation-zone-page // (no hyphenation, if the word part is completely inside the Page end zone: // "iner-tially", but "except" and not "ex-cept")
uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator(); if (!xHyphenator->hasLocale(lang::Locale(u"en"_ustr, u"US"_ustr, OUString()))) return;
createSwDoc("tdf165984.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// paragraph with loext:hyphenation-zone-paragraph="7.62cm" // This was "tially. Even" (now disabled hyphenation in the last full paragraph line)
assertXPath(pXmlDoc, "/root/page[1]/body/txt/SwParaPortion/SwLineLayout[6]", "portion",
u"inertially. Even");
// 3-page paragraph, loext:hyphenation-zone-page="5.08cm"
assertXPath(pXmlDoc, "/root/page[2]/body/txt/SwParaPortion/SwLineLayout[1]", "portion",
u"tially. Even just one ");
// disabled hyphenation by hyphenation-zone-page="5.08cm" // This ended with "ex-"
assertXPath(pXmlDoc, "/root/page[2]/body/txt/SwParaPortion/SwLineLayout[12]", "portion",
u"of the Earth is space ");
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf126154)
{ // minimum, desired and maximum word spacing
uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator(); if (!xHyphenator->hasLocale(lang::Locale(u"en"_ustr, u"US"_ustr, OUString()))) return;
createSwDoc("tdf126154.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// only desired word space: 100%, 100%, 100% // 5 lines are hyphenated
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[2]/SwParaPortion/SwLineLayout[1]", "portion",
u",, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bulum ");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[3]/SwParaPortion/SwLineLayout[1]", "portion",
u",,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bu");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[4]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bu");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[5]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bu");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[6]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bu");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[7]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bu");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[8]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti ");
// also minimum word space: 80%, 100%, 100% // only a single line was hyphenated from the previous ones // TODO: fix possible interoperability issues, allow optional limitation of hyphenation again
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[10]/SwParaPortion/SwLineLayout[1]", "portion",
u",, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bulum "); // This was "... bulum c" (more shrinking, than needed to remove hyphenation)
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[11]/SwParaPortion/SwLineLayout[1]", "portion",
u",,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bulum ");
assertXPath(pXmlDoc, "/root/page[1]/body/txt[12]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
u"Vesti bulum ");
assertXPath(pXmlDoc, "/root/page[1]/body/txt[13]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
u"Vesti bu");
assertXPath(pXmlDoc, "/root/page[1]/body/txt[14]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
u"Vesti bu");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[15]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bu");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[16]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti ");
// minimum, desired and maximum word spacing: 80%, 100%, 133% // no hyphenation in the same text: hyphenation of all the short words were limited // by the minimum and maximum word spacing settings // TODO: fix possible interoperability issues, allow optional limitation of hyphenation again
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[18]/SwParaPortion/SwLineLayout[1]", "portion",
u",, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bulum "); // This was "... bulum c" (more shrinking, than needed to remove hyphenation)
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[19]/SwParaPortion/SwLineLayout[1]", "portion",
u",,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bulum ");
assertXPath(pXmlDoc, "/root/page[1]/body/txt[20]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
u"Vesti bulum ");
assertXPath(pXmlDoc, "/root/page[1]/body/txt[21]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
u"Vesti bu");
assertXPath(pXmlDoc, "/root/page[1]/body/txt[22]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
u"Vesti bu");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[23]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti ");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[24]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti ");
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf106234)
{
createSwDoc("tdf106234.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump(); // In justified paragraphs, there is justification between left tabulators and manual line breaks
assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[1]/SwGluePortion", "type", u"PortionType::Margin");
assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout[1]/SwGluePortion", "width", u"0"); // but not after centered, right and decimal tabulators
assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout[1]/SwGluePortion", "type", u"PortionType::Margin"); // This was a justified line, without width
assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout[1]/SwGluePortion", "width", u"7882");
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf126154_minimum_shrinking)
{ // minimum, desired and maximum word spacing
uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator(); if (!xHyphenator->hasLocale(lang::Locale(u"en"_ustr, u"US"_ustr, OUString()))) return;
createSwDoc("tdf126154_minimum_shrinking.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// only desired word space: 100%, 100%, 100% // 5 lines are hyphenated
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[2]/SwParaPortion/SwLineLayout[1]", "portion",
u",, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bulum ");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[3]/SwParaPortion/SwLineLayout[1]", "portion",
u",,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bu");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[4]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bu");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[5]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bu");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[6]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bu");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[7]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bu");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[8]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti ");
// also minimum word space: 80%, 100%, 100% // only a single line was yphenated from the previous ones // TODO: fix possible interoperability issues, allow optional limitation of hyphenation again
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[10]/SwParaPortion/SwLineLayout[1]", "portion",
u",, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bulum ");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[11]/SwParaPortion/SwLineLayout[1]", "portion",
u",,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bulum ");
assertXPath(pXmlDoc, "/root/page[1]/body/txt[12]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
u"Vesti bulum ");
assertXPath(pXmlDoc, "/root/page[1]/body/txt[13]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
u"Vesti bu");
assertXPath(pXmlDoc, "/root/page[1]/body/txt[14]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
u"Vesti bu");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[15]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bu");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[16]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti ");
// minimum, desired and maximum word spacing: 80%, 100%, 133% // no hyphenation in the same text: hyphenation of all the short words were limited // by the minimum and maximum word spacing settings // TODO: fix possible interoperability issues, allow optional limitation of hyphenation again
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[18]/SwParaPortion/SwLineLayout[1]", "portion",
u",, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bulum ");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[19]/SwParaPortion/SwLineLayout[1]", "portion",
u",,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti bulum ");
assertXPath(pXmlDoc, "/root/page[1]/body/txt[20]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
u"Vesti bulum ");
assertXPath(pXmlDoc, "/root/page[1]/body/txt[21]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
u"Vesti bu");
assertXPath(pXmlDoc, "/root/page[1]/body/txt[22]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
u"Vesti bu");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[23]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti ");
assertXPath(
pXmlDoc, "/root/page[1]/body/txt[24]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,,,,, , , , , , , , Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vesti ");
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf126154_portion)
{ // text portions with word spacing, paragraph end zone and hyphenation zone
uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator(); if (!xHyphenator->hasLocale(lang::Locale(u"en"_ustr, u"US"_ustr, OUString()))) return;
createSwDoc("tdf126154_portion.fodt"); // Ensure that all text portions are calculated before testing.
SwViewShell* pViewShell = getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
CPPUNIT_ASSERT(pViewShell);
pViewShell->Reformat();
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// only maximum word spacing: 133% // This was "... Vesti bu" (not disabled hyphenation because of text portion)
assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,,,,,,,,,,,,,,,,,, , , , , , , , , , , , , , , , Lorem ipsum dolor sit amet, "
u"consectetur adipiscing elit. Vesti ");
// minimum: 80%, desired: 100%, maximum word spacing: 133% // prefer maximum word spacing, not minimum word spacing, if the weighted word space // is nearer to the desired word space
assertXPath(pXmlDoc, "/root/page[1]/body/txt[4]/SwParaPortion/SwLineLayout[1]", "portion",
u",,,,,,,,,,,,,,,,,,,,, , , , , , , , , , , , , , , , Lorem ipsum dolor sit amet, "
u"consectetur adipiscing elit. Vesti ");
// paragraph end zone // This was "... other celes" (not disabled hyphenation because of text portion)
assertXPath(pXmlDoc, "/root/page[1]/body/txt[6]/SwParaPortion/SwLineLayout[8]", "portion",
u"cally atmospherically atmospherically atmospherically. The Earth is no different "
u"to any other ");
// hyphenation // This was "... other celes" (not disabled hyphenation because of text portion)
assertXPath(pXmlDoc, "/root/page[1]/body/txt[8]/SwParaPortion/SwLineLayout[8]", "portion",
u"cally atmospherically atmospherically atmospherically. The Earth is no different "
u"to any other ");
}
// the problem was that the first entry was on page 7, 2nd on page 9 etc.
assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[1]/SwParaPortion/SwLineLayout/SwLinePortion[1]", "portion", u"Foo");
assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[1]/SwParaPortion/SwLineLayout/SwLinePortion[2]", "portion", u"5");
assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[2]/SwParaPortion/SwLineLayout/SwLinePortion[1]", "portion", u"bar");
assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[2]/SwParaPortion/SwLineLayout/SwLinePortion[2]", "portion", u"7");
assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[3]/SwParaPortion/SwLineLayout/SwLinePortion[1]", "portion", u"Three");
assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[3]/SwParaPortion/SwLineLayout/SwLinePortion[2]", "portion", u"7");
// check first content page has the footnotes
assertXPath(pXmlDoc, "/root/page[5]/body/txt[1]/SwParaPortion/SwLineLayout", "portion", u"Foo");
assertXPath(pXmlDoc, "/root/page[4]/ftncont", 0);
assertXPath(pXmlDoc, "/root/page[5]/ftncont/ftn", 5);
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf120287b)
{
createSwDoc("tdf120287b.fodt");
xmlDocUniquePtr pXmlDoc = parseLayoutDump(); // This was 1418, TabOverMargin did the right split of the paragraph to two // lines, but then calculated a too large tab portion size on the first // line.
assertXPath(
pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[@type='PortionType::TabRight']", "width", u"1");
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf120287c)
{
createSwDoc("tdf120287c.fodt");
xmlDocUniquePtr pXmlDoc = parseLayoutDump(); // This was 3, the second line was broken into a 2nd and a 3rd one, // not rendering text outside the paragraph frame like Word 2013 does.
assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout", 2);
}
// Word 2013 puts all tabs into one line, the last 8 of them are off the page
assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout", 1);
assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout/" "child::*[@type='PortionType::TabCenter']",
1);
assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout/" "child::*[@type='PortionType::TabRight']",
1);
assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout/" "child::*[@type='PortionType::TabLeft']",
9);
}
// Word 2013 puts all tabs and the field following into one line // and also puts the field off the page
assertXPath(pXmlDoc, "/root/page[1]/footer/txt[1]/SwParaPortion/SwLineLayout", 1);
assertXPath(pXmlDoc, "/root/page[1]/footer/txt[1]/SwParaPortion/SwLineLayout/" "child::*[@type='PortionType::TabCenter']",
1);
assertXPath(pXmlDoc, "/root/page[1]/footer/txt[1]/SwParaPortion/SwLineLayout/" "child::*[@type='PortionType::TabRight']",
1);
assertXPath(pXmlDoc, "/root/page[1]/footer/txt[1]/SwParaPortion/SwLineLayout/" "child::*[@type='PortionType::TabRight']", "width", u"4446"); // was very small: 24
assertXPath(pXmlDoc, "/root/page[1]/footer/txt[1]/SwParaPortion/SwLineLayout/" "child::*[@type='PortionType::TabLeft']",
0);
}
// Word 2013 puts all tabs into one line, the last 17 of them are off the page
assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout", 1);
assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout/" "child::*[@type='PortionType::TabCenter']",
1); // the right tab is exactly at the margin of the paragraph
assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout/" "child::*[@type='PortionType::TabRight']",
1);
assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout/" "child::*[@type='PortionType::TabLeft']",
20);
}
{
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
assertXPath(pXmlDoc, "/root/page[2]/body/txt", 6);
assertXPath(pXmlDoc, "/root/page[2]/body/txt[6]/SwParaPortion/SwLineLayout", 2);
assertXPath(pXmlDoc, "/root/page[2]/body/txt[6]/SwParaPortion/SwLineLayout[2]", "portion",
u"long as two lines.");
assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/SwParaPortion/SwLineLayout", 3);
assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/SwParaPortion/SwLineLayout[1]", "portion",
u"This paragraph is even longer so that ");
}
// this should bring one line back
xStyle->setPropertyValue(u"ParaTopMargin"_ustr, uno::Any(sal_Int32(200)));
Scheduler::ProcessEventsToIdle();
{
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
assertXPath(pXmlDoc, "/root/page[2]/body/txt", 7);
assertXPath(pXmlDoc, "/root/page[2]/body/txt[7]/SwParaPortion/SwLineLayout", 1);
assertXPath(pXmlDoc, "/root/page[2]/body/txt[7]/SwParaPortion/SwLineLayout[1]", "portion",
u"This paragraph is even longer so that ");
assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/SwParaPortion/SwLineLayout", 2);
assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/SwParaPortion/SwLineLayout[1]", "portion",
u"it is now three lines long though ");
}
// this should bring second line back
xStyle->setPropertyValue(u"ParaTopMargin"_ustr, uno::Any(sal_Int32(120)));
Scheduler::ProcessEventsToIdle();
{
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
assertXPath(pXmlDoc, "/root/page[2]/body/txt", 7);
assertXPath(pXmlDoc, "/root/page[2]/body/txt[7]/SwParaPortion/SwLineLayout", 2);
assertXPath(pXmlDoc, "/root/page[2]/body/txt[7]/SwParaPortion/SwLineLayout[1]", "portion",
u"This paragraph is even longer so that ");
assertXPath(pXmlDoc, "/root/page[2]/body/txt[7]/SwParaPortion/SwLineLayout[2]", "portion",
u"it is now three lines long though ");
assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/SwParaPortion/SwLineLayout", 1);
assertXPath(pXmlDoc, "/root/page[3]/body/txt[1]/SwParaPortion/SwLineLayout[1]", "portion",
u"containing a single sentence.");
}
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf122878)
{
createSwDoc("tdf122878.docx");
xmlDocUniquePtr pXmlDoc = parseLayoutDump(); const sal_Int32 nTblTop
= getXPath(pXmlDoc, "/root/page[1]/footer/txt/anchored/fly/tab/infos/bounds", "top")
.toInt32();
SwDoc* pDoc = getSwDoc();
SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); auto pPage1 = dynamic_cast<SwPageFrame*>(pLayout->Lower());
CPPUNIT_ASSERT(pPage1);
SwFrame* pBody = pPage1->FindBodyCont(); for (SwFrame* pFrame = pBody->GetLower(); pFrame; pFrame = pFrame->GetNext())
{ const sal_Int32 nTxtBottom = pFrame->getFrameArea().Bottom(); // No body paragraphs should overlap the table in the footer
CPPUNIT_ASSERT_MESSAGE(
OString("testing paragraph #" + OString::number(pFrame->GetFrameId())).getStr(),
nTxtBottom <= nTblTop);
}
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf122607_regression)
{ // 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(u"Hidden"_ustr, -1, uno::Any(true),
beans::PropertyState_DIRECT_VALUE) },
};
// inline the loading because currently properties can't be passed...
OUString const url(createFileURL(u"tdf122607_leerzeile.odt"));
loadWithParams(url, comphelper::containerToSequence(aFilterOptions));
save(u"writer_pdf_Export"_ustr);
xmlDocUniquePtr 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", "mbFixSize",
u"false");
assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[1]/infos/bounds", "top", u"2977");
assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[1]/infos/bounds", "height", u"241");
assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[2]/infos/bounds", "mbFixSize",
u"true"); // this was 3034, causing the overlap
assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[2]/infos/bounds", "top", u"3218");
assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[2]/infos/bounds", "height", u"164");
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, TestTdf150616)
{ // 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(u"Hidden"_ustr, -1, uno::Any(true),
beans::PropertyState_DIRECT_VALUE) },
};
// inline the loading because currently properties can't be passed...
OUString const url(createFileURL(u"in_056132_mod.odt"));
loadWithParams(url, comphelper::containerToSequence(aFilterOptions));
save(u"writer_pdf_Export"_ustr);
// Dump the rendering of the first page as an XML file.
std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
MetafileXmlDump dumper;
xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
CPPUNIT_ASSERT(pXmlDoc);
// Without the accompanying fix in place, this test would have failed, as // the orientation was 0 (layout did not take btlr direction request from // doc model).
assertXPath(pXmlDoc, "//font[1]", "orientation", u"900");
#if !defined(MACOSX) && !defined(_WIN32) // macOS fails with x == 2662 for some reason. // Without the accompanying fix in place, this test would have failed with 'Expected: 1915; // Actual : 1756', i.e. the AAA1 text was too close to the left cell border due to an ascent vs // descent mismatch when calculating the baseline offset of the text portion.
assertXPath(pXmlDoc, "//textarray[1]", "x", u"1915");
assertXPath(pXmlDoc, "//textarray[1]", "y", u"2707");
// Without the accompanying fix in place, this test would have failed with 'Expected: 1979; // Actual : 2129', i.e. the gray background of the "AAA2." text was too close to the right edge // of the text portion. Now it's exactly behind the text portion.
assertXPath(pXmlDoc, "(//rect)[2]", "left", u"1979");
// Without the accompanying fix in place, this test would have failed with 'Expected: 269; // Actual : 0', i.e. the AAA2 frame was not visible due to 0 width.
pXmlDoc = parseLayoutDump();
assertXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "width", u"269");
// Test the position of the cursor after doc load. // We expect that it's inside the first text frame in the first cell. // More precisely, this is a bottom to top vertical frame, so we expect it's at the start, which // means it's at the lower half of the text frame rectangle (vertically).
SwWrtShell* pWrtShell = pShell->GetWrtShell();
CPPUNIT_ASSERT(pWrtShell);
const SwRect& rCharRect = pWrtShell->GetCharRect();
SwTwips nFirstParaTop
= getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[1]/infos/bounds", "top").toInt32();
SwTwips nFirstParaHeight
= getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[1]/infos/bounds", "height")
.toInt32();
SwTwips nFirstParaMiddle = nFirstParaTop + nFirstParaHeight / 2;
SwTwips nFirstParaBottom = nFirstParaTop + nFirstParaHeight; // Without the accompanying fix in place, this test would have failed: the lower half (vertical) // range was 2273 -> 2835, the good vertical position is 2730, the bad one was 1830.
CPPUNIT_ASSERT_GREATER(nFirstParaMiddle, rCharRect.Top());
CPPUNIT_ASSERT_LESS(nFirstParaBottom, rCharRect.Top());
// Save initial cursor position.
SwPosition aCellStart = *pWrtShell->GetCursor()->Start();
// Test that pressing "up" at the start of the cell goes to the next character position.
SwNodeOffset nNodeIndex = pWrtShell->GetCursor()->Start()->GetNodeIndex();
sal_Int32 nIndex = pWrtShell->GetCursor()->Start()->GetContentIndex();
KeyEvent aKeyEvent(0, KEY_UP);
SwEditWin& rEditWin = pShell->GetView()->GetEditWin();
rEditWin.KeyInput(aKeyEvent);
Scheduler::ProcessEventsToIdle(); // Without the accompanying fix in place, this test would have failed: "up" was interpreted as // logical "left", which does nothing if you're at the start of the text anyway.
CPPUNIT_ASSERT_EQUAL(nIndex + 1, pWrtShell->GetCursor()->Start()->GetContentIndex());
// Test that pressing "right" goes to the next paragraph (logical "down").
sal_Int32 nContentIndex = pWrtShell->GetCursor()->Start()->GetContentIndex();
aKeyEvent = KeyEvent(0, KEY_RIGHT);
rEditWin.KeyInput(aKeyEvent);
Scheduler::ProcessEventsToIdle(); // Without the accompanying fix in place, this test would have failed: the cursor went to the // paragraph after the table.
CPPUNIT_ASSERT_EQUAL(nNodeIndex + 1, pWrtShell->GetCursor()->Start()->GetNodeIndex());
// Test that we have the correct character index after traveling to the next paragraph. // Without the accompanying fix in place, this test would have failed: char position was 5, i.e. // the cursor jumped to the end of the paragraph for no reason.
CPPUNIT_ASSERT_EQUAL(nContentIndex, pWrtShell->GetCursor()->Start()->GetContentIndex());
// Test that clicking "below" the second paragraph positions the cursor at the start of the // second paragraph.
SwDoc* pDoc = getSwDoc();
SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
SwPosition aPosition(aCellStart);
SwTwips nSecondParaLeft
= getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "left")
.toInt32();
SwTwips nSecondParaWidth
= getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "width")
.toInt32();
SwTwips nSecondParaTop
= getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "top").toInt32();
SwTwips nSecondParaHeight
= getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "height")
.toInt32();
Point aPoint;
aPoint.setX(nSecondParaLeft + nSecondParaWidth / 2);
aPoint.setY(nSecondParaTop + nSecondParaHeight - 100);
SwCursorMoveState aState(CursorMoveState::NONE);
pLayout->GetModelPositionForViewPoint(&aPosition, aPoint, &aState);
CPPUNIT_ASSERT_EQUAL(aCellStart.GetNodeIndex() + 1, aPosition.GetNodeIndex()); // Without the accompanying fix in place, this test would have failed: character position was 5, // i.e. cursor was at the end of the paragraph.
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), aPosition.GetContentIndex());
// Test that the selection rectangles are inside the cell frame if we select all the cell // content.
SwTwips nCellLeft
= getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/infos/bounds", "left").toInt32();
SwTwips nCellWidth
= getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/infos/bounds", "width").toInt32();
SwTwips nCellTop
= getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/infos/bounds", "top").toInt32();
SwTwips nCellHeight
= getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/infos/bounds", "height").toInt32();
SwRect aCellRect(Point(nCellLeft, nCellTop), Size(nCellWidth, nCellHeight));
pWrtShell->SelAll();
SwShellCursor* pShellCursor = pWrtShell->getShellCursor(/*bBlock=*/false);
CPPUNIT_ASSERT(!pShellCursor->empty()); // Without the accompanying fix in place, this test would have failed with: // selection rectangle 269x2573@(1970,2172) is not inside cell rectangle 3207x1134@(1593,1701) // i.e. the selection went past the bottom border of the cell frame. for (constauto& rRect : *pShellCursor)
{
std::stringstream ss;
ss << "selection rectangle " << rRect << " is not inside cell rectangle " << aCellRect;
CPPUNIT_ASSERT_MESSAGE(ss.str(), aCellRect.Contains(rRect));
}
// Make sure that the correct rectangle gets repainted on scroll.
SwFrame* pPageFrame = pLayout->GetLower();
CPPUNIT_ASSERT(pPageFrame->IsPageFrame());
SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pFrame);
pTextFrame->SwapWidthAndHeight(); // Mimic what normally SwTextFrame::PaintSwFrame() does:
SwRect aRect(4207, 2273, 269, 572);
pTextFrame->SwitchVerticalToHorizontal(aRect); // Without the accompanying fix in place, this test would have failed with: // Expected: 572x269@(1691,4217) // Actual : 572x269@(2263,4217) // i.e. the paint rectangle position was incorrect, text was not painted on scrolling up.
CPPUNIT_ASSERT_EQUAL(SwRect(1691, 4217, 572, 269), aRect); #endif
}
// Make sure spellchecker has done its job already
Scheduler::ProcessEventsToIdle();
uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator(); if (!xHyphenator->hasLocale(lang::Locale("de", "DE", OUString()))) return;
xmlDocUniquePtr pXmlDoc = parseLayoutDump(); // Make sure that the arrow on the left is not there (the first portion's type is // PortionType::Arrow if it's there)
assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/txt/SwParaPortion/SwLineLayout[1]/child::*[1]", "type", u"PortionType::Text");
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf123651)
{
createSwDoc("tdf123651.docx");
xmlDocUniquePtr pXmlDoc = parseLayoutDump(); // Without the accompanying fix in place, this test would have failed with 'Expected: 7639; // Actual: 12926'. The shape was below the second "Lorem ipsum" text, not above it. const sal_Int32 nTopValue
= getXPath(pXmlDoc, "//anchored/SwAnchoredDrawObject/bounds", "top").toInt32();
CPPUNIT_ASSERT_DOUBLES_EQUAL(7639, nTopValue, 10);
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf116501)
{ //just care it doesn't freeze
createSwDoc("tdf116501.odt");
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf123163)
{ //just care it doesn't assert
createSwDoc("tdf123163-1.docx");
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testAbi11870)
{ //just care it doesn't assert
createSwDoc("abi11870-2.odt");
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testOfz64109)
{ //just care it doesn't assert
createSwDoc("ofz64109-1.fodt");
}
// Without the accompanying fix in place, this test would have failed, as the height of the // first page was 15840 twips, instead of the much smaller 276.
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
sal_Int32 nOther = getXPath(pXmlDoc, "/root/page[1]/infos/bounds", "height").toInt32();
sal_Int32 nLast = getXPath(pXmlDoc, "/root/page[2]/infos/bounds", "height").toInt32();
CPPUNIT_ASSERT_GREATER(nOther, nLast);
}
// 2nd paragraph has a tab over the right margin, and with the TabOverMargin compat option, // there is enough space to have all content in a single line. // Without the accompanying fix in place, this test would have failed, there were 2 lines.
assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout", 1);
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testImageComment)
{ // Load a document that has "aaa" in it, then a commented image (4th char is the as-char image, // 5th char is the comment anchor).
createSwDoc("image-comment.odt");
SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
// Look up a layout position which is on the right of the image.
SwRootFrame* pRoot = pWrtShell->GetLayout();
CPPUNIT_ASSERT(pRoot->GetLower()->IsPageFrame());
SwPageFrame* pPage = static_cast<SwPageFrame*>(pRoot->GetLower());
CPPUNIT_ASSERT(pPage->GetLower()->IsBodyFrame());
SwBodyFrame* pBody = static_cast<SwBodyFrame*>(pPage->GetLower());
CPPUNIT_ASSERT(pBody->GetLower()->IsTextFrame());
SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pBody->GetLower());
CPPUNIT_ASSERT(pTextFrame->GetDrawObjs());
SwSortedObjs& rDrawObjs = *pTextFrame->GetDrawObjs();
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rDrawObjs.size());
SwAnchoredObject* pDrawObj = rDrawObjs[0]; const SwRect aDrawObjRect = pDrawObj->GetObjRect();
Point aPoint = aDrawObjRect.Center();
aPoint.setX(aPoint.getX() + aDrawObjRect.Width() / 2);
// Ask for the doc model pos of this layout point.
SwPosition aPosition(*pTextFrame->GetTextNodeForFirstText());
pTextFrame->GetModelPositionForViewPoint(&aPosition, aPoint);
// Without the accompanying fix in place, this test would have failed with: // - Expected: 5 // - Actual : 4 // i.e. the cursor got positioned between the image and its comment, so typing extended the // comment, instead of adding content after the commented image.
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(5), aPosition.GetContentIndex());
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testScriptField)
{ // Test clicking script field inside table ( tdf#141079 )
createSwDoc("tdf141079.odt");
SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
// Look up layout position which is the first cell in the table
SwRootFrame* pRoot = pWrtShell->GetLayout();
CPPUNIT_ASSERT(pRoot->GetLower()->IsPageFrame());
SwPageFrame* pPage = static_cast<SwPageFrame*>(pRoot->GetLower());
CPPUNIT_ASSERT(pPage->GetLower()->IsBodyFrame());
SwBodyFrame* pBody = static_cast<SwBodyFrame*>(pPage->GetLower());
CPPUNIT_ASSERT(pBody->GetLower()->IsTextFrame());
SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pBody->GetLower());
CPPUNIT_ASSERT(pTextFrame->GetNext()->IsTabFrame());
SwFrame* pTable = pTextFrame->GetNext();
SwFrame* pRow1 = pTable->GetLower();
CPPUNIT_ASSERT(pRow1->GetLower()->IsCellFrame());
SwFrame* pCell1 = pRow1->GetLower();
CPPUNIT_ASSERT(pCell1->GetLower()->IsTextFrame());
SwTextFrame* pCellTextFrame = static_cast<SwTextFrame*>(pCell1->GetLower()); const SwRect& rCellRect = pCell1->getFrameArea();
Point aPoint = rCellRect.Center();
aPoint.setX(aPoint.getX() - rCellRect.Width() / 2);
// Ask for the doc model pos of this layout point.
SwPosition aPosition(*pCellTextFrame->GetTextNodeForFirstText());
pCellTextFrame->GetModelPositionForViewPoint(&aPosition, aPoint);
// Position was 1 without the fix from tdf#141079
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), aPosition.GetContentIndex());
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testCommentCursorPosition)
{ // Load a document that has "aaa" in it, followed by three comments.
createSwDoc("endOfLineComments.odt");
SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
// Set a point in the whitespace past the end of the first line.
Point aPoint = pWrtShell->getShellCursor(false)->GetSttPos();
aPoint.setX(aPoint.getX() + 10000);
// Ask for the doc model pos of this layout point.
SwPosition aPosition(*pTextFrame->GetTextNodeForFirstText());
pTextFrame->GetModelPositionForViewPoint(&aPosition, aPoint);
// Without the accompanying fix in place, this test would have failed with: // - Expected: 6 // - Actual : 3 or 4 // i.e. the cursor got positioned before the comments, // so typing extended the first comment instead of adding content after the comments.
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(6), aPosition.GetContentIndex()); // The second line is also important, but can't be auto-tested // since the failing situation depends on GetViewWidth which is zero in the headless tests. // bb<comment>| - the cursor should move behind the |, not before it.
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testCombiningCharacterCursorPosition)
{ // Load a document that has "a" in it, followed by a combining acute in a separate rext span
createSwDoc("tdf138592-a-acute.fodt");
SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
// Set a point in the whitespace past the end of the first line.
Point aPoint = pWrtShell->getShellCursor(false)->GetSttPos();
aPoint.AdjustX(10000);
// Ask for the doc model pos of this layout point.
SwPosition aPosition(*pTextFrame->GetTextNodeForFirstText());
pTextFrame->GetModelPositionForViewPoint(&aPosition, aPoint);
// Without the accompanying fix in place, this test would have failed with: // - Expected: 2 // - Actual : 1 // i.e. the cursor got positioned before the acute, so typing shifted the acute (applying it // to newly typed characters) instead of adding content after it.
CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aPosition.GetContentIndex());
}
// Dump the rendering of the first page as an XML file.
std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
MetafileXmlDump dumper;
xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
CPPUNIT_ASSERT(pXmlDoc);
// This failed, if numbering of cell A1 is missing // (A1: left indent: 3 cm, first line indent: -3 cm // A2: left indent: 0 cm, first line indent: 0 cm)
assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[1]/text", u"1.");
assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[3]/text", u"2.");
assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[5]/text", u"3.");
}
// there are 2 pages
assertXPath(pXmlDoc, "/root/page", 2); // table and first para on first page
assertXPath(pXmlDoc, "/root/page[1]/body/tab", 1);
assertXPath(pXmlDoc, "/root/page[1]/body/txt", 1);
assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored", 0); // paragraph with large fly on second page
assertXPath(pXmlDoc, "/root/page[2]/body/tab", 0);
assertXPath(pXmlDoc, "/root/page[2]/body/txt", 1);
assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly", 1);
assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "top", u"17897");
assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "height",
u"15819");
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testShapeAllowOverlap)
{ // Need to find out why this fails on macOS and why this is unstable on Windows. #if !defined(MACOSX) && !defined(_WIN32) // Create an empty document with two, intentionally overlapping shapes. // Set their AllowOverlap property to false.
createSwDoc();
uno::Reference<lang::XMultiServiceFactory> xDocument(mxComponent, uno::UNO_QUERY);
awt::Point aPoint(1000, 1000);
awt::Size aSize(2000, 2000);
uno::Reference<drawing::XShape> xShape(
xDocument->createInstance(u"com.sun.star.drawing.RectangleShape"_ustr), uno::UNO_QUERY);
xShape->setPosition(aPoint);
xShape->setSize(aSize);
uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xDocument, uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY);
xShapeProperties->setPropertyValue(u"AllowOverlap"_ustr, uno::Any(false));
xShapeProperties->setPropertyValue(u"AnchorType"_ustr,
uno::Any(text::TextContentAnchorType_AT_CHARACTER));
xDrawPageSupplier->getDrawPage()->add(xShape);
// Now verify that the rectangle of the anchored objects don't overlap.
SwDoc* pDoc = getSwDoc();
SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
SwFrame* pPageFrame = pLayout->GetLower();
SwFrame* pBodyFrame = pPageFrame->GetLower();
SwFrame* pTextFrame = pBodyFrame->GetLower();
CPPUNIT_ASSERT(pTextFrame->GetDrawObjs());
SwSortedObjs& rObjs = *pTextFrame->GetDrawObjs();
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rObjs.size());
SwAnchoredObject* pFirst = rObjs[0];
SwAnchoredObject* pSecond = rObjs[1]; // Without the accompanying fix in place, this test would have failed: the layout dump was // <bounds left="1984" top="1984" width="1137" height="1137"/> // <bounds left="2551" top="2551" width="1137" height="1137"/> // so there was a clear vertical overlap. (Allow for 1px tolerance.)
OString aMessage = "Unexpected overlap: first shape's bottom is "
+ OString::number(pFirst->GetObjRect().Bottom()) + ", second shape's top is "
+ OString::number(pSecond->GetObjRect().Top());
CPPUNIT_ASSERT_MESSAGE(aMessage.getStr(),
std::abs(pFirst->GetObjRect().Bottom() - pSecond->GetObjRect().Top())
< 15); #endif
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testShapeAllowOverlapWrap)
{ // Create an empty document with two, intentionally overlapping shapes. // Set their AllowOverlap property to false and their wrap to through.
createSwDoc();
uno::Reference<lang::XMultiServiceFactory> xDocument(mxComponent, uno::UNO_QUERY);
awt::Point aPoint(1000, 1000);
awt::Size aSize(2000, 2000);
uno::Reference<drawing::XShape> xShape(
xDocument->createInstance(u"com.sun.star.drawing.RectangleShape"_ustr), uno::UNO_QUERY);
xShape->setPosition(aPoint);
xShape->setSize(aSize);
uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xDocument, uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY);
xShapeProperties->setPropertyValue(u"AllowOverlap"_ustr, uno::Any(false));
xShapeProperties->setPropertyValue(u"AnchorType"_ustr,
uno::Any(text::TextContentAnchorType_AT_CHARACTER));
xShapeProperties->setPropertyValue(u"Surround"_ustr, uno::Any(text::WrapTextMode_THROUGH));
xDrawPageSupplier->getDrawPage()->add(xShape);
// Now verify that the rectangle of the anchored objects do overlap.
SwDoc* pDoc = getSwDoc();
SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
SwFrame* pPageFrame = pLayout->GetLower();
SwFrame* pBodyFrame = pPageFrame->GetLower();
SwFrame* pTextFrame = pBodyFrame->GetLower();
CPPUNIT_ASSERT(pTextFrame->GetDrawObjs());
SwSortedObjs& rObjs = *pTextFrame->GetDrawObjs();
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rObjs.size());
SwAnchoredObject* pFirst = rObjs[0];
SwAnchoredObject* pSecond = rObjs[1]; // Without the accompanying fix in place, this test would have failed: AllowOverlap=no had // priority over Surround=through (which is bad for Word compat).
CPPUNIT_ASSERT(pSecond->GetObjRect().Overlaps(pFirst->GetObjRect()));
}
// Without the accompanying fix in place, this test would have failed with: // - Expected: 1 // - Actual : 2 // i.e. the last line in the body text had 2 lines, while it should have 1, as Word does (as the // fly frame does not intersect with the print area of the paragraph.)
assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout", 1);
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf124601)
{ // This is a testcase for the ContinuousEndnotes compat flag. // The document has 2 pages, the endnote anchor is on the first page. // The endnote should be on the 2nd page together with the last page content.
createSwDoc("tdf124601.doc");
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// Without the accompanying fix in place, this test would have failed with: // - Expected: 2 // - Actual : 3 // i.e. there was a separate endnote page, even when the ContinuousEndnotes compat option was // on.
assertXPath(pXmlDoc, "/root/page", 2);
assertXPath(pXmlDoc, "/root/page[2]//ftncont", 1);
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf124601b)
{ // Table has an image, which is anchored in the first row, but its vertical position is large // enough to be rendered in the second row. // The shape has layoutInCell=1, so should match what Word does here. // Also the horizontal position should be in the last column, even if the anchor is in the // last-but-one column.
createSwDoc("tdf124601b.doc");
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
sal_Int32 nFlyTop = getXPath(pXmlDoc, "//anchored/fly/infos/bounds", "top").toInt32();
sal_Int32 nFlyLeft = getXPath(pXmlDoc, "//anchored/fly/infos/bounds", "left").toInt32();
sal_Int32 nFlyRight
= nFlyLeft + getXPath(pXmlDoc, "//anchored/fly/infos/bounds", "width").toInt32();
sal_Int32 nSecondRowTop = getXPath(pXmlDoc, "//tab/row[2]/infos/bounds", "top").toInt32();
sal_Int32 nLastCellLeft
= getXPath(pXmlDoc, "//tab/row[1]/cell[5]/infos/bounds", "left").toInt32();
sal_Int32 nLastCellRight
= nLastCellLeft + getXPath(pXmlDoc, "//tab/row[1]/cell[5]/infos/bounds", "width").toInt32(); // Without the accompanying fix in place, this test would have failed with: // - Expected greater than: 3736 // - Actual : 2852 // i.e. the image was still inside the first row.
CPPUNIT_ASSERT_GREATER(nSecondRowTop, nFlyTop);
// Without the accompanying fix in place, this test would have failed with: // - Expected greater than: 9640 // - Actual : 9639 // i.e. the right edge of the image was not within the bounds of the last column, the right edge // was in the last-but-one column.
CPPUNIT_ASSERT_GREATER(nLastCellLeft, nFlyRight);
CPPUNIT_ASSERT_LESS(nLastCellRight, nFlyRight);
}
// Set left and right margin.
SvxLRSpaceItem aLRSpace = rPageSet.GetLRSpace();
aLRSpace.SetLeft(SvxIndentValue::twips(1418));
aLRSpace.SetRight(SvxIndentValue::twips(1418));
rPageFormat.SetFormatAttr(aLRSpace);
pDoc->ChgPageDesc(0, rPageDesc);
// Insert the text.
pWrtShell->Insert2(u"HHH"_ustr);
xmlDocUniquePtr pXmlDoc = parseLayoutDump(); // Without the accompanying fix in place, this test would have failed with: // - Expected: 1 // - Actual : 2 // i.e. the italic string was broken into 2 lines, while Word kept it in a single line.
assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout", 1);
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testContinuousEndnotesInsertPageAtStart)
{ // Create a new document with CONTINUOUS_ENDNOTES enabled.
createSwDoc();
SwDoc* pDoc = getSwDoc();
pDoc->getIDocumentSettingAccess().set(DocumentSettingId::CONTINUOUS_ENDNOTES, true);
// Insert a second page, and an endnote on the 2nd page (both the anchor and the endnote is on // the 2nd page).
SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
pWrtShell->InsertPageBreak();
pWrtShell->InsertFootnote(u"endnote"_ustr, /*bEndNote=*/true, /*bEdit=*/false);
// Add a new page at the start of the document.
pWrtShell->SttEndDoc(/*bStart=*/true);
pWrtShell->InsertPageBreak();
// Make sure that the endnote is moved from the 2nd page to the 3rd one.
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
assertXPath(pXmlDoc, "/root/page", 3); // Without the accompanying fix in place, this test would have failed with: // - Expected: 1 // - Actual : 0 // i.e. the footnote container remained on page 2.
assertXPath(pXmlDoc, "/root/page[3]//ftncont", 1);
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testContinuousEndnotesDeletePageAtStart)
{ // Create a new document with CONTINUOUS_ENDNOTES enabled.
createSwDoc();
SwDoc* pDoc = getSwDoc();
pDoc->getIDocumentSettingAccess().set(DocumentSettingId::CONTINUOUS_ENDNOTES, true);
// Insert a second page, and an endnote on the 2nd page (both the anchor and the endnote is on // the 2nd page).
SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
pWrtShell->InsertPageBreak();
pWrtShell->InsertFootnote(u"endnote"_ustr, /*bEndNote=*/true, /*bEdit=*/false);
// Remove the empty page at the start of the document.
pWrtShell->SttEndDoc(/*bStart=*/true);
pWrtShell->DelRight();
// Make sure that the endnote is moved from the 2nd page to the 1st one.
xmlDocUniquePtr pXmlDoc = parseLayoutDump(); // Without the accompanying fix in place, this test would have failed with: // - Expected: 1 // - Actual : 2 // i.e. the endnote remained on an (otherwise) empty 2nd page.
assertXPath(pXmlDoc, "/root/page", 1);
assertXPath(pXmlDoc, "/root/page[1]//ftncont", 1);
}
SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
SwPosition aPosition = *pWrtShell->GetCursor()->Start();
SwPosition aFirstRow(aPosition);
SwCursorMoveState aState(CursorMoveState::NONE);
pLayout->GetModelPositionForViewPoint(&aPosition, aPoint, &aState); // Second row is +3: end node, start node and the first text node in the 2nd row.
SwNodeOffset nExpected = aFirstRow.GetNodeIndex() + 3;
// Without the accompanying fix in place, this test would have failed with: // - Expected: 14 // - Actual : 11 // i.e. clicking on the center of the 2nd row placed the cursor in the 1st row.
CPPUNIT_ASSERT_EQUAL(nExpected, aPosition.GetNodeIndex());
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf156724)
{ // 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(u"Hidden"_ustr, -1, uno::Any(true),
beans::PropertyState_DIRECT_VALUE) },
};
// inline the loading because currently properties can't be passed...
OUString const url(createFileURL(u"fdo56797-2-min.odt"));
loadWithParams(url, comphelper::containerToSequence(aFilterOptions));
save(u"writer_pdf_Export"_ustr);
xmlDocUniquePtr pXmlDoc = parseLayoutDump(); // both pages have a tab frame and one footnote
assertXPath(pXmlDoc, "/root/page[1]/body/tab", 1);
assertXPath(pXmlDoc, "/root/page[1]/ftncont", 1);
assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn", 1);
assertXPath(pXmlDoc, "/root/page[2]/body/tab", 1);
assertXPath(pXmlDoc, "/root/page[2]/ftncont", 1);
assertXPath(pXmlDoc, "/root/page[2]/ftncont/ftn", 1);
assertXPath(pXmlDoc, "/root/page", 2);
}
{
xmlDocUniquePtr pXmlDoc = parseLayoutDump(); // the problem was that the 3rd paragraph didn't move to page 1
assertXPath(pXmlDoc, "/root/page", 1);
assertXPath(pXmlDoc, "/root/page[1]/body/txt", 3);
}
{
xmlDocUniquePtr pXmlDoc = parseLayoutDump(); // the problem was that this did not shrink
assertXPath(pXmlDoc, "/root/page/body/txt[3]/anchored/fly/infos/bounds", "height", u"448");
}
// Hide the section auto xTextSectionsSupplier = mxComponent.queryThrow<css::text::XTextSectionsSupplier>(); auto xSections = xTextSectionsSupplier->getTextSections();
CPPUNIT_ASSERT(xSections); auto xSection = xSections->getByName(u"Section1"_ustr).queryThrow<css::beans::XPropertySet>();
xSection->setPropertyValue(u"IsVisible"_ustr, css::uno::Any(false));
calcLayout();
{
xmlDocUniquePtr pXmlDoc = parseLayoutDump(); // the problem was that 3 of the text frames had 0 height because Format was skipped
assertXPath(pXmlDoc, "/root/page/body/section/txt/infos/bounds[@height='0']", 0);
}
}
// these are hidden by moving to invisible layer, they're still in layout
{
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
assertXPath(pXmlDoc, "//anchored/fly", 6);
CPPUNIT_ASSERT_EQUAL(size_t(6), pDrawPage->GetObjCount()); for (int i = 0; i < 6; ++i)
{
CPPUNIT_ASSERT_EQUAL(invisibleHeaven, int(pDrawPage->GetObj(i)->GetLayer().get()));
}
}
// Show the section auto xTextSectionsSupplier = mxComponent.queryThrow<css::text::XTextSectionsSupplier>(); auto xSections = xTextSectionsSupplier->getTextSections();
CPPUNIT_ASSERT(xSections); auto xSection = xSections->getByName(u"Anlage"_ustr).queryThrow<css::beans::XPropertySet>();
xSection->setPropertyValue(u"IsVisible"_ustr, css::uno::Any(true));
calcLayout();
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.66Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-04-26)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.