summaryrefslogtreecommitdiff
path: root/sc
diff options
context:
space:
mode:
authorTibor Nagy <nagy.tibor2@nisz.hu>2021-03-04 14:30:21 +0100
committerLászló Németh <nemeth@numbertext.org>2021-03-26 14:41:03 +0100
commit967e0cc303c7be4a88905b327b9d02ba12f5e375 (patch)
tree94ab66d2ae4564227294a4971f3b4ac96d1a811e /sc
parented62bbc71a8469fe74a699528398326e551e7301 (diff)
tdf#119292 sc layout: fix overlapping wrapped cell texts
if rotated by 90 or 270 degrees using clipping to cell boundaries, like MSO does. E.g. this avoid of importing MSO documents with unreadable header cells. Note: it's possible to improve the patch extending clipping for the neighboring empty area instead of clipping all text exceeding the cell boundary (as in the case of the non-rotated, non-wrapped text). Co-authored-by: Attila Szűcs (NISZ) Change-Id: Idd37f7eb7208ff3818dcdab93ef0ec57275db954 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111964 Tested-by: László Németh <nemeth@numbertext.org> Reviewed-by: László Németh <nemeth@numbertext.org>
Diffstat (limited to 'sc')
-rw-r--r--sc/inc/fillinfo.hxx4
-rw-r--r--sc/qa/unit/data/xlsx/tdf119292.xlsxbin0 -> 10764 bytes
-rw-r--r--sc/qa/unit/subsequent_filters-test.cxx41
-rw-r--r--sc/source/ui/inc/output.hxx7
-rw-r--r--sc/source/ui/view/output.cxx44
-rw-r--r--sc/source/ui/view/output2.cxx64
6 files changed, 114 insertions, 46 deletions
diff --git a/sc/inc/fillinfo.hxx b/sc/inc/fillinfo.hxx
index e18e3f545536..c4f995c21c1d 100644
--- a/sc/inc/fillinfo.hxx
+++ b/sc/inc/fillinfo.hxx
@@ -42,10 +42,10 @@ enum class ScRotateDir : sal_uInt8 {
};
enum class ScClipMark : sal_uInt8 {
- NONE = 0x00, Left = 0x01, Right = 0x02
+ NONE = 0x00, Left = 0x01, Right = 0x02, Bottom = 0x03, Top = 0x04
};
namespace o3tl {
- template<> struct typed_flags<ScClipMark> : is_typed_flags<ScClipMark, 0x03> {};
+ template<> struct typed_flags<ScClipMark> : is_typed_flags<ScClipMark, 0x07> {};
}
const sal_uInt8 SC_CLIPMARK_SIZE = 64;
diff --git a/sc/qa/unit/data/xlsx/tdf119292.xlsx b/sc/qa/unit/data/xlsx/tdf119292.xlsx
new file mode 100644
index 000000000000..cf3d3dc08dbb
--- /dev/null
+++ b/sc/qa/unit/data/xlsx/tdf119292.xlsx
Binary files differ
diff --git a/sc/qa/unit/subsequent_filters-test.cxx b/sc/qa/unit/subsequent_filters-test.cxx
index 0807f29a3587..3d886c7b10fb 100644
--- a/sc/qa/unit/subsequent_filters-test.cxx
+++ b/sc/qa/unit/subsequent_filters-test.cxx
@@ -109,6 +109,7 @@ public:
//ods, xls, xlsx filter tests
void testCondFormatOperatorsSameRangeXLSX();
+ void testTdf119292();
void testCondFormatFormulaIsXLSX();
void testCondFormatBeginsAndEndsWithXLSX();
void testExtCondFormatXLSX();
@@ -316,6 +317,7 @@ public:
CPPUNIT_TEST_SUITE(ScFiltersTest);
CPPUNIT_TEST(testCondFormatOperatorsSameRangeXLSX);
+ CPPUNIT_TEST(testTdf119292);
CPPUNIT_TEST(testCondFormatFormulaIsXLSX);
CPPUNIT_TEST(testCondFormatBeginsAndEndsWithXLSX);
CPPUNIT_TEST(testExtCondFormatXLSX);
@@ -582,21 +584,54 @@ void ScFiltersTest::testCondFormatOperatorsSameRangeXLSX()
CPPUNIT_ASSERT_EQUAL(ScFormatEntry::Type::ExtCondition, pEntry->GetType());
const ScCondFormatEntry* pCondition = static_cast<const ScCondFormatEntry*>(pEntry);
- CPPUNIT_ASSERT_EQUAL( ScConditionMode::ContainsText, pCondition->GetOperation());
+ CPPUNIT_ASSERT_EQUAL(ScConditionMode::ContainsText, pCondition->GetOperation());
pEntry = pFormat->GetEntry(1);
CPPUNIT_ASSERT(pEntry);
CPPUNIT_ASSERT_EQUAL(ScFormatEntry::Type::ExtCondition, pEntry->GetType());
pCondition = static_cast<const ScCondFormatEntry*>(pEntry);
- CPPUNIT_ASSERT_EQUAL( ScConditionMode::BeginsWith, pCondition->GetOperation());
+ CPPUNIT_ASSERT_EQUAL(ScConditionMode::BeginsWith, pCondition->GetOperation());
pEntry = pFormat->GetEntry(2);
CPPUNIT_ASSERT(pEntry);
CPPUNIT_ASSERT_EQUAL(ScFormatEntry::Type::ExtCondition, pEntry->GetType());
pCondition = static_cast<const ScCondFormatEntry*>(pEntry);
- CPPUNIT_ASSERT_EQUAL( ScConditionMode::EndsWith, pCondition->GetOperation());
+ CPPUNIT_ASSERT_EQUAL(ScConditionMode::EndsWith, pCondition->GetOperation());
+
+ xDocSh->DoClose();
+}
+
+void ScFiltersTest::testTdf119292()
+{
+ ScDocShellRef xDocSh = loadDoc(u"tdf119292.", FORMAT_XLSX);
+ CPPUNIT_ASSERT_MESSAGE("Failed to load tdf119292.xlsx", xDocSh.is());
+
+ ScDocument& rDoc = xDocSh->GetDocument();
+ auto* pDev = rDoc.GetRefDevice();
+ Size aMarkSize(4, 6);
+ Color aArrowFillCol(COL_LIGHTRED);
+
+ // check the points of the polygon if the text is rotated 90 degrees
+ tools::Rectangle aMarkRect1(0, 0, 45, 3);
+ tools::Polygon aPoly90degrees = SvxFont::DrawArrow(*pDev, aMarkRect1, aMarkSize, aArrowFillCol, true, true);
+ Point aPoly90Pos1 = aPoly90degrees.GetPoint(0);
+ Point aPoly90Pos2 = aPoly90degrees.GetPoint(1);
+ Point aPoly90Pos3 = aPoly90degrees.GetPoint(2);
+ CPPUNIT_ASSERT_EQUAL(Point(19,3),aPoly90Pos1);
+ CPPUNIT_ASSERT_EQUAL(Point(22,0),aPoly90Pos2);
+ CPPUNIT_ASSERT_EQUAL(Point(25,3),aPoly90Pos3);
+
+ // check the points of the polygon if the text is rotated 270 degrees
+ tools::Rectangle aMarkRect2(89, 62, 134, 57);
+ tools::Polygon aPoly270degrees = SvxFont::DrawArrow(*pDev, aMarkRect2, aMarkSize, aArrowFillCol, false, true);
+ Point aPoly270Pos1 = aPoly270degrees.GetPoint(0);
+ Point aPoly270Pos2 = aPoly270degrees.GetPoint(1);
+ Point aPoly270Pos3 = aPoly270degrees.GetPoint(2);
+ CPPUNIT_ASSERT_EQUAL(Point(108,54),aPoly270Pos1);
+ CPPUNIT_ASSERT_EQUAL(Point(111,57),aPoly270Pos2);
+ CPPUNIT_ASSERT_EQUAL(Point(114,54),aPoly270Pos3);
xDocSh->DoClose();
}
diff --git a/sc/source/ui/inc/output.hxx b/sc/source/ui/inc/output.hxx
index e45fe29e14ac..b3079259f8b0 100644
--- a/sc/source/ui/inc/output.hxx
+++ b/sc/source/ui/inc/output.hxx
@@ -231,6 +231,7 @@ private:
bool bSnapPixel;
bool bAnyClipped; // internal
+ bool bVertical;
bool bTabProtected;
bool bLayoutRTL;
@@ -277,11 +278,11 @@ private:
std::unique_ptr<ScFieldEditEngine> CreateOutputEditEngine();
- void ShowClipMarks( DrawEditParam& rParam, tools::Long nEngineHeight, const Size& aCellSize,
- bool bMerged, OutputAreaParam& aAreaParam );
+ void ShowClipMarks( DrawEditParam& rParam, tools::Long nEngineWidth, const Size& aCellSize,
+ bool bMerged, OutputAreaParam& aAreaParam, bool bTop );
ClearableClipRegionPtr Clip(DrawEditParam& rParam, const Size& aCellSize, OutputAreaParam& aAreaParam,
- tools::Long nEngineHeight, bool bWrapFields);
+ tools::Long nEngineWidth, bool bWrapFields, bool bTop);
bool AdjustAreaParamClipRect(OutputAreaParam& rAreaParam);
tools::Long SetEngineTextAndGetWidth( DrawEditParam& rParam, const OUString& rSetString,
diff --git a/sc/source/ui/view/output.cxx b/sc/source/ui/view/output.cxx
index b73b2fd0980b..fc1750f53e14 100644
--- a/sc/source/ui/view/output.cxx
+++ b/sc/source/ui/view/output.cxx
@@ -173,6 +173,7 @@ ScOutputData::ScOutputData( OutputDevice* pNewDev, ScOutputType eNewType,
bMarkClipped( false ), // sal_False for printer/metafile etc.
bSnapPixel( false ),
bAnyClipped( false ),
+ bVertical(false),
mpTargetPaintWindow(nullptr), // #i74769# use SdrPaintWindow direct
mpSpellCheckCxt(nullptr)
{
@@ -2552,19 +2553,42 @@ void ScOutputData::DrawClipMarks()
tools::Long nMarkPixel = static_cast<tools::Long>( SC_CLIPMARK_SIZE * mnPPTX );
Size aMarkSize( nMarkPixel, (nMarkPixel-1)*2 );
- if ( pInfo->nClipMark & ( bLayoutRTL ? ScClipMark::Right : ScClipMark::Left ) )
+ if (bVertical)
{
- // visually left
- tools::Rectangle aMarkRect = aCellRect;
- aMarkRect.SetRight( aCellRect.Left()+nMarkPixel-1 );
- SvxFont::DrawArrow( *mpDev, aMarkRect, aMarkSize, aArrowFillCol, true );
+ if (pInfo->nClipMark & (bLayoutRTL ? ScClipMark::Bottom : ScClipMark::Top))
+ {
+ // visually top
+ tools::Rectangle aMarkRect = aCellRect;
+ aMarkRect.SetBottom(aCellRect.Top() + nMarkPixel - 1);
+ SvxFont::DrawArrow(*mpDev, aMarkRect, aMarkSize, aArrowFillCol, true, true);
+ }
+ if (pInfo->nClipMark & (bLayoutRTL ? ScClipMark::Top : ScClipMark::Bottom))
+ {
+ // visually bottom
+ tools::Rectangle aMarkRect = aCellRect;
+ aMarkRect.SetTop(aCellRect.Bottom() + nMarkPixel + 1);
+ SvxFont::DrawArrow(*mpDev, aMarkRect, aMarkSize, aArrowFillCol, false,
+ true);
+ }
}
- if ( pInfo->nClipMark & ( bLayoutRTL ? ScClipMark::Left : ScClipMark::Right ) )
+ else
{
- // visually right
- tools::Rectangle aMarkRect = aCellRect;
- aMarkRect.SetLeft( aCellRect.Right()-nMarkPixel+1 );
- SvxFont::DrawArrow( *mpDev, aMarkRect, aMarkSize, aArrowFillCol, false );
+ if (pInfo->nClipMark & (bLayoutRTL ? ScClipMark::Right : ScClipMark::Left))
+ {
+ // visually left
+ tools::Rectangle aMarkRect = aCellRect;
+ aMarkRect.SetRight(aCellRect.Left() + nMarkPixel - 1);
+ SvxFont::DrawArrow(*mpDev, aMarkRect, aMarkSize, aArrowFillCol, true,
+ false);
+ }
+ if (pInfo->nClipMark & (bLayoutRTL ? ScClipMark::Left : ScClipMark::Right))
+ {
+ // visually right
+ tools::Rectangle aMarkRect = aCellRect;
+ aMarkRect.SetLeft(aCellRect.Right() - nMarkPixel + 1);
+ SvxFont::DrawArrow(*mpDev, aMarkRect, aMarkSize, aArrowFillCol, false,
+ false);
+ }
}
}
nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
diff --git a/sc/source/ui/view/output2.cxx b/sc/source/ui/view/output2.cxx
index 4d5003bdc02e..e2726517a874 100644
--- a/sc/source/ui/view/output2.cxx
+++ b/sc/source/ui/view/output2.cxx
@@ -3186,48 +3186,56 @@ void ScOutputData::DrawEditStandard(DrawEditParam& rParam)
rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
}
-void ScOutputData::ShowClipMarks( DrawEditParam& rParam, tools::Long nEngineHeight, const Size& aCellSize,
- bool bMerged, OutputAreaParam& aAreaParam)
+void ScOutputData::ShowClipMarks( DrawEditParam& rParam, tools::Long nEngineWidth, const Size& aCellSize,
+ bool bMerged, OutputAreaParam& aAreaParam, bool bTop)
{
- // Show clip marks if height is at least 5pt too small and
+ // Show clip marks if width is at least 5pt too small and
// there are several lines of text.
// Not for asian vertical text, because that would interfere
// with the default right position of the text.
// Only with automatic line breaks, to avoid having to find
// the cells with the horizontal end of the text again.
- if ( !(nEngineHeight - aCellSize.Height() > 100 &&
- rParam.mbBreak && bMarkClipped &&
- ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 )) )
- return;
-
- CellInfo* pClipMarkCell = nullptr;
- if ( bMerged )
+ if (nEngineWidth - aCellSize.Width() > 100 && rParam.mbBreak && bMarkClipped
+ && (rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1))
{
- // anywhere in the merged area...
- SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
- pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].pCellInfo[nClipX+1];
- }
- else
- pClipMarkCell = &rParam.mpThisRowInfo->pCellInfo[rParam.mnX+1];
-
- pClipMarkCell->nClipMark |= ScClipMark::Right; //! also allow left?
- bAnyClipped = true;
+ CellInfo* pClipMarkCell = nullptr;
+ if (bMerged)
+ {
+ // anywhere in the merged area...
+ SCCOL nClipX = (rParam.mnX < nX1) ? nX1 : rParam.mnX;
+ pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].pCellInfo[nClipX + 1];
+ }
+ else
+ pClipMarkCell = &rParam.mpThisRowInfo->pCellInfo[rParam.mnX + 1];
- const tools::Long nMarkPixel = static_cast<tools::Long>( SC_CLIPMARK_SIZE * mnPPTX );
- if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
- aAreaParam.maClipRect.AdjustRight( -nMarkPixel );
+ bAnyClipped = true;
+ bVertical = true;
+ const tools::Long nMarkPixel = static_cast<tools::Long>(SC_CLIPMARK_SIZE * mnPPTX);
+ if (bTop)
+ {
+ pClipMarkCell->nClipMark |= ScClipMark::Top;
+ if (aAreaParam.maClipRect.Top() - nMarkPixel < aAreaParam.maClipRect.Bottom())
+ aAreaParam.maClipRect.AdjustTop(+nMarkPixel);
+ }
+ else
+ {
+ pClipMarkCell->nClipMark |= ScClipMark::Bottom;
+ if (aAreaParam.maClipRect.Top() - nMarkPixel < aAreaParam.maClipRect.Bottom())
+ aAreaParam.maClipRect.AdjustBottom(-nMarkPixel);
+ }
+ }
}
ClearableClipRegionPtr ScOutputData::Clip( DrawEditParam& rParam, const Size& aCellSize,
- OutputAreaParam& aAreaParam, tools::Long nEngineHeight,
- bool bWrapFields)
+ OutputAreaParam& aAreaParam, tools::Long nEngineWidth,
+ bool bWrapFields, bool bTop)
{
// Also take fields in a cell with automatic breaks into account: clip to cell width
bool bClip = AdjustAreaParamClipRect(aAreaParam) || aAreaParam.mbLeftClip || aAreaParam.mbRightClip || bWrapFields;
bool bSimClip = false;
const Size& aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
- if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
+ if ( nEngineWidth >= aCellSize.Width() + aRefOne.Width() )
{
const ScMergeAttr* pMerge = &rParam.mpPattern->GetItem(ATTR_MERGE);
const bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
@@ -3243,7 +3251,7 @@ ClearableClipRegionPtr ScOutputData::Clip( DrawEditParam& rParam, const Size& aC
else
bSimClip = true;
- ShowClipMarks( rParam, nEngineHeight, aCellSize, bMerged, aAreaParam);
+ ShowClipMarks( rParam, nEngineWidth, aCellSize, bMerged, aAreaParam, bTop);
}
// Clip marks are already handled in GetOutputArea
@@ -3425,7 +3433,7 @@ void ScOutputData::DrawEditBottomTop(DrawEditParam& rParam)
Point aURLStart;
{
- const auto pClipRegion = Clip( rParam, aCellSize, aAreaParam, nEngineHeight, bWrapFields );
+ const auto pClipRegion = Clip( rParam, aCellSize, aAreaParam, nEngineWidth, bWrapFields, true );
Point aLogicStart(nStartX, nStartY);
rParam.calcStartPosForVertical(aLogicStart, aCellSize.Width(), nEngineWidth, nTopM, mpRefDevice);
@@ -3671,7 +3679,7 @@ void ScOutputData::DrawEditTopBottom(DrawEditParam& rParam)
Point aURLStart;
{
- const auto pClipRegion = Clip( rParam, aCellSize, aAreaParam, nEngineHeight, bWrapFields );
+ const auto pClipRegion = Clip( rParam, aCellSize, aAreaParam, nEngineWidth, bWrapFields, false );
Point aLogicStart(nStartX, nStartY);
rParam.calcStartPosForVertical(aLogicStart, aCellSize.Width(), nEngineWidth, nTopM, mpRefDevice);