[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-6.2' - 4 commits - filter/source sd/qa
Marco Cecchetti (via logerrit)
logerrit at kemper.freedesktop.org
Wed Jan 20 06:49:00 UTC 2021
filter/source/svg/presentation_engine.js | 202 +++++++++++++++++++-----
filter/source/svg/svgexport.cxx | 73 ++++++--
filter/source/svg/svgwriter.cxx | 35 ++++
filter/source/svg/svgwriter.hxx | 1
sd/qa/unit/SVGExportTests.cxx | 14 +
sd/qa/unit/data/odp/slide-custom-background.odp |binary
6 files changed, 264 insertions(+), 61 deletions(-)
New commits:
commit 10db92590353caeb515dd650a32eb09f352eea98
Author: Marco Cecchetti <marco.cecchetti at collabora.com>
AuthorDate: Sun Jan 17 23:36:53 2021 +0100
Commit: Andras Timar <andras.timar at collabora.com>
CommitDate: Tue Jan 19 15:16:08 2021 +0100
filter: svg: js engine: improving text fields handling
Added support for slide number and current date, current time fields
inserted by the user on slides or master pages.
Change-Id: If21b06c58e8fdcc240a540ee6fa87f48a6eb86af
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/109496
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
Reviewed-by: Ashod Nakashian <ash at collabora.com>
diff --git a/filter/source/svg/presentation_engine.js b/filter/source/svg/presentation_engine.js
index 4dd876defba9..d0d0a0b60db7 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -4458,6 +4458,8 @@ var aSlideNumberClassName = 'Slide_Number';
var aDateTimeClassName = 'Date/Time';
var aFooterClassName = 'Footer';
var aHeaderClassName = 'Header';
+var aDateClassName = 'Date';
+var aTimeClassName = 'Time';
// Creating a namespace dictionary.
var NSS = {};
@@ -4895,6 +4897,8 @@ function MetaDocument()
this.aTextFieldHandlerSet = {};
this.aTextFieldContentProviderSet = [];
this.aSlideNumberProvider = new SlideNumberProvider( this.nStartSlideNumber + 1, this.sPageNumberingType );
+ this.aCurrentDateProvider = new CurrentDateTimeProvider( null, '<date>' );
+ this.aCurrentTimeProvider = new CurrentDateTimeProvider( null, '<time>' );
// We create a map with key an id and value the svg element containing
// the animations performed on the slide with such an id.
@@ -5050,6 +5054,9 @@ function MetaSlide( sMetaSlideId, aMetaDoc )
this.backgroundId = this.backgroundElement.getAttribute( 'id' );
}
+ // We initialize text fields
+ this.initPlaceholderElements();
+
// We initialize the MasterPage object that provides direct access to
// the target master page element.
this.masterPage = this.initMasterPage();
@@ -5076,6 +5083,8 @@ function MetaSlide( sMetaSlideId, aMetaDoc )
this.aTextFieldContentProviderSet[aDateTimeClassName] = this.initDateTimeFieldContentProvider( aOOOAttrDateTimeField );
this.aTextFieldContentProviderSet[aFooterClassName] = this.initFixedTextFieldContentProvider( aOOOAttrFooterField );
this.aTextFieldContentProviderSet[aHeaderClassName] = this.initFixedTextFieldContentProvider( aOOOAttrHeaderField );
+ this.aTextFieldContentProviderSet[aDateClassName] = this.theMetaDoc.aCurrentDateProvider;
+ this.aTextFieldContentProviderSet[aTimeClassName] = this.theMetaDoc.aCurrentTimeProvider;
// We init the slide duration when automatic slide transition is enabled
this.fDuration = this.initSlideDuration();
@@ -5146,6 +5155,23 @@ updateMasterPageView : function()
},
/*** private methods ***/
+
+// It handles a text field inserted on a slide, not on a master page.
+initPlaceholderElements : function()
+{
+ var aPlaceholderList = getElementsByClassName(this.pageElement , 'PlaceholderText' );
+ var i = 0;
+ for( ; i < aPlaceholderList.length; ++i )
+ {
+ var aPlaceholderElem = aPlaceholderList[i];
+ var sContent = aPlaceholderElem.textContent;
+ if( sContent === '<date>' )
+ aPlaceholderElem.textContent = new Date().toLocaleDateString();
+ else if( sContent === '<time>' )
+ aPlaceholderElem.textContent = new Date().toLocaleTimeString();
+ }
+},
+
initMasterPage : function()
{
var sMasterPageId = this.element.getAttributeNS( NSS['ooo'], aOOOAttrMaster );
@@ -5322,6 +5348,34 @@ getSlideAnimationsRoot : function()
}; // end MetaSlide prototype
+function getTextFieldType ( elem )
+{
+ var sFieldType = null;
+ var sClass = elem.getAttribute('class');
+ if( sClass.endsWith( 'TextShape' ) )
+ {
+ var aPlaceholderElement = getElementByClassName( elem, 'PlaceholderText' );
+ if (aPlaceholderElement)
+ {
+ var sContent = aPlaceholderElement.textContent
+ if (sContent === '<number>')
+ sFieldType = aSlideNumberClassName;
+ else if (sContent === '<date>')
+ sFieldType = aDateClassName;
+ else if (sContent === '<time>')
+ sFieldType = aTimeClassName;
+ }
+ }
+ return sFieldType;
+}
+
+function isTextFieldByClassName ( sClassName )
+{
+ return sClassName === aDateTimeClassName || sClassName === aFooterClassName
+ || sClassName === aHeaderClassName || sClassName.startsWith( aSlideNumberClassName )
+ || sClassName.startsWith( aDateClassName ) || sClassName.startsWith( aTimeClassName );
+}
+
/** Class MasterPage
* This class gives direct access to a master page element and to the following
* elements included in the master page:
@@ -5384,6 +5438,7 @@ function MasterPage( sMasterPageId, aMetaSlide )
// The background objects group element that contains every element presents
// on the master page except the background element.
this.backgroundObjects = getElementByClassName( this.element, 'BackgroundObjects' );
+ this.aBackgroundObjectSubGroupIdList = [];
if( this.backgroundObjects )
{
this.backgroundObjectsId = this.backgroundObjects.getAttribute( 'id' );
@@ -5397,13 +5452,26 @@ function MasterPage( sMasterPageId, aMetaSlide )
var nSubGroupId = 1;
var sClass;
var sId = '';
- this.aBackgroundObjectSubGroupIdList = [];
var i = 0;
for( ; i < aBackgroundObjectList.length; ++i )
{
- sClass = aBackgroundObjectList[i].getAttribute( 'class' );
- if( !sClass || ( ( sClass !== aDateTimeClassName ) && ( sClass !== aFooterClassName )
- && ( sClass !== aHeaderClassName ) && ( sClass !== aSlideNumberClassName ) ) )
+ var aObject = aBackgroundObjectList[i];
+ sClass = null;
+ var sFieldType = getTextFieldType( aObject );
+ if( sFieldType && aObject.firstElementChild )
+ {
+ var sObjId = aObject.firstElementChild.getAttribute( 'id' );
+ if( sObjId )
+ {
+ sClass = sFieldType + '.' + sObjId;
+ aObject.setAttribute('class', sClass);
+ }
+ }
+ if( !sClass )
+ {
+ sClass = aBackgroundObjectList[i].getAttribute('class');
+ }
+ if( !sClass || !isTextFieldByClassName( sClass ) )
{
if( nCount === 0 )
{
@@ -5447,10 +5515,14 @@ MasterPage.prototype =
initPlaceholderShapes : function()
{
- this.aPlaceholderShapeSet[ aSlideNumberClassName ] = new PlaceholderShape( this, aSlideNumberClassName );
- this.aPlaceholderShapeSet[ aDateTimeClassName ] = new PlaceholderShape( this, aDateTimeClassName );
- this.aPlaceholderShapeSet[ aFooterClassName ] = new PlaceholderShape( this, aFooterClassName );
- this.aPlaceholderShapeSet[ aHeaderClassName ] = new PlaceholderShape( this, aHeaderClassName );
+ var sClassName;
+ var i = 0;
+ for( ; i < this.aBackgroundObjectSubGroupIdList.length; ++i )
+ {
+ sClassName = this.aBackgroundObjectSubGroupIdList[i];
+ if( isTextFieldByClassName( sClassName ) )
+ this.aPlaceholderShapeSet[ sClassName ] = new PlaceholderShape( this, sClassName );
+ }
}
}; // end MasterPage prototype
@@ -5694,22 +5766,25 @@ MasterPageView.prototype.createElement = function()
for( ; i < aBackgroundObjectSubGroupIdList.length; ++i )
{
sId = aBackgroundObjectSubGroupIdList[i];
- if( sId === aSlideNumberClassName )
+ if( sId.startsWith( aSlideNumberClassName ) )
{
// Slide Number Field
// The cloned element is appended directly to the field group element
// since there is no slide number field content shared between two slide
// (because the slide number of two slide is always different).
- if( aPlaceholderShapeSet[aSlideNumberClassName] &&
- aPlaceholderShapeSet[aSlideNumberClassName].isValid() &&
- this.aMetaSlide.nIsPageNumberVisible &&
+ var nIsPageNumberVisible = sId === aSlideNumberClassName ? this.aMetaSlide.nIsPageNumberVisible : true;
+ if( aPlaceholderShapeSet[sId] &&
+ aPlaceholderShapeSet[sId].isValid() &&
+ nIsPageNumberVisible &&
aTextFieldContentProviderSet[aSlideNumberClassName] )
{
- this.aSlideNumberFieldHandler =
- new SlideNumberFieldHandler( aPlaceholderShapeSet[aSlideNumberClassName],
- aTextFieldContentProviderSet[aSlideNumberClassName] );
- this.aSlideNumberFieldHandler.update( this.aMetaSlide.nSlideNumber );
- this.aSlideNumberFieldHandler.appendTo( this.aBackgroundObjectsElement );
+ var aSlideNumberFieldHandler =
+ new SlideNumberFieldHandler( aPlaceholderShapeSet[sId],
+ aTextFieldContentProviderSet[aSlideNumberClassName] );
+ aSlideNumberFieldHandler.update( this.aMetaSlide.nSlideNumber );
+ aSlideNumberFieldHandler.appendTo( this.aBackgroundObjectsElement );
+ if ( sId === aSlideNumberClassName )
+ this.aSlideNumberFieldHandler = aSlideNumberFieldHandler;
}
}
else if( sId === aDateTimeClassName )
@@ -5745,6 +5820,18 @@ MasterPageView.prototype.createElement = function()
aTextFieldHandlerSet, sMasterSlideId );
}
}
+ else if( sId.startsWith( aDateClassName ) )
+ {
+ this.initTextFieldHandler( sId, aPlaceholderShapeSet,
+ aTextFieldContentProviderSet, aDefsElement,
+ aTextFieldHandlerSet, sMasterSlideId );
+ }
+ else if( sId.startsWith( aTimeClassName ) )
+ {
+ this.initTextFieldHandler( sId, aPlaceholderShapeSet,
+ aTextFieldContentProviderSet, aDefsElement,
+ aTextFieldHandlerSet, sMasterSlideId );
+ }
else
{
// init BackgroundObjectSubGroup elements
@@ -5766,23 +5853,25 @@ MasterPageView.prototype.createElement = function()
};
MasterPageView.prototype.initTextFieldHandler =
- function( sClassName, aPlaceholderShapeSet, aTextFieldContentProviderSet,
+ function( sId, aPlaceholderShapeSet, aTextFieldContentProviderSet,
aDefsElement, aTextFieldHandlerSet, sMasterSlideId )
{
var sRefId = null;
var aTextFieldHandler = null;
- var aPlaceholderShape = aPlaceholderShapeSet[sClassName];
+ var sClassName = sId.split('.')[0];
+ var aPlaceholderShape = aPlaceholderShapeSet[sId];
+ var aTextFieldContentProvider = aTextFieldContentProviderSet[sClassName];
if( aPlaceholderShape && aPlaceholderShape.isValid()
- && aTextFieldContentProviderSet[sClassName] )
+ && aTextFieldContentProvider )
{
- var sTextFieldContentProviderId = aTextFieldContentProviderSet[sClassName].sId;
+ var sTextFieldContentProviderId = aTextFieldContentProvider.sId;
// We create only one single TextFieldHandler object (and so one only
// text field clone) per master slide and text content.
if ( !aTextFieldHandlerSet[ sMasterSlideId ][ sTextFieldContentProviderId ] )
{
aTextFieldHandlerSet[ sMasterSlideId ][ sTextFieldContentProviderId ] =
new TextFieldHandler( aPlaceholderShape,
- aTextFieldContentProviderSet[sClassName] );
+ aTextFieldContentProvider );
aTextFieldHandler = aTextFieldHandlerSet[ sMasterSlideId ][ sTextFieldContentProviderId ];
aTextFieldHandler.update();
aTextFieldHandler.appendTo( aDefsElement );
@@ -5794,7 +5883,7 @@ MasterPageView.prototype.initTextFieldHandler =
sRefId = aTextFieldHandler.sId;
}
else if( aPlaceholderShape && aPlaceholderShape.element && aPlaceholderShape.element.firstElementChild
- && !aPlaceholderShape.textElement && !aTextFieldContentProviderSet[sClassName] )
+ && !aPlaceholderShape.textElement && !aTextFieldContentProvider )
{
sRefId = aPlaceholderShape.element.firstElementChild.getAttribute('id');
}
@@ -6013,10 +6102,16 @@ FixedTextProvider.prototype.update = function( aFixedTextField )
* The svg element that contains the date/time format for one or more
* master slide date/time field.
*/
-function CurrentDateTimeProvider( aTextFieldContentElement )
+function CurrentDateTimeProvider( aTextFieldContentElement, sDateTimeFormat )
{
CurrentDateTimeProvider.superclass.constructor.call( this, aTextFieldContentElement );
- this.dateTimeFormat = getOOOAttribute( aTextFieldContentElement, aOOOAttrDateTimeFormat );
+ if( aTextFieldContentElement )
+ this.dateTimeFormat = getOOOAttribute( aTextFieldContentElement, aOOOAttrDateTimeFormat );
+ else
+ {
+ this.dateTimeFormat = sDateTimeFormat;
+ this.sId = 'DateTimeProvider.' + sDateTimeFormat;
+ }
}
extend( CurrentDateTimeProvider, TextFieldContentProvider );
@@ -6031,17 +6126,22 @@ extend( CurrentDateTimeProvider, TextFieldContentProvider );
*/
CurrentDateTimeProvider.prototype.update = function( aDateTimeField )
{
- var sText = this.createDateTimeText( this.dateTimeFormat );
+ var sText = this.createDateTimeText();
aDateTimeField.setTextContent( sText );
};
/*** private methods ***/
-CurrentDateTimeProvider.prototype.createDateTimeText = function( /*sDateTimeFormat*/ )
+CurrentDateTimeProvider.prototype.createDateTimeText = function()
{
// TODO handle date/time format
- var aDate = new Date();
- var sDate = aDate.toLocaleString();
+ var sDate;
+ if( this.dateTimeFormat === '<date>' )
+ sDate = new Date().toLocaleDateString();
+ else if( this.dateTimeFormat === '<time>' )
+ sDate = new Date().toLocaleTimeString();
+ else
+ sDate = new Date().toLocaleDateString();
return sDate;
};
diff --git a/filter/source/svg/svgwriter.cxx b/filter/source/svg/svgwriter.cxx
index e4a7c4bac7a7..2e4c00b7fbf8 100644
--- a/filter/source/svg/svgwriter.cxx
+++ b/filter/source/svg/svgwriter.cxx
@@ -1091,9 +1091,9 @@ bool SVGTextWriter::nextTextPortion()
{
mrCurrentTextPortion.clear();
mbIsURLField = false;
- mbIsPlaceholderShape = false;
if( mrTextPortionEnumeration.is() && mrTextPortionEnumeration->hasMoreElements() )
{
+ mbIsPlaceholderShape = false;
#if OSL_DEBUG_LEVEL > 0
OUString sInfo;
#endif
@@ -1111,6 +1111,7 @@ bool SVGTextWriter::nextTextPortion()
}
#endif
msPageCount = "";
+ msDateTimeType = "";
if( xPortionTextRange.is() )
{
#if OSL_DEBUG_LEVEL > 0
@@ -1157,6 +1158,31 @@ bool SVGTextWriter::nextTextPortion()
#if OSL_DEBUG_LEVEL > 0
sInfo += "text field type: " + sFieldName + "; content: " + xTextField->getPresentation( /* show command: */ false ) + "; ";
#endif
+ // This case handle Date or Time text field inserted by the user
+ // on both page/master page. It doesn't handle the standard Date/Time field.
+ if( sFieldName == "DateTime" )
+ {
+ Reference<XPropertySet> xTextFieldPropSet(xTextField, UNO_QUERY);
+ if( xTextFieldPropSet.is() )
+ {
+ Reference<XPropertySetInfo> xPropSetInfo = xTextFieldPropSet->getPropertySetInfo();
+ if( xPropSetInfo.is() )
+ {
+ // The standard Date/Time field has no property.
+ // Trying to get a property value on such field would cause a runtime exception.
+ // So the hasPropertyByName check is needed.
+ bool bIsFixed = true;
+ if( xPropSetInfo->hasPropertyByName("IsFixed") && ( ( xTextFieldPropSet->getPropertyValue( "IsFixed" ) ) >>= bIsFixed ) && !bIsFixed )
+ {
+ bool bIsDate;
+ if( xPropSetInfo->hasPropertyByName("IsDate") && ( ( xTextFieldPropSet->getPropertyValue( "IsDate" ) ) >>= bIsDate ) )
+ {
+ msDateTimeType = OUString::createFromAscii( bIsDate ? "<date>" : "<time>" );
+ }
+ }
+ }
+ }
+ }
if( sFieldName == "DateTime" || sFieldName == "Header"
|| sFieldName == "Footer" || sFieldName == "PageNumber" )
{
@@ -1684,6 +1710,13 @@ void SVGTextWriter::implWriteTextPortion( const Point& rPos,
SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
mrExport.GetDocHandler()->characters( msPageCount );
}
+ // This case handle Date or Time text field inserted by the user
+ // on both page/master page. It doesn't handle the standard Date/Time field.
+ else if ( !msDateTimeType.isEmpty() )
+ {
+ SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
+ mrExport.GetDocHandler()->characters( msDateTimeType );
+ }
else
{
SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
diff --git a/filter/source/svg/svgwriter.hxx b/filter/source/svg/svgwriter.hxx
index e8396f16b886..541a39eaa843 100644
--- a/filter/source/svg/svgwriter.hxx
+++ b/filter/source/svg/svgwriter.hxx
@@ -249,6 +249,7 @@ class SVGTextWriter final
OUString msUrl;
OUString msHyperlinkIdList;
OUString msPageCount;
+ OUString msDateTimeType;
bool mbIsPlaceholderShape;
static const bool mbIWS = false;
vcl::Font maCurrentFont;
commit 8d29f3ab72ec91ab7fad55379a14afd41112532a
Author: Marco Cecchetti <marco.cecchetti at collabora.com>
AuthorDate: Tue Jan 12 15:29:44 2021 +0100
Commit: Andras Timar <andras.timar at collabora.com>
CommitDate: Tue Jan 19 15:15:43 2021 +0100
filter: svg: when date/time field is edited directly in mp, is not shown
If a date/time or footer text field in the master page is editede
directly instead of being filled through the header/footer dialog, is
not displayed by the js engine.
Change-Id: I4a8aa3a6b5e9931ea0b997d611ce54e8481dbbcb
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/109175
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
Reviewed-by: Andras Timar <andras.timar at collabora.com>
diff --git a/filter/source/svg/presentation_engine.js b/filter/source/svg/presentation_engine.js
index 3d82aac0eaab..4dd876defba9 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -5556,9 +5556,9 @@ PlaceholderShape.prototype.init = function()
}
}
}
- this.element = aTextFieldElement;
this.textElement = aPlaceholderElement;
}
+ this.element = aTextFieldElement;
}
};
@@ -5769,9 +5769,10 @@ MasterPageView.prototype.initTextFieldHandler =
function( sClassName, aPlaceholderShapeSet, aTextFieldContentProviderSet,
aDefsElement, aTextFieldHandlerSet, sMasterSlideId )
{
+ var sRefId = null;
var aTextFieldHandler = null;
- if( aPlaceholderShapeSet[sClassName] &&
- aPlaceholderShapeSet[sClassName].isValid()
+ var aPlaceholderShape = aPlaceholderShapeSet[sClassName];
+ if( aPlaceholderShape && aPlaceholderShape.isValid()
&& aTextFieldContentProviderSet[sClassName] )
{
var sTextFieldContentProviderId = aTextFieldContentProviderSet[sClassName].sId;
@@ -5780,7 +5781,7 @@ MasterPageView.prototype.initTextFieldHandler =
if ( !aTextFieldHandlerSet[ sMasterSlideId ][ sTextFieldContentProviderId ] )
{
aTextFieldHandlerSet[ sMasterSlideId ][ sTextFieldContentProviderId ] =
- new TextFieldHandler( aPlaceholderShapeSet[sClassName],
+ new TextFieldHandler( aPlaceholderShape,
aTextFieldContentProviderSet[sClassName] );
aTextFieldHandler = aTextFieldHandlerSet[ sMasterSlideId ][ sTextFieldContentProviderId ];
aTextFieldHandler.update();
@@ -5790,13 +5791,22 @@ MasterPageView.prototype.initTextFieldHandler =
{
aTextFieldHandler = aTextFieldHandlerSet[ sMasterSlideId ][ sTextFieldContentProviderId ];
}
+ sRefId = aTextFieldHandler.sId;
+ }
+ else if( aPlaceholderShape && aPlaceholderShape.element && aPlaceholderShape.element.firstElementChild
+ && !aPlaceholderShape.textElement && !aTextFieldContentProviderSet[sClassName] )
+ {
+ sRefId = aPlaceholderShape.element.firstElementChild.getAttribute('id');
+ }
+ if( sRefId )
+ {
// We create a <use> element referring to the cloned text field and
// append it to the field group element.
- var aTextFieldElement = document.createElementNS( NSS['svg'], 'use' );
- aTextFieldElement.setAttribute( 'class', sClassName );
- setNSAttribute( 'xlink', aTextFieldElement,
- 'href', '#' + aTextFieldHandler.sId );
+ var aTextFieldElement = document.createElementNS(NSS['svg'], 'use');
+ aTextFieldElement.setAttribute('class', sClassName);
+ setNSAttribute('xlink', aTextFieldElement,
+ 'href', '#' + sRefId);
// node linking
this.aBackgroundObjectsElement.appendChild( aTextFieldElement );
}
commit c54784beade263fc8cb1a0b240dc3974887f22a3
Author: Marco Cecchetti <marco.cecchetti at collabora.com>
AuthorDate: Tue Jan 12 17:55:08 2021 +0100
Commit: Andras Timar <andras.timar at collabora.com>
CommitDate: Tue Jan 19 15:15:20 2021 +0100
filter: svg: slide custom background unit test
Change-Id: I29990218bfa6095c368ed36ebc9cca909d2136fb
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/109189
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
Reviewed-by: Marco Cecchetti <marco.cecchetti at collabora.com>
diff --git a/sd/qa/unit/SVGExportTests.cxx b/sd/qa/unit/SVGExportTests.cxx
index 8c55bf45d48b..57e5f3fcfc0a 100644
--- a/sd/qa/unit/SVGExportTests.cxx
+++ b/sd/qa/unit/SVGExportTests.cxx
@@ -23,6 +23,7 @@
#define SVG_G *[name()='g']
#define SVG_TEXT *[name()='text']
#define SVG_TSPAN *[name()='tspan']
+#define SVG_DEFS *[name()='defs']
using namespace css;
@@ -124,9 +125,20 @@ public:
1);
}
+ void testSVGExporSlidetCustomBackground()
+ {
+ executeExport("slide-custom-background.odp");
+
+ xmlDocPtr svgDoc = parseXml(maTempFile);
+ CPPUNIT_ASSERT(svgDoc);
+
+ assertXPath(svgDoc, MAKE_PATH_STRING( /SVG_SVG/SVG_G[2]/SVG_G/SVG_G/SVG_G/SVG_G/SVG_DEFS ), "class", "SlideBackground");
+ }
+
CPPUNIT_TEST_SUITE(SdSVGFilterTest);
CPPUNIT_TEST(testSVGExportTextDecorations);
CPPUNIT_TEST(testSVGExportJavascriptURL);
+ CPPUNIT_TEST(testSVGExporSlidetCustomBackground);
CPPUNIT_TEST_SUITE_END();
};
diff --git a/sd/qa/unit/data/odp/slide-custom-background.odp b/sd/qa/unit/data/odp/slide-custom-background.odp
new file mode 100644
index 000000000000..df07c6f34579
Binary files /dev/null and b/sd/qa/unit/data/odp/slide-custom-background.odp differ
commit 92e9de9ab53ae717693c7097c9390d26b9564c1b
Author: Marco Cecchetti <marco.cecchetti at collabora.com>
AuthorDate: Mon Jan 11 10:28:57 2021 +0100
Commit: Andras Timar <andras.timar at collabora.com>
CommitDate: Tue Jan 19 15:14:45 2021 +0100
filter: svg: slide with a custom background are not exported correctly
When a slide has a custom background, the background overlaps any
master page object: text fields, shapes, ...
Change-Id: Icc410617760502fa4092cfe248155b3e20906abb
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/109089
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
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 150510446324..3d82aac0eaab 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -359,7 +359,7 @@ function uniqueArray(src, key, sort) {
* @returns {String|Undefined} prefixed
*/
function prefixed(obj, property) {
- // tml: Have to check for obj being undefined
+ // tml: Have to check for obj being undefined
if (obj === undefined) {
return undefined;
}
@@ -4436,6 +4436,7 @@ var aOOOAttrSlide = 'slide';
var aOOOAttrMaster = 'master';
var aOOOAttrSlideDuration = 'slide-duration';
var aOOOAttrHasTransition = 'has-transition';
+var aOOOAttrHasCustomBackground = 'has-custom-background';
var aOOOAttrBackgroundVisibility = 'background-visibility';
var aOOOAttrMasterObjectsVisibility = 'master-objects-visibility';
var aOOOAttrPageNumberVisibility = 'page-number-visibility';
@@ -5042,10 +5043,20 @@ function MetaSlide( sMetaSlideId, aMetaDoc )
assert( this.pageElement,
'MetaSlide: page element <' + this.slideId + '> not found.' );
+ // The slide custom background element and its id attribute.
+ this.backgroundElement = getElementByClassName( this.pageElement, 'Background' );
+ if( this.backgroundElement )
+ {
+ this.backgroundId = this.backgroundElement.getAttribute( 'id' );
+ }
+
// We initialize the MasterPage object that provides direct access to
// the target master page element.
this.masterPage = this.initMasterPage();
+ // We check if the slide has a custom background which overrides the one of the targeted master page
+ this.bHasCustomBackground = this.initHasCustomBackground();
+
// We initialize visibility properties of the target master page elements.
this.nAreMasterObjectsVisible = this.initVisibilityProperty( aOOOAttrMasterObjectsVisibility, VISIBLE );
this.nIsBackgroundVisible = this.initVisibilityProperty( aOOOAttrBackgroundVisibility, VISIBLE );
@@ -5167,6 +5178,12 @@ initHasTransition : function()
return ( sHasTransition === 'true' );
},
+initHasCustomBackground : function()
+{
+ var sHasCustomBackground = this.element.getAttributeNS( NSS['ooo'], aOOOAttrHasCustomBackground );
+ return ( sHasCustomBackground === 'true' );
+},
+
initVisibilityProperty : function( aVisibilityAttribute, nDefaultValue )
{
var nVisibility = nDefaultValue;
@@ -5646,10 +5663,11 @@ MasterPageView.prototype.createElement = function()
// init the Background element
if( this.aMetaSlide.nIsBackgroundVisible )
{
+ var nBackgroundId = this.aMetaSlide.bHasCustomBackground ? this.aMetaSlide.backgroundId : this.aMasterPage.backgroundId;
this.aBackgroundElement = theDocument.createElementNS( NSS['svg'], 'use' );
this.aBackgroundElement.setAttribute( 'class', 'Background' );
setNSAttribute( 'xlink', this.aBackgroundElement,
- 'href', '#' + this.aMasterPage.backgroundId );
+ 'href', '#' + nBackgroundId );
// node linking
aMasterPageViewElement.appendChild( this.aBackgroundElement );
diff --git a/filter/source/svg/svgexport.cxx b/filter/source/svg/svgexport.cxx
index ac16f7e754f6..938d833c1275 100644
--- a/filter/source/svg/svgexport.cxx
+++ b/filter/source/svg/svgexport.cxx
@@ -33,6 +33,8 @@
#include <com/sun/star/xml/sax/Writer.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/drawing/ShapeCollection.hpp>
+#include <com/sun/star/drawing/BitmapMode.hpp>
+#include <com/sun/star/drawing/RectanglePoint.hpp>
#include <rtl/bootstrap.hxx>
#include <svtools/miscopt.hxx>
@@ -85,6 +87,7 @@ static const char aOOOElemTextField[] = NSPREFIX "text_field";
// ooo xml attributes for meta_slide
static const char aOOOAttrSlide[] = NSPREFIX "slide";
static const char aOOOAttrMaster[] = NSPREFIX "master";
+static const char aOOOAttrHasCustomBackground[] = NSPREFIX "has-custom-background";
static const char aOOOAttrBackgroundVisibility[] = NSPREFIX "background-visibility";
static const char aOOOAttrMasterObjectsVisibility[] = NSPREFIX "master-objects-visibility";
static const char aOOOAttrSlideDuration[] = NSPREFIX "slide-duration";
@@ -1155,6 +1158,19 @@ void SVGFilter::implGenerateMetaData()
VariableDateTimeField aVariableDateTimeField;
FooterField aFooterField;
+ // check if the slide has a custom background wich overlaps the matser page background
+ Reference< XPropertySet > xBackground;
+ xPropSet->getPropertyValue( "Background" ) >>= xBackground;
+ if( xBackground.is() )
+ {
+ drawing::FillStyle aFillStyle;
+ bool assigned = ( xBackground->getPropertyValue( "FillStyle" ) >>= aFillStyle );
+ // has a custom background ?
+ if( assigned && aFillStyle != drawing::FillStyle_NONE )
+ mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, aOOOAttrHasCustomBackground, "true" );
+
+ }
+
xPropSet->getPropertyValue( "IsBackgroundVisible" ) >>= bBackgroundVisibility;
// in case the attribute is set to its default value it is not appended to the meta-slide element
if( !bBackgroundVisibility ) // visibility default value: 'visible'
@@ -1760,35 +1776,48 @@ bool SVGFilter::implExportPage( const OUString & sPageId,
const GDIMetaFile& rMtf = (*mpObjects)[ rxPage ].GetRepresentation();
if( rMtf.GetActionSize() )
{
- // background id = "bg-" + page id
+ // If this is not a master page wrap the slide custom background
+ // by a <defs> element.
+ // Slide custom background, if any, is referenced at a different position
+ // in order to not overlap background objects.
+ std::unique_ptr<SvXMLElementExport> xDefsExp;
+ if (!bMaster) // insert the <defs> open tag related to the slide background
+ {
+ mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class", "SlideBackground" );
+ xDefsExp.reset( new SvXMLElementExport( *mpSVGExport, XML_NAMESPACE_NONE, "defs", true, true ) );
+ }
+ {
+ // background id = "bg-" + page id
OUString sBackgroundId = "bg-";
sBackgroundId += sPageId;
- mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", sBackgroundId );
-
- // At present (LibreOffice 3.4.0) the 'IsBackgroundVisible' property is not handled
- // by Impress; anyway we handle this property as referring only to the visibility
- // of the master page background. So if a slide has its own background object,
- // the visibility of such a background object is always inherited from the visibility
- // of the parent slide regardless of the value of the 'IsBackgroundVisible' property.
- // This means that we need to set up the visibility attribute only for the background
- // element of a master page.
- if( !mbPresentation && bMaster )
- {
- if( !mVisiblePagePropSet.bIsBackgroundVisible )
+ mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "id", sBackgroundId );
+
+ // At present (LibreOffice 3.4.0) the 'IsBackgroundVisible' property is not handled
+ // by Impress; anyway we handle this property as referring only to the visibility
+ // of the master page background. So if a slide has its own background object,
+ // the visibility of such a background object is always inherited from the visibility
+ // of the parent slide regardless of the value of the 'IsBackgroundVisible' property.
+ // This means that we need to set up the visibility attribute only for the background
+ // element of a master page.
+ if( !mbPresentation && bMaster )
{
- mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "visibility", "hidden" );
+ if( !mVisiblePagePropSet.bIsBackgroundVisible )
+ {
+ mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "visibility", "hidden" );
+ }
}
- }
- mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class", "Background" );
+ mpSVGExport->AddAttribute( XML_NAMESPACE_NONE, "class", "Background" );
+
+ // insert the <g> open tag related to the Background
+ SvXMLElementExport aExp2( *mpSVGExport, XML_NAMESPACE_NONE, "g", true, true );
- // insert the <g> open tag related to the Background
- SvXMLElementExport aExp2( *mpSVGExport, XML_NAMESPACE_NONE, "g", true, true );
+ // append all elements that make up the Background
+ const Point aNullPt;
+ mpSVGWriter->WriteMetaFile( aNullPt, rMtf.GetPrefSize(), rMtf, SVGWRITER_WRITE_FILL );
+ } // insert the </g> closing tag related to the Background
- // append all elements that make up the Background
- const Point aNullPt;
- mpSVGWriter->WriteMetaFile( aNullPt, rMtf.GetPrefSize(), rMtf, SVGWRITER_WRITE_FILL );
- } // insert the </g> closing tag related to the Background
+ } // insert the </defs> closing tag related to the slide background
}
// In case we are dealing with a master page we need to group all its shapes
diff --git a/sd/qa/unit/SVGExportTests.cxx b/sd/qa/unit/SVGExportTests.cxx
index 400d604e786c..8c55bf45d48b 100644
--- a/sd/qa/unit/SVGExportTests.cxx
+++ b/sd/qa/unit/SVGExportTests.cxx
@@ -120,7 +120,7 @@ public:
// There should be only one child (no link to javascript url)
assertXPathChildren(svgDoc,
MAKE_PATH_STRING(/ SVG_SVG / SVG_G[2] / SVG_G / SVG_G / SVG_G / SVG_G
- / SVG_G[4] / SVG_G),
+ / SVG_G[3] / SVG_G),
1);
}
More information about the Libreoffice-commits
mailing list