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;

Reply via email to