SVGTests.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "mozilla/dom/SVGTests.h"
  6. #include "DOMSVGStringList.h"
  7. #include "nsSVGFeatures.h"
  8. #include "mozilla/dom/SVGSwitchElement.h"
  9. #include "nsCharSeparatedTokenizer.h"
  10. #include "nsStyleUtil.h"
  11. #include "mozilla/Preferences.h"
  12. #include "nsIContentInlines.h"
  13. namespace mozilla {
  14. namespace dom {
  15. nsIAtom** SVGTests::sStringListNames[3] =
  16. {
  17. &nsGkAtoms::requiredFeatures,
  18. &nsGkAtoms::requiredExtensions,
  19. &nsGkAtoms::systemLanguage,
  20. };
  21. SVGTests::SVGTests()
  22. {
  23. mStringListAttributes[LANGUAGE].SetIsCommaSeparated(true);
  24. }
  25. already_AddRefed<DOMSVGStringList>
  26. SVGTests::RequiredFeatures()
  27. {
  28. nsCOMPtr<nsIDOMSVGElement> elem = do_QueryInterface(this);
  29. nsSVGElement* element = static_cast<nsSVGElement*>(elem.get());
  30. return DOMSVGStringList::GetDOMWrapper(
  31. &mStringListAttributes[FEATURES], element, true, FEATURES);
  32. }
  33. already_AddRefed<DOMSVGStringList>
  34. SVGTests::RequiredExtensions()
  35. {
  36. nsCOMPtr<nsIDOMSVGElement> elem = do_QueryInterface(this);
  37. nsSVGElement* element = static_cast<nsSVGElement*>(elem.get());
  38. return DOMSVGStringList::GetDOMWrapper(
  39. &mStringListAttributes[EXTENSIONS], element, true, EXTENSIONS);
  40. }
  41. already_AddRefed<DOMSVGStringList>
  42. SVGTests::SystemLanguage()
  43. {
  44. nsCOMPtr<nsIDOMSVGElement> elem = do_QueryInterface(this);
  45. nsSVGElement* element = static_cast<nsSVGElement*>(elem.get());
  46. return DOMSVGStringList::GetDOMWrapper(
  47. &mStringListAttributes[LANGUAGE], element, true, LANGUAGE);
  48. }
  49. bool
  50. SVGTests::HasExtension(const nsAString& aExtension)
  51. {
  52. return nsSVGFeatures::HasExtension(aExtension, IsInChromeDoc());
  53. }
  54. bool
  55. SVGTests::IsConditionalProcessingAttribute(const nsIAtom* aAttribute) const
  56. {
  57. for (uint32_t i = 0; i < ArrayLength(sStringListNames); i++) {
  58. if (aAttribute == *sStringListNames[i]) {
  59. return true;
  60. }
  61. }
  62. return false;
  63. }
  64. int32_t
  65. SVGTests::GetBestLanguagePreferenceRank(const nsSubstring& aAcceptLangs) const
  66. {
  67. const nsDefaultStringComparator defaultComparator;
  68. if (!mStringListAttributes[LANGUAGE].IsExplicitlySet()) {
  69. return -2;
  70. }
  71. int32_t lowestRank = -1;
  72. for (uint32_t i = 0; i < mStringListAttributes[LANGUAGE].Length(); i++) {
  73. nsCharSeparatedTokenizer languageTokenizer(aAcceptLangs, ',');
  74. int32_t index = 0;
  75. while (languageTokenizer.hasMoreTokens()) {
  76. const nsSubstring &languageToken = languageTokenizer.nextToken();
  77. bool exactMatch = (languageToken == mStringListAttributes[LANGUAGE][i]);
  78. bool prefixOnlyMatch =
  79. !exactMatch &&
  80. nsStyleUtil::DashMatchCompare(mStringListAttributes[LANGUAGE][i],
  81. languageTokenizer.nextToken(),
  82. defaultComparator);
  83. if (index == 0 && exactMatch) {
  84. // best possible match
  85. return 0;
  86. }
  87. if ((exactMatch || prefixOnlyMatch) &&
  88. (lowestRank == -1 || 2 * index + prefixOnlyMatch < lowestRank)) {
  89. lowestRank = 2 * index + prefixOnlyMatch;
  90. }
  91. ++index;
  92. }
  93. }
  94. return lowestRank;
  95. }
  96. const nsString * const SVGTests::kIgnoreSystemLanguage = (nsString *) 0x01;
  97. bool
  98. SVGTests::PassesConditionalProcessingTests(const nsString *aAcceptLangs) const
  99. {
  100. // Required Extensions
  101. //
  102. // The requiredExtensions attribute defines a list of required language
  103. // extensions. Language extensions are capabilities within a user agent that
  104. // go beyond the feature set defined in the SVG specification.
  105. // Each extension is identified by a URI reference.
  106. // For now, claim that mozilla's SVG implementation supports XHTML and MathML.
  107. if (mStringListAttributes[EXTENSIONS].IsExplicitlySet()) {
  108. if (mStringListAttributes[EXTENSIONS].IsEmpty()) {
  109. return false;
  110. }
  111. for (uint32_t i = 0; i < mStringListAttributes[EXTENSIONS].Length(); i++) {
  112. if (!nsSVGFeatures::HasExtension(mStringListAttributes[EXTENSIONS][i], IsInChromeDoc())) {
  113. return false;
  114. }
  115. }
  116. }
  117. if (aAcceptLangs == kIgnoreSystemLanguage) {
  118. return true;
  119. }
  120. // systemLanguage
  121. //
  122. // Evaluates to "true" if one of the languages indicated by user preferences
  123. // exactly equals one of the languages given in the value of this parameter,
  124. // or if one of the languages indicated by user preferences exactly equals a
  125. // prefix of one of the languages given in the value of this parameter such
  126. // that the first tag character following the prefix is "-".
  127. if (mStringListAttributes[LANGUAGE].IsExplicitlySet()) {
  128. if (mStringListAttributes[LANGUAGE].IsEmpty()) {
  129. return false;
  130. }
  131. // Get our language preferences
  132. const nsAutoString acceptLangs(aAcceptLangs ? *aAcceptLangs :
  133. Preferences::GetLocalizedString("intl.accept_languages"));
  134. if (acceptLangs.IsEmpty()) {
  135. NS_WARNING("no default language specified for systemLanguage conditional test");
  136. return false;
  137. }
  138. const nsDefaultStringComparator defaultComparator;
  139. for (uint32_t i = 0; i < mStringListAttributes[LANGUAGE].Length(); i++) {
  140. nsCharSeparatedTokenizer languageTokenizer(acceptLangs, ',');
  141. while (languageTokenizer.hasMoreTokens()) {
  142. if (nsStyleUtil::DashMatchCompare(mStringListAttributes[LANGUAGE][i],
  143. languageTokenizer.nextToken(),
  144. defaultComparator)) {
  145. return true;
  146. }
  147. }
  148. }
  149. return false;
  150. }
  151. return true;
  152. }
  153. bool
  154. SVGTests::ParseConditionalProcessingAttribute(nsIAtom* aAttribute,
  155. const nsAString& aValue,
  156. nsAttrValue& aResult)
  157. {
  158. for (uint32_t i = 0; i < ArrayLength(sStringListNames); i++) {
  159. if (aAttribute == *sStringListNames[i]) {
  160. nsresult rv = mStringListAttributes[i].SetValue(aValue);
  161. if (NS_FAILED(rv)) {
  162. mStringListAttributes[i].Clear();
  163. }
  164. MaybeInvalidate();
  165. return true;
  166. }
  167. }
  168. return false;
  169. }
  170. void
  171. SVGTests::UnsetAttr(const nsIAtom* aAttribute)
  172. {
  173. for (uint32_t i = 0; i < ArrayLength(sStringListNames); i++) {
  174. if (aAttribute == *sStringListNames[i]) {
  175. mStringListAttributes[i].Clear();
  176. MaybeInvalidate();
  177. return;
  178. }
  179. }
  180. }
  181. nsIAtom*
  182. SVGTests::GetAttrName(uint8_t aAttrEnum) const
  183. {
  184. return *sStringListNames[aAttrEnum];
  185. }
  186. void
  187. SVGTests::GetAttrValue(uint8_t aAttrEnum, nsAttrValue& aValue) const
  188. {
  189. MOZ_ASSERT(aAttrEnum < ArrayLength(sStringListNames),
  190. "aAttrEnum out of range");
  191. aValue.SetTo(mStringListAttributes[aAttrEnum], nullptr);
  192. }
  193. void
  194. SVGTests::MaybeInvalidate()
  195. {
  196. nsCOMPtr<nsIDOMSVGElement> elem = do_QueryInterface(this);
  197. nsSVGElement* element = static_cast<nsSVGElement*>(elem.get());
  198. nsIContent* parent = element->GetFlattenedTreeParent();
  199. if (parent &&
  200. parent->NodeInfo()->Equals(nsGkAtoms::svgSwitch, kNameSpaceID_SVG)) {
  201. static_cast<dom::SVGSwitchElement*>(parent)->MaybeInvalidate();
  202. }
  203. }
  204. } // namespace dom
  205. } // namespace mozilla