summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Cecchetti <marco.cecchetti@collabora.com>2021-02-19 16:04:07 +0100
committerMarco Cecchetti <marco.cecchetti@collabora.com>2021-03-09 15:37:53 +0100
commitbbf4589df239f480a69f5beba4016c53b8da535e (patch)
treeb80e431e8429670c7e199121ece5a27b739ff6eb
parentbee3a7bdd0effd15f36e3debd1c6e20af12b4ea3 (diff)
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@gmail.com> Reviewed-by: Andras Timar <andras.timar@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111848 Tested-by: Jenkins Reviewed-by: Marco Cecchetti <marco.cecchetti@collabora.com>
-rw-r--r--filter/source/svg/presentation_engine.js125
-rw-r--r--filter/source/svg/svgexport.cxx6
2 files changed, 83 insertions, 48 deletions
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;