Date: prev next · Thread: first prev next last
2010 Archives by date, by thread · List index


Hi Caolan,

took your patch, handled one more case - could you please review &
commit to libreoffice-3-3 if ok?

Cheers,

-- Thorsten
From 25ae4e3bf1632150aa54769ed5b3235cbfa2af2f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= <caolanm@redhat.com>
Date: Fri, 3 Dec 2010 11:15:24 +0100
Subject: [PATCH] Fix glyph fallback for cairocanvas (fdo#31243)

* set font fallback info on glyph vector inside vcl
* pick actual fallback font when rendering glyphs in cairocanvas
---
 canvas/source/cairo/cairo_textlayout.cxx |  323 +++++++++++++++++-------------
 vcl/inc/vcl/sysdata.hxx                  |    9 +-
 vcl/source/gdi/outdev3.cxx               |    8 +-
 3 files changed, 189 insertions(+), 151 deletions(-)

diff --git a/canvas/source/cairo/cairo_textlayout.cxx b/canvas/source/cairo/cairo_textlayout.cxx
index d8b8126..506c9d5 100644
--- a/canvas/source/cairo/cairo_textlayout.cxx
+++ b/canvas/source/cairo/cairo_textlayout.cxx
@@ -106,6 +106,11 @@ namespace cairocanvas
             // as required at the API spec
             rOutDev.SetLayoutMode( nLayoutMode | TEXT_LAYOUT_TEXTORIGIN_LEFT );
         }
+
+        bool compareFallbacks(const SystemGlyphData&rA, const SystemGlyphData &rB)
+        {
+            return rA.fallbacklevel < rB.fallbacklevel;
+        }
     }
 
     TextLayout::TextLayout( const rendering::StringContext&    aText, 
@@ -364,7 +369,6 @@ namespace cairocanvas
         return true;
     }
 
-        
   /**
    * TextLayout::draw
    *
@@ -405,18 +409,41 @@ namespace cairocanvas
                                                       
::canvas::tools::numeric_cast<USHORT>(maText.Length),
                                                       maLogicalAdvancements.getLength() ? 
aOffsets.get() : NULL);
 
+        // Sort them so that all glyphs on the same glyph fallback level are consecutive
+        std::sort(aSysLayoutData.rGlyphData.begin(), aSysLayoutData.rGlyphData.end(), 
compareFallbacks);
+        bool bCairoRenderable = true;
+
+        //Pull all the fonts we need to render the text
+        typedef std::pair<SystemFontData,int> FontLevel;
+        typedef std::vector<FontLevel> FontLevelVector;
+        FontLevelVector aFontData;
+        SystemGlyphDataVector::const_iterator aIter=aSysLayoutData.rGlyphData.begin();
+        const SystemGlyphDataVector::const_iterator aEnd=aSysLayoutData.rGlyphData.end();
+        for( ; aIter != aEnd; ++aIter )
+        {
+            if( aFontData.empty() || aIter->fallbacklevel != aFontData.back().second )
+            {
+                aFontData.push_back(FontLevel(rOutDev.GetSysFontData(aIter->fallbacklevel), 
+                                              aIter->fallbacklevel));
+                if( !isCairoRenderable(aFontData.back().first) )
+                {
+                    bCairoRenderable = false;
+                    OSL_TRACE(":cairocanvas::TextLayout::draw(S,O,p,v,r): VCL FALLBACK %s%s%s%s - 
%s",
+                              maLogicalAdvancements.getLength() ? "ADV " : "",
+                              aFontData.back().first.bAntialias ? "AA " : "",
+                              aFontData.back().first.bFakeBold ? "FB " : "",
+                              aFontData.back().first.bFakeItalic ? "FI " : "",
+                              ::rtl::OUStringToOString( maText.Text.copy( maText.StartPosition, 
maText.Length ),
+                                                        RTL_TEXTENCODING_UTF8 ).getStr());
+                    break;
+                }
+            }
+        }
+
         // The ::GetSysTextLayoutData(), i.e. layouting of text to glyphs can change the font 
being used.
         // The fallback checks need to be done after final font is known.
-        if (!isCairoRenderable(aSysLayoutData.aSysFontData))    // VCL FALLBACKS
+        if (!bCairoRenderable)    // VCL FALLBACKS
         {
-            OSL_TRACE(":cairocanvas::TextLayout::draw(S,O,p,v,r): VCL FALLBACK %s%s%s%s - %s",
-                      maLogicalAdvancements.getLength() ? "ADV " : "",
-                      aSysLayoutData.aSysFontData.bAntialias ? "AA " : "",
-                      aSysLayoutData.aSysFontData.bFakeBold ? "FB " : "",
-                      aSysLayoutData.aSysFontData.bFakeItalic ? "FI " : "",
-                      ::rtl::OUStringToOString( maText.Text.copy( maText.StartPosition, 
maText.Length ),
-                                                RTL_TEXTENCODING_UTF8 ).getStr());
-            
             if (maLogicalAdvancements.getLength())        // VCL FALLBACK - with glyph advances
             {
                 rOutDev.DrawTextArray( rOutpos, maText.Text, aOffsets.get(),
@@ -438,145 +465,159 @@ namespace cairocanvas
         /**
          * Setup platform independent glyph vector into cairo-based glyphs vector. 
          **/
-        
-        // setup glyphs
-        std::vector<cairo_glyph_t> cairo_glyphs;
-        cairo_glyphs.reserve( 256 );
-        
-        for( int nStart = 0; nStart < (int) aSysLayoutData.rGlyphData.size(); nStart++ )
+       
+        // Loop through the fonts used and render the matching glyphs for each
+        FontLevelVector::const_iterator aFontDataIter = aFontData.begin();
+        const FontLevelVector::const_iterator aFontDataEnd = aFontData.end();
+        for( ; aFontDataIter != aFontDataEnd; ++aFontDataIter )
         {
-            cairo_glyph_t aGlyph;
-            SystemGlyphData systemGlyph = aSysLayoutData.rGlyphData.at(nStart);
-            aGlyph.index = systemGlyph.index;
-#ifdef CAIRO_HAS_WIN32_SURFACE
-            // Cairo requires standard glyph indexes (ETO_GLYPH_INDEX), while vcl/win/* uses ucs4 
chars. 
-            // Convert to standard indexes
-            aGlyph.index = cairo::ucs4toindex((unsigned int) aGlyph.index, 
aSysLayoutData.aSysFontData.hFont);
-#endif
-            aGlyph.x = systemGlyph.x;
-            aGlyph.y = systemGlyph.y;
-            cairo_glyphs.push_back(aGlyph);
-        }
-
-        if (cairo_glyphs.empty()) return true;  //true or false??
-        
-        /**
-         * Setup font
-         **/        
-        cairo_font_face_t* font_face = NULL;
+            const SystemFontData &rSysFontData = aFontDataIter->first;
 
-#ifdef CAIRO_HAS_QUARTZ_SURFACE
-        // TODO: use cairo_quartz_font_face_create_for_cgfont(cgFont)
-        //       when CGFont (Mac OS X 10.5 API) is provided by the AQUA VCL backend.
-        font_face = cairo_quartz_font_face_create_for_atsu_font_id((ATSUFontID) 
aSysLayoutData.aSysFontData.aATSUFontID);
-        
-#elif defined CAIRO_HAS_WIN32_SURFACE        
-  #if (OSL_DEBUG_LEVEL > 1)
-        GetObjectW( aSysLayoutData.aSysFontData.hFont, sizeof(logfont), &logfont );
-  #endif
-        // Note: cairo library uses logfont fallbacks when lfEscapement, lfOrientation and lfWidth 
are not zero.
-        // VCL always has non-zero value for lfWidth
-        font_face = cairo_win32_font_face_create_for_hfont(aSysLayoutData.aSysFontData.hFont);
-        
-#elif defined CAIRO_HAS_XLIB_SURFACE
-        font_face = 
cairo_ft_font_face_create_for_ft_face((FT_Face)aSysLayoutData.aSysFontData.nFontId,
-                                                          aSysLayoutData.aSysFontData.nFontFlags);
-#else
-# error Native API needed. 
-#endif
+            // setup glyphs
+            std::vector<cairo_glyph_t> cairo_glyphs;
+            cairo_glyphs.reserve( 256 );
+            
+            SystemGlyphDataVector::const_iterator aIter=aSysLayoutData.rGlyphData.begin();
+            const SystemGlyphDataVector::const_iterator aEnd=aSysLayoutData.rGlyphData.end();
+            for( ; aIter != aEnd; ++aIter )
+            {
+                SystemGlyphData systemGlyph = *aIter;
+                if( systemGlyph.fallbacklevel != aFontDataIter->second )
+                    continue;
+
+                cairo_glyph_t aGlyph;
+                aGlyph.index = systemGlyph.index;
+    #ifdef CAIRO_HAS_WIN32_SURFACE
+                // Cairo requires standard glyph indexes (ETO_GLYPH_INDEX), while vcl/win/* uses 
ucs4 chars. 
+                // Convert to standard indexes
+                aGlyph.index = cairo::ucs4toindex((unsigned int) aGlyph.index, rSysFontData.hFont);
+    #endif
+                aGlyph.x = systemGlyph.x;
+                aGlyph.y = systemGlyph.y;
+                cairo_glyphs.push_back(aGlyph);
+            }
 
-        CairoSharedPtr pSCairo = pSurface->getCairo();
-        
-        cairo_set_font_face( pSCairo.get(), font_face);
-
-        // create default font options. cairo_get_font_options() does not retrieve the surface 
defaults,
-        // only what has been set before with cairo_set_font_options()
-        cairo_font_options_t* options = cairo_font_options_create();
-        if (aSysLayoutData.aSysFontData.bAntialias) {
-            // CAIRO_ANTIALIAS_GRAY provides more similar result to VCL Canvas,
-            // so we're not using CAIRO_ANTIALIAS_SUBPIXEL
-            cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY); 
-        }
-        cairo_set_font_options( pSCairo.get(), options);
-
-        // Font color
-        Color mTextColor = rOutDev.GetTextColor();
-        cairo_set_source_rgb(pSCairo.get(), 
-                             mTextColor.GetRed()/255.0, 
-                             mTextColor.GetGreen()/255.0,
-                             mTextColor.GetBlue()/255.0);
-        
-        // Font rotation and scaling
-        cairo_matrix_t m;
-        Font aFont = rOutDev.GetFont();
-        FontMetric aMetric( rOutDev.GetFontMetric(aFont) );
-        long nWidth = 0;
-        
-        // width calculation is deep magic and platform/font dependant.
-        // width == 0 means no scaling, and usually width == height means the same.
-        // Other values mean horizontal scaling (narrow or stretching)
-        // see issue #101566
-
-        //proper scale calculation across platforms
-        if (aFont.GetWidth() == 0) {
-            nWidth = aFont.GetHeight();
-        } else {
-            // any scaling needs to be relative to the platform-dependent definition
-            // of height of the font
-            nWidth = aFont.GetWidth() * aFont.GetHeight() / aMetric.GetHeight();
-        }
-        
-        cairo_matrix_init_identity(&m);
-        
-        if (aSysLayoutData.orientation) cairo_matrix_rotate(&m, (3600 - 
aSysLayoutData.orientation) * M_PI / 1800.0);
-        
-        cairo_matrix_scale(&m, nWidth, aFont.GetHeight());
+            if (cairo_glyphs.empty()) 
+                continue;
+            
+            /**
+             * Setup font
+             **/        
+            cairo_font_face_t* font_face = NULL;
+
+    #ifdef CAIRO_HAS_QUARTZ_SURFACE
+            // TODO: use cairo_quartz_font_face_create_for_cgfont(cgFont)
+            //       when CGFont (Mac OS X 10.5 API) is provided by the AQUA VCL backend.
+            font_face = cairo_quartz_font_face_create_for_atsu_font_id((ATSUFontID) 
rSysFontData.aATSUFontID);
+            
+    #elif defined CAIRO_HAS_WIN32_SURFACE        
+      #if (OSL_DEBUG_LEVEL > 1)
+            GetObjectW( rSysFontData.hFont, sizeof(logfont), &logfont );
+      #endif
+            // Note: cairo library uses logfont fallbacks when lfEscapement, lfOrientation and 
lfWidth are not zero.
+            // VCL always has non-zero value for lfWidth
+            font_face = cairo_win32_font_face_create_for_hfont(rSysFontData.hFont);
+            
+    #elif defined CAIRO_HAS_XLIB_SURFACE
+            font_face = cairo_ft_font_face_create_for_ft_face((FT_Face)rSysFontData.nFontId,
+                                                              rSysFontData.nFontFlags);
+    #else
+    # error Native API needed. 
+    #endif
+
+            CairoSharedPtr pSCairo = pSurface->getCairo();
+            
+            cairo_set_font_face( pSCairo.get(), font_face);
+
+            // create default font options. cairo_get_font_options() does not retrieve the surface 
defaults,
+            // only what has been set before with cairo_set_font_options()
+            cairo_font_options_t* options = cairo_font_options_create();
+            if (rSysFontData.bAntialias) {
+                // CAIRO_ANTIALIAS_GRAY provides more similar result to VCL Canvas,
+                // so we're not using CAIRO_ANTIALIAS_SUBPIXEL
+                cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY); 
+            }
+            cairo_set_font_options( pSCairo.get(), options);
+
+            // Font color
+            Color mTextColor = rOutDev.GetTextColor();
+            cairo_set_source_rgb(pSCairo.get(), 
+                                 mTextColor.GetRed()/255.0, 
+                                 mTextColor.GetGreen()/255.0,
+                                 mTextColor.GetBlue()/255.0);
+            
+            // Font rotation and scaling
+            cairo_matrix_t m;
+            Font aFont = rOutDev.GetFont();
+            FontMetric aMetric( rOutDev.GetFontMetric(aFont) );
+            long nWidth = 0;
+            
+            // width calculation is deep magic and platform/font dependant.
+            // width == 0 means no scaling, and usually width == height means the same.
+            // Other values mean horizontal scaling (narrow or stretching)
+            // see issue #101566
+
+            //proper scale calculation across platforms
+            if (aFont.GetWidth() == 0) {
+                nWidth = aFont.GetHeight();
+            } else {
+                // any scaling needs to be relative to the platform-dependent definition
+                // of height of the font
+                nWidth = aFont.GetWidth() * aFont.GetHeight() / aMetric.GetHeight();
+            }
+            
+            cairo_matrix_init_identity(&m);
+            
+            if (aSysLayoutData.orientation) cairo_matrix_rotate(&m, (3600 - 
aSysLayoutData.orientation) * M_PI / 1800.0);
+            
+            cairo_matrix_scale(&m, nWidth, aFont.GetHeight());
 
-        //faux italics
-        if (aSysLayoutData.aSysFontData.bFakeItalic) m.xy = -m.xx * 0x6000L / 0x10000L;
-        
-        cairo_set_font_matrix(pSCairo.get(), &m);
-        
-        OSL_TRACE("\r\n:cairocanvas::TextLayout::draw(S,O,p,v,r): Size:(%d,%d), W:%d->%d, Pos 
(%d,%d), G(%d,%d,%d) %s%s%s%s || Name:%s - %s", 
-                  aFont.GetWidth(),
-                  aFont.GetHeight(),
-                  aMetric.GetWidth(),
-                  nWidth,
-                  (int) rOutpos.X(),
-                  (int) rOutpos.Y(),
-                  cairo_glyphs[0].index, cairo_glyphs[1].index, cairo_glyphs[2].index, 
-                  maLogicalAdvancements.getLength() ? "ADV " : "",
-                  aSysLayoutData.aSysFontData.bAntialias ? "AA " : "",
-                  aSysLayoutData.aSysFontData.bFakeBold ? "FB " : "",
-                  aSysLayoutData.aSysFontData.bFakeItalic ? "FI " : "",
-#if (defined CAIRO_HAS_WIN32_SURFACE) && (OSL_DEBUG_LEVEL > 1)
-                  ::rtl::OUStringToOString( reinterpret_cast<const sal_Unicode*> 
(logfont.lfFaceName), RTL_TEXTENCODING_UTF8 ).getStr(),
-#else
-                  ::rtl::OUStringToOString( aFont.GetName(), RTL_TEXTENCODING_UTF8 ).getStr(),
-#endif
-                  ::rtl::OUStringToOString( maText.Text.copy( maText.StartPosition, maText.Length 
),
-                                            RTL_TEXTENCODING_UTF8 ).getStr()
-            );
-        
-        cairo_show_glyphs(pSCairo.get(), &cairo_glyphs[0], cairo_glyphs.size());
-        
-        //faux bold
-        if (aSysLayoutData.aSysFontData.bFakeBold) {
-            double bold_dx = 0.5 * sqrt( 0.7 * aFont.GetHeight() );
-            int total_steps = 2 * ((int) (bold_dx + 0.5));
+            //faux italics
+            if (rSysFontData.bFakeItalic) m.xy = -m.xx * 0x6000L / 0x10000L;
+            
+            cairo_set_font_matrix(pSCairo.get(), &m);
+            
+            OSL_TRACE("\r\n:cairocanvas::TextLayout::draw(S,O,p,v,r): Size:(%d,%d), W:%d->%d, Pos 
(%d,%d), G(%d,%d,%d) %s%s%s%s || Name:%s - %s", 
+                      aFont.GetWidth(),
+                      aFont.GetHeight(),
+                      aMetric.GetWidth(),
+                      nWidth,
+                      (int) rOutpos.X(),
+                      (int) rOutpos.Y(),
+                      cairo_glyphs[0].index, cairo_glyphs[1].index, cairo_glyphs[2].index, 
+                      maLogicalAdvancements.getLength() ? "ADV " : "",
+                      rSysFontData.bAntialias ? "AA " : "",
+                      rSysFontData.bFakeBold ? "FB " : "",
+                      rSysFontData.bFakeItalic ? "FI " : "",
+    #if (defined CAIRO_HAS_WIN32_SURFACE) && (OSL_DEBUG_LEVEL > 1)
+                      ::rtl::OUStringToOString( reinterpret_cast<const sal_Unicode*> 
(logfont.lfFaceName), RTL_TEXTENCODING_UTF8 ).getStr(),
+    #else
+                      ::rtl::OUStringToOString( aFont.GetName(), RTL_TEXTENCODING_UTF8 ).getStr(),
+    #endif
+                      ::rtl::OUStringToOString( maText.Text.copy( maText.StartPosition, 
maText.Length ),
+                                                RTL_TEXTENCODING_UTF8 ).getStr()
+                );
+            
+            cairo_show_glyphs(pSCairo.get(), &cairo_glyphs[0], cairo_glyphs.size());
             
-            // loop to draw the text for every half pixel of displacement
-            for (int nSteps = 0; nSteps < total_steps; nSteps++) {
-                for(int nGlyphIdx = 0; nGlyphIdx < (int) cairo_glyphs.size(); nGlyphIdx++) {
-                    cairo_glyphs[nGlyphIdx].x += bold_dx * nSteps / total_steps;
+            //faux bold
+            if (rSysFontData.bFakeBold) {
+                double bold_dx = 0.5 * sqrt( 0.7 * aFont.GetHeight() );
+                int total_steps = 2 * ((int) (bold_dx + 0.5));
+                
+                // loop to draw the text for every half pixel of displacement
+                for (int nSteps = 0; nSteps < total_steps; nSteps++) {
+                    for(int nGlyphIdx = 0; nGlyphIdx < (int) cairo_glyphs.size(); nGlyphIdx++) {
+                        cairo_glyphs[nGlyphIdx].x += bold_dx * nSteps / total_steps;
+                    }
+                    cairo_show_glyphs(pSCairo.get(), &cairo_glyphs[0], cairo_glyphs.size());
                 }
-                cairo_show_glyphs(pSCairo.get(), &cairo_glyphs[0], cairo_glyphs.size());
+                OSL_TRACE(":cairocanvas::TextLayout::draw(S,O,p,v,r): FAKEBOLD - dx:%d", (int) 
bold_dx);
             }
-            OSL_TRACE(":cairocanvas::TextLayout::draw(S,O,p,v,r): FAKEBOLD - dx:%d", (int) 
bold_dx);
+            
+            cairo_restore( pSCairo.get() );
+            cairo_font_face_destroy(font_face); 
         }
-        
-        cairo_restore( pSCairo.get() );
-        cairo_font_face_destroy(font_face); 
         return true;
     }
 
diff --git a/vcl/inc/vcl/sysdata.hxx b/vcl/inc/vcl/sysdata.hxx
index 018872b..1a8f56d 100644
--- a/vcl/inc/vcl/sysdata.hxx
+++ b/vcl/inc/vcl/sysdata.hxx
@@ -151,6 +151,7 @@ struct SystemGlyphData
     unsigned long        index;
     double               x;
     double               y;
+    int                  fallbacklevel;
 };
 
 
@@ -179,12 +180,12 @@ struct SystemFontData
 // - SystemTextLayoutData -
 // --------------------
 
+typedef std::vector<SystemGlyphData> SystemGlyphDataVector;
 struct SystemTextLayoutData
 {
-    unsigned long      nSize;                      // size in bytes of this structure
-    std::vector<SystemGlyphData> rGlyphData;    // glyph data
-    int             orientation;                // Text orientation
-    SystemFontData aSysFontData;                // Font data for the text layout
+    unsigned long            nSize;         // size in bytes of this structure
+    SystemGlyphDataVector rGlyphData;    // glyph data
+    int                   orientation;   // Text orientation
 };
 
 #endif // _SV_SYSDATA_HXX
diff --git a/vcl/source/gdi/outdev3.cxx b/vcl/source/gdi/outdev3.cxx
index b898258..96bfab5 100644
--- a/vcl/source/gdi/outdev3.cxx
+++ b/vcl/source/gdi/outdev3.cxx
@@ -7339,7 +7339,6 @@ SystemTextLayoutData OutputDevice::GetSysTextLayoutData(const Point& 
rStartPt, c
     // setup glyphs
     Point aPos;
     sal_GlyphId aGlyphId;
-    int nFallbacklevel = 0;
     for( int nStart = 0; rLayout->GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); )
     {
         // NOTE: Windows backend is producing unicode chars (ucs4), so on windows,
@@ -7349,15 +7348,12 @@ SystemTextLayoutData OutputDevice::GetSysTextLayoutData(const Point& 
rStartPt, c
         aGlyph.index = static_cast<unsigned long> (aGlyphId & GF_IDXMASK);
         aGlyph.x = aPos.X();
         aGlyph.y = aPos.Y();
-        aSysLayoutData.rGlyphData.push_back(aGlyph);
-
         int nLevel = (aGlyphId & GF_FONTMASK) >> GF_FONTSHIFT;
-        if (nLevel > nFallbacklevel && nLevel < MAX_FALLBACK)
-            nFallbacklevel = nLevel;
+        aGlyph.fallbacklevel = nLevel < MAX_FALLBACK ? nLevel : 0;
+        aSysLayoutData.rGlyphData.push_back(aGlyph);
     }
 
     // Get font data
-    aSysLayoutData.aSysFontData = GetSysFontData(nFallbacklevel);
     aSysLayoutData.orientation = rLayout->GetOrientation();
     
     rLayout->Release();
-- 
1.7.1

Attachment: pgpK149_K69ZZ.pgp
Description: PGP signature


Context


Privacy Policy | Impressum (Legal Info) | Copyright information: Unless otherwise specified, all text and images on this website are licensed under the Creative Commons Attribution-Share Alike 3.0 License. This does not include the source code of LibreOffice, which is licensed under the Mozilla Public License (MPLv2). "LibreOffice" and "The Document Foundation" are registered trademarks of their corresponding registered owners or are in actual use as trademarks in one or more countries. Their respective logos and icons are also subject to international copyright laws. Use thereof is explained in our trademark policy.