Menu

Verbose Path Syntax

SourceForge Editorial Staff

Verbose Path Syntax

Issue:

In the initial days of FXG 1.0 development, Path elements could specify their data in two ways:

  1. As a short-hand syntax, similar to SVG, ie:

    <path data="M 3.0 0.0 L 3.0 1.0 L 4.0 1.0 L 4.0 2.0 C"></path>

      2. As a long-hand, more verbose but readable, syntax , ie:  

<Path>
 <segments>
  <MoveSegment x="3" y="0" />
  <LineSegment x="3" y="1" />
  <LineSegment x="4" y="1" />
  <LineSegment x="4" y="2" />
  <CloseSegment />
 </segments>
</Path>

The two above were equivalent.

We then rev'ed FXG 1.0 to only allow short-hand syntax since that was what the CS tools were generating, and it did not seem necessary to the FXG stakeholders to have two ways of specifying the same data commands.

We'd like to go ahead and make this change in MXML graphics as well. We would like to make internal the path segment classes. This would mean the segment classes would not be usable in markup, nor would they be externally accessible to developers as typed segment objects. The short-hand syntax was always parsed into typed objects that were stored in the Path.segments property. Users could poke into the segments array to access individual path commands as MoveSegment object, LineSegment objects, etc. We'd be removing this property as well as other segment-associated API's. The full list is documented in the Resolutions section below.

The classes in question being removed from markup/external access are:

spark.primitives.PathSegment;
spark.primitives.CloseSegment;
spark.primitives.CubicBezierSegment;
spark.primitives.LineSegment;
spark.primitives.MoveSegment;
spark.primitives.QuadraticBezierSegment;

The impetus behind this move is two-fold:

1. No concrete use-cases/compelling reason that benefited having these classes laying around for consumption in markup that couldn't be solved in other ways, like re-setting Path.data. This begged the question - why have these classes at all? If we want to add them in later, that's fine - but we didn't want to be boxed into supporting them if we do deem them unnecessary at a later date. Its important to note that there was one use-case we wrestled with that is not possible if we yank the segment classes. Currently, developers can use data-binding with the verbose path syntax to animate individual path segments. For example, something like this:

<HSlider minimum="0" maximum="10" id="hsl" liveDragging="true"/>

<Path id="p" width="100" height="100">
    <segments>
    <MoveSegment x="3" y="{hsl.value}" />
    <LineSegment x="3" y="1" />
    <LineSegment x="4" y="1" />
    <LineSegment x="4" y="2" />
    <CloseSegment />
    </segments>
 <stroke>
    <SolidColorStroke color="#FFCC00" />
 </stroke>
</Path>

If we yank the path segment classes, this will not be possible. Instead, users would have to reset the data property over time to represent the move segment changing position. To counter the unwieldiness of this, as a possible B-feature we should look into adding API's that let you poke into a Path data's parsed representation to access and modify individual data commands. (Note for Flex 4, we'll be adding a data structure to cache the parsing of a Path's data, but its still a B-feature to add API's to modify individual data commands. This is tracked via bug SDK-19713)

By adding this in as a helpful utility, we can make the work as performant as we desire.

2. Savings with respect to SWF size, memory and runtime performance. These are quantified in the Performance section below. 

Performance Analysis:

SWF Size: We are essentially creating the same number of classes behind the scenes, they are now just private internal classes. Should there be a savings? There seems to be, but its nominal. The following test was ran to try to gauge the potential savings - with the path segment classes collapsed as internal classes, and various API's related to segment management yanked, we compiled a simple Flex application with a single Path defined in it. The same example was compiled against trunk. The SWF size difference was measured:

With path segment classes publicly accessible SWF Size: 1134780 bytes

Without path segment classes publicly accessible SWF Size: 1132379 bytes

Total Savings: 2401 bytes.

Memory:  Since essentially we are creating the same number of classes behind the scenes, the incremental gains we are making is by reducing event listeners. This will be a drop in the bucket. I tried to quantify the gain roughly by exaggerating my testcase and querying System.totalMemory. I render 1000 Paths and poll System.totalMemory before the rendering and after (I force a call to the GC via the localConnection hack to force the GC to run). The test happens in both trunk and the build that contains the collapsing of the Path segment classes and removal of segment-management API's/event listening. The results are below.

With path segment classes publicly accessible, memory used to render 1000 data-heavy Paths: 4,403,200 bytes

Without path segment classes publicly accessible, memory used to render 1000 data-heavy Paths: 4,217,088 bytes

Difference: 186,112 bytes. So, there is approximately a 186 byte savings per Path with regards to memory consumption when using a build where Path segments are not accessible as typed objects.

Runtime Performance: I tried quantifying how long it takes to realize a Path using the short-hand syntax vs. the verbose syntax. In the case of the verbose tags, the compiler will generate factory method, one for each tag and call them all in succession and then shove everything into an array. In the shorthand syntax, we parse the string and walk the results and create the classes programmatically. I used the following test to try to gauge runtime performance. Using a build with the verbose path syntax classes made internal, and all segment-related management API's yanked, I measured how long it took to draw 1000 data-heavy Paths. I used getTimer() calls to flank the rendering process and get a handle on time to execute. I then ran the same test against trunk.

With path segment classes publicly accessible, time to create 1000 heavy Paths: 134 ms

With path segment classes publicly accessible, time to create 1000 heavy Paths: 106 ms

Total savings: 28 ms

Proposal

Collapse the PathSegment class and its derivatives as private classes in Path and hide them from external use. This includes:

  • Fold the following segment classes as internal classes in Path.

spark.primitives.PathSegment;
spark.primitives.CloseSegment;
spark.primitives.CubicBezierSegment;
spark.primitives.LineSegment;
spark.primitives.MoveSegment;
spark.primitives.QuadraticBezierSegment;

  • Remove all the above-stated path segment's classes extensions of EventDispatcher, dispatching of events when properties change, Bindable metadata, Inspectable metadata including notification methods like Path.segmentChanged, etc.
  • Remove Path.segment

Related

Wiki: Flex 4

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.