/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/SVGTests.h" #include "DOMSVGStringList.h" #include "nsSVGFeatures.h" #include "mozilla/dom/SVGSwitchElement.h" #include "nsCharSeparatedTokenizer.h" #include "nsStyleUtil.h" #include "mozilla/Preferences.h" namespace mozilla { namespace dom { nsStaticAtom* const SVGTests::sStringListNames[3] = { nsGkAtoms::requiredFeatures, nsGkAtoms::requiredExtensions, nsGkAtoms::systemLanguage, }; SVGTests::SVGTests() { mStringListAttributes[LANGUAGE].SetIsCommaSeparated(true); } already_AddRefed SVGTests::RequiredFeatures() { return DOMSVGStringList::GetDOMWrapper(&mStringListAttributes[FEATURES], AsSVGElement(), true, FEATURES); } already_AddRefed SVGTests::RequiredExtensions() { return DOMSVGStringList::GetDOMWrapper(&mStringListAttributes[EXTENSIONS], AsSVGElement(), true, EXTENSIONS); } already_AddRefed SVGTests::SystemLanguage() { return DOMSVGStringList::GetDOMWrapper(&mStringListAttributes[LANGUAGE], AsSVGElement(), true, LANGUAGE); } bool SVGTests::HasExtension(const nsAString& aExtension) { return nsSVGFeatures::HasExtension(aExtension, AsSVGElement()->IsInChromeDocument()); } bool SVGTests::IsConditionalProcessingAttribute( const nsAtom* aAttribute) const { for (uint32_t i = 0; i < ArrayLength(sStringListNames); i++) { if (aAttribute == sStringListNames[i]) { return true; } } return false; } int32_t SVGTests::GetBestLanguagePreferenceRank( const nsAString& aAcceptLangs) const { const nsCaseInsensitiveStringComparator caseInsensitiveComparator; if (!mStringListAttributes[LANGUAGE].IsExplicitlySet()) { return -2; } int32_t lowestRank = -1; for (uint32_t i = 0; i < mStringListAttributes[LANGUAGE].Length(); i++) { nsCharSeparatedTokenizer languageTokenizer(aAcceptLangs, ','); int32_t index = 0; while (languageTokenizer.hasMoreTokens()) { const nsAString& languageToken = languageTokenizer.nextToken(); bool exactMatch = languageToken.Equals(mStringListAttributes[LANGUAGE][i], caseInsensitiveComparator); bool prefixOnlyMatch = !exactMatch && nsStyleUtil::DashMatchCompare(mStringListAttributes[LANGUAGE][i], languageTokenizer.nextToken(), caseInsensitiveComparator); if (index == 0 && exactMatch) { // best possible match return 0; } if ((exactMatch || prefixOnlyMatch) && (lowestRank == -1 || 2 * index + prefixOnlyMatch < lowestRank)) { lowestRank = 2 * index + prefixOnlyMatch; } ++index; } } return lowestRank; } const nsString* const SVGTests::kIgnoreSystemLanguage = (nsString*)0x01; bool SVGTests::PassesConditionalProcessingTests( const nsString* aAcceptLangs) const { // Required Extensions // // The requiredExtensions attribute defines a list of required language // extensions. Language extensions are capabilities within a user agent that // 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()) { return false; } for (uint32_t i = 0; i < mStringListAttributes[EXTENSIONS].Length(); i++) { if (!nsSVGFeatures::HasExtension(mStringListAttributes[EXTENSIONS][i], AsSVGElement()->IsInChromeDocument())) { return false; } } } if (aAcceptLangs == kIgnoreSystemLanguage) { return true; } // 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()) { return false; } // Get our language preferences nsAutoString acceptLangs; if (aAcceptLangs) { acceptLangs.Assign(*aAcceptLangs); } else { Preferences::GetLocalizedString("intl.accept_languages", acceptLangs); } if (acceptLangs.IsEmpty()) { NS_WARNING( "no default language specified for systemLanguage conditional test"); return false; } const nsCaseInsensitiveStringComparator caseInsensitiveComparator; for (uint32_t i = 0; i < mStringListAttributes[LANGUAGE].Length(); i++) { nsCharSeparatedTokenizer languageTokenizer(acceptLangs, ','); while (languageTokenizer.hasMoreTokens()) { if (nsStyleUtil::DashMatchCompare(mStringListAttributes[LANGUAGE][i], languageTokenizer.nextToken(), caseInsensitiveComparator)) { return true; } } } return false; } return true; } bool SVGTests::ParseConditionalProcessingAttribute(nsAtom* aAttribute, const nsAString& aValue, nsAttrValue& aResult) { for (uint32_t i = 0; i < ArrayLength(sStringListNames); i++) { if (aAttribute == sStringListNames[i]) { nsresult rv = mStringListAttributes[i].SetValue(aValue); if (NS_FAILED(rv)) { mStringListAttributes[i].Clear(); } MaybeInvalidate(); return true; } } return false; } void SVGTests::UnsetAttr(const nsAtom* aAttribute) { for (uint32_t i = 0; i < ArrayLength(sStringListNames); i++) { if (aAttribute == sStringListNames[i]) { mStringListAttributes[i].Clear(); MaybeInvalidate(); return; } } } nsStaticAtom* SVGTests::GetAttrName(uint8_t aAttrEnum) const { return sStringListNames[aAttrEnum]; } void SVGTests::GetAttrValue(uint8_t aAttrEnum, nsAttrValue& aValue) const { MOZ_ASSERT(aAttrEnum < ArrayLength(sStringListNames), "aAttrEnum out of range"); aValue.SetTo(mStringListAttributes[aAttrEnum], nullptr); } void SVGTests::MaybeInvalidate() { nsIContent* parent = AsSVGElement()->GetFlattenedTreeParent(); if (parent && parent->NodeInfo()->Equals(nsGkAtoms::svgSwitch, kNameSpaceID_SVG)) { static_cast(parent)->MaybeInvalidate(); } } } // namespace dom } // namespace mozilla