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();