Platform/GFX/2013-April-2

From MozillaWiki
< Platform‎ | GFX
Jump to: navigation, search

Urgent Bug Triage

Bugs tracked for upcoming Firefox releases:

Gfx bugs

Including Image, Canvas 2D, and WebGL.

Layout bugs

Media bugs

Agenda

  • GDC wrap-up
  • Web Animations feedback
  • Async pan/zoom work update
  • SkiaGL update
  • Images and Temporary Surfaces

Web Animations feedback

Editor's Draft: https://dvcs.w3.org/hg/FXTF/raw-file/default/web-anim/index.html

Background:

  • Make a common model for animation features on the Web encompassing CSS animations/transitions and SVG animations.
    • Synchronization: global clock. Can synchronize animations from CSS/SVG/script.
    • Possible to implement using same animation engine—all declarative markup benefits from same optimizations
  • Add an API onto the model
    • Possible to inspect the state of animations in a page regardless of source (CSS/SVG/script)
    • Easy to create animations from script that are accelerated/synchronized/frame-rate independent/etc.


Status: Hoping to ask for permission to publish FPWD in 1~2 months.

Vendor status:

  • Mozilla, Google, and Adobe developing spec and polyfill
  • Apple support model, concern about API surface area
  • Microsoft have made only a few comments, seem supportive?
    • Developed in response to previous PM's request for a unified model and an API
  • Polyfill may provide some fallback in short-term: https://github.com/web-animations/web-animations-js


Would appreciate Mozilla input, particularly on the following 3 issues

Send feedback to:


Issue 1: Compositing animations together

Background: There are three ways to combine animations that target the same property:

  1. The one with the highest priority wins (CSS; SVG w/ additive="replace")
  2. Add them together: lower + higher (SVG w/ additive="sum")
  3. Interpolate from the "underlying value" (result of lower priority animations) to the destination value (SVG "to-animation"; CSS appears to do this but actually snapshots the underlying value and does (1))


Issue: How do we represent these in the model?

Approach A) Offer three compositing modes: replace (1), add (2), and merge (3)

  • Complex. Especially for the very common case of wanting to simply animate "to" a value. You have to set up a merge operation for this or have a constructor that does magic behind the scenes to do it for you.
  • Adds new functionality.


Approach B) Offer two compositing modes: replace (1) or add (2)

When you have a keyframes animation with no 0%/100% do (3)

  • Simple.
  • Similar to CSS with regards to missing keyframes (but subtly different since it doesn't snapshot the underlying value).
  • Concern about it being incomplete—you can have "holes" at the ends of the keyframes but not in the middle.


Approach C) Allow each key frame value to specify if it is additive or not

e.g. left: "+0", "50", "+20"

  • Most flexible.
  • Doesn't help with other types of animations like path animations.
  • Difficult to set behavior across-the-board (add a default compositing mode as well?)
  • Syntax like the above wouldn't work: extra constructs (e.g. add('6px')) would probably be required


Issue 2: Separating play control from animation definition

Background: Timing groups can repeat and sequence their children.

Issue: Adding play control (pause, seeking etc.) to animations and timing groups themselves produces a lot of situations where the resulting behavior is not obvious (what happens if you seek the child of a group that loops? Does the group wait? Is everything back to normal on the next loop?)

Approach A) Put play control on the animations / timing groups themselves

Define how the operations behave when there is a parent timing group (e.g. seeking an animation that is part of a group throws/silently fails)

  • Simple
  • Similar to HTMLMediaElement / MediaController (when seeking an HTMLMediaElement that has a media controller, it throws an InvalidStateError exception)
  • Methods behave differently on animations depending on whether they have a parent group or not


Approach B) (Current spec) Make a separate object for play control (the Player) associated with the root timing group an animation is part of

To pause an animation you do animation.getPlayer().pause() and it pauses everything in that tree

  • Consistent—no exceptions or changing behavior
  • More complex
  • Makes it obvious that an animation may be part of a more complex arrangement


Issue 3: Representing timing parameters in the API

Background: Timing groups and animations (collectively called timed items) have various timing parameters such as "iteration duration". The iteration duration can take a value like "auto". For things like timing groups that means the duration of the group stretches to fit its children.

Issue: We need a way from the API to represent both the "auto" value and the resolved numeric value. In the future we'll probably also extend durations to include percentages. (We are also trying to make these objects easy to create and keep the API surface area low.)

Approach A) (Current spec) Have a dictionary for specified timing parameters

To change parameters you set the whole thing.

interface TimedItem : EventTarget {
   // Specified timing
   TimingDictionary getTiming ();
   TimingDictionary setTiming (TimingDictionary timing);
   
   // Calculated timing
   readonly attribute double              startTime;
   readonly attribute unrestricted double iterationDuration;
   readonly attribute unrestricted double activeDuration;
   readonly attribute unrestricted double endTime;
};

interface Animation : TimedItem { ... };
interface TimingGroup : TimedItem { ... };

dictionary TimingDictionary {
   double                             startDelay = 0;
   FillMode                           fillMode = "forwards";
   (unrestricted double or DOMString) iterationDuration = "auto";
   (unrestricted double or DOMString) activeDuration = "auto";
   double                             playbackRate = 1.0;
   ...
};

Animations and TimingGroups have a ctor that takes a TimingDictionary.

 elem.animate({ left: '100px' }, { iterationDuration: 3, fillMode = "none" });

(There's also a shortcut for just setting the iterationDuration)

Usage:

 var specifiedDur = anim.getTiming().iterationDuration; // "auto"
 var computedDur = anim.iterationDuration; // 5
 
 // Update duration to 3s
 var timing = anim.getSpecified();
 timing.iterationDuration = 3;
 anim.setTiming(timing);
   
 // Reset duration to 'auto'
 timing.iterationDuration = "auto";
 anim.setTiming(timing);

Note that the following clobbers all other properties:

 anim.setTiming({ iterationDuration: 3 })
  • Re-uses the TimingDictionary definition to keep API surface area small.
  • Changing timing parameters can have knock-on effects since it effects the scheduling of other items in the hierarchy and this API makes that more obvious.
  • Specified timing and computed timing are separate (I'm not sure if this is helpful or not. It means that in many cases the place where you read parameters differs from where you set them but others in the group find this distinction useful.)
  • The fact that anim.setTiming({ iterationDuration: 3 }) clobbers other parameters is sure to trip people up


Approach B) Introduce an additional Timing interface that is basically a live version of the dictionary used for construction

Usage:

 var specifiedDur = anim.specified.iterationDuration; // "auto"
 var computedDur = anim.iterationDuration; // 5
 
 // Update duration to 3s
 timing.specified.iterationDuration = 3;
  
 // Reset duration to 'auto'
 timing.specified.iterationDuration = "auto";
  • Duplication of parameters: a dictionary version and an interface version → increases API surface area, awkward to maintain / spec
  • Specified timing and computed timing are separate (again, not certain if this is helpful or confusing)


Approach C) Combine the specified and computed timing

interface TimedItem : EventTarget {
   // Timing
   attribute double   startDelay;
   attribute FillMode fillMode;
   attribute Duration iterationDuration;
   attribute Duration activeDuration;
   attribute double   playbackRate;
   // ...
   
   // Scheduled time
   readonly attribute double              startTime;
   readonly attribute unrestricted double endTime;
};

interface Duration {
  double    sec;
  DOMString string;
}

Usage:

 var specifiedDur = anim.iterationDuration.string; // "auto"
 var computedDur = anim.iterationDuration.sec; // 5
 
 // Update duration to 3s
 anim.iterationDuration.sec = 3;
 // anim.iterationDuration.string -> "3s"
 
 // Update duration to 3s (alt.)
 anim.iterationDuration.string = "3s";
 // anim.iterationDuration.sec -> 3
 
 // Reset to auto
 anim.iterationDuration.string = "auto";  
 // anim.iterationDuration.sec -> 5
  • Some duplication of parameters between the dictionary and TimedItem
  • Mixes specified and computed timing
  • Setting and reading duration happens in same place
  • Mimicks patterns proposed for CSS Lengths and SVGLength
  • Easy to extend this to support percentage measures in the future (which is likely for duration properties)
  • Not easy to apply this pattern to other parameters in the future (e.g. if we want to make playbackRate accept a string we'd have to introduce another attribute in order to use the same pattern)