package com.intellij.flex.uiDesigner.abc; import com.adobe.fxg.FXGParserFactory; import com.adobe.fxg.swf.FXG2SWFTranscoder; import com.adobe.internal.fxg.dom.GraphicNode; import flash.swf.CompressionLevel; import flash.swf.SwfEncoder; import flash.swf.Tag; import flash.swf.TagEncoder; import flash.swf.tags.*; import flash.swf.types.ImportRecord; import flash.swf.types.Matrix; import flash.swf.types.Rect; import gnu.trove.THashSet; import org.jetbrains.annotations.Nullable; import java.awt.*; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Iterator; import java.util.Set; public class FxgTranscoder extends SymbolTranscoderBase { private GraphicNode node; @Override protected void readSource(InputStream in, long inputLength) throws IOException { node = (GraphicNode)FXGParserFactory.createDefaultParser().parse(in); buffer = ByteBuffer.allocate(8 * 1024).order(ByteOrder.LITTLE_ENDIAN); } @Override protected void transcode(boolean writeBounds) throws IOException { fileLength = SYMBOL_CLASS_TAG_FULL_LENGTH + SwfUtil.getWrapLength(); FXG2SWFTranscoder transcoder = new FXG2SWFTranscoder(); DefineSprite spriteDefinition = (DefineSprite)transcoder.transcode(node); MyTagEncoder tagEncoder = new MyTagEncoder(); define(spriteDefinition, new THashSet<>(), tagEncoder); fileLength += tagEncoder.getWriter().getPos(); bounds = computeBounds(spriteDefinition, null, null); if (writeBounds) { writeMovieBounds(); } final byte[] symbolOwnClassAbc = getSymbolOwnClassAbc((short)1); fileLength += symbolOwnClassAbc.length; SwfUtil.header(fileLength, out); tagEncoder.getWriter().writeTo(out, CompressionLevel.BestSpeed); out.write(symbolOwnClassAbc); writeSymbolClass(tagEncoder.getDictionary().getId(spriteDefinition)); SwfUtil.footer(out); } private static Rectangle computeBounds(Tag tag, @Nullable Rectangle computedBounds, @Nullable Matrix matrix) { if (tag instanceof PlaceObject) { PlaceObject placeTag = (PlaceObject)tag; computedBounds = computeBounds(placeTag.ref, computedBounds, placeTag.hasMatrix() ? placeTag.matrix : null); } else if (tag instanceof DefineShape) { Rect shapeBounds = ((DefineShape)tag).bounds; Rectangle rectangle = new Rectangle(shapeBounds.xMin, shapeBounds.yMin, shapeBounds.getWidth(), shapeBounds.getHeight()); if (matrix != null) { rectangle.x += matrix.translateX; rectangle.y += matrix.translateY; if (matrix.hasScale) { rectangle.width *= matrix.scaleX / 65536; rectangle.height *= matrix.scaleY / 65536; } } if (computedBounds == null) { computedBounds = rectangle; } else { computedBounds = computedBounds.union(rectangle); } } else if (tag instanceof DefineSprite) { for (Tag subTag : ((DefineSprite)tag).tagList.tags) { computedBounds = computeBounds(subTag, computedBounds, null); } } return computedBounds; } private static final class MyTagEncoder extends TagEncoder { private MyTagEncoder() { tagw = createEncoder(getSwfVersion()); writer = createEncoder(getSwfVersion()); } @Override public CompressionLevel getCompressionLevel() { return CompressionLevel.BestSpeed; } public SwfEncoder getWriter() { return writer; } @Override protected int getSwfVersion() { return 11; } } private static void define(Tag tag, Set<Tag> defined, MyTagEncoder tagVisitor) { if (!defined.add(tag)) { return; } for (Iterator i = tag.getReferences(); i.hasNext(); ) { define((Tag)i.next(), defined, tagVisitor); } if (tag instanceof ImportRecord) { return; } tag.visit(tagVisitor); Tag visitAfter; if (tag instanceof DefineSprite) { visitAfter = ((DefineSprite)tag).scalingGrid; } else if (tag instanceof DefineButton) { visitAfter = ((DefineButton)tag).scalingGrid; } else if (tag instanceof DefineShape) { visitAfter = ((DefineShape)tag).scalingGrid; } else if (tag instanceof DefineFont3) { visitAfter = ((DefineFont3)tag).zones; } else if (tag instanceof DefineEditText) { visitAfter = ((DefineEditText)tag).csmTextSettings; } else if (tag instanceof DefineText) { visitAfter = ((DefineText)tag).csmTextSettings; } else { return; } visitAfter(visitAfter, defined, tagVisitor); if (tag instanceof DefineFont) { visitAfter(((DefineFont)tag).license, defined, tagVisitor); } } private static void visitAfter(@Nullable Tag visitAfter, Set<Tag> defined, MyTagEncoder tagVisitor) { if (defined.add(visitAfter) && visitAfter != null) { visitAfter.visit(tagVisitor); } } }