[Libreoffice-commits] core.git: filter/source

Marco Cecchetti (via logerrit) logerrit at kemper.freedesktop.org
Tue Mar 9 14:38:35 UTC 2021


 filter/source/svg/presentation_engine.js |  125 +++++++++++++++++++------------
 filter/source/svg/svgexport.cxx          |    6 +
 2 files changed, 83 insertions(+), 48 deletions(-)

New commits:
commit bbf4589df239f480a69f5beba4016c53b8da535e
Author:     Marco Cecchetti <marco.cecchetti at collabora.com>
AuthorDate: Fri Feb 19 16:04:07 2021 +0100
Commit:     Marco Cecchetti <marco.cecchetti at collabora.com>
CommitDate: Tue Mar 9 15:37:53 2021 +0100

    filter: svg: js engine: misplaced text: improving text field handling
    
    Change-Id: I8b5f9a39b3cd3fcfdae0d088eae0a875cf9404ee
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111065
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
    Reviewed-by: Andras Timar <andras.timar at collabora.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111848
    Tested-by: Jenkins
    Reviewed-by: Marco Cecchetti <marco.cecchetti at collabora.com>

diff --git a/filter/source/svg/presentation_engine.js b/filter/source/svg/presentation_engine.js
index 275d455ca4e5..377647c8ec1c 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -5589,68 +5589,99 @@ PlaceholderShape.prototype.isValid = function()
  */
 PlaceholderShape.prototype.init = function()
 {
-
     var aTextFieldElement = getElementByClassName( this.masterPage.backgroundObjects, this.className );
     if( aTextFieldElement )
     {
-        var aPlaceholderElement = getElementByClassName( aTextFieldElement, 'PlaceholderText' );
-        if( aPlaceholderElement )
+        var aTextElem = getElementByClassName( aTextFieldElement, 'SVGTextShape' );
+        if( aTextElem )
         {
-            // Each text field element has an invisible rectangle that can be
-            // regarded as the text field bounding box.
-            // We exploit such a feature and the exported text adjust attribute
-            // value in order to set up correctly the position and text
-            // adjustment for the placeholder element.
-            var aSVGRectElem = getElementByClassName( aTextFieldElement, 'BoundingBox' );
-            if( aSVGRectElem )
+            var aPlaceholderElement = getElementByClassName(aTextElem, 'PlaceholderText');
+            if( aPlaceholderElement )
             {
-                var aRect = new Rectangle( aSVGRectElem );
-                var sTextAdjust = getOOOAttribute( aTextFieldElement, aOOOAttrTextAdjust ) || 'left';
-                var sTextAnchor, sX;
-                if( sTextAdjust == 'left' )
-                {
-                    sTextAnchor = 'start';
-                    sX = String( aRect.left );
-                }
-                else if( sTextAdjust == 'right' )
-                {
-                    sTextAnchor = 'end';
-                    sX = String( aRect.right );
-                }
-                else if( sTextAdjust == 'center' )
+                // SVG 1.1 does not support text wrapping wrt a rectangle.
+                // When a text shape contains a placeholder, setting up the position
+                // of each text line doesn't work since the position is computed
+                // before replacing the placeholder text.
+                // Anyway each text shape has an invisible rectangle that can be
+                // regarded as the text shape bounding box.
+                // We exploit such a feature and the exported text adjust attribute
+                // value in order to set up correctly the position and text
+                // adjustment for the text shape content.
+                // We assume that once the real value has been substituted to
+                // the placeholder the resulting content is no more than a single line.
+                // So we remove from <tspan> elements used for setting up the
+                // position of text lines (class TextPosition) the 'x' and 'y' attribute.
+                // In the general case we would need to implement a function
+                // which is able to compute at which words the text shape content has
+                // to be wrapped.
+                var aSVGRectElem = getElementByClassName( aTextFieldElement, 'BoundingBox' );
+                if( aSVGRectElem )
                 {
-                    sTextAnchor = 'middle';
-                    var nMiddle = ( aRect.left + aRect.right ) / 2;
-                    sX = String( parseInt( String( nMiddle ) ) );
+                    var aRect = new Rectangle( aSVGRectElem );
+                    var sTextAdjust = getOOOAttribute( aTextFieldElement, aOOOAttrTextAdjust );
+                    // the bbox of the text shape is indeed a bit larger, there is a bit of internal padding
+                    var nMargin = 250; // 1000th mm
+                    var sTextAnchor, sX;
+                    if( sTextAdjust == 'left' )
+                    {
+                        sTextAnchor = 'start';
+                        sX = String( Math.trunc( aRect.left + nMargin ) );
+                    }
+                    else if( sTextAdjust == 'right' )
+                    {
+                        sTextAnchor = 'end';
+                        sX = String( Math.trunc( aRect.right - nMargin ) );
+                    }
+                    else if( sTextAdjust == 'center' )
+                    {
+                        sTextAnchor = 'middle';
+                        var nMiddle = ( aRect.left + aRect.right ) / 2;
+                        sX = String( parseInt( String( nMiddle ) ) );
+                    }
+                    if( sTextAnchor )
+                    {
+                        aTextElem.setAttribute( 'text-anchor', sTextAnchor );
+                        if( sX )
+                            aTextElem.setAttribute( 'x', sX );
+
+                        var aTSpanElements = getElementsByClassName( aTextElem, 'TextPosition' );
+                        if( aTSpanElements )
+                        {
+                            var i = 0;
+                            for( ; i < aTSpanElements.length; ++i )
+                            {
+                                var aTSpanElem = aTSpanElements[i];
+                                aTSpanElem.removeAttribute( 'x' );
+                                if( i !== 0 )
+                                    aTSpanElem.removeAttribute( 'y' );
+                            }
+                        }
+                    }
                 }
-                if( sTextAnchor )
-                    aPlaceholderElement.setAttribute( 'text-anchor', sTextAnchor );
-                if( sX )
-                    aPlaceholderElement.setAttribute( 'x', sX );
-            }
 
-            // date/time fields were not exported correctly when positioned chars are used
-            if( this.masterPage.metaSlide.theMetaDoc.bIsUsePositionedChars )
-            {
-                // We remove all text lines but the first one used as placeholder.
-                var aTextLineGroupElem = aPlaceholderElement.parentNode.parentNode;
-                if( aTextLineGroupElem )
+                // date/time fields were not exported correctly when positioned chars are used
+                if( this.masterPage.metaSlide.theMetaDoc.bIsUsePositionedChars )
                 {
-                    // Just to be sure it is the element we are looking for.
-                    var sFontFamilyAttr = aTextLineGroupElem.getAttribute( 'font-family' );
-                    if( sFontFamilyAttr )
+                    // We remove all text lines but the first one used as placeholder.
+                    var aTextLineGroupElem = aPlaceholderElement.parentNode.parentNode;
+                    if( aTextLineGroupElem )
                     {
-                        var aChildSet = getElementChildren( aTextLineGroupElem );
-                        if( aChildSet.length > 1  )
-                            var i = 1;
-                        for( ; i < aChildSet.length; ++i )
+                        // Just to be sure it is the element we are looking for.
+                        var sFontFamilyAttr = aTextLineGroupElem.getAttribute( 'font-family' );
+                        if( sFontFamilyAttr )
                         {
-                            aTextLineGroupElem.removeChild( aChildSet[i] );
+                            var aChildSet = getElementChildren( aTextLineGroupElem );
+                            if( aChildSet.length > 1 )
+                                var i = 1;
+                            for( ; i < aChildSet.length; ++i )
+                            {
+                                aTextLineGroupElem.removeChild( aChildSet[i] );
+                            }
                         }
                     }
                 }
+                this.textElement = aPlaceholderElement;
             }
-            this.textElement = aPlaceholderElement;
         }
         this.element = aTextFieldElement;
     }
diff --git a/filter/source/svg/svgexport.cxx b/filter/source/svg/svgexport.cxx
index 96da555f5279..d3e074620e66 100644
--- a/filter/source/svg/svgexport.cxx
+++ b/filter/source/svg/svgexport.cxx
@@ -2110,14 +2110,18 @@ bool SVGFilter::implExportShape( const Reference< css::drawing::XShape >& rxShap
                         bool bIsPageNumber  = ( aShapeClass == "Slide_Number" );
                         bool bIsFooter      = ( aShapeClass == "Footer" );
                         bool bIsDateTime    = ( aShapeClass == "Date/Time" );
-                        if( bIsPageNumber || bIsDateTime || bIsFooter )
+                        bool bTextField = bIsPageNumber || bIsFooter || bIsDateTime;
+                        if( bTextField )
                         {
                             // to notify to the SVGActionWriter::ImplWriteActions method
                             // that we are dealing with a placeholder shape
                             pElementId = &sPlaceholderTag;
 
                             mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "visibility", "hidden" );
+                        }
 
+                        if( bTextField || ( aShapeClass == "TextShape" ) )
+                        {
                             sal_uInt16 nTextAdjust = sal_uInt16(ParagraphAdjust_LEFT);
                             OUString sTextAdjust;
                             xShapePropSet->getPropertyValue( "ParaAdjust" ) >>= nTextAdjust;


More information about the Libreoffice-commits mailing list