Hmm, spoke too soon. Seems it's still a Confluence bug. I checked further and found Firefox implementation actually does conform to what's described at http://www.w3.org/TR/html401/struct/links.html. Based on the allowed character set for HTML element IDs (http://www.w3.org/TR/html401/types.html#type-name), it only allows [A-Za-z0-9_.:-]. Firefox supports all of them. Additionally, ',', '%' etc. (in fact most of the printable characters), are supported in Firefox.
So it's really not a firefox problem as it does conform to the standards.
Upon further inspection, I found that the reason why some links do not work in Firefox is because of the escaping in the IDs. For example, the following situation would work in Firefox:
<a href="#:">test</a>
...
<h2 id=":">first heading</h2>
So does:
<a href="#%3A">test</a>
...
<h2 id=":">first heading</h2>
But not:
<a href="#%3A">test</a>
...
<h2 id="%3A">first heading</h2>
This suggests that Firefox only unescapes the URI in <a> (correct behavior) but not ID (again, I believe it's the correct behavior too. Why should browsers unescape characters in IDs? Unicode argument does not apply here. In fact, it's surprising that other browsers would all be behaving incorrectly including Opera, as suggested by the other user).
So here're my suggestions as to how one could address this problem:
1. One could change the code in com.atlassian.confluence.renderer.NoAnchorHeadingBlockRenderer to escape the string in <a>, but do not escape them in <h2 id... etc. This, however, runs into the risk that some characters MUST be escaped. For example, "
2. One could escape the code in both <a> and <h2 id... BUT get rid of the '%' after escaping the string. This way you're left with a unique, standards-conforming string for both link and ID and they'd work in all browsers.
What's more, I do not understand the logic of escaping everything except for space character, which was just discarded. It seems to me if the space is not regarded as important for uniqueness, so are all the punctuations, which are all escaped by your renderer after removing space. So the method 2 above should be used for space character too and the result would have guaranteed uniqueness even for any situation. So instead of removing space then escape, the procedure should become (not remove space), escape, then remove % character.
BTW, I also noticed that your renderer for some reason was using the deprecated ' in <a href='uri'> instead of <a href="uri">. " should be used instead of '.
Hmm, so I guess the existing document fragments links are hard-coded that's why you can't change encoding now.
But anyway reverting back is probably better given that it's always a little worrisome that those elements (like <h2>) are forced to have an id, which could interfere with other macros (if any) that also need to modify element ids.