Re: [webcomponents] Adjusting offsetParent, offsetTop, offsetLeft properties in Shadow DOM

2013-03-28 Thread Elliott Sprehn
On Mon, Mar 25, 2013 at 2:48 AM, Dominic Cooney domin...@chromium.orgwrote:

 On Sun, Mar 24, 2013 at 3:50 PM, Elliott Sprehn espr...@gmail.com wrote:


 On Mon, Mar 18, 2013 at 4:48 AM, Dominic Cooney domin...@chromium.orgwrote:

 ...

 I think the offset{Parent, Top, Left} properties should be adjusted.
 This means that in the above example, b.offsetParent would be body and
 b.offsetLeft would be silently adjusted to accumulate an offset of 10px
 from c. I think this makes sense because typical uses of offsetParent and
 offsetLeft, etc. are used to calculate the position of one element in the
 coordinate space of another element, and adjusting these properties to work
 this way will mean code that naively implements this use case will continue
 to work.

 This behavior is unfortunately slightly lossy: If the author had #c and
 wanted to calculate the position of #b in the coordinate space of #c, they
 will need to do some calculation to work it out via body. But presumably
 a script of this nature is aware of the existence of Shadow DOM.

 The question of what to do for offset* properties across a shadow
 boundary when the shadow *is* traversable is a vexing one. In this case
 there is no node disclosed that you could not find anyway using
 .shadowRoot, etc. tree walking. From that point of view it seems acceptable
 for offsetParent to return an offsetParent inside the (traversable) shadow.


 This seems like correct behavior. We should walk up to find a traversable
 parent and then offsetLeft/offsetTop should be relative to those.

 (Note in webkit this is trivial since offsetLeft, offsetTop both call
 offsetParent internally and then compute their value from it)



 On the other hand, this violates the lower-boundary encapsulation of the
 Shadow DOM spec. This means that pages that are using traversable shadows,
 but relying on convention (ie don't use new properties like .shadowRoot)
 to get the encapsulation benefits of Shadow DOM, now have to audit the
 offsetParent property. It also means you need to have two ways of dealing
 with offsetParent in both user agents and author scripts. So for simplicity
 and consistency I think it makes sense to treat both traversable and
 non-traversable shadows uniformly.


 I disagree with this


 Which part?

 Returning an element inside Shadow DOM in an attribute of a node outside
 Shadow DOM violates lower boundary encapsulation.


Yes, it's sad that you can fall into a shadow by mistake here where all
the other APIs were designed to prevent that.


 If offsetParent returns an element inside traversable Shadow DOM, pages
 that are using traversable shadows but relying on convention to get
 encapsulation benefits will have to audit uses of the offsetParent property.

 If offsetParent returns an element inside traversable Shadow DOM (but not
 non-traversable Shadow DOM), there are two ways of dealing with
 offsetParent in the user agent.

 If offsetParent returns an element inside traversable Shadow DOM (but not
 non-traversable Shadow DOM), there are two ways of dealing with
 offsetParent in author scripts.


What you're proposing doesn't reduce the issues. There's still two cases,
you're just offloading all the complexity into author code by making them
walk up the tree and call getComputedStyle everywhere.



 It makes sense to treat both traversable and non-traversable shadows
 uniformly.


I disagree with this statement. By the virtue of what a non-traversable
shadow is we need to treat it special all over the place.




 since it means offsetParent returns a nonsensical value for elements in,
 or projected into, traversable shadow roots as it traverses all the way up
 into the main page until it's not inside a ShadowRoot anymore.


 In what way is that nonsensical? The return value makes sense at the level
 of abstraction the code calling innerParent is working at.


var rect = node.offsetParent.getBoundingClientRect();
node.style.top = computePosition(rect);
node.style.left = computePosition(rect);

Since you're walking all the way out of the shadow into the main page
you're going to get a nonsense result here. More importantly since all the
apps we've seen built using custom elements so far have x-app and the
entire app down there you're effectively saying that offsetParent should
return body for nearly every element in a Toolkit app and that the
feature becomes totally useless.




 offsetParent is very useful to find your positioned parent, and you're
 crippling that feature and making authors use distributedParent +
 getComputedStyle() repeatedly which is considerably more expensive.


 What are those use cases, except finding the position of an element
 relative to another element, which I think is not excessively complicated
 by what I am proposing here?


Not complicated, just very expensive. getComputedStyle allocates a new
object on every invocation and does string parsing. Unfortunately it seems
jQuery already does this:

Re: [webcomponents] Adjusting offsetParent, offsetTop, offsetLeft properties in Shadow DOM

2013-03-28 Thread Elliott Sprehn
On Wed, Mar 27, 2013 at 2:02 PM, Boris Zbarsky bzbar...@mit.edu wrote:

 Scott Miles wrote:

  This is a thorny problem, but my initial reaction is that you
  threaded the needle appropriately. I don't see how we avoid some
  lossiness in this situation.

 Note that if you're using offsetWith/Height/Top/Bottom you already lose,
 because they return integers.

 I think we should be doing what we can to discourage use of these broken
 APIs, for what it's worth, instead of worrying how we can extend their
 already-incorrect behavior to cover more cases well.


That's fair, how do you feel about getPositionedAncestor(bool
includingTraversableShadows) ? This would solve the primary use cases for
offsetParent, and also mean jQuery wouldn't need to call getComputedStyle
all the way up the tree.

Walking the box tree is super fast in C++, and isPositioned is a bitfield
check. Doing this in JS with getComputedStyle is quite a lot more expensive
(allocate CSSComputedStyleDeclaration, parse the property name, return the
position value, compare the string).

- E


Re: [webcomponents] Adjusting offsetParent, offsetTop, offsetLeft properties in Shadow DOM

2013-03-28 Thread Scott González
On Thu, Mar 28, 2013 at 12:49 PM, Elliott Sprehn espr...@gmail.com wrote:

 On Mon, Mar 25, 2013 at 2:48 AM, Dominic Cooney domin...@chromium.orgwrote:

 On Sun, Mar 24, 2013 at 3:50 PM, Elliott Sprehn espr...@gmail.comwrote:

 offsetParent is very useful to find your positioned parent, and you're
 crippling that feature and making authors use distributedParent +
 getComputedStyle() repeatedly which is considerably more expensive.


 What are those use cases, except finding the position of an element
 relative to another element, which I think is not excessively complicated
 by what I am proposing here?


 Not complicated, just very expensive. getComputedStyle allocates a new
 object on every invocation and does string parsing. Unfortunately it seems
 jQuery already does this:
 https://github.com/jquery/jquery/blob/master/src/offset.js#L126


I read this last sentence as The most popular JavaScript library doesn't
suffer from any problems with this proposal. This is unfortunate. I'm sure
you meant that it's unfortunate that we take the slow path, but as Boris
has already stated Note that if you're using offsetWith/Height/Top/Left
you already lose, because they return integers. We tried to ignore this
problem for years. Unfortunately, he's right and using offset* will
eventually sneak up and cause seemingly inexplicable bugs. Also,
considering that jQuery is already doing this, it seems clear that this
isn't a performance bottleneck.

FWIW, I was going to make the same exact argument that this proposal was
going to break code for positioning elements relative to other elements,
which is something we do dynamically all the time in jQuery UI. But then I
looked at the code in jQuery core and asked Mike Sherov if he could provide
feedback. I think he never did because there just doesn't seem to be a good
response. Coincidentally, a few days later, Mike and I were reviewing some
completely unrelated code and spent at least half an hour trying to figure
out why some elements were being positioned 1px off from their expected
location and it came down to offset* being lossy.


Re: [webcomponents] Adjusting offsetParent, offsetTop, offsetLeft properties in Shadow DOM

2013-03-28 Thread Boris Zbarsky

On 3/28/13 12:55 PM, Elliott Sprehn wrote:

and isPositioned is a bitfield check


That happens to be a WebKit-specific claim, as far as I can tell.

 parse the property name

As is this.

But yes, the general claim that the JS APIs for doing this right now are 
full of performance fail stands.  ;)


-Boris



Re: [webcomponents] Adjusting offsetParent, offsetTop, offsetLeft properties in Shadow DOM

2013-03-27 Thread Boris Zbarsky

Scott Miles wrote:

 This is a thorny problem, but my initial reaction is that you
 threaded the needle appropriately. I don't see how we avoid some
 lossiness in this situation.

Note that if you're using offsetWith/Height/Top/Bottom you already lose, 
because they return integers.


I think we should be doing what we can to discourage use of these broken 
APIs, for what it's worth, instead of worrying how we can extend their 
already-incorrect behavior to cover more cases well.


-Boris



Re: [webcomponents] Adjusting offsetParent, offsetTop, offsetLeft properties in Shadow DOM

2013-03-27 Thread Boris Zbarsky

On 3/27/13 2:02 PM, Boris Zbarsky wrote:

Note that if you're using offsetWith/Height/Top/Bottom you already lose,


s/Bottom/Left/, of course.

-Boris



Re: [webcomponents] Adjusting offsetParent, offsetTop, offsetLeft properties in Shadow DOM

2013-03-25 Thread Dominic Cooney
On Sun, Mar 24, 2013 at 3:50 PM, Elliott Sprehn espr...@gmail.com wrote:


 On Mon, Mar 18, 2013 at 4:48 AM, Dominic Cooney domin...@chromium.orgwrote:

 ...

 I think the offset{Parent, Top, Left} properties should be adjusted. This
 means that in the above example, b.offsetParent would be body and
 b.offsetLeft would be silently adjusted to accumulate an offset of 10px
 from c. I think this makes sense because typical uses of offsetParent and
 offsetLeft, etc. are used to calculate the position of one element in the
 coordinate space of another element, and adjusting these properties to work
 this way will mean code that naively implements this use case will continue
 to work.

 This behavior is unfortunately slightly lossy: If the author had #c and
 wanted to calculate the position of #b in the coordinate space of #c, they
 will need to do some calculation to work it out via body. But presumably
 a script of this nature is aware of the existence of Shadow DOM.

 The question of what to do for offset* properties across a shadow
 boundary when the shadow *is* traversable is a vexing one. In this case
 there is no node disclosed that you could not find anyway using
 .shadowRoot, etc. tree walking. From that point of view it seems acceptable
 for offsetParent to return an offsetParent inside the (traversable) shadow.


 This seems like correct behavior. We should walk up to find a traversable
 parent and then offsetLeft/offsetTop should be relative to those.

 (Note in webkit this is trivial since offsetLeft, offsetTop both call
 offsetParent internally and then compute their value from it)



 On the other hand, this violates the lower-boundary encapsulation of the
 Shadow DOM spec. This means that pages that are using traversable shadows,
 but relying on convention (ie don't use new properties like .shadowRoot)
 to get the encapsulation benefits of Shadow DOM, now have to audit the
 offsetParent property. It also means you need to have two ways of dealing
 with offsetParent in both user agents and author scripts. So for simplicity
 and consistency I think it makes sense to treat both traversable and
 non-traversable shadows uniformly.


 I disagree with this


Which part?

Returning an element inside Shadow DOM in an attribute of a node outside
Shadow DOM violates lower boundary encapsulation.

If offsetParent returns an element inside traversable Shadow DOM, pages
that are using traversable shadows but relying on convention to get
encapsulation benefits will have to audit uses of the offsetParent property.

If offsetParent returns an element inside traversable Shadow DOM (but not
non-traversable Shadow DOM), there are two ways of dealing with
offsetParent in the user agent.

If offsetParent returns an element inside traversable Shadow DOM (but not
non-traversable Shadow DOM), there are two ways of dealing with
offsetParent in author scripts.

It makes sense to treat both traversable and non-traversable shadows
uniformly.


 since it means offsetParent returns a nonsensical value for elements in,
 or projected into, traversable shadow roots as it traverses all the way up
 into the main page until it's not inside a ShadowRoot anymore.


In what way is that nonsensical? The return value makes sense at the level
of abstraction the code calling innerParent is working at.


 offsetParent is very useful to find your positioned parent, and you're
 crippling that feature and making authors use distributedParent +
 getComputedStyle() repeatedly which is considerably more expensive.


What are those use cases, except finding the position of an element
relative to another element, which I think is not excessively complicated
by what I am proposing here?

Dominic


Re: [webcomponents] Adjusting offsetParent, offsetTop, offsetLeft properties in Shadow DOM

2013-03-24 Thread Elliott Sprehn
On Mon, Mar 18, 2013 at 4:48 AM, Dominic Cooney domin...@chromium.orgwrote:

 ...

 I think the offset{Parent, Top, Left} properties should be adjusted. This
 means that in the above example, b.offsetParent would be body and
 b.offsetLeft would be silently adjusted to accumulate an offset of 10px
 from c. I think this makes sense because typical uses of offsetParent and
 offsetLeft, etc. are used to calculate the position of one element in the
 coordinate space of another element, and adjusting these properties to work
 this way will mean code that naively implements this use case will continue
 to work.

 This behavior is unfortunately slightly lossy: If the author had #c and
 wanted to calculate the position of #b in the coordinate space of #c, they
 will need to do some calculation to work it out via body. But presumably
 a script of this nature is aware of the existence of Shadow DOM.

 The question of what to do for offset* properties across a shadow boundary
 when the shadow *is* traversable is a vexing one. In this case there is no
 node disclosed that you could not find anyway using .shadowRoot, etc. tree
 walking. From that point of view it seems acceptable for offsetParent to
 return an offsetParent inside the (traversable) shadow.


This seems like correct behavior. We should walk up to find a traversable
parent and then offsetLeft/offsetTop should be relative to those.

(Note in webkit this is trivial since offsetLeft, offsetTop both call
offsetParent internally and then compute their value from it)



 On the other hand, this violates the lower-boundary encapsulation of the
 Shadow DOM spec. This means that pages that are using traversable shadows,
 but relying on convention (ie don't use new properties like .shadowRoot)
 to get the encapsulation benefits of Shadow DOM, now have to audit the
 offsetParent property. It also means you need to have two ways of dealing
 with offsetParent in both user agents and author scripts. So for simplicity
 and consistency I think it makes sense to treat both traversable and
 non-traversable shadows uniformly.


I disagree with this since it means offsetParent returns a nonsensical
value for elements in, or projected into, traversable shadow roots as it
traverses all the way up into the main page until it's not inside a
ShadowRoot anymore.

offsetParent is very useful to find your positioned parent, and you're
crippling that feature and making authors use distributedParent +
getComputedStyle() repeatedly which is considerably more expensive.

- E


Re: [webcomponents] Adjusting offsetParent, offsetTop, offsetLeft properties in Shadow DOM

2013-03-23 Thread Scott Miles
Sorry for the late response, this is one of those bad cases where agreement
was expressed as silence.

This is a thorny problem, but my initial reaction is that you threaded the
needle appropriately. I don't see how we avoid some lossiness in this
situation.

Scott


On Mon, Mar 18, 2013 at 1:48 AM, Dominic Cooney domin...@chromium.orgwrote:

 Summary: I think the Shadow DOM spec should specify how offset* properties
 are handled around shadows. Further, I think traversable and
 non-traversable shadows should be handled uniformly. The offsetParent
 property should return the first offsetParent at the same level of shadow
 as the receiver, or the document, to maintain lower-boundary encapsulation.
 And the offset{Top, Left} properties should be accumulated across skipped
 offsetParents.

 Problem:

 It seems the consensus is that there will be two kinds of shadows, ones
 that are exposed to the page through properties such as
 HTMLElement.shadowRoot, and ones that aren't [1]. The language is emerging
 but for now I will refer to these as traversable and non-traversable
 shadows respectively.

 In both cases, there's a question of how to handle HTMLElement.offset*
  properties, particularly offsetParent. [2]

 Let's talk about a specific example:

 div id=a
   div id=b

 {#a's ShadowRoot}
   div id=c style=position: relative; left: 10px;
 div id=d
   content

 In this case, the positioned ancestor of #b is #c. What should the result
 of b.offsetParent be?

 If the ShadowRoot is not traversable it is clear that b.offsetParent
 should NOT be c. If it were, it would be very difficult to use
 not-traversable shadows that don't accidentally leak an internal node.
 (Especially when you consider that c could be a pseudo-element, and the
 author could set position: relative on the element that way.)

 Discussion:

 I think the offset{Parent, Top, Left} properties should be adjusted. This
 means that in the above example, b.offsetParent would be body and
 b.offsetLeft would be silently adjusted to accumulate an offset of 10px
 from c. I think this makes sense because typical uses of offsetParent and
 offsetLeft, etc. are used to calculate the position of one element in the
 coordinate space of another element, and adjusting these properties to work
 this way will mean code that naively implements this use case will continue
 to work.

 This behavior is unfortunately slightly lossy: If the author had #c and
 wanted to calculate the position of #b in the coordinate space of #c, they
 will need to do some calculation to work it out via body. But presumably
 a script of this nature is aware of the existence of Shadow DOM.

 The question of what to do for offset* properties across a shadow boundary
 when the shadow *is* traversable is a vexing one. In this case there is no
 node disclosed that you could not find anyway using .shadowRoot, etc. tree
 walking. From that point of view it seems acceptable for offsetParent to
 return an offsetParent inside the (traversable) shadow.

 On the other hand, this violates the lower-boundary encapsulation of the
 Shadow DOM spec. This means that pages that are using traversable shadows,
 but relying on convention (ie don't use new properties like .shadowRoot)
 to get the encapsulation benefits of Shadow DOM, now have to audit the
 offsetParent property. It also means you need to have two ways of dealing
 with offsetParent in both user agents and author scripts. So for simplicity
 and consistency I think it makes sense to treat both traversable and
 non-traversable shadows uniformly.

 Dominic

 [1] Thread starts here: 
 http://lists.w3.org/Archives/Public/public-webapps/2013JanMar/0535.html
 [2] http://www.w3.org/TR/cssom-view/#offset-attributes


 http://goto.google.com/dc-email-sla



[webcomponents] Adjusting offsetParent, offsetTop, offsetLeft properties in Shadow DOM

2013-03-18 Thread Dominic Cooney
Summary: I think the Shadow DOM spec should specify how offset* properties
are handled around shadows. Further, I think traversable and
non-traversable shadows should be handled uniformly. The offsetParent
property should return the first offsetParent at the same level of shadow
as the receiver, or the document, to maintain lower-boundary encapsulation.
And the offset{Top, Left} properties should be accumulated across skipped
offsetParents.

Problem:

It seems the consensus is that there will be two kinds of shadows, ones
that are exposed to the page through properties such as
HTMLElement.shadowRoot, and ones that aren't [1]. The language is emerging
but for now I will refer to these as traversable and non-traversable
shadows respectively.

In both cases, there's a question of how to handle HTMLElement.offset*
 properties, particularly offsetParent. [2]

Let's talk about a specific example:

div id=a
  div id=b

{#a's ShadowRoot}
  div id=c style=position: relative; left: 10px;
div id=d
  content

In this case, the positioned ancestor of #b is #c. What should the result
of b.offsetParent be?

If the ShadowRoot is not traversable it is clear that b.offsetParent
should NOT be c. If it were, it would be very difficult to use
not-traversable shadows that don't accidentally leak an internal node.
(Especially when you consider that c could be a pseudo-element, and the
author could set position: relative on the element that way.)

Discussion:

I think the offset{Parent, Top, Left} properties should be adjusted. This
means that in the above example, b.offsetParent would be body and
b.offsetLeft would be silently adjusted to accumulate an offset of 10px
from c. I think this makes sense because typical uses of offsetParent and
offsetLeft, etc. are used to calculate the position of one element in the
coordinate space of another element, and adjusting these properties to work
this way will mean code that naively implements this use case will continue
to work.

This behavior is unfortunately slightly lossy: If the author had #c and
wanted to calculate the position of #b in the coordinate space of #c, they
will need to do some calculation to work it out via body. But presumably
a script of this nature is aware of the existence of Shadow DOM.

The question of what to do for offset* properties across a shadow boundary
when the shadow *is* traversable is a vexing one. In this case there is no
node disclosed that you could not find anyway using .shadowRoot, etc. tree
walking. From that point of view it seems acceptable for offsetParent to
return an offsetParent inside the (traversable) shadow.

On the other hand, this violates the lower-boundary encapsulation of the
Shadow DOM spec. This means that pages that are using traversable shadows,
but relying on convention (ie don't use new properties like .shadowRoot)
to get the encapsulation benefits of Shadow DOM, now have to audit the
offsetParent property. It also means you need to have two ways of dealing
with offsetParent in both user agents and author scripts. So for simplicity
and consistency I think it makes sense to treat both traversable and
non-traversable shadows uniformly.

Dominic

[1] Thread starts here: 
http://lists.w3.org/Archives/Public/public-webapps/2013JanMar/0535.html
[2] http://www.w3.org/TR/cssom-view/#offset-attributes


http://goto.google.com/dc-email-sla