include/vcl/outdev.hxx | 12 ++++ svx/source/svdraw/svdpagv.cxx | 77 +++++++++++++++++++++------ vcl/source/outdev/rect.cxx | 117 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 188 insertions(+), 18 deletions(-)
New commits: commit 5eac589ffae1bf1ea027d48ce52a6ae20f67084e Author: Tamás Zolnai <[email protected]> AuthorDate: Tue Nov 11 13:30:24 2025 +0100 Commit: Tamás Zolnai <[email protected]> CommitDate: Mon Nov 17 10:38:15 2025 +0100 tdf#89544: Display small, 3x3 pixel crosses for main grid points. In Writer (and in Calc). To improve visibility of the grid. The same happens in Draw and in Impress. Implement the same behaviour for Witer (and Calc). Writer is the main scope, but Calc shares the rendering code with Writer and I don't see a good reason to increase the complexity of the code by defining different behaviour for Calc. Change-Id: I26ba02ff02c73a37e8780a67acf4c516c59c193a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194021 Reviewed-by: Tamás Zolnai <[email protected]> Tested-by: Jenkins diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx index f4fda52dd089..d01705d04af9 100644 --- a/include/vcl/outdev.hxx +++ b/include/vcl/outdev.hxx @@ -612,6 +612,18 @@ public: void DrawGrid( const tools::Rectangle& rRect, const Size& rDist, DrawGridFlags nFlags ); + /** Draw a grid of small crosses. + + @param rGridArea The area where grid points are positioned. + @param rGridDistance Distances of grid points horizontally and vertically. + @param rDrawingArea Whole drawing area, defining the visible area where crosses should be drawn. + + @note The rGridArea typically covers a larger area of the page, than the rDrawingArea, because some grid points might be outside + of the drawing area, but we still need to draw them partially. Even if the center of the cross is not visible, one edge + of the cross can hang into the visible area. + */ + void DrawGridOfCrosses( const tools::Rectangle& rGridArea, const Size& rGridDistance, const tools::Rectangle& rDrawingArea ); + ///@} /** @name Invert functions diff --git a/svx/source/svdraw/svdpagv.cxx b/svx/source/svdraw/svdpagv.cxx index 04783b04dc0c..dd809885df98 100644 --- a/svx/source/svdraw/svdpagv.cxx +++ b/svx/source/svdraw/svdpagv.cxx @@ -472,6 +472,7 @@ void SdrPageView::DrawPageViewGrid(OutputDevice& rOut, const tools::Rectangle& r y2=rGF.GetUserArea().Bottom(); aGridOrigin=rGF.GetUserArea().TopLeft(); } + const tools::Rectangle aGridBoundingBox(x1, y1, x2, y2); if (!rRect.IsEmpty()) { Size a1PixSiz(rOut.PixelToLogic(Size(1,1))); tools::Long nX1Pix=a1PixSiz.Width(); // add 1 pixel of tolerance @@ -530,17 +531,37 @@ void SdrPageView::DrawPageViewGrid(OutputDevice& rOut, const tools::Rectangle& r for(sal_uInt16 a=0;a<nSteps;a++) { - // Make sure the origin of the subgrid is within the drawing area - const Point aSubGridPosition(nAnchorPos + ((nx1 * (nStartStep + a)) / nSteps), yBigOrg); - if (!aDrawingArea.Contains(aSubGridPosition)) + Point aSubGridPosition(nAnchorPos + ((nx1 * (nStartStep + a)) / nSteps), yBigOrg); + if(aSubGridPosition.X() == xBigOrg) // Main grid points { - continue; + // For cross rendering we need an extended grid area to handle partly rendered grid markers + if(aGridBoundingBox.Contains(Point(aSubGridPosition.X() - nx1, aSubGridPosition.Y()))) + { + aSubGridPosition.Move(-nx1, 0); + } + + if(aGridBoundingBox.Contains(Point(aSubGridPosition.X(), aSubGridPosition.Y() - ny1))) + { + aSubGridPosition.Move(0, -ny1); + } + rOut.DrawGridOfCrosses( + tools::Rectangle( aSubGridPosition, + Point(std::min(x2 + nx1, aGridBoundingBox.Right()), std::min(y2 + ny1, aGridBoundingBox.Bottom()))), + Size( nx1, ny1 ), aDrawingArea ); + } + else // Subdivision points + { + // Make sure the origin of the subgrid is within the drawing area + if(!aDrawingArea.Contains(aSubGridPosition)) + { + continue; + } + + // draw + rOut.DrawGrid( + tools::Rectangle( aSubGridPosition, Point(x2, y2) ), + Size( nx1, ny1 ), DrawGridFlags::Dots ); } - - // draw - rOut.DrawGrid( - tools::Rectangle( aSubGridPosition, Point(x2, y2) ), - Size( nx1, ny1 ), DrawGridFlags::Dots ); } } } @@ -577,17 +598,37 @@ void SdrPageView::DrawPageViewGrid(OutputDevice& rOut, const tools::Rectangle& r for(sal_uInt16 a=0;a<nSteps;a++) { - // Make sure the origin of the subgrid is within the drawing area - const Point aSubGridPosition(xBigOrg, nAnchorPos + ((ny1 * (nStartStep + a)) / nSteps)); - if (!aDrawingArea.Contains(aSubGridPosition)) + Point aSubGridPosition(xBigOrg, nAnchorPos + ((ny1 * (nStartStep + a)) / nSteps)); + if(aSubGridPosition.Y() == yBigOrg) // Main grid points { - continue; + // For cross rendering we need an extended grid area to handle partly rendered grid markers + if(aGridBoundingBox.Contains(Point(aSubGridPosition.X() - nx1, aSubGridPosition.Y()))) + { + aSubGridPosition.Move(-nx1, 0); + } + + if(aGridBoundingBox.Contains(Point(aSubGridPosition.X(), aSubGridPosition.Y() - ny1))) + { + aSubGridPosition.Move(0, -ny1); + } + rOut.DrawGridOfCrosses( + tools::Rectangle( aSubGridPosition, + Point(std::min(x2 + nx1, aGridBoundingBox.Right()), std::min(y2 + ny1, aGridBoundingBox.Bottom()))), + Size( nx1, ny1 ), aDrawingArea ); + } + else // Subdivision points + { + // Make sure the origin of the subgrid is within the drawing area + if(!aDrawingArea.Contains(aSubGridPosition)) + { + continue; + } + + // draw + rOut.DrawGrid( + tools::Rectangle( aSubGridPosition, Point(x2, y2) ), + Size( nx1, ny1 ), DrawGridFlags::Dots ); } - - // draw - rOut.DrawGrid( - tools::Rectangle( aSubGridPosition, Point(x2, y2) ), - Size( nx1, ny1 ), DrawGridFlags::Dots ); } } } diff --git a/vcl/source/outdev/rect.cxx b/vcl/source/outdev/rect.cxx index c2731237d1cf..27ad85802e22 100644 --- a/vcl/source/outdev/rect.cxx +++ b/vcl/source/outdev/rect.cxx @@ -326,6 +326,123 @@ void OutputDevice::DrawGrid( const tools::Rectangle& rRect, const Size& rDist, D EnableMapMode( bOldMap ); } +void OutputDevice::DrawGridOfCrosses(const tools::Rectangle& rGridArea, const Size& rGridDistance, + const tools::Rectangle& rDrawingArea) +{ + assert(!is_double_buffered_window()); + + if (!mbLineColor || ImplIsRecordLayout()) + { + return; + } + + if (!mpGraphics && !AcquireGraphics()) + { + return; + } + assert(mpGraphics); + + if (mbInitClipRegion) + { + InitClipRegion(); + } + + if (mbOutputClipped) + { + return; + } + + if (mbInitLineColor) + { + InitLineColor(); + } + + if (rDrawingArea.IsEmpty()) + { + return; + } + + const tools::Long nDistanceX = rGridDistance.Width(); + const tools::Long nDistanceY = rGridDistance.Height(); + tools::Long nX = rGridArea.Left(); + tools::Long nY = rGridArea.Top(); + + // Collect horizontal positions of the grid points + std::vector<tools::Long> aHorzBuffer; + aHorzBuffer.reserve(rGridArea.GetWidth() / nDistanceX + 1); + while (nX <= rGridArea.Right()) + { + aHorzBuffer.push_back(nX); + nX += nDistanceX; + } + + // Collect vertical positions of the grid points + std::vector<tools::Long> aVertBuffer; + aVertBuffer.reserve(rGridArea.GetHeight() / nDistanceY + 1); + while (nY <= rGridArea.Bottom()) + { + aVertBuffer.push_back(nY); + nY += nDistanceY; + } + + const tools::Long nTopPixel = ImplLogicYToDevicePixel(rDrawingArea.Top()); + const tools::Long nBottomPixel = ImplLogicYToDevicePixel(rDrawingArea.Bottom()); + const tools::Long nLeftPixel = ImplLogicXToDevicePixel(rDrawingArea.Left()); + const tools::Long nRightPixel = ImplLogicXToDevicePixel(rDrawingArea.Right()); + + // Draw 3x3 pixel crosses within the drawing area + const tools::Long nHalfCrossSize = 1; + for (const tools::Long nPositionX : aHorzBuffer) + { + const tools::Long nPositionXPixel = ImplLogicXToDevicePixel(nPositionX); + for (const tools::Long nPositionY : aVertBuffer) + { + const tools::Long nPositionYPixel = ImplLogicYToDevicePixel(nPositionY); + const tools::Long nStartXPixel = std::max(nPositionXPixel - nHalfCrossSize, nLeftPixel); + if (nStartXPixel > nRightPixel) + { + continue; + } + const tools::Long nEndXPixel + = std::min(nPositionXPixel + nHalfCrossSize + 1, nRightPixel); + if (nEndXPixel < nLeftPixel) + { + continue; + } + const tools::Long nStartYPixel = std::max(nPositionYPixel - nHalfCrossSize, nTopPixel); + if (nStartYPixel > nBottomPixel) + { + continue; + } + const tools::Long nEndYPixel + = std::min(nPositionYPixel + nHalfCrossSize + 1, nBottomPixel); + if (nEndYPixel < nTopPixel) + { + continue; + } + + const bool bOldMap = mbMap; + EnableMapMode(false); + + // Draw horizontal line if visible + if (nPositionY >= rDrawingArea.Top() && nPositionY <= rDrawingArea.Bottom()) + { + mpGraphics->DrawLine(nStartXPixel, nPositionYPixel, nEndXPixel, nPositionYPixel, + *this); + } + + // Draw vertical line if visible + if (nPositionX >= rDrawingArea.Left() && nPositionX <= rDrawingArea.Right()) + { + mpGraphics->DrawLine(nPositionXPixel, nStartYPixel, nPositionXPixel, nEndYPixel, + *this); + } + + EnableMapMode(bOldMap); + } + } +} + BmpMirrorFlags AdjustTwoRect( SalTwoRect& rTwoRect, const Size& rSizePix ) { BmpMirrorFlags nMirrFlags = BmpMirrorFlags::NONE;
