Calc/Implementation/Calc styles export

From Apache OpenOffice Wiki
< Calc‎ | Implementation
Revision as of 12:28, 8 August 2012 by Tan Li (Talk | contribs)

Jump to: navigation, search


Basic concept of Styles

In the OpenDocument format, formatting properties, which influences the visual representation of objects, are stored in styles. Using styles to store formatting properties has advantages such as, format information is separated from document content, and styles enable consistent formatting and changing of formatting for objects subject to styles. Following picture is a sample of OpenDocument styles.xml file. This file is the main file for styles storage.

Styles.xml .jpg

As styles.xml shows, both <style:default-style> and <style:style> in <office:styles> have a “style:name” attribute. In fact, styles and font face declarations are referenced by their style:name attribute[1]. A referenced style or font face declaration should be defined in the same file as the reference, or in styles.xml. Styles built in the stylist (can be used by click menu "Format"--"Styles and formatting") or ones that you create there, will have names like “Heading 1” or Custom Citation. Automatic styles <office:automatic-styles> will have names consisting of style-family abbreviation followed by a number; a style name such as T1 is the first automatic style for style:family="text"; P3 would be the third style for paragraphs, ta2 would be the second style for a table, ro4 would be the fourth style for a table row, etc(please refer content.xml for OpenDocument). The other attribute of interest is the optional parent-style-name, which you will find in styles that have been derived from other styles. <style:font-face> element represents a font face declaration which documents the properties of a font used in a document. OpenDocument font face declarations may have an unique name. This name can be used inside styles (as an attribute of <style:text-properties> element) as value of the style:font-name attribute to select a font face declaration. <style:style> element represents styles,and <style:default-style> element represents default styles. A default style specifies default formatting properties for a style family. These defaults are used if a formatting property is neither specified by an automatic nor a common style. Default styles exist for all style families that are represented by the <style:style> element specified by the style:family attribute. An OpenDocument document should contain the default styles of the style families for which are used in common or automatic styles in the document.<office:master-styles> <style:master-page> defines page styles which is in stylist.

File:Styles font face.xml .jpg

Attributes for elements defined by OpenDocument are divided between those used by structural elements[2] versus those used by <style:*-properties> elements. Attributes have default values defined by reference[2] standard, and when any element appears in a document instance without such an attribute, consumers should behave as if the attribute is present with the defined default value. <style:*-properties> elements is commonly used to aggregate attributes of one type for specific style. Formatting definitions are expressed as attributes on the <style:*-properties> elements or as child elements of these elements. From code perspective, these <office:styles> , <office:automatic-styles> etc elements in styles.xml is written by SvXMLExport::exportDoc( enum ::xmloff::token::XMLTokenEnum eClass ), when export ods, eClass is XML_SPREADSHEET. For example, ImplExportStyles() inside SvXMLExport::exportDoc() is for writing <office:styles> elements, _ExportFontDecls(); is for <office:font-face-decls>, and ImplExportAutoStyles() is for <office:automatic-styles>. Inside ImplExportStyles() , ScXMLExport::_ExportStyles will call exportDefaultStyle(), exportDataStyles(), exportStyleFamily() etc, in turn to export <style:default-style> <number:number-style>, <style:style> etc. ScXMLImportWrapper::ExportToComponent() is called with different parameters to export each file inside ods, such as styles.xml, content.xml.

Styles export sequence diagrams overview

<style:font-face> elements export is mainly in following sequence, Styles font face export.jpg <style: default style> elements is exported generally as following sequece,

 Defaultstyle.jpg

Automatic styles export is mainly as below,

 Autostyle.jpg

Main class for export, SvXMLExport and ScXMLExport

SvXMLExport is the main class for XML file export. It implements several UNO interfaces such as ::com::sun::star::document::Xfilter, which is used by service ImportFilter or ExportFilter to support loading/saving of documents in different formats, and ::com::sun::star::xml::sax::XDocumentHandler plus ::com::sun::star::xml::sax::XEntendedDocumentHandler, which is interfaces for calling SAX(an event-based sequential access parser API ). It also holds ::com::sun::star::frame::XModel to access document data model. And it use XMLFontAutoStylePool, SvXMLAutoStylePoolP to manage font declarations and automatic styles store plus export. Member UniReference< XMLPageExport > mxPageExport is used as child exporter, which export page styles; and UniReference< XMLShapeExport > mxShapeExport for exporting shape styles. It has function ImplExportStyles( ) for <office:styles> export, _ImplExportMasterStyles() for <style:master-styles> export, etc. ScXMLExport is derived from SvXMLExport and it holds specific SvXMLExportPropertyMapper for SC module, such as xCellStylesExportPropertySetMapper, xRowStylesExportPropertySetMapper. And ScColumnStyles, ScRowStyles etc for corresponding automatic styles export. It implements _ExportFontDecls(), _ExportStyles(), _ExportAutoStyles() etc to actually export styles. ScXMLExport will be constructed once writing a XML file such as styles.xml, content.xml.

class XMLOFF_DLLPUBLIC SvXMLExport 
{
		…
 	SvXMLNamespaceMap			*mpNamespaceMap;	// the namepspace map
 	SvXMLUnitConverter			*mpUnitConv;		// the unit converter
 
 	UniReference< SvXMLAutoStylePoolP > mxAutoStylePool;
 
 	UniReference< XMLFontAutoStylePool > mxFontAutoStylePool;
 
 	SAL_DLLPRIVATE void ImplExportMeta(); // <office:meta>
 	SAL_DLLPRIVATE void ImplExportSettings(); // <office:settings>
 	SAL_DLLPRIVATE void ImplExportStyles( sal_Bool bUsed ); // <office:styles>
 	SAL_DLLPRIVATE void ImplExportAutoStyles( sal_Bool bUsed );// <office:automatic-styles>
 	SAL_DLLPRIVATE void ImplExportMasterStyles( sal_Bool bUsed ); // <office:master-styles>
 	SAL_DLLPRIVATE void ImplExportContent(); // <office:body>
 
 	// This method can be overloaded to export the font declarations
 	// The default implementation will export the contents of the
 	// XMLFontAutoStylePool if it has been created.
 	virtual void _ExportFontDecls();
 
 	// This method should be overloaded to export the content of <style:styles>.
 	// If bUsed is set, used styles should be exported only.
 	// Overloaded Methods must call this method !
 	virtual void _ExportStyles( sal_Bool bUsed ) ;
 
     // methods for accessing the document handler and handling SAX errors
 	void StartElement(sal_uInt16 nPrefix,
                         enum ::xmloff::token::XMLTokenEnum eName,
 					    sal_Bool bIgnWSOutside );
 		…
} 

SvXMLElementExport is helper class to export an element, its constructors prints a start tag with the common attributes. For example, SvXMLElementExport aElement( GetExport(), XML_NAMESPACE_STYLE, XML_FONT_FACE, sal_True, sal_True ) could print tag <style:font-face style:name="Arial" svg:font-family="Arial" style:font-pitch="variable" /> . Constructor of SvXMLElementExport will indirectly call SvXMLExport::StartElement() to write XML. And the destructor ~SvXMLElementExport() prints an end tag. For different properties, process of writing XML is quite differently. Handling color will use XMLColorPropHdl for writing XML and string using XMLStringProHdl; meanwhile XMLPropertyHandler is abstract base-class for different XML-types. Derivations of XMLPropertyHandler knows how to compare, im/export a special XML-type. Some property types need SvXMLUnitConverter converts values from their internal represantation to the textual form used in xml and back.Most of the methods are static but the SvXMLUnitConverter can also store default units for both numerical and textual measures. For example, when XMLFontPitchPropHdl writing FontPitch property to XML, it use SvXMLUnitConverter::convertEnum() to convert enum FontPitch to textual form, by searching SvXMLEnumMapEntry aFontPitchMapping[] it will get mapped XMLTokenEnum and finally get corresponding text in xmltoken.cxx. Sample code is as below.

static SvXMLEnumMapEntry __READONLY_DATA aFontPitchMapping[] =
{ 
 	{ XML_FIXED,		    PITCH_FIXED		},
 	{ XML_VARIABLE,	        PITCH_VARIABLE	},
 	{ XML_TOKEN_INVALID,    0 				}
};
sal_Bool XMLFontPitchPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const
{ 
 	sal_Bool bRet = sal_False;
 	sal_Int16 nPitch = sal_Int16();
 	OUStringBuffer aOut;

 	FontPitch ePitch = PITCH_DONTKNOW;
 	if( rValue >>= nPitch )
 		ePitch =  (FontPitch)nPitch;
 
 	if( PITCH_DONTKNOW != ePitch )
 	{
 		bRet = SvXMLUnitConverter::convertEnum( aOut, ePitch, aFontPitchMapping, XML_FIXED );
 		rStrExpValue = aOut.makeStringAndClear();
 	}

 	return bRet;
} 

XMLPropertySetMapper, SvXMLExportPropertyMapper, XMLPropertySetMapperEntry_Impl

XMLPropertySetMapper is helper class for XML im/export, it holds a pointer to a given array of XMLPropertySetMapperEntry_Impl, which is added by XMLPropertySetMapper::XMLPropertySetMapper(const XMLPropertyMapEntry* pEntries, const UniReference< XMLPropertyHandlerFactory >& rFactory ). XMLPropertyMapEntry* pEntries is usually passed from static array, such as XMLPropertyMapEntry aXMLScCellStylesProperties[], defined in xmlstyle.cxx, txtprmap.cxx etc. XMLPropertySetMapperEntry_Impl is basic element for export XML, it transforms XMLTokenEnum meXMLName inside XMLPropertyMapEntry to sXMLAttributeName, which will be written in XML, so it holds a Sequence of XML-names (for properties) for writing XML. XMLPropertySetMapperEntry_Impl also holds nContextId for context filter, for example, in text properties context, nContextId will only count id for text properties, it is defined intuitive in txtprmap.cxx, such as #define CTF_CHARHEIGHT (XML_TEXT_CTF_START + 1). sAPIPropertyName in XMLPropertySetMapperEntry_Impl is for UNO property-name. XMLPropertySetMapper provides several methods to access data from XMLPropertySetMapperEntry_Impl array, such as GetEntryXMLName( sal_Int32 nIndex ), GetEntryNameSpace( sal_Int32 nIndex ). Sample code is as below.


// xmloff\source\text\txtprmap.cxx
XMLPropertyMapEntry aXMLParaPropMap[] , hundreds of entries.
XMLPropertyMapEntry aXMLSectionPropMap
XMLPropertyMapEntry aXMLTextPropMap[]
XMLPropertyMapEntry aXMLShapePropMap[]
XMLPropertyMapEntry aXMLParaPropMap[] =
{
	// RES_UNKNOWNATR_CONTAINER
	MP_E( "ParaUserDefinedAttributes", TEXT, XMLNS, XML_TYPE_ATTRIBUTE_CONTAINER | MID_FLAG_SPECIAL_ITEM, 0 ),
	// RES_LR_SPACE
	MP_E( "ParaLeftMargin",			FO,	MARGIN,		 XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPE	            RTY, CTF_PARAMARGINALL ),
	...
 }

 //ScXMLExport:: ScXMLExport()
	xCellStylesPropertySetMapper = new XMLPropertySetMapper((XMLPropertyMapEntry*)aXMLScCellStylesProperties,    xScPropHdlFactory);
	xColumnStylesPropertySetMapper = new XMLPropertySetMapper((XMLPropertyMapEntry*)aXMLScColumnStylesProperties,   xScPropHdlFactory);
	xCellStylesExportPropertySetMapper = new ScXMLCellExportPropertyMapper(xCellStylesPropertySetMapper);

class XMLPropertySetMapper
{ 
  	...
 	/** Returns the flags of an entry */
 	sal_uInt32 GetEntryFlags( sal_Int32 nIndex ) const
 
 	/** Returns the type of an entry */
 	sal_uInt32 GetEntryType( sal_Int32 nIndex,  sal_Bool bWithFlags = sal_True )  const
 
 	/** Returns the namespace-key of an entry */
	sal_uInt16 GetEntryNameSpace( sal_Int32 nIndex ) const

	/** Returns the 'local' XML-name of the entry */
	const ::rtl::OUString& GetEntryXMLName( sal_Int32 nIndex ) const
	
	/** Retrieves a PropertyHandler for that property wich placed at nIndex in the XMLPropertyMapEntry-array */
	const XMLPropertyHandler* GetPropertyHandler( sal_Int32 nIndex ) const

	/** import/export
	    This methods calls the respective im/export-method of the respective PropertyHandler. */
	virtual sal_Bool exportXML( ::rtl::OUString& rStrExpValue,
								const XMLPropertyState& rProperty,
								const SvXMLUnitConverter& rUnitConverter ) const;

	...
 }

For nType in property map entry (XMLPropertySetMapperEntry_Impl), 15th to 18th bits from right of it are for type index, mnIndex in XMLPropertyState correspond to this index, which will be mapped for query information when exportXML(). And 32nd to 14th bits from right of nType are used as flags, such as following definition in Xmltypes.hxx (lib\xmloff\inc\xmloff).

  // Import and Export: The property in question must exist. No call to hasPropertyByName is required.
 #define MID_FLAG_MUST_EXIST				0x00400000
 // Export only: When exporting defaults, export this property even if it is not set
#define MID_FLAG_DEFAULT_ITEM_EXPORT	0x00200000

SvXMLExportPropertyMapper is the base class of ScXMLCellExportPropertyMapper, ScXMLColumnExportPropertyMapper etc. They hold XMLPropertySetMapper and knows how to compare with parameter XPropertySet and filter unwanted properties. SvXMLExportPropertyMapper has method Filter( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet>) , which filter properties and only take all properties of the XPropertySet which are also found in the XMLPropertyMapEntry-array and which are not default or inherited. SvXMLExportPropertyMapper also has method FilterDefaults( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > rPropSet ) , which has quite similar process as Filter() except that it only takes properties that have the map flag MID_FLAG_DEFAULT_ITEM_EXPORT, and instead of the property's value, its defualt value is set for export. It holds mxNextMapper for stacked contextfilter(), which will be described afterwards. For writing XML, it has method exportXML(), which fills the SvXMLAttributeList& rAttrList with the items in std::vector< XMLPropertyState >& rProperties , and has handleSpecialItem() for every item that has the MID_FLAG_SPECIAL_ITEM_EXPORT flag.

For Filter() or FilterDefaults(), it will first exclude mapperEntries which has flag MID_FLAG_NO_PROPERTY_EXPORT out of properties intended export. Entries that is included in properties intended to export should furthmore meet followings, first, it has flags MID_FLAG_MUST_EXIST or input XPropertySet contains property type of this entry; second, ODFVersion is meeted; third, pass FillPropertyStateArray(aPropStateArray, xPropSet, maPropMapper, bDefault) and remain;(for FilterDefaults() , bDefault == true, and false for Filter() ); fourth, pass ContextFilter() and remain.

In FillPropertyStateArray(aPropStateArray, xPropSet, maPropMapper,bDefault), code will judge bDefault to export properties with defualt value or new value. Output parameter aPropStateArray will then filtered by stacked mxNextMapper->ContextFilter( ). Sample code is as below.

//SvXMLExportPropertyMapper::Filter( ), that is equal as  _Filter(rPropSet, sal_False)
		for( sal_Int32 i=0; i < nProps; i++ )
		{
			const OUString& rAPIName = maPropMapper->GetEntryAPIName( i );
			const sal_Int32 nFlags = maPropMapper->GetEntryFlags( i );
			if( (0 == (nFlags & MID_FLAG_NO_PROPERTY_EXPORT)) &&
				( (0 != (nFlags & MID_FLAG_MUST_EXIST)) ||
				  xInfo->hasPropertyByName( rAPIName ) ) )
            {
                const SvtSaveOptions::ODFDefaultVersion nCurrentVersion(  SvtSaveOptions().GetODFDefaultVersion() );
                const SvtSaveOptions::ODFDefaultVersion nEarliestODFVersionForExport(
                        maPropMapper->GetEarliestODFVersionForExport( i ) );
                if( nCurrentVersion >= nEarliestODFVersionForExport
                         || nCurrentVersion == SvtSaveOptions::ODFVER_UNKNOWN
                         || nEarliestODFVersionForExport == SvtSaveOptions::ODFVER_UNKNOWN )
                    pFilterInfo->AddProperty(rAPIName, i);
            }

}


ContextFilter() is application-specific filter, just as XMLPageExportPropertyMapper, ScXMLCellExportPropertyMapper, XMLTextExportPropertySetMapper has different implementation, and by default it do nothing. Take XMLTextExportPropertySetMapper for exmaple, ContextFilter() is as follows,

void XMLTextExportPropertySetMapper::ContextFilter(
	::std::vector< XMLPropertyState >& rProperties,
	Reference< XPropertySet > rPropSet ) const
	void XMLTextExportPropertySetMapper::ContextFontFilter(XMLPropertyState *pFontNameState,
	XMLPropertyState *pFontFamilyNameState,
	XMLPropertyState *pFontStyleNameState,
	XMLPropertyState *pFontFamilyState,
	XMLPropertyState *pFontPitchState,
	XMLPropertyState *pFontCharsetState ) const
 {	...
	OUString sName( ((SvXMLExport&)GetExport()).GetFontAutoStylePool()->Find(
						sFamilyName, sStyleName, nFamily, nPitch, eEnc ) );
	if( sName.getLength() )
	{
		pFontNameState->maValue <<= sName;
		if( pFontFamilyNameState )
			pFontFamilyNameState->mnIndex = -1;
		if( pFontStyleNameState )
			pFontStyleNameState->mnIndex = -1;

if( pFontFamilyState )

			pFontFamilyState->mnIndex = -1;
		if( pFontPitchState )
			pFontPitchState->mnIndex = -1;

if( pFontCharsetState )

			pFontCharsetState->mnIndex = -1;
	}
	...
}

When Find( sFamilyName, sStyleName, nFamily, nPitch, eEnc ) got valid sName, then text specific properties pFontFamilyNameState, pFontStyleNameState will be filtered and not exported, meanwhile pFontNameState is enough to determine needed element attributes.

After above filter process, SvXMLExportPropertyMapper::exportXML() will use the filter result std::vector< XMLPropertyState >& rProperties to write XML. In outer iteration of exportXML( ), code will iterate each type of 14 property types ( PAGE, SECTION, TEXT, GRAPHIC,CHART, COLUMN etc.) to export each type in turn ( write all of one type's property value string in XML files and then the next type, in order to show different type of properties in different lines inside XML tags, just like below picture). Cell style.jpg The XML parts in this picture is write by ScXMLExport::_ExportStyles, aStylesExp.exportDefaultStyle(xProperties, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME)), xCellStylesExportPropertySetMapper). For the first type of properties, _exportXML( ) will iterate each element of std::vector< XMLPropertyState >& rProperties, and set rPropTypeFlags which marks property-map entries containing which property types. For the second type and so on, if judge rPropTypeFlags don't contain the type, it will not call _exportXML( ) so as to reduce time cost. For each type, code will iterate every property in rProperties, if property index is among nPropMapStartIdx and nPropMapEndIdx of XMLPropertySetMapper and property type matchs, it will be exported. In _exportXML( ), if rPropTypeFlags match MID_FLAG_ELEMENT_ITEM_EXPORT, it will be stored in SvUShorts* pIndexArray, and finally call SvXMLExportPropertyMapper::exportElementItems() to export.

In above exportXML(), each property in rProperties is queried probably by several times, so the performance improvemence could be considered. There are also some styles which don't call SvXMLExportPropertyMapper::exportXML(). When XMLPageExport export automatic-styles, code will call ScXMLAutoStylePoolP::exportStyleAttributes() to export attributes of each style type, for example, style:name="ta1" style:family="table", and style:master-page-name, which is in XMLPropertyMapEntry aXMLScTableStylesProperties[]. style:master-page-name is not like two other entries in aXMLScTableStylesProperties [], which is exported by SvXMLExportPropertyMapper::exportXML() and put into child elements.

Personal tools