node-webodf-ilkkah
Version:
WebODF - JavaScript Document Engine http://webodf.org/
756 lines (694 loc) • 31.6 kB
JavaScript
/**
* Copyright (C) 2012-2013 KO GmbH <copyright@kogmbh.com>
*
* @licstart
* This file is part of WebODF.
*
* WebODF is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License (GNU AGPL)
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* WebODF is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with WebODF. If not, see <http://www.gnu.org/licenses/>.
* @licend
*
* @source: http://www.webodf.org/
* @source: https://github.com/kogmbh/WebODF/
*/
/*global Node, odf, runtime, core*/
/**
* @constructor
*/
odf.Formatting = function Formatting() {
"use strict";
var /**@type{odf.OdfContainer}*/
odfContainer,
/**@type{odf.StyleInfo}*/
styleInfo = new odf.StyleInfo(),
/**@const*/
svgns = odf.Namespaces.svgns,
/**@const*/
stylens = odf.Namespaces.stylens,
/**@const*/
textns = odf.Namespaces.textns,
/**@const*/
numberns = odf.Namespaces.numberns,
/**@const*/
fons = odf.Namespaces.fons,
odfUtils = odf.OdfUtils,
domUtils = core.DomUtils,
utils = new core.Utils(),
cssUnits = new core.CSSUnits(),
// TODO: needs to be extended. Possibly created together with CSS from sone default description?
/**@const
@type {!Object.<!string,!odf.Formatting.StyleData>}*/
builtInDefaultStyleAttributesByFamily = {
'paragraph' : {
'style:paragraph-properties': {
'fo:text-align': 'left'
}
}
},
/**@const*/
defaultPageFormatSettings = {
width: "21.001cm", // showing as 21.00 in page format dialog but the value is actually 21.001 in the xml
height: "29.7cm",
margin: "2cm",
padding: "0cm"
}; // LO 4.1.1.2's default page format settings.
/**
* Returns a JSON representation of the built-in default style attributes
* of a given style family.
* Creates a deep copy, so the result can be modified by the callee.
* If there are no such attributes, null is returned.
* @param {string} styleFamily
* @return {!odf.Formatting.StyleData}
*/
function getSystemDefaultStyleAttributes(styleFamily) {
var result,
/**@type{!odf.Formatting.StyleData|undefined}*/
builtInDefaultStyleAttributes = builtInDefaultStyleAttributesByFamily[styleFamily];
if (builtInDefaultStyleAttributes) {
// reusing mergeObjects to copy builtInDefaultStyleAttributes into the result
result = utils.mergeObjects({}, builtInDefaultStyleAttributes);
} else {
result = {};
}
return result;
}
this.getSystemDefaultStyleAttributes = getSystemDefaultStyleAttributes;
/**
* @param {!odf.OdfContainer} odfcontainer
* @return {undefined}
*/
this.setOdfContainer = function (odfcontainer) {
odfContainer = odfcontainer;
};
/**
* Returns a font face declarations map, where the key is the style:name and
* the value is the svg:font-family or null, if none set but a svg:font-face-uri
* @return {!Object.<string,string>}
*/
function getFontMap() {
var fontFaceDecls = odfContainer.rootElement.fontFaceDecls,
/**@type {!Object.<string,string>}*/
fontFaceDeclsMap = {},
node,
name,
family;
node = fontFaceDecls && fontFaceDecls.firstElementChild;
while (node) {
name = node.getAttributeNS(stylens, 'name');
if (name) {
// add family name as value, or, if there is a
// font-face-uri, an empty string
family = node.getAttributeNS(svgns, 'font-family');
if (family || node.getElementsByTagNameNS(svgns, 'font-face-uri').length > 0) {
fontFaceDeclsMap[name] = family;
}
}
node = node.nextElementSibling;
}
return fontFaceDeclsMap;
}
this.getFontMap = getFontMap;
/**
* Loop over the <style:style> elements and place the attributes
* style:name and style:display-name in an array.
* @return {!Array}
*/
this.getAvailableParagraphStyles = function () {
var node = odfContainer.rootElement.styles,
p_family,
p_name,
p_displayName,
paragraphStyles = [];
node = node && node.firstElementChild;
while (node) {
if (node.localName === "style" && node.namespaceURI === stylens) {
p_family = node.getAttributeNS(stylens, 'family');
if (p_family === "paragraph") {
p_name = node.getAttributeNS(stylens, 'name');
p_displayName = node.getAttributeNS(stylens, 'display-name') || p_name;
if (p_name && p_displayName) {
paragraphStyles.push({
name: p_name,
displayName: p_displayName
});
}
}
}
node = node.nextElementSibling;
}
return paragraphStyles;
};
/**
* Returns if the given style is used anywhere in the document.
* @param {!Element} styleElement
* @return {!boolean}
*/
this.isStyleUsed = function (styleElement) {
var hasDerivedStyles, isUsed,
root = odfContainer.rootElement;
hasDerivedStyles = styleInfo.hasDerivedStyles(root,
odf.Namespaces.lookupNamespaceURI, styleElement);
isUsed =
new styleInfo.UsedStyleList(root.styles).uses(styleElement)
|| new styleInfo.UsedStyleList(root.automaticStyles).uses(styleElement)
|| new styleInfo.UsedStyleList(root.body).uses(styleElement);
return hasDerivedStyles || isUsed;
};
/**
* @param {!string} family
* @return {?Element}
*/
function getDefaultStyleElement(family) {
var node = odfContainer.rootElement.styles.firstElementChild;
while (node) {
if (node.namespaceURI === stylens
&& node.localName === "default-style"
&& node.getAttributeNS(stylens, 'family') === family) {
return node;
}
node = node.nextElementSibling;
}
return null;
}
this.getDefaultStyleElement = getDefaultStyleElement;
/**
* Fetch style element associated with the requested name and family
* @param {!string} styleName
* @param {!string} family
* @param {!Array.<!Element>=} styleElements Specific style trees to search. If unspecified will search both automatic
* and user-created styles
* @return {?Element}
*/
function getStyleElement(styleName, family, styleElements) {
var node,
nodeStyleName,
styleListElement,
i;
styleElements = styleElements || [odfContainer.rootElement.automaticStyles, odfContainer.rootElement.styles];
for (i = 0; i < styleElements.length; i += 1) {
styleListElement = /**@type{!Element}*/(styleElements[i]);
node = styleListElement.firstElementChild;
while (node) {
nodeStyleName = node.getAttributeNS(stylens, 'name');
if (node.namespaceURI === stylens
&& node.localName === "style"
&& node.getAttributeNS(stylens, 'family') === family
&& nodeStyleName === styleName) {
return node;
}
if (family === "list-style"
&& node.namespaceURI === textns
&& node.localName === "list-style"
&& nodeStyleName === styleName) {
return node;
}
if (family === "data"
&& node.namespaceURI === numberns
&& nodeStyleName === styleName) {
return node;
}
node = node.nextElementSibling;
}
}
return null;
}
this.getStyleElement = getStyleElement;
/**
* Returns a JSON representation of the style attributes of a given style element
* @param {!Element} styleNode
* @return {!odf.Formatting.StyleData}
*/
function getStyleAttributes(styleNode) {
var i, a, map, ai,
propertiesMap = {},
propertiesNode = styleNode.firstElementChild;
while (propertiesNode) {
if (propertiesNode.namespaceURI === stylens) {
map = propertiesMap[propertiesNode.nodeName] = {};
a = propertiesNode.attributes;
for (i = 0; i < a.length; i += 1) {
ai = /**@type{!Attr}*/(a.item(i));
map[ai.name] = ai.value;
}
}
propertiesNode = propertiesNode.nextElementSibling;
}
a = styleNode.attributes;
for (i = 0; i < a.length; i += 1) {
ai = /**@type{!Attr}*/(a.item(i));
propertiesMap[ai.name] = ai.value;
}
return propertiesMap;
}
this.getStyleAttributes = getStyleAttributes;
/**
* Returns a JSON representation of the style attributes of a given style element, also containing attributes
* inherited from it's ancestry - up to and including the document's default style for the family.
* @param {!Element} styleNode
* @param {!boolean=} includeSystemDefault True by default. Specify false to suppress inclusion of system defaults
* @return {!odf.Formatting.StyleData}
*/
function getInheritedStyleAttributes(styleNode, includeSystemDefault) {
var styleListElement = odfContainer.rootElement.styles,
parentStyleName,
propertiesMap,
inheritedPropertiesMap = {},
styleFamily = styleNode.getAttributeNS(stylens, 'family'),
node = styleNode;
// Iterate through the style ancestry
while (node) {
propertiesMap = getStyleAttributes(node);
// All child properties should override any matching parent properties
inheritedPropertiesMap = utils.mergeObjects(propertiesMap, inheritedPropertiesMap);
parentStyleName = node.getAttributeNS(stylens, 'parent-style-name');
if (parentStyleName) {
node = getStyleElement(parentStyleName, styleFamily, [styleListElement]);
} else {
node = null;
}
}
// Next incorporate attributes from the default style
node = getDefaultStyleElement(styleFamily);
if (node) {
propertiesMap = getStyleAttributes(node);
// All child properties should override any matching parent properties
inheritedPropertiesMap = utils.mergeObjects(propertiesMap, inheritedPropertiesMap);
}
// Last incorporate attributes from the built-in default style
if (includeSystemDefault !== false) {
propertiesMap = getSystemDefaultStyleAttributes(styleFamily);
// All child properties should override any matching parent properties
inheritedPropertiesMap = utils.mergeObjects(propertiesMap, inheritedPropertiesMap);
}
return inheritedPropertiesMap;
}
this.getInheritedStyleAttributes = getInheritedStyleAttributes;
/**
* Get the name of the first common style in the parent style chain.
* If none is found, null is returned and you should assume the Default style.
* @param {!string} styleName
* @return {?string}
*/
this.getFirstCommonParentStyleNameOrSelf = function (styleName) {
var automaticStyleElementList = odfContainer.rootElement.automaticStyles,
styleElementList = odfContainer.rootElement.styles,
styleElement;
// first look for automatic style with the name and get its parent style
styleElement = getStyleElement(styleName, "paragraph", [automaticStyleElementList]);
if (styleElement) {
styleName = styleElement.getAttributeNS(stylens, 'parent-style-name');
if (!styleName) {
return null;
}
}
// then see if that style is in common styles
styleElement = getStyleElement(styleName, "paragraph", [styleElementList]);
if (!styleElement) {
return null;
}
return styleName;
};
/**
* Returns if there is an automatic or common paragraph style with the given name.
* @param {!string} styleName
* @return {!boolean}
*/
this.hasParagraphStyle = function (styleName) {
return Boolean(getStyleElement(styleName, "paragraph"));
};
/**
* Builds up a style chain for a given node by climbing up all parent nodes and checking for style information
* @param {!Node} node
* @param {!Object.<!string, !Array.<!Object>>=} collectedChains Dictionary to add any new style chains to
* @return {!Array.<!Object>|undefined}
*/
function buildStyleChain(node, collectedChains) {
var parent = /**@type{!Element}*/(node.nodeType === Node.TEXT_NODE
? node.parentNode : node),
nodeStyles,
appliedStyles = [],
/**@type{string}*/
chainKey = '',
foundContainer = false;
while (parent && (!odfUtils.isInlineRoot(parent)) && (parent.parentNode !== odfContainer.rootElement)) {
if (!foundContainer && odfUtils.isGroupingElement(parent)) {
foundContainer = true;
}
nodeStyles = styleInfo.determineStylesForNode(parent);
if (nodeStyles) {
appliedStyles.push(nodeStyles);
}
parent = /**@type{!Element}*/(parent.parentNode);
}
/**
* @param {!Array.<!Object.<string,!Object.<string,number>>>} usedStyleMap
*/
function chainStyles(usedStyleMap) {
Object.keys(usedStyleMap).forEach(function (styleFamily) {
Object.keys(usedStyleMap[styleFamily]).forEach(function (styleName) {
chainKey += '|' + styleFamily + ':' + styleName + '|';
});
});
}
if (foundContainer) {
appliedStyles.forEach(chainStyles);
if (collectedChains) {
collectedChains[chainKey] = appliedStyles;
}
}
return foundContainer ? appliedStyles : undefined;
}
/**
* Returns true if the supplied style node is a common style.
* From the OpenDocument spec:
*
* "Common and automatic styles behave differently in OpenDocument editing consumers. Common
* styles are presented to the user as a named set of formatting properties. The formatting
* properties of an automatic style are presented to a user as properties of the object to
* which the style is applied."
*
* http://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part1.html#element-office_automatic-styles
*
* @param {!Node} styleNode
* @return {!boolean}
*/
function isCommonStyleElement(styleNode) {
return styleNode.parentNode === odfContainer.rootElement.styles;
}
/**
* Takes a provided style chain and calculates the resulting inherited style, starting from the outer-most to the
* inner-most style
* @param {!Array.<!Object>} styleChain Ordered list starting from inner-most style to outer-most style
* @return {!odf.Formatting.AppliedStyle}
*/
function calculateAppliedStyle(styleChain) {
var mergedChildStyle = { orderedStyles: [], styleProperties: {} };
// The complete style is built up by starting at the base known style and merging each new entry
// on top of it, so the inner-most style properties override the outer-most
styleChain.forEach(function (elementStyleSet) {
Object.keys(/**@type{!Object}*/(elementStyleSet)).forEach(function (styleFamily) {
// Expect there to only be a single style for a given family per element (e.g., 1 text, 1 paragraph)
var styleName = Object.keys(elementStyleSet[styleFamily])[0],
styleSummary = {
name: styleName,
family: styleFamily,
displayName: undefined,
isCommonStyle: false
},
styleElement,
parentStyle;
styleElement = getStyleElement(styleName, styleFamily);
if (styleElement) {
parentStyle = getInheritedStyleAttributes(/**@type{!Element}*/(styleElement));
mergedChildStyle.styleProperties = utils.mergeObjects(parentStyle, mergedChildStyle.styleProperties);
styleSummary.displayName = styleElement.getAttributeNS(stylens, 'display-name') || undefined;
styleSummary.isCommonStyle = isCommonStyleElement(styleElement);
} else {
runtime.log("No style element found for '" + styleName + "' of family '" + styleFamily + "'");
}
mergedChildStyle.orderedStyles.push(styleSummary);
});
});
return mergedChildStyle;
}
/**
* Returns an array of all unique styles in the given text nodes
* @param {!Array.<!Node>} nodes
* @param {!Object.<!string, !odf.Formatting.AppliedStyle>=} calculatedStylesCache Short-lived cache of calculated styles.
* Useful if a function is looking up the style information for multiple nodes without updating
* any style definitions.
* @return {!Array.<!odf.Formatting.AppliedStyle>}
*/
function getAppliedStyles(nodes, calculatedStylesCache) {
var styleChains = {},
styles = [];
if (!calculatedStylesCache) {
calculatedStylesCache = {}; // Makes the following logic easier as a cache can be assumed to exist
}
nodes.forEach(function (n) {
buildStyleChain(n, styleChains);
});
Object.keys(styleChains).forEach(function (key) {
if (!calculatedStylesCache[key]) {
calculatedStylesCache[key] = calculateAppliedStyle(styleChains[key]);
}
styles.push(calculatedStylesCache[key]);
});
return styles;
}
this.getAppliedStyles = getAppliedStyles;
/**
* Returns a the applied style to the current node
* @param {!Node} node
* @param {!Object.<!string, !odf.Formatting.AppliedStyle>=} calculatedStylesCache Short-lived cache of calculated styles.
* Useful if a function is looking up the style information for multiple nodes without updating
* any style definitions.
* @return {!odf.Formatting.AppliedStyle|undefined}
*/
this.getAppliedStylesForElement = function (node, calculatedStylesCache) {
return getAppliedStyles([node], calculatedStylesCache)[0];
};
/**
* Overrides the specific properties on the styleNode from the values in the supplied properties Object.
* If a newStylePrefix is supplied, this method will automatically generate a unique name for the style node
* @param {!Element} styleNode
* @param {!odf.Formatting.StyleData} properties Prefix to put in front of new auto styles
*/
this.updateStyle = function (styleNode, properties) {
var fontName, fontFaceNode, textProperties;
domUtils.mapObjOntoNode(styleNode, properties, odf.Namespaces.lookupNamespaceURI);
textProperties = /**@type {!odf.Formatting.StyleData|undefined}*/(properties["style:text-properties"]);
fontName = /**@type {!string}*/(textProperties && textProperties["style:font-name"]);
if (fontName && !getFontMap().hasOwnProperty(fontName)) {
fontFaceNode = styleNode.ownerDocument.createElementNS(stylens, 'style:font-face');
fontFaceNode.setAttributeNS(stylens, 'style:name', fontName);
fontFaceNode.setAttributeNS(svgns, 'svg:font-family', fontName);
odfContainer.rootElement.fontFaceDecls.appendChild(fontFaceNode);
}
};
/**
* Create a style object (JSON-equivalent) that is equivalent to inheriting from the parent
* style and family, and applying the specified overrides.
* This contains logic for simulating inheritance for automatic styles
* @param {!string} parentStyleName
* @param {!string} family
* @param {!odf.Formatting.StyleData} overrides
* @return {!odf.Formatting.StyleData}
*/
this.createDerivedStyleObject = function(parentStyleName, family, overrides) {
var originalStyleElement = /**@type{!Element}*/(getStyleElement(parentStyleName, family)),
newStyleObject;
runtime.assert(Boolean(originalStyleElement), "No style element found for '" + parentStyleName + "' of family '" + family + "'");
if (isCommonStyleElement(originalStyleElement)) {
newStyleObject = { "style:parent-style-name": parentStyleName };
} else {
// Automatic styles cannot be inherited from. The way to create a derived style is to clone it entirely
newStyleObject = getStyleAttributes(originalStyleElement);
}
newStyleObject["style:family"] = family;
utils.mergeObjects(newStyleObject, overrides);
return newStyleObject;
};
/**
* Get the default tab-stop distance defined for this document
* See http://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part1.html#property-style_tab-stop-distance
* @return {?{value: !number, unit: !string}}
*/
this.getDefaultTabStopDistance = function () {
var defaultParagraph = getDefaultStyleElement('paragraph'),
paragraphProperties = defaultParagraph && defaultParagraph.firstElementChild,
tabStopDistance;
while (paragraphProperties) {
if (paragraphProperties.namespaceURI === stylens && paragraphProperties.localName === "paragraph-properties") {
tabStopDistance = paragraphProperties.getAttributeNS(stylens, "tab-stop-distance");
}
paragraphProperties = paragraphProperties.nextElementSibling;
}
if (!tabStopDistance) {
tabStopDistance = "1.25cm"; // What is the default value for tab stops? Pulled this from LO 4.1.1
}
return odfUtils.parseNonNegativeLength(tabStopDistance);
};
/**
* Find a master page definition with the specified name
* @param {!string} pageName
* @return {?Element}
*/
function getMasterPageElement(pageName) {
var node = odfContainer.rootElement.masterStyles.firstElementChild;
while (node) {
if (node.namespaceURI === stylens
&& node.localName === "master-page"
&& node.getAttributeNS(stylens, "name") === pageName) {
break;
}
node = node.nextElementSibling;
}
return node;
}
this.getMasterPageElement = getMasterPageElement;
/**
* Gets the associated page layout style node for the given style and family.
* @param {!string} styleName
* @param {!string} styleFamily either 'paragraph' or 'table'
* @return {?Element}
*/
function getPageLayoutStyleElement(styleName, styleFamily) {
var masterPageName,
layoutName,
pageLayoutElements,
/**@type{?Element}*/
node,
i,
styleElement = getStyleElement(styleName, styleFamily);
runtime.assert(styleFamily === "paragraph" || styleFamily === "table",
"styleFamily must be either paragraph or table");
if (styleElement) {
masterPageName = styleElement.getAttributeNS(stylens, "master-page-name");
if (masterPageName) {
node = getMasterPageElement(masterPageName);
if (!node) {
runtime.log("WARN: No master page definition found for " + masterPageName);
}
}
// TODO If element has no master-page-name defined find the master-page-name from closest previous sibling
// See http://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part1.html#__RefHeading__1417948_253892949
if (!node) {
// Fallback 1: LibreOffice usually puts a page layout in called "Standard"
node = getMasterPageElement("Standard");
}
if (!node) {
// Fallback 2: Find any page style
node = /**@type{?Element}*/(odfContainer.rootElement.masterStyles.getElementsByTagNameNS(stylens, "master-page")[0]);
if (!node) {
// See http://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part1.html#element-style_master-page
// "All documents shall contain at least one master page element."
runtime.log("WARN: Document has no master pages defined");
}
}
if (node) {
// It would be surprising if we still haven't found a page by now. Still, better safe than sorry!
// Note, all warnings are already logged in the above conditions
layoutName = node.getAttributeNS(stylens, "page-layout-name");
pageLayoutElements = odfContainer.rootElement.automaticStyles.getElementsByTagNameNS(stylens, "page-layout");
for (i = 0; i < pageLayoutElements.length; i += 1) {
node = /**@type{!Element}*/(pageLayoutElements.item(i));
if (node.getAttributeNS(stylens, "name") === layoutName) {
return node;
}
}
}
}
return null;
}
/**
* @param {?string|undefined} length
* @param {string=} defaultValue
* @return {!number|undefined}
*/
function lengthInPx(length, defaultValue) {
var measure;
if (length) {
measure = cssUnits.convertMeasure(length, "px");
}
if (measure === undefined && defaultValue) {
measure = cssUnits.convertMeasure(defaultValue, "px");
}
return measure;
}
/**
* Gets the width and height of content area in pixels.
* @param {string} styleName
* @param {string} styleFamily
* @return {!{width: number, height: number}} Available content size in pixels
*/
this.getContentSize = function(styleName, styleFamily) {
var pageLayoutElement,
props,
defaultOrientedPageWidth,
defaultOrientedPageHeight,
pageWidth,
pageHeight,
margin,
marginLeft,
marginRight,
marginTop,
marginBottom,
padding,
paddingLeft,
paddingRight,
paddingTop,
paddingBottom;
pageLayoutElement = getPageLayoutStyleElement(styleName, styleFamily);
if (!pageLayoutElement) {
pageLayoutElement = domUtils.getDirectChild(odfContainer.rootElement.styles, stylens, "default-page-layout");
}
props = domUtils.getDirectChild(pageLayoutElement, stylens, "page-layout-properties");
if (props) {
// set page's default width and height based on print orientation
if (props.getAttributeNS(stylens, "print-orientation") === "landscape") {
// swap the default width and height around in landscape
defaultOrientedPageWidth = defaultPageFormatSettings.height;
defaultOrientedPageHeight = defaultPageFormatSettings.width;
} else {
defaultOrientedPageWidth = defaultPageFormatSettings.width;
defaultOrientedPageHeight = defaultPageFormatSettings.height;
}
pageWidth = lengthInPx(props.getAttributeNS(fons, "page-width"), defaultOrientedPageWidth);
pageHeight = lengthInPx(props.getAttributeNS(fons, "page-height"), defaultOrientedPageHeight);
margin = lengthInPx(props.getAttributeNS(fons, "margin"));
if (margin === undefined) {
marginLeft = lengthInPx(props.getAttributeNS(fons, "margin-left"), defaultPageFormatSettings.margin);
marginRight = lengthInPx(props.getAttributeNS(fons, "margin-right"), defaultPageFormatSettings.margin);
marginTop = lengthInPx(props.getAttributeNS(fons, "margin-top"), defaultPageFormatSettings.margin);
marginBottom = lengthInPx(props.getAttributeNS(fons, "margin-bottom"), defaultPageFormatSettings.margin);
} else {
marginLeft = marginRight = marginTop = marginBottom = margin;
}
padding = lengthInPx(props.getAttributeNS(fons, "padding"));
if (padding === undefined) {
paddingLeft = lengthInPx(props.getAttributeNS(fons, "padding-left"), defaultPageFormatSettings.padding);
paddingRight = lengthInPx(props.getAttributeNS(fons, "padding-right"), defaultPageFormatSettings.padding);
paddingTop = lengthInPx(props.getAttributeNS(fons, "padding-top"), defaultPageFormatSettings.padding);
paddingBottom = lengthInPx(props.getAttributeNS(fons, "padding-bottom"), defaultPageFormatSettings.padding);
} else {
paddingLeft = paddingRight = paddingTop = paddingBottom = padding;
}
} else {
pageWidth = lengthInPx(defaultPageFormatSettings.width);
pageHeight = lengthInPx(defaultPageFormatSettings.height);
margin = lengthInPx(defaultPageFormatSettings.margin);
marginLeft = marginRight = marginTop = marginBottom = margin;
padding = lengthInPx(defaultPageFormatSettings.padding);
paddingLeft = paddingRight = paddingTop = paddingBottom = padding;
}
return {
width: pageWidth - marginLeft - marginRight - paddingLeft - paddingRight,
height: pageHeight - marginTop - marginBottom - paddingTop - paddingBottom
};
};
};
/**@typedef{{
name:!string,
family:!string,
displayName:(!string|undefined),
isCommonStyle:!boolean
}}*/
odf.Formatting.StyleMetadata;
/**@typedef{!Object.<!string,(!string|!Object.<!string,!string>)>}*/
odf.Formatting.StyleData;
/**@typedef{{
orderedStyles:!Array.<!odf.Formatting.StyleMetadata>,
styleProperties:!odf.Formatting.StyleData
}}*/
odf.Formatting.AppliedStyle;