summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarco Cecchetti <marco.cecchetti@collabora.com>2021-02-19 16:04:07 +0100
committerAndras Timar <andras.timar@collabora.com>2021-02-22 20:04:48 +0100
commit5ad541462aec381bb6a9d86db5ed20ecb6ddb496 (patch)
treee77ef7e309823e78c1db9ed818938c6c1fc69181
parentfilter: svg: unit test for placeholder locale (diff)
downloadcore-5ad541462aec381bb6a9d86db5ed20ecb6ddb496.tar.gz
core-5ad541462aec381bb6a9d86db5ed20ecb6ddb496.zip
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>
-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 0d4fc767c4ad..24fd4f53d2a7 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -5575,68 +5575,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 dec88345b43d..1f71feafe93a 100644
--- a/filter/source/svg/svgexport.cxx
+++ b/filter/source/svg/svgexport.cxx
@@ -2135,14 +2135,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;