Re: [cssom] CSS Value API

On Apr 6, 2010, at 3:28 AM, Anne van Kesteren wrote:

> On Thu, 25 Mar 2010 16:10:58 +0100, Anne van Kesteren <annevk@opera.com> wrote:
>> [...]
>> 
>> Thoughts on this are very much welcome. Some brainstorming during the F2F might also be a good use of time if we limit the amount of time :-)
> 
> This is a fairly long email describing a value API proposal for CSS. None of this made it into CSSOM yet. Hopefully people can make the time to review this and point out mistakes or ideas for improvement. Feel free to ask any questions. I'll do my best to reply timely.
> 
> TERMINOLOGY
> 
> The terminology is abbreviated here to make the proposal more easily to skim through.
> 
> value -- the value of a property
> 
>  margin: 20px 20px
>  the value is 20px 20px
> 
> component value -- one of the components of a value
> 
>  margin: 20px 20px
>  the component values are 20px and 20px
>  color: <color>
>  the component value is <color>
> 
> map value -- component values are independent but grouped in a single value
> 
>  border:2px solid red
>  the value of this property is a map value
> 
> list value -- component values are comma-separated
> 
>  cursor:url(big), pointer;
>  the value of this property is a list value
> 
> space-list value -- component values are space-separated, possibly with a maximum length
> 
>  counter-increment: foo 1 bar 2
>  the value of this property is a space-list value of map values
>  (or a single ident)
> 
>  margin:20px 20px
>  the value of this property is a space-list value of map values
>  (but limited in length)
> 
> 
> INTERFACES
> 
> All values implement a single base interface, CSSValue. This interface has all the various value types exposed as string constants and the value it currently exposes can be read by getting its type attribute. It uses string constants to make extensibility easier and uses constants to make optimizations easier. It also has a cssText attribute for parsing from string and serializing purposes.
> 
> Map values implement an interface (CSSMapValue) with a single attribute, named m for now, to access a map object (CSSMap). The map object has a named getter and a way to iterate over the items in a map. (I.e. there's length, getter key(int), and getter item(string).) The map object is not directly implemented on the value object to prevent potential future clashes between new members of the value object and existing keys on the map object. (An alternative design for CSSMap might be to just expose string[] keys and getter item(string) as to not reveal ordering and allow more optimizations.)
> 
> List values and space-list values behave similarly to map values (CSSListValue, CSSList), except their attribute is named l, for now. Interface-wise they are identical but to distinguish them the type attribute will return a different value. List and space-list values can also be mutated. I.e. new items can be added and existing items can be removed.
> 
> Components have specific interfaces depending on the type of component. A value implements all the various component interfaces it supports. E.g. 'width' takes both <length> and <percentage> so value objects for it will support both the length and percentage component interfaces.
> 
> 
> VALUE ATTRIBUTE
> 
> I also want to give CSSValue a value attribute. This attribute is of type any. I.e. it can return anything and be set to anything. What you can set it to and what you get out of it depends on the type attribute of CSSValue. In some cases this will be the same as mutating a specific member, such as px on <length>, but for some types this makes sense as the only accessor, e.g. <string> and <ident>.
> 
> 
> ADDING LIST ITEMS
> 
> Currently everything with appending in the CSSOM is done from a string. I'm inclined to follow that model for now. We could construct a way to create all these various kind of objects, but that would be tricky and not very convenient for authors. We could also have a method that appends an object of the right type at a certain position and then let authors modify it after it is appended. I'm open to suggestions.
> 
> 
> EXAMPLES
> 
> 'color': Returns an object that implements CSSValue and the interface for <color>.
> 
>  ele.style.color.red++
> 
> 'margin': Returns an object that implements CSSValue and CSSListValue. Its associated CSSList has up to four items, each of which implements CSSValue and the interfaces for <length>, <percentage>, and <ident>.
> 
>  ele.style.margin.l[0].px++ // increases the px value of the first item
> 
> 'border-top': Returns an object that implements CSSValue and CSSMapValue. Its associated CSSMap has three items, named "width", "style", and "color". Each of the items implement CSSValue and the appropriate component value interface.
> 
>  ele.style.borderTop.m.style.value = "double"
> 
> 'border-image': Returns an object that implements CSSValue and CSSMapValue. Its associated CSSMap has five items, named "source", "slice", "width", "outset", and "repeat". The "source" item implements CSSValue, <image>, and <ident>. "slice" implements CSSValue and CSSMapValue. Its associated CSSMap consists of two items, one a CSSListValue and one an <ident>... 'border-image' is definitely doable with generics (just follow the patterns outlined so far), but for complex properties like these we might actually want to simplify matters and offer a more high-level API. E.g. for "slice" a CSSValue/CSSListValue that also has the ability to easily set the 'fill' keyword rather than having to use a CSSMapValue/CSSMap around them.

How do you see transforms and CSSMatrix fitting into this? Currently you define a transform property like this:

	transform:translate(20px, 50%) rotate(45deg) scale(0.5) translateZ(5px);

In WebKit, a transform is a CSSValueList. Each element of the list is one transform function (4 in the above example) and is of type CSSTransformValue. This inherits from CSSValueList and adds a enum which is the type of the function (e.g., TRANSLATE or ROTATE). Each element of the CSSTransformValue represents a param of the transform function and is always a primitive value. So here we're using a list not to represent separate items for a property as in background, but to represent separate components of a single item.

Does this fit in your model?

-----
~Chris
cmarrin@apple.com

Received on Tuesday, 6 April 2010 23:30:49 UTC