summaryrefslogtreecommitdiffstats
path: root/dom/svg/SVGTests.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/svg/SVGTests.cpp')
-rw-r--r--dom/svg/SVGTests.cpp158
1 files changed, 100 insertions, 58 deletions
diff --git a/dom/svg/SVGTests.cpp b/dom/svg/SVGTests.cpp
index 6603663445..058065618e 100644
--- a/dom/svg/SVGTests.cpp
+++ b/dom/svg/SVGTests.cpp
@@ -5,12 +5,13 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/SVGTests.h"
+
#include "DOMSVGStringList.h"
+#include "nsCharSeparatedTokenizer.h"
#include "nsIContent.h"
#include "nsIContentInlines.h"
#include "mozilla/dom/SVGSwitchElement.h"
-#include "nsCharSeparatedTokenizer.h"
-#include "nsStyleUtil.h"
+#include "mozilla/intl/oxilangtag_ffi_generated.h"
#include "mozilla/Preferences.h"
namespace mozilla::dom {
@@ -58,39 +59,84 @@ bool SVGTests::IsConditionalProcessingAttribute(
return false;
}
-int32_t SVGTests::GetBestLanguagePreferenceRank(
- const nsAString& aAcceptLangs) const {
- if (!mStringListAttributes[LANGUAGE].IsExplicitlySet()) {
- return -2;
+// Find the best match from aAvailLangs for the users accept-languages,
+// returning the index in the aAvailLangs list, or -1 if no match.
+int32_t FindBestLanguage(const nsTArray<nsCString>& aAvailLangs) {
+ AutoTArray<nsCString, 16> reqLangs;
+ nsCString acceptLangs;
+ Preferences::GetLocalizedCString("intl.accept_languages", acceptLangs);
+ nsCCharSeparatedTokenizer languageTokenizer(acceptLangs, ',');
+ while (languageTokenizer.hasMoreTokens()) {
+ reqLangs.AppendElement(languageTokenizer.nextToken());
}
- int32_t lowestRank = -1;
-
- for (uint32_t i = 0; i < mStringListAttributes[LANGUAGE].Length(); i++) {
- int32_t index = 0;
- for (const nsAString& languageToken :
- nsCharSeparatedTokenizer(aAcceptLangs, ',').ToRange()) {
- bool exactMatch = languageToken.Equals(mStringListAttributes[LANGUAGE][i],
- nsCaseInsensitiveStringComparator);
- bool prefixOnlyMatch =
- !exactMatch && nsStyleUtil::DashMatchCompare(
- mStringListAttributes[LANGUAGE][i], languageToken,
- nsCaseInsensitiveStringComparator);
- if (index == 0 && exactMatch) {
- // best possible match
- return 0;
+ for (const auto& req : reqLangs) {
+ for (const auto& avail : aAvailLangs) {
+ if (avail.Length() > req.Length()) {
+ // Ensure that en does not match en-us, i.e. you need to have en in
+ // intl.accept_languages to match en in markup.
+ continue;
}
- if ((exactMatch || prefixOnlyMatch) &&
- (lowestRank == -1 || 2 * index + prefixOnlyMatch < lowestRank)) {
- lowestRank = 2 * index + prefixOnlyMatch;
+ using namespace intl::ffi;
+ struct LangTagDelete {
+ void operator()(LangTag* aLangTag) const { lang_tag_destroy(aLangTag); }
+ };
+ UniquePtr<LangTag, LangTagDelete> langTag(lang_tag_new(&avail));
+ if (langTag && lang_tag_matches(langTag.get(), &req)) {
+ return &avail - &aAvailLangs[0];
}
- ++index;
}
}
- return lowestRank;
+ return -1;
}
-bool SVGTests::PassesConditionalProcessingTestsIgnoringSystemLanguage() const {
+nsIContent* SVGTests::FindActiveSwitchChild(
+ const dom::SVGSwitchElement* aSwitch) {
+ AutoTArray<nsCString, 16> availLocales;
+ AutoTArray<nsIContent*, 16> children;
+ nsIContent* defaultChild = nullptr;
+ for (auto* child = aSwitch->GetFirstChild(); child;
+ child = child->GetNextSibling()) {
+ if (!child->IsElement()) {
+ continue;
+ }
+ nsCOMPtr<SVGTests> tests(do_QueryInterface(child));
+ if (tests) {
+ if (!tests->mPassesConditionalProcessingTests.valueOr(true) ||
+ !tests->PassesRequiredExtensionsTests()) {
+ continue;
+ }
+ const auto& languages = tests->mStringListAttributes[LANGUAGE];
+ if (!languages.IsExplicitlySet()) {
+ if (!defaultChild) {
+ defaultChild = child;
+ }
+ continue;
+ }
+ for (uint32_t i = 0; i < languages.Length(); i++) {
+ children.AppendElement(child);
+ availLocales.AppendElement(NS_ConvertUTF16toUTF8(languages[i]));
+ }
+ }
+ }
+
+ // For each entry in availLocales, we expect to have a corresponding entry
+ // in children that provides the child node associated with that locale.
+ MOZ_ASSERT(children.Length() == availLocales.Length());
+
+ if (availLocales.IsEmpty()) {
+ return defaultChild;
+ }
+
+ int32_t index = FindBestLanguage(availLocales);
+ if (index >= 0) {
+ return children[index];
+ }
+
+ return defaultChild;
+}
+
+bool SVGTests::PassesRequiredExtensionsTests() const {
// Required Extensions
//
// The requiredExtensions attribute defines a list of required language
@@ -98,12 +144,15 @@ bool SVGTests::PassesConditionalProcessingTestsIgnoringSystemLanguage() const {
// go beyond the feature set defined in the SVG specification.
// Each extension is identified by a URI reference.
// For now, claim that mozilla's SVG implementation supports XHTML and MathML.
- if (mStringListAttributes[EXTENSIONS].IsExplicitlySet()) {
- if (mStringListAttributes[EXTENSIONS].IsEmpty()) {
+ const auto& extensions = mStringListAttributes[EXTENSIONS];
+ if (extensions.IsExplicitlySet()) {
+ if (extensions.IsEmpty()) {
+ mPassesConditionalProcessingTests = Some(false);
return false;
}
- for (uint32_t i = 0; i < mStringListAttributes[EXTENSIONS].Length(); i++) {
- if (!HasExtension(mStringListAttributes[EXTENSIONS][i])) {
+ for (uint32_t i = 0; i < extensions.Length(); i++) {
+ if (!HasExtension(extensions[i])) {
+ mPassesConditionalProcessingTests = Some(false);
return false;
}
}
@@ -112,45 +161,36 @@ bool SVGTests::PassesConditionalProcessingTestsIgnoringSystemLanguage() const {
}
bool SVGTests::PassesConditionalProcessingTests() const {
- if (!PassesConditionalProcessingTestsIgnoringSystemLanguage()) {
+ if (mPassesConditionalProcessingTests) {
+ return mPassesConditionalProcessingTests.value();
+ }
+ if (!PassesRequiredExtensionsTests()) {
return false;
}
// systemLanguage
//
- // Evaluates to "true" if one of the languages indicated by user preferences
- // exactly equals one of the languages given in the value of this parameter,
- // or if one of the languages indicated by user preferences exactly equals a
- // prefix of one of the languages given in the value of this parameter such
- // that the first tag character following the prefix is "-".
- if (mStringListAttributes[LANGUAGE].IsExplicitlySet()) {
- if (mStringListAttributes[LANGUAGE].IsEmpty()) {
+ // Evaluates to true if there's a BCP 47 match for the one of the user
+ // preference languages with one of the languages given in the value of
+ // this parameter.
+ const auto& languages = mStringListAttributes[LANGUAGE];
+ if (languages.IsExplicitlySet()) {
+ if (languages.IsEmpty()) {
+ mPassesConditionalProcessingTests = Some(false);
return false;
}
- // Get our language preferences
- nsAutoString acceptLangs;
- Preferences::GetLocalizedString("intl.accept_languages", acceptLangs);
-
- if (acceptLangs.IsEmpty()) {
- NS_WARNING(
- "no default language specified for systemLanguage conditional test");
- return false;
+ AutoTArray<nsCString, 4> availLocales;
+ for (uint32_t i = 0; i < languages.Length(); i++) {
+ availLocales.AppendElement(NS_ConvertUTF16toUTF8(languages[i]));
}
- for (uint32_t i = 0; i < mStringListAttributes[LANGUAGE].Length(); i++) {
- nsCharSeparatedTokenizer languageTokenizer(acceptLangs, ',');
- while (languageTokenizer.hasMoreTokens()) {
- if (nsStyleUtil::DashMatchCompare(mStringListAttributes[LANGUAGE][i],
- languageTokenizer.nextToken(),
- nsCaseInsensitiveStringComparator)) {
- return true;
- }
- }
- }
- return false;
+ mPassesConditionalProcessingTests =
+ Some(FindBestLanguage(availLocales) >= 0);
+ return mPassesConditionalProcessingTests.value();
}
+ mPassesConditionalProcessingTests = Some(true);
return true;
}
@@ -163,6 +203,7 @@ bool SVGTests::ParseConditionalProcessingAttribute(nsAtom* aAttribute,
if (NS_FAILED(rv)) {
mStringListAttributes[i].Clear();
}
+ mPassesConditionalProcessingTests = Nothing();
MaybeInvalidate();
return true;
}
@@ -174,6 +215,7 @@ void SVGTests::UnsetAttr(const nsAtom* aAttribute) {
for (uint32_t i = 0; i < ArrayLength(sStringListNames); i++) {
if (aAttribute == sStringListNames[i]) {
mStringListAttributes[i].Clear();
+ mPassesConditionalProcessingTests = Nothing();
MaybeInvalidate();
return;
}