vcl/unx/generic/gdi/cairotextrender.cxx |   51 +++++++++++++++++++++++---------
 1 file changed, 37 insertions(+), 14 deletions(-)

New commits:
commit bfe18cbb5eebe975bd469bb884b4c86f03fc48c0
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Tue Nov 29 20:26:49 2022 +0000
Commit:     Caolán McNamara <caol...@redhat.com>
CommitDate: Wed Nov 30 12:15:44 2022 +0100

    Related: tdf#152094 experiment with snapping to a subpixel
    
    Change-Id: Ieb4fbd135f618d7e46762b0ac297446308c75755
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143474
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caol...@redhat.com>

diff --git a/vcl/unx/generic/gdi/cairotextrender.cxx 
b/vcl/unx/generic/gdi/cairotextrender.cxx
index 95e11f9614a7..0a5ae547360c 100644
--- a/vcl/unx/generic/gdi/cairotextrender.cxx
+++ b/vcl/unx/generic/gdi/cairotextrender.cxx
@@ -23,6 +23,7 @@
 
 #include <unx/fc_fontoptions.hxx>
 #include <unx/freetype_glyphcache.hxx>
+#include <headless/CairoCommon.hxx>
 #include <vcl/svapp.hxx>
 #include <sallayout.hxx>
 #include <salinst.hxx>
@@ -167,12 +168,30 @@ void CairoTextRender::DrawTextLayout(const 
GenericSalLayout& rLayout, const SalG
 
     const bool bResolutionIndependentLayoutEnabled = 
rLayout.GetTextRenderModeForResolutionIndependentLayout();
 
+    /*
+     * It might be ideal to cache surface and cairo context between calls and
+     * only destroy it when the drawable changes, but to do that we need to at
+     * least change the SalFrame etc impls to dtor the SalGraphics *before* the
+     * destruction of the windows they reference
+    */
+    cairo_t *cr = syncCairoContext(getCairoContext());
+    if (!cr)
+    {
+        SAL_WARN("vcl", "no cairo context for text");
+        return;
+    }
+
     std::vector<cairo_glyph_t> cairo_glyphs;
     std::vector<int> glyph_extrarotation;
     cairo_glyphs.reserve( 256 );
 
+    double nSnapToSubPixelDiff = 0.0;
+    double nXScale, nYScale;
+    dl_cairo_surface_get_device_scale(cairo_get_target(cr), &nXScale, 
&nYScale);
+
     DevicePoint aPos;
     const GlyphItem* pGlyph;
+    const GlyphItem* pPrevGlyph = nullptr;
     int nStart = 0;
     while (rLayout.GetNextGlyph(&pGlyph, aPos, nStart))
     {
@@ -184,13 +203,30 @@ void CairoTextRender::DrawTextLayout(const 
GenericSalLayout& rLayout, const SalG
         const bool bVertical = pGlyph->IsVertical();
         glyph_extrarotation.push_back(bVertical ? 1 : 0);
 
-        // tdf#150507 like skia even when subpixel rendering pixel snap y
         if (bResolutionIndependentLayoutEnabled)
         {
+            // tdf#150507 like skia, even when subpixel rendering pixel, snap y
             if (!bVertical)
                 aGlyph.y = std::floor(aGlyph.y + 0.5);
             else
                 aGlyph.x = std::floor(aGlyph.x + 0.5);
+
+            // tdf#152094 snap to 1/4 of a pixel after a run of whitespace,
+            // probably a little dubious, but maybe worth a shot for lodpi
+            double& rGlyphDimension = !bVertical ? aGlyph.x : aGlyph.y;
+            const int nSubPixels = 4 * (!bVertical ? nXScale : nYScale);
+            if (pGlyph->IsSpacing())
+                nSnapToSubPixelDiff = 0;
+            else if (pPrevGlyph && pPrevGlyph->IsSpacing())
+            {
+                double nSnapToSubPixel = std::floor(rGlyphDimension * 
nSubPixels) / nSubPixels;
+                nSnapToSubPixelDiff = rGlyphDimension - nSnapToSubPixel;
+                rGlyphDimension = nSnapToSubPixel;
+            }
+            else
+                rGlyphDimension -= nSnapToSubPixelDiff;
+
+            pPrevGlyph = pGlyph;
         }
 
         cairo_glyphs.push_back(aGlyph);
@@ -222,19 +258,6 @@ void CairoTextRender::DrawTextLayout(const 
GenericSalLayout& rLayout, const SalG
         return;
     }
 
-    /*
-     * It might be ideal to cache surface and cairo context between calls and
-     * only destroy it when the drawable changes, but to do that we need to at
-     * least change the SalFrame etc impls to dtor the SalGraphics *before* the
-     * destruction of the windows they reference
-    */
-    cairo_t *cr = syncCairoContext(getCairoContext());
-    if (!cr)
-    {
-        SAL_WARN("vcl", "no cairo context for text");
-        return;
-    }
-
 #if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
     if (__lsan_disable)
         __lsan_disable();

Reply via email to