Hi Cameron,
One other thing occured to me on this point. You need to
look out for is SVGOMCSSImportedElementRoot this is used for
the 'use' element where we clone the referenced content into
the referencing document, obviously the id's from these
cloned subtrees shouldn't be counted. Just trying to
make it interesting ;)
Thomas DeWeese wrote:
Cameron McCormack wrote:
Ah I see, the SVGSVGElement.getElementById (which I hadn't noticed
existed) restricts to the subtree.
2) Adding/removing elements/subtree's. Someone can add a whole
subtree to a document and all those nodes need to have their
id's added, also when a subtree is removed there id's need to
be removed (which might reveal a hidden duplicate id...).
Yes, I found I had to track whether certain elements were in the
document tree or not so that the ids would only be hashed when the
subtree was inserted.
3) For things like document fragments or simply disconnected
node tree's they should probably have an independent id space.
Hmm, document fragments was one that I'd dismissed since there is no
getElementById method on a DocumentFragment.
The first is fairly easily solved by simply ensuring that
'this' (in getElementById) is an ancestor of the element found in the
hash table. If it isn't then return null.
But yeah, that would work.
The second is trickier. A few ideas, detecting that an old
element has been removed from the tree should be fairly easy
given the 'parent' check above (it will fail). Although it points out
that the hash entries should be soft references so that elements that
were once part of the tree with an id can still be GC'ed. There
is a significant issue about what should happen if the hashed node
isn't listed (see next section).
Or you could just make sure that the references are removed from the
hash table when the subtree is removed from the document tree.
Well, I would really rather avoid making add/remove heavy weight
in order to make getElementById light weight. This is exactly why
we have SoftReferences and they are really pretty simple to use.
Adding nodes, the simple thing would be to just walk the new
subtree and add it's nodes to the parent document. One issue will
be the handling of duplicate Id's. They may be duplicates because
the old element was recently removed, or they may be duplicates
because for the next instant both nodes will be in the tree (they
add then remove for example). In the second case the "hard ass"
response is throw an illegal state exception... This will not win
very many friends however it is probably the 'correct' thing to do.
If you don't do this, then you run the risk that when you remove a
subtree there were element's that had the same id that were shadowed
which would be a pain to track.
I have a hash table of linked lists holding all of the elements with
that id, so that when a duplicate id element is removed, leaving a
single element with the id, getElementById will work again.
Yah, I considered this option, but it didn't feel right to
bend over backwards to support invalid content. A small suggestion
for a case like this that I have seen done is to normally store
a reference to the Element, and only when you get a 'conflict'
do you create the list and store the list (using an instanceof
check). This means that in the usual case you avoid the list
overhead.
Another option would be to be slightly lazy about it, so when
subtree's are added mark them as 'dirty', when someone asks for an id
- check the hash table if it is present and still part of the document
great return it. Otherwise start walking the 'dirty' subtree's adding
id's as you go, until you get to the one you want (or return null).
This is nice from the point of view of not making 'add' overly
expensive.
This is not a bad idea, but I think won't increase performance for cases
like this:
<g id="g1"/>
<g id="g2"/>
<g id="g3"/>
<g id="g4"/>
...
and your script looks up each of these IDs in order.
True it won't help in this case but it won't hurt either. The win
from my point of view is that it pushes most of the cost of hashing
Id's into getElementById so you only pay for it if/when you use it.
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]