blob: 49659935755b581e362b4dad6fe8a2b360dff630 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package flashx.textLayout.conversion
{
import flash.utils.Dictionary;
import flashx.textLayout.debug.assert;
import flashx.textLayout.elements.ContainerFormattedElement;
import flashx.textLayout.elements.DivElement;
import flashx.textLayout.elements.FlowElement;
import flashx.textLayout.elements.FlowGroupElement;
import flashx.textLayout.elements.FlowValueHolder;
import flashx.textLayout.elements.InlineGraphicElement;
import flashx.textLayout.elements.LinkElement;
import flashx.textLayout.elements.ListElement;
import flashx.textLayout.elements.ParagraphFormattedElement;
import flashx.textLayout.elements.SpanElement;
import flashx.textLayout.elements.SubParagraphGroupElement;
import flashx.textLayout.elements.TCYElement;
import flashx.textLayout.elements.TextFlow;
import flashx.textLayout.formats.FormatValue;
import flashx.textLayout.formats.ITextLayoutFormat;
import flashx.textLayout.formats.ListMarkerFormat;
import flashx.textLayout.formats.TextLayoutFormat;
import flashx.textLayout.formats.WhiteSpaceCollapse;
import flashx.textLayout.property.Property;
import flashx.textLayout.tlf_internal;
use namespace tlf_internal;
[ExcludeClass]
/**
* @private
* Export filter for TextLayout format.
*/
internal class TextLayoutExporter extends BaseTextLayoutExporter
{
static private var _formatDescription:Object= TextLayoutFormat.description;
public function TextLayoutExporter()
{
super(new Namespace("http://ns.adobe.com/textLayout/2008"), null, TextLayoutImporter.defaultConfiguration);
}
static private const brTabRegEx:RegExp = new RegExp("[" + "\u2028" + "\t" + "]"); // Doesn't /\u2028\t/ work?
/** Gets the regex that specifies characters to be replaced with XML elements
* Note: Each match is a single character
*/
protected override function get spanTextReplacementRegex():RegExp
{
return brTabRegEx;
}
/** Gets the xml element used to represent a character in the export format
*/
protected override function getSpanTextReplacementXML(ch:String):XML
{
var replacementXML:XML;
if (ch == '\u2028')
replacementXML = <br/>;
else if (ch == '\t')
replacementXML = <tab/>;
else
{
CONFIG::debug {assert(false, "Did not recognize character to be replaced with XML"); }
return null;
}
replacementXML.setNamespace(flowNS);
return replacementXML;
}
/** Helper function to export styles (core or user) in the form of xml attributes or xml children
* @private
*/
tlf_internal function createStylesFromDescription(styles:Object, description:Object, includeUserStyles:Boolean, exclusions:Array):Array
{
var sortableStyles:Array = [];
for (var key:String in styles)
{
var val:Object = styles[key];
if (exclusions && exclusions.indexOf(val) != -1)
continue;
var prop:Property = description[key];
if (!prop)
{
if (includeUserStyles)
{
// User style
if ((val is String) || val.hasOwnProperty("toString"))
{
// Is or can be converted to a String which will be used as an XML attribute value
sortableStyles.push({xmlName:key, xmlVal:val});
}
}
}
else if (val is TextLayoutFormat)
{
// A style dictionary; Will be converted to an XMLList containing elements to be added as children
var customDictProp:XMLList = exportObjectAsTextLayoutFormat(key,(val as TextLayoutFormat).getStyles());
if (customDictProp)
sortableStyles.push({xmlName:key, xmlVal:customDictProp});
}
else
sortableStyles.push({xmlName:key, xmlVal:prop.toXMLString(val)});
}
return sortableStyles;
}
tlf_internal function exportObjectAsTextLayoutFormat(key:String,styleDict:Object):XMLList
{
// link attributes and ListMarkerFormat
var elementName:String;
var description:Object;
if (key == LinkElement.LINK_NORMAL_FORMAT_NAME || key == LinkElement.LINK_ACTIVE_FORMAT_NAME || key == LinkElement.LINK_HOVER_FORMAT_NAME)
{
elementName = "TextLayoutFormat";
description = TextLayoutFormat.description;
}
else if (key == ListElement.LIST_MARKER_FORMAT_NAME)
{
elementName = "ListMarkerFormat";
description = ListMarkerFormat.description;
}
if (elementName == null)
return null;
// create the element
var formatXML:XML = <{elementName}/>;
formatXML.setNamespace(flowNS);
var sortableStyles:Array = createStylesFromDescription(styleDict, description, true, null);
exportStyles(XMLList(formatXML), sortableStyles);
// create the link format element
var propertyXML:XMLList = XMLList(<{key}/>);
propertyXML.appendChild(formatXML);
return propertyXML;
}
protected override function exportFlowElement(flowElement:FlowElement):XMLList
{
var rslt:XMLList = super.exportFlowElement(flowElement);
var allStyles:Object = flowElement.styles;
if (allStyles)
{
// WhiteSpaceCollapse attribute should never be exported (except on TextFlow -- handled separately)
delete allStyles[TextLayoutFormat.whiteSpaceCollapseProperty.name];
// To prevent "inherit" from getting exported for the root node, comment in the following line, and remove the one after that (only need one call to exportStyles
var sortableStyles:Array = createStylesFromDescription(allStyles,formatDescription,true,flowElement.parent ? null : [FormatValue.INHERIT]);
exportStyles(rslt, sortableStyles );
}
// export id and styleName
if (flowElement.id != null)
rslt.@["id"] = flowElement.id;
if (flowElement.typeName != flowElement.defaultTypeName)
rslt.@["typeName"] = flowElement.typeName;
return rslt;
}
/** Base functionality for exporting an Image. Exports as a FlowElement,
* and exports image properties.
* @param exporter Root object for the export
* @param image Element to export
* @return XMLList XML for the element
*/
static public function exportImage(exporter:BaseTextLayoutExporter, image:InlineGraphicElement):XMLList
{
var output:XMLList = exportFlowElement(exporter, image);
// output the img specific values
if (image.height !== undefined)
output.@height = image.height;
if (image.width !== undefined)
output.@width = image.width;
// output.@rotation = image.rotation; don't support rotation yet
if (image.source != null)
output.@source = image.source;
if (image.float != undefined)
output.@float = image.float;
return output;
}
/** Base functionality for exporting a LinkElement. Exports as a FlowGroupElement,
* and exports link properties.
* @param exporter Root object for the export
* @param link Element to export
* @return XMLList XML for the element
*/
static public function exportLink(exporter:BaseTextLayoutExporter, link:LinkElement):XMLList
{
var output:XMLList = exportFlowGroupElement(exporter, link);
if (link.href)
output.@href= link.href;
if (link.target)
output.@target = link.target;
return output;
}
/** Base functionality for exporting a DivElement. Exports as a FlowContainerFormattedElement
* @param exporter Root object for the export
* @param div Element to export
* @return XMLList XML for the element
*/
static public function exportDiv(exporter:BaseTextLayoutExporter, div:DivElement):XMLList
{
return exportContainerFormattedElement(exporter, div);
}
/** Base functionality for exporting a SubParagraphGroupElement. Exports as a FlowGroupElement
* @param exporter Root object for the export
* @param elem Element to export
* @return XMLList XML for the element
*/
static public function exportSPGE(exporter:BaseTextLayoutExporter, elem:SubParagraphGroupElement):XMLList
{
return exportFlowGroupElement(exporter, elem);
}
/** Base functionality for exporting a TCYElement. Exports as a FlowGroupElement
* @param exporter Root object for the export
* @param tcy Element to export
* @return XMLList XML for the element
*/
static public function exportTCY(exporter:BaseTextLayoutExporter, tcy:TCYElement):XMLList
{
return exportFlowGroupElement(exporter, tcy);
}
override protected function get formatDescription():Object
{
return _formatDescription;
}
}
}