vcl/unx/generic/gdi/cairotextrender.cxx |  112 +++++++++++++++++++++++++-------
 1 file changed, 89 insertions(+), 23 deletions(-)

New commits:
commit 53e24da3698ddb5f976cec0ae8eb8b2a2ab2c4c6
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Tue Apr 4 19:46:05 2023 +0100
Commit:     Caolán McNamara <caol...@redhat.com>
CommitDate: Wed Apr 5 09:41:41 2023 +0200

    tdf#132112 excessive stretch of braces can trigger freetype into an error
    
    which propogates to cairo and once a cairo surface is in an error state,
    that cannot be cleared and all subsequent drawing fails, so bodge that
    with a high degree of stretch we draw the brace without stretch to a
    temp surface and stretch that to give a far poorer visual result, but
    one that can at least be rendered.
    
    Change-Id: I6b8bb079e82c3cf03a908de750c5c445ad230750
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150031
    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 8f093c02c126..32561cbb036e 100644
--- a/vcl/unx/generic/gdi/cairotextrender.cxx
+++ b/vcl/unx/generic/gdi/cairotextrender.cxx
@@ -285,7 +285,8 @@ void CairoTextRender::DrawTextLayout(const 
GenericSalLayout& rLayout, const SalG
         cairo_glyphs.push_back(aGlyph);
     }
 
-    if (cairo_glyphs.empty())
+    const size_t nGlyphs = cairo_glyphs.size();
+    if (!nGlyphs)
         return;
 
     const vcl::font::FontSelectPattern& rFSD = 
rInstance.GetFontSelectPattern();
@@ -303,14 +304,6 @@ void CairoTextRender::DrawTextLayout(const 
GenericSalLayout& rLayout, const SalG
         return;
     }
 
-    int nRatio = nWidth * 10 / nHeight;
-    if (nRatio >= 5120)
-    {
-        // as seen with freetype 2.12.1, so cairo surface status is "fail"
-        SAL_WARN("vcl", "rendering text would fail with stretch of: " << 
nRatio / 10.0);
-        return;
-    }
-
 #if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
     if (nHeight > 8000)
     {
@@ -323,7 +316,78 @@ void CairoTextRender::DrawTextLayout(const 
GenericSalLayout& rLayout, const SalG
         SAL_WARN("vcl", "rendering text would use > 2G Memory: " << nWidth);
         return;
     }
+#endif
+
+    clipRegion(cr);
+
+    cairo_set_source_rgb(cr,
+        mnTextColor.GetRed()/255.0,
+        mnTextColor.GetGreen()/255.0,
+        mnTextColor.GetBlue()/255.0);
+
+    int nRatio = nWidth * 10 / nHeight;
+
+    // tdf#132112 excessive stretch of underbrace and overbrace can trigger 
freetype into an error, which propogates to cairo
+    // and once a cairo surface is in an error state, that cannot be cleared 
and all subsequent drawing fails, so bodge that
+    // with a high degree of stretch we draw the brace without stretch to a 
temp surface and stretch that to give a far
+    // poorer visual result, but one that can be rendered.
+    if (nGlyphs == 1 && nRatio > 100 && (cairo_glyphs[0].index == 974 || 
cairo_glyphs[0].index == 975) &&
+        rFSD.maTargetName == "OpenSymbol" && !glyph_extrarotation.back() && 
!rLayout.GetOrientation())
+    {
+        CairoFontsCache::CacheId aId = makeCacheId(rLayout);
+        aId.mbVerticalMetrics = false;
+
+        ApplyFont(cr, aId, nWidth, nHeight, 0, rLayout);
+        cairo_text_extents_t stretched_extents;
+        cairo_glyph_extents(cr, cairo_glyphs.data(), nGlyphs, 
&stretched_extents);
+
+        ApplyFont(cr, aId, nHeight, nHeight, 0, rLayout);
+        cairo_text_extents_t unstretched_extents;
+        cairo_glyph_extents(cr, cairo_glyphs.data(), nGlyphs, 
&unstretched_extents);
+
+        cairo_surface_t *target = cairo_get_target(cr);
+        cairo_surface_t *temp_surface = cairo_surface_create_similar(target, 
cairo_surface_get_content(target),
+                                                                     
unstretched_extents.width, unstretched_extents.height);
+        cairo_t *temp_cr = cairo_create(temp_surface);
+        cairo_glyph_t glyph;
+        glyph.x = -unstretched_extents.x_bearing;
+        glyph.y = -unstretched_extents.y_bearing;
+        glyph.index = cairo_glyphs[0].index;
+
+        ApplyFont(temp_cr, aId, nHeight, nHeight, 0, rLayout);
 
+        cairo_set_source_rgb(temp_cr,
+            mnTextColor.GetRed()/255.0,
+            mnTextColor.GetGreen()/255.0,
+            mnTextColor.GetBlue()/255.0);
+
+        cairo_show_glyphs(temp_cr, &glyph, 1);
+        cairo_destroy(temp_cr);
+
+        cairo_set_source_surface(cr, temp_surface, cairo_glyphs[0].x, 
cairo_glyphs[0].y + stretched_extents.y_bearing);
+
+        cairo_pattern_t* sourcepattern = cairo_get_source(cr);
+        cairo_matrix_t matrix;
+        cairo_pattern_get_matrix(sourcepattern, &matrix);
+        cairo_matrix_scale(&matrix, unstretched_extents.width / 
stretched_extents.width, 1);
+        cairo_pattern_set_matrix(sourcepattern, &matrix);
+
+        cairo_rectangle(cr, cairo_glyphs[0].x, cairo_glyphs[0].y + 
stretched_extents.y_bearing, stretched_extents.width, stretched_extents.height);
+        cairo_fill(cr);
+
+        cairo_surface_destroy(temp_surface);
+
+        return;
+    }
+
+    if (nRatio >= 5120)
+    {
+        // as seen with freetype 2.12.1, so cairo surface status is "fail"
+        SAL_WARN("vcl", "rendering text would fail with stretch of: " << 
nRatio / 10.0);
+        return;
+    }
+
+#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
     if (__lsan_disable)
         __lsan_disable();
 #endif
@@ -364,13 +428,6 @@ void CairoTextRender::DrawTextLayout(const 
GenericSalLayout& rLayout, const SalG
             cairo_set_font_options(cr, pFontOptions);
     }
 
-    clipRegion(cr);
-
-    cairo_set_source_rgb(cr,
-        mnTextColor.GetRed()/255.0,
-        mnTextColor.GetGreen()/255.0,
-        mnTextColor.GetBlue()/255.0);
-
     CairoFontsCache::CacheId aId = makeCacheId(rLayout);
 
     std::vector<int>::const_iterator aEnd = glyph_extrarotation.end();
commit 2510d4805482d2cec9059065174825b4260adf0f
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Tue Apr 4 17:26:24 2023 +0100
Commit:     Caolán McNamara <caol...@redhat.com>
CommitDate: Wed Apr 5 09:41:32 2023 +0200

    split out a makeCacheId
    
    Change-Id: I89fbaca1fa7303904681f75ee4a7fc90aeb9ef8e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150030
    Tested-by: Caolán McNamara <caol...@redhat.com>
    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 f3fb3bde6b83..8f093c02c126 100644
--- a/vcl/unx/generic/gdi/cairotextrender.cxx
+++ b/vcl/unx/generic/gdi/cairotextrender.cxx
@@ -188,7 +188,7 @@ static void ApplyFont(cairo_t* cr, const 
CairoFontsCache::CacheId& rId, double n
     if (nGlyphRotation)
         cairo_matrix_rotate(&m, toRadian(Degree10(nGlyphRotation * 900)));
 
-    const FreetypeFontInstance& rInstance = 
static_cast<FreetypeFontInstance&>(rLayout.GetFont());
+    const LogicalFontInstance& rInstance = rLayout.GetFont();
     if (rInstance.NeedsArtificialItalic())
     {
         cairo_matrix_t shear;
@@ -200,11 +200,24 @@ static void ApplyFont(cairo_t* cr, const 
CairoFontsCache::CacheId& rId, double n
     cairo_set_font_matrix(cr, &m);
 }
 
-void CairoTextRender::DrawTextLayout(const GenericSalLayout& rLayout, const 
SalGraphics& rGraphics)
+static CairoFontsCache::CacheId makeCacheId(const GenericSalLayout& rLayout)
 {
     const FreetypeFontInstance& rInstance = 
static_cast<FreetypeFontInstance&>(rLayout.GetFont());
     const FreetypeFont& rFont = rInstance.GetFreetypeFont();
 
+    FT_Face aFace = rFont.GetFtFace();
+    CairoFontsCache::CacheId aId;
+    aId.maFace = aFace;
+    aId.mpOptions = rFont.GetFontOptions();
+    aId.mbEmbolden = rInstance.NeedsArtificialBold();
+
+    return aId;
+}
+
+void CairoTextRender::DrawTextLayout(const GenericSalLayout& rLayout, const 
SalGraphics& rGraphics)
+{
+    const LogicalFontInstance& rInstance = rLayout.GetFont();
+
     const bool bResolutionIndependentLayoutEnabled = 
rLayout.GetTextRenderModeForResolutionIndependentLayout();
 
     /*
@@ -358,11 +371,7 @@ void CairoTextRender::DrawTextLayout(const 
GenericSalLayout& rLayout, const SalG
         mnTextColor.GetGreen()/255.0,
         mnTextColor.GetBlue()/255.0);
 
-    FT_Face aFace = rFont.GetFtFace();
-    CairoFontsCache::CacheId aId;
-    aId.maFace = aFace;
-    aId.mpOptions = rFont.GetFontOptions();
-    aId.mbEmbolden = rInstance.NeedsArtificialBold();
+    CairoFontsCache::CacheId aId = makeCacheId(rLayout);
 
     std::vector<int>::const_iterator aEnd = glyph_extrarotation.end();
     std::vector<int>::const_iterator aStart = glyph_extrarotation.begin();

Reply via email to