зеркало из https://github.com/mozilla/gecko-dev.git
Bug 582361 - Align scrolling to a fragment with HTML spec. r=emilio
Differential Revision: https://phabricator.services.mozilla.com/D187362
This commit is contained in:
Родитель
3792f1958f
Коммит
66ffe4b27e
|
@ -10850,6 +10850,7 @@ nsresult nsDocShell::OpenRedirectedChannel(nsDocShellLoadState* aLoadState) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/#scrolling-to-a-fragment
|
||||
nsresult nsDocShell::ScrollToAnchor(bool aCurHasRef, bool aNewHasRef,
|
||||
nsACString& aNewHash, uint32_t aLoadType) {
|
||||
if (!mCurrentURI) {
|
||||
|
@ -10879,88 +10880,71 @@ nsresult nsDocShell::ScrollToAnchor(bool aCurHasRef, bool aNewHasRef,
|
|||
// Both the new and current URIs refer to the same page. We can now
|
||||
// browse to the hash stored in the new URI.
|
||||
|
||||
if (!aNewHash.IsEmpty()) {
|
||||
// anchor is there, but if it's a load from history,
|
||||
// we don't have any anchor jumping to do
|
||||
bool scroll = aLoadType != LOAD_HISTORY && aLoadType != LOAD_RELOAD_NORMAL;
|
||||
// If it's a load from history, we don't have any anchor jumping to do.
|
||||
// Scrollbar position will be restored by the caller based on positions stored
|
||||
// in session history.
|
||||
bool scroll = aLoadType != LOAD_HISTORY && aLoadType != LOAD_RELOAD_NORMAL;
|
||||
|
||||
// We assume that the bytes are in UTF-8, as it says in the
|
||||
// spec:
|
||||
// http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1
|
||||
|
||||
// We try the UTF-8 string first, and then try the document's
|
||||
// charset (see below). If the string is not UTF-8,
|
||||
// conversion will fail and give us an empty Unicode string.
|
||||
// In that case, we should just fall through to using the
|
||||
// page's charset.
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
NS_ConvertUTF8toUTF16 uStr(aNewHash);
|
||||
if (!uStr.IsEmpty()) {
|
||||
rv = presShell->GoToAnchor(uStr, scroll, ScrollFlags::ScrollSmoothAuto);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
char* str = ToNewCString(aNewHash, mozilla::fallible);
|
||||
if (!str) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
nsUnescape(str);
|
||||
NS_ConvertUTF8toUTF16 utf16Str(str);
|
||||
if (!utf16Str.IsEmpty()) {
|
||||
rv = presShell->GoToAnchor(utf16Str, scroll,
|
||||
ScrollFlags::ScrollSmoothAuto);
|
||||
}
|
||||
free(str);
|
||||
}
|
||||
|
||||
// Above will fail if the anchor name is not UTF-8. Need to
|
||||
// convert from document charset to unicode.
|
||||
if (NS_FAILED(rv)) {
|
||||
// Get a document charset
|
||||
NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
|
||||
Document* doc = mContentViewer->GetDocument();
|
||||
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
|
||||
nsAutoCString charset;
|
||||
doc->GetDocumentCharacterSet()->Name(charset);
|
||||
|
||||
nsCOMPtr<nsITextToSubURI> textToSubURI =
|
||||
do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Unescape and convert to unicode
|
||||
nsAutoString uStr;
|
||||
|
||||
rv = textToSubURI->UnEscapeAndConvert(charset, aNewHash, uStr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Ignore return value of GoToAnchor, since it will return an error
|
||||
// if there is no such anchor in the document, which is actually a
|
||||
// success condition for us (we want to update the session history
|
||||
// with the new URI no matter whether we actually scrolled
|
||||
// somewhere).
|
||||
//
|
||||
// When aNewHash contains "%00", unescaped string may be empty.
|
||||
// And GoToAnchor asserts if we ask it to scroll to an empty ref.
|
||||
presShell->GoToAnchor(uStr, scroll && !uStr.IsEmpty(),
|
||||
ScrollFlags::ScrollSmoothAuto);
|
||||
}
|
||||
} else {
|
||||
// Tell the shell it's at an anchor, without scrolling.
|
||||
if (aNewHash.IsEmpty()) {
|
||||
// 2. If fragment is the empty string, then return the special value top of
|
||||
// the document.
|
||||
//
|
||||
// Tell the shell it's at an anchor without scrolling.
|
||||
presShell->GoToAnchor(u""_ns, false);
|
||||
|
||||
// An empty anchor was found, but if it's a load from history,
|
||||
// we don't have to jump to the top of the page. Scrollbar
|
||||
// position will be restored by the caller, based on positions
|
||||
// stored in session history.
|
||||
if (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL) {
|
||||
return NS_OK;
|
||||
if (scroll) {
|
||||
// Scroll to the top of the page. Ignore the return value; failure to
|
||||
// scroll here (e.g. if there is no root scrollframe) is not grounds for
|
||||
// canceling the load!
|
||||
SetCurScrollPosEx(0, 0);
|
||||
}
|
||||
// An empty anchor. Scroll to the top of the page. Ignore the
|
||||
// return value; failure to scroll here (e.g. if there is no
|
||||
// root scrollframe) is not grounds for canceling the load!
|
||||
SetCurScrollPosEx(0, 0);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// 3. Let potentialIndicatedElement be the result of finding a potential
|
||||
// indicated element given document and fragment.
|
||||
NS_ConvertUTF8toUTF16 uStr(aNewHash);
|
||||
auto rv = presShell->GoToAnchor(uStr, scroll, ScrollFlags::ScrollSmoothAuto);
|
||||
|
||||
// 4. If potentialIndicatedElement is not null, then return
|
||||
// potentialIndicatedElement.
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// 5. Let fragmentBytes be the result of percent-decoding fragment.
|
||||
nsAutoCString fragmentBytes;
|
||||
const bool unescaped = NS_UnescapeURL(aNewHash.Data(), aNewHash.Length(),
|
||||
/* aFlags = */ 0, fragmentBytes);
|
||||
|
||||
if (!unescaped) {
|
||||
// Another attempt is only necessary if characters were unescaped.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (fragmentBytes.IsEmpty()) {
|
||||
// When aNewHash contains "%00", the unescaped string may be empty, and
|
||||
// GoToAnchor asserts if we ask it to scroll to an empty ref.
|
||||
presShell->GoToAnchor(u""_ns, false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// 6. Let decodedFragment be the result of running UTF-8 decode without BOM on
|
||||
// fragmentBytes.
|
||||
nsAutoString decodedFragment;
|
||||
rv = UTF_8_ENCODING->DecodeWithoutBOMHandling(fragmentBytes, decodedFragment);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// 7. Set potentialIndicatedElement to the result of finding a potential
|
||||
// indicated element given document and decodedFragment.
|
||||
//
|
||||
// Ignore the return value of GoToAnchor, since it will return an error if
|
||||
// there is no such anchor in the document, which is actually a success
|
||||
// condition for us (we want to update the session history with the new URI no
|
||||
// matter whether we actually scrolled somewhere).
|
||||
presShell->GoToAnchor(decodedFragment, scroll, ScrollFlags::ScrollSmoothAuto);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -13108,6 +13108,7 @@ void Document::SetScrollToRef(nsIURI* aDocumentURI) {
|
|||
}
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/#scrolling-to-a-fragment
|
||||
void Document::ScrollToRef() {
|
||||
if (mScrolledToRefAlready) {
|
||||
RefPtr<PresShell> presShell = GetPresShell();
|
||||
|
@ -13117,53 +13118,52 @@ void Document::ScrollToRef() {
|
|||
return;
|
||||
}
|
||||
|
||||
// 2. If fragment is the empty string, then return the special value top of
|
||||
// the document.
|
||||
if (mScrollToRef.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<PresShell> presShell = GetPresShell();
|
||||
if (presShell) {
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
// We assume that the bytes are in UTF-8, as it says in the spec:
|
||||
// http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1
|
||||
NS_ConvertUTF8toUTF16 ref(mScrollToRef);
|
||||
// Check an empty string which might be caused by the UTF-8 conversion
|
||||
if (!ref.IsEmpty()) {
|
||||
// Note that GoToAnchor will handle flushing layout as needed.
|
||||
rv = presShell->GoToAnchor(ref, mChangeScrollPosWhenScrollingToRef);
|
||||
} else {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
if (!presShell) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
nsAutoCString buff;
|
||||
const bool unescaped =
|
||||
NS_UnescapeURL(mScrollToRef.BeginReading(), mScrollToRef.Length(),
|
||||
/*aFlags =*/0, buff);
|
||||
// 3. Let potentialIndicatedElement be the result of finding a potential
|
||||
// indicated element given document and fragment.
|
||||
NS_ConvertUTF8toUTF16 ref(mScrollToRef);
|
||||
auto rv = presShell->GoToAnchor(ref, mChangeScrollPosWhenScrollingToRef);
|
||||
|
||||
// This attempt is only necessary if characters were unescaped.
|
||||
if (unescaped) {
|
||||
NS_ConvertUTF8toUTF16 utf16Str(buff);
|
||||
if (!utf16Str.IsEmpty()) {
|
||||
rv = presShell->GoToAnchor(utf16Str,
|
||||
mChangeScrollPosWhenScrollingToRef);
|
||||
}
|
||||
}
|
||||
// 4. If potentialIndicatedElement is not null, then return
|
||||
// potentialIndicatedElement.
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mScrolledToRefAlready = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// If UTF-8 URI failed then try to assume the string as a
|
||||
// document's charset.
|
||||
if (NS_FAILED(rv)) {
|
||||
const Encoding* encoding = GetDocumentCharacterSet();
|
||||
rv = encoding->DecodeWithoutBOMHandling(unescaped ? buff : mScrollToRef,
|
||||
ref);
|
||||
if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
|
||||
rv = presShell->GoToAnchor(ref, mChangeScrollPosWhenScrollingToRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mScrolledToRefAlready = true;
|
||||
}
|
||||
// 5. Let fragmentBytes be the result of percent-decoding fragment.
|
||||
nsAutoCString fragmentBytes;
|
||||
const bool unescaped =
|
||||
NS_UnescapeURL(mScrollToRef.Data(), mScrollToRef.Length(),
|
||||
/* aFlags = */ 0, fragmentBytes);
|
||||
|
||||
if (!unescaped || fragmentBytes.IsEmpty()) {
|
||||
// Another attempt is only necessary if characters were unescaped.
|
||||
return;
|
||||
}
|
||||
|
||||
// 6. Let decodedFragment be the result of running UTF-8 decode without BOM on
|
||||
// fragmentBytes.
|
||||
nsAutoString decodedFragment;
|
||||
rv = UTF_8_ENCODING->DecodeWithoutBOMHandling(fragmentBytes, decodedFragment);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
// 7. Set potentialIndicatedElement to the result of finding a potential
|
||||
// indicated element given document and decodedFragment.
|
||||
rv = presShell->GoToAnchor(decodedFragment,
|
||||
mChangeScrollPosWhenScrollingToRef);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mScrolledToRefAlready = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -416,18 +416,9 @@ void nsHtml5TreeOperation::SetHTMLElementAttributes(
|
|||
nsAtom* localName = aAttributes->getLocalNameNoBoundsCheck(i);
|
||||
nsAtom* prefix = aAttributes->getPrefixNoBoundsCheck(i);
|
||||
int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
|
||||
|
||||
nsString value; // Not Auto, because using it to hold nsStringBuffer*
|
||||
val.ToString(value);
|
||||
if (nsGkAtoms::a == aName && nsGkAtoms::name == localName) {
|
||||
// This is an HTML5-incompliant Geckoism.
|
||||
// Remove when fixing bug 582361
|
||||
NS_ConvertUTF16toUTF8 cname(value);
|
||||
NS_ConvertUTF8toUTF16 uv(nsUnescape(cname.BeginWriting()));
|
||||
aElement->SetAttr(nsuri, localName, prefix, uv, false);
|
||||
} else {
|
||||
aElement->SetAttr(nsuri, localName, prefix, value, false);
|
||||
}
|
||||
aElement->SetAttr(nsuri, localName, prefix, value, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
[fragment-and-encoding-2.html]
|
||||
max-asserts: 4
|
||||
expected:
|
||||
if (os == "android") and fission: [OK, TIMEOUT]
|
|
@ -1,6 +0,0 @@
|
|||
[fragment-and-encoding.html]
|
||||
max-asserts: 5
|
||||
expected:
|
||||
if (os == "android") and fission: [OK, TIMEOUT]
|
||||
[%FF should not find U+00FF as decoding it gives U+FFFD]
|
||||
expected: FAIL
|
|
@ -1,5 +0,0 @@
|
|||
[scroll-frag-non-utf8-encoded-document.html]
|
||||
expected:
|
||||
if (os == "android") and fission: [OK, TIMEOUT]
|
||||
[Fragment Navigation: fragment id should not be found in non UTF8 document]
|
||||
expected: FAIL
|
|
@ -1,6 +1,4 @@
|
|||
[scroll-frag-percent-encoded.html]
|
||||
expected:
|
||||
if (os == "android") and fission: [OK, TIMEOUT]
|
||||
[Fragment Navigation: fragment id should be percent-decoded]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
|
Загрузка…
Ссылка в новой задаче