nsStyleUtil.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  1. /* -*- Mode: C++; tab-width: 2; 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 "nsStyleUtil.h"
  6. #include "nsStyleConsts.h"
  7. #include "nsIContent.h"
  8. #include "nsCSSProps.h"
  9. #include "nsContentUtils.h"
  10. #include "nsRuleNode.h"
  11. #include "nsROCSSPrimitiveValue.h"
  12. #include "nsStyleStruct.h"
  13. #include "nsIContentPolicy.h"
  14. #include "nsIContentSecurityPolicy.h"
  15. #include "nsIURI.h"
  16. #include "nsPrintfCString.h"
  17. using namespace mozilla;
  18. //------------------------------------------------------------------------------
  19. // Font Algorithm Code
  20. //------------------------------------------------------------------------------
  21. // Compare two language strings
  22. bool nsStyleUtil::DashMatchCompare(const nsAString& aAttributeValue,
  23. const nsAString& aSelectorValue,
  24. const nsStringComparator& aComparator)
  25. {
  26. bool result;
  27. uint32_t selectorLen = aSelectorValue.Length();
  28. uint32_t attributeLen = aAttributeValue.Length();
  29. if (selectorLen > attributeLen) {
  30. result = false;
  31. }
  32. else {
  33. nsAString::const_iterator iter;
  34. if (selectorLen != attributeLen &&
  35. *aAttributeValue.BeginReading(iter).advance(selectorLen) !=
  36. char16_t('-')) {
  37. // to match, the aAttributeValue must have a dash after the end of
  38. // the aSelectorValue's text (unless the aSelectorValue and the
  39. // aAttributeValue have the same text)
  40. result = false;
  41. }
  42. else {
  43. result = StringBeginsWith(aAttributeValue, aSelectorValue, aComparator);
  44. }
  45. }
  46. return result;
  47. }
  48. bool
  49. nsStyleUtil::ValueIncludes(const nsSubstring& aValueList,
  50. const nsSubstring& aValue,
  51. const nsStringComparator& aComparator)
  52. {
  53. const char16_t *p = aValueList.BeginReading(),
  54. *p_end = aValueList.EndReading();
  55. while (p < p_end) {
  56. // skip leading space
  57. while (p != p_end && nsContentUtils::IsHTMLWhitespace(*p))
  58. ++p;
  59. const char16_t *val_start = p;
  60. // look for space or end
  61. while (p != p_end && !nsContentUtils::IsHTMLWhitespace(*p))
  62. ++p;
  63. const char16_t *val_end = p;
  64. if (val_start < val_end &&
  65. aValue.Equals(Substring(val_start, val_end), aComparator))
  66. return true;
  67. ++p; // we know the next character is not whitespace
  68. }
  69. return false;
  70. }
  71. void nsStyleUtil::AppendEscapedCSSString(const nsAString& aString,
  72. nsAString& aReturn,
  73. char16_t quoteChar)
  74. {
  75. NS_PRECONDITION(quoteChar == '\'' || quoteChar == '"',
  76. "CSS strings must be quoted with ' or \"");
  77. aReturn.Append(quoteChar);
  78. const char16_t* in = aString.BeginReading();
  79. const char16_t* const end = aString.EndReading();
  80. for (; in != end; in++) {
  81. if (*in < 0x20 || (*in >= 0x7F && *in < 0xA0)) {
  82. // Escape U+0000 through U+001F and U+007F through U+009F numerically.
  83. aReturn.AppendPrintf("\\%hx ", *in);
  84. } else {
  85. if (*in == '"' || *in == '\'' || *in == '\\') {
  86. // Escape backslash and quote characters symbolically.
  87. // It's not technically necessary to escape the quote
  88. // character that isn't being used to delimit the string,
  89. // but we do it anyway because that makes testing simpler.
  90. aReturn.Append(char16_t('\\'));
  91. }
  92. aReturn.Append(*in);
  93. }
  94. }
  95. aReturn.Append(quoteChar);
  96. }
  97. /* static */ void
  98. nsStyleUtil::AppendEscapedCSSIdent(const nsAString& aIdent, nsAString& aReturn)
  99. {
  100. // The relevant parts of the CSS grammar are:
  101. // ident ([-]?{nmstart}|[-][-]){nmchar}*
  102. // nmstart [_a-z]|{nonascii}|{escape}
  103. // nmchar [_a-z0-9-]|{nonascii}|{escape}
  104. // nonascii [^\0-\177]
  105. // escape {unicode}|\\[^\n\r\f0-9a-f]
  106. // unicode \\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?
  107. // from http://www.w3.org/TR/CSS21/syndata.html#tokenization but
  108. // modified for idents by
  109. // http://dev.w3.org/csswg/cssom/#serialize-an-identifier and
  110. // http://dev.w3.org/csswg/css-syntax/#would-start-an-identifier
  111. const char16_t* in = aIdent.BeginReading();
  112. const char16_t* const end = aIdent.EndReading();
  113. if (in == end)
  114. return;
  115. // A leading dash does not need to be escaped as long as it is not the
  116. // *only* character in the identifier.
  117. if (*in == '-') {
  118. if (in + 1 == end) {
  119. aReturn.Append(char16_t('\\'));
  120. aReturn.Append(char16_t('-'));
  121. return;
  122. }
  123. aReturn.Append(char16_t('-'));
  124. ++in;
  125. }
  126. // Escape a digit at the start (including after a dash),
  127. // numerically. If we didn't escape it numerically, it would get
  128. // interpreted as a numeric escape for the wrong character.
  129. if (in != end && ('0' <= *in && *in <= '9')) {
  130. aReturn.AppendPrintf("\\%hx ", *in);
  131. ++in;
  132. }
  133. for (; in != end; ++in) {
  134. char16_t ch = *in;
  135. if (ch == 0x00) {
  136. aReturn.Append(char16_t(0xFFFD));
  137. } else if (ch < 0x20 || (0x7F <= ch && ch < 0xA0)) {
  138. // Escape U+0000 through U+001F and U+007F through U+009F numerically.
  139. aReturn.AppendPrintf("\\%hx ", *in);
  140. } else {
  141. // Escape ASCII non-identifier printables as a backslash plus
  142. // the character.
  143. if (ch < 0x7F &&
  144. ch != '_' && ch != '-' &&
  145. (ch < '0' || '9' < ch) &&
  146. (ch < 'A' || 'Z' < ch) &&
  147. (ch < 'a' || 'z' < ch)) {
  148. aReturn.Append(char16_t('\\'));
  149. }
  150. aReturn.Append(ch);
  151. }
  152. }
  153. }
  154. // unquoted family names must be a sequence of idents
  155. // so escape any parts that require escaping
  156. static void
  157. AppendUnquotedFamilyName(const nsAString& aFamilyName, nsAString& aResult)
  158. {
  159. const char16_t *p, *p_end;
  160. aFamilyName.BeginReading(p);
  161. aFamilyName.EndReading(p_end);
  162. bool moreThanOne = false;
  163. while (p < p_end) {
  164. const char16_t* identStart = p;
  165. while (++p != p_end && *p != ' ')
  166. /* nothing */ ;
  167. nsDependentSubstring ident(identStart, p);
  168. if (!ident.IsEmpty()) {
  169. if (moreThanOne) {
  170. aResult.Append(' ');
  171. }
  172. nsStyleUtil::AppendEscapedCSSIdent(ident, aResult);
  173. moreThanOne = true;
  174. }
  175. ++p;
  176. }
  177. }
  178. /* static */ void
  179. nsStyleUtil::AppendEscapedCSSFontFamilyList(
  180. const mozilla::FontFamilyList& aFamilyList,
  181. nsAString& aResult)
  182. {
  183. const nsTArray<FontFamilyName>& fontlist = aFamilyList.GetFontlist();
  184. size_t i, len = fontlist.Length();
  185. for (i = 0; i < len; i++) {
  186. if (i != 0) {
  187. aResult.Append(',');
  188. }
  189. const FontFamilyName& name = fontlist[i];
  190. switch (name.mType) {
  191. case eFamily_named:
  192. AppendUnquotedFamilyName(name.mName, aResult);
  193. break;
  194. case eFamily_named_quoted:
  195. AppendEscapedCSSString(name.mName, aResult);
  196. break;
  197. default:
  198. name.AppendToString(aResult);
  199. }
  200. }
  201. }
  202. /* static */ void
  203. nsStyleUtil::AppendBitmaskCSSValue(nsCSSPropertyID aProperty,
  204. int32_t aMaskedValue,
  205. int32_t aFirstMask,
  206. int32_t aLastMask,
  207. nsAString& aResult)
  208. {
  209. for (int32_t mask = aFirstMask; mask <= aLastMask; mask <<= 1) {
  210. if (mask & aMaskedValue) {
  211. AppendASCIItoUTF16(nsCSSProps::LookupPropertyValue(aProperty, mask),
  212. aResult);
  213. aMaskedValue &= ~mask;
  214. if (aMaskedValue) { // more left
  215. aResult.Append(char16_t(' '));
  216. }
  217. }
  218. }
  219. MOZ_ASSERT(aMaskedValue == 0, "unexpected bit remaining in bitfield");
  220. }
  221. /* static */ void
  222. nsStyleUtil::AppendAngleValue(const nsStyleCoord& aAngle, nsAString& aResult)
  223. {
  224. MOZ_ASSERT(aAngle.IsAngleValue(), "Should have angle value");
  225. // Append number.
  226. AppendCSSNumber(aAngle.GetAngleValue(), aResult);
  227. // Append unit.
  228. switch (aAngle.GetUnit()) {
  229. case eStyleUnit_Degree: aResult.AppendLiteral("deg"); break;
  230. case eStyleUnit_Grad: aResult.AppendLiteral("grad"); break;
  231. case eStyleUnit_Radian: aResult.AppendLiteral("rad"); break;
  232. case eStyleUnit_Turn: aResult.AppendLiteral("turn"); break;
  233. default: NS_NOTREACHED("unrecognized angle unit");
  234. }
  235. }
  236. /* static */ void
  237. nsStyleUtil::AppendPaintOrderValue(uint8_t aValue,
  238. nsAString& aResult)
  239. {
  240. static_assert
  241. (NS_STYLE_PAINT_ORDER_BITWIDTH * NS_STYLE_PAINT_ORDER_LAST_VALUE <= 8,
  242. "SVGStyleStruct::mPaintOrder and local variables not big enough");
  243. if (aValue == NS_STYLE_PAINT_ORDER_NORMAL) {
  244. aResult.AppendLiteral("normal");
  245. return;
  246. }
  247. // Append the minimal value necessary for the given paint order.
  248. static_assert(NS_STYLE_PAINT_ORDER_LAST_VALUE == 3,
  249. "paint-order values added; check serialization");
  250. // The following relies on the default order being the order of the
  251. // constant values.
  252. const uint8_t MASK = (1 << NS_STYLE_PAINT_ORDER_BITWIDTH) - 1;
  253. uint32_t lastPositionToSerialize = 0;
  254. for (uint32_t position = NS_STYLE_PAINT_ORDER_LAST_VALUE - 1;
  255. position > 0;
  256. position--) {
  257. uint8_t component =
  258. (aValue >> (position * NS_STYLE_PAINT_ORDER_BITWIDTH)) & MASK;
  259. uint8_t earlierComponent =
  260. (aValue >> ((position - 1) * NS_STYLE_PAINT_ORDER_BITWIDTH)) & MASK;
  261. if (component < earlierComponent) {
  262. lastPositionToSerialize = position - 1;
  263. break;
  264. }
  265. }
  266. for (uint32_t position = 0; position <= lastPositionToSerialize; position++) {
  267. if (position > 0) {
  268. aResult.Append(' ');
  269. }
  270. uint8_t component = aValue & MASK;
  271. switch (component) {
  272. case NS_STYLE_PAINT_ORDER_FILL:
  273. aResult.AppendLiteral("fill");
  274. break;
  275. case NS_STYLE_PAINT_ORDER_STROKE:
  276. aResult.AppendLiteral("stroke");
  277. break;
  278. case NS_STYLE_PAINT_ORDER_MARKERS:
  279. aResult.AppendLiteral("markers");
  280. break;
  281. default:
  282. NS_NOTREACHED("unexpected paint-order component value");
  283. }
  284. aValue >>= NS_STYLE_PAINT_ORDER_BITWIDTH;
  285. }
  286. }
  287. /* static */ void
  288. nsStyleUtil::AppendFontFeatureSettings(const nsTArray<gfxFontFeature>& aFeatures,
  289. nsAString& aResult)
  290. {
  291. for (uint32_t i = 0, numFeat = aFeatures.Length(); i < numFeat; i++) {
  292. const gfxFontFeature& feat = aFeatures[i];
  293. if (i != 0) {
  294. aResult.AppendLiteral(", ");
  295. }
  296. // output tag
  297. char tag[7];
  298. tag[0] = '"';
  299. tag[1] = (feat.mTag >> 24) & 0xff;
  300. tag[2] = (feat.mTag >> 16) & 0xff;
  301. tag[3] = (feat.mTag >> 8) & 0xff;
  302. tag[4] = feat.mTag & 0xff;
  303. tag[5] = '"';
  304. tag[6] = 0;
  305. aResult.AppendASCII(tag);
  306. // output value, if necessary
  307. if (feat.mValue == 0) {
  308. // 0 ==> off
  309. aResult.AppendLiteral(" off");
  310. } else if (feat.mValue > 1) {
  311. aResult.Append(' ');
  312. aResult.AppendInt(feat.mValue);
  313. }
  314. // else, omit value if 1, implied by default
  315. }
  316. }
  317. /* static */ void
  318. nsStyleUtil::AppendFontFeatureSettings(const nsCSSValue& aSrc,
  319. nsAString& aResult)
  320. {
  321. nsCSSUnit unit = aSrc.GetUnit();
  322. if (unit == eCSSUnit_Normal) {
  323. aResult.AppendLiteral("normal");
  324. return;
  325. }
  326. NS_PRECONDITION(unit == eCSSUnit_PairList || unit == eCSSUnit_PairListDep,
  327. "improper value unit for font-feature-settings:");
  328. nsTArray<gfxFontFeature> featureSettings;
  329. nsRuleNode::ComputeFontFeatures(aSrc.GetPairListValue(), featureSettings);
  330. AppendFontFeatureSettings(featureSettings, aResult);
  331. }
  332. /* static */ void
  333. nsStyleUtil::GetFunctionalAlternatesName(int32_t aFeature,
  334. nsAString& aFeatureName)
  335. {
  336. aFeatureName.Truncate();
  337. nsCSSKeyword key =
  338. nsCSSProps::ValueToKeywordEnum(aFeature,
  339. nsCSSProps::kFontVariantAlternatesFuncsKTable);
  340. NS_ASSERTION(key != eCSSKeyword_UNKNOWN, "bad alternate feature type");
  341. AppendUTF8toUTF16(nsCSSKeywords::GetStringValue(key), aFeatureName);
  342. }
  343. /* static */ void
  344. nsStyleUtil::SerializeFunctionalAlternates(
  345. const nsTArray<gfxAlternateValue>& aAlternates,
  346. nsAString& aResult)
  347. {
  348. nsAutoString funcName, funcParams;
  349. uint32_t numValues = aAlternates.Length();
  350. uint32_t feature = 0;
  351. for (uint32_t i = 0; i < numValues; i++) {
  352. const gfxAlternateValue& v = aAlternates.ElementAt(i);
  353. if (feature != v.alternate) {
  354. feature = v.alternate;
  355. if (!funcName.IsEmpty() && !funcParams.IsEmpty()) {
  356. if (!aResult.IsEmpty()) {
  357. aResult.Append(char16_t(' '));
  358. }
  359. // append the previous functional value
  360. aResult.Append(funcName);
  361. aResult.Append(char16_t('('));
  362. aResult.Append(funcParams);
  363. aResult.Append(char16_t(')'));
  364. }
  365. // function name
  366. GetFunctionalAlternatesName(v.alternate, funcName);
  367. NS_ASSERTION(!funcName.IsEmpty(), "unknown property value name");
  368. // function params
  369. funcParams.Truncate();
  370. AppendEscapedCSSIdent(v.value, funcParams);
  371. } else {
  372. if (!funcParams.IsEmpty()) {
  373. funcParams.AppendLiteral(", ");
  374. }
  375. AppendEscapedCSSIdent(v.value, funcParams);
  376. }
  377. }
  378. // append the previous functional value
  379. if (!funcName.IsEmpty() && !funcParams.IsEmpty()) {
  380. if (!aResult.IsEmpty()) {
  381. aResult.Append(char16_t(' '));
  382. }
  383. aResult.Append(funcName);
  384. aResult.Append(char16_t('('));
  385. aResult.Append(funcParams);
  386. aResult.Append(char16_t(')'));
  387. }
  388. }
  389. /* static */ void
  390. nsStyleUtil::ComputeFunctionalAlternates(const nsCSSValueList* aList,
  391. nsTArray<gfxAlternateValue>& aAlternateValues)
  392. {
  393. gfxAlternateValue v;
  394. aAlternateValues.Clear();
  395. for (const nsCSSValueList* curr = aList; curr != nullptr; curr = curr->mNext) {
  396. // list contains function units
  397. if (curr->mValue.GetUnit() != eCSSUnit_Function) {
  398. continue;
  399. }
  400. // element 0 is the propval in ident form
  401. const nsCSSValue::Array *func = curr->mValue.GetArrayValue();
  402. // lookup propval
  403. nsCSSKeyword key = func->Item(0).GetKeywordValue();
  404. NS_ASSERTION(key != eCSSKeyword_UNKNOWN, "unknown alternate property value");
  405. int32_t alternate;
  406. if (key == eCSSKeyword_UNKNOWN ||
  407. !nsCSSProps::FindKeyword(key,
  408. nsCSSProps::kFontVariantAlternatesFuncsKTable,
  409. alternate)) {
  410. NS_NOTREACHED("keyword not a font-variant-alternates value");
  411. continue;
  412. }
  413. v.alternate = alternate;
  414. // other elements are the idents associated with the propval
  415. // append one alternate value for each one
  416. uint32_t numElems = func->Count();
  417. for (uint32_t i = 1; i < numElems; i++) {
  418. const nsCSSValue& value = func->Item(i);
  419. NS_ASSERTION(value.GetUnit() == eCSSUnit_Ident,
  420. "weird unit found in variant alternate");
  421. if (value.GetUnit() != eCSSUnit_Ident) {
  422. continue;
  423. }
  424. value.GetStringValue(v.value);
  425. aAlternateValues.AppendElement(v);
  426. }
  427. }
  428. }
  429. static void
  430. AppendSerializedUnicodePoint(uint32_t aCode, nsACString& aBuf)
  431. {
  432. aBuf.Append(nsPrintfCString("%0X", aCode));
  433. }
  434. // A unicode-range: descriptor is represented as an array of integers,
  435. // to be interpreted as a sequence of pairs: min max min max ...
  436. // It is in source order. (Possibly it should be sorted and overlaps
  437. // consolidated, but right now we don't do that.)
  438. /* static */ void
  439. nsStyleUtil::AppendUnicodeRange(const nsCSSValue& aValue, nsAString& aResult)
  440. {
  441. NS_PRECONDITION(aValue.GetUnit() == eCSSUnit_Null ||
  442. aValue.GetUnit() == eCSSUnit_Array,
  443. "improper value unit for unicode-range:");
  444. aResult.Truncate();
  445. if (aValue.GetUnit() != eCSSUnit_Array)
  446. return;
  447. nsCSSValue::Array const & sources = *aValue.GetArrayValue();
  448. nsAutoCString buf;
  449. MOZ_ASSERT(sources.Count() % 2 == 0,
  450. "odd number of entries in a unicode-range: array");
  451. for (uint32_t i = 0; i < sources.Count(); i += 2) {
  452. uint32_t min = sources[i].GetIntValue();
  453. uint32_t max = sources[i+1].GetIntValue();
  454. // We don't try to replicate the U+XX?? notation.
  455. buf.AppendLiteral("U+");
  456. AppendSerializedUnicodePoint(min, buf);
  457. if (min != max) {
  458. buf.Append('-');
  459. AppendSerializedUnicodePoint(max, buf);
  460. }
  461. buf.AppendLiteral(", ");
  462. }
  463. buf.Truncate(buf.Length() - 2); // remove the last comma-space
  464. CopyASCIItoUTF16(buf, aResult);
  465. }
  466. /* static */ void
  467. nsStyleUtil::AppendSerializedFontSrc(const nsCSSValue& aValue,
  468. nsAString& aResult)
  469. {
  470. // A src: descriptor is represented as an array value; each entry in
  471. // the array can be eCSSUnit_URL, eCSSUnit_Local_Font, or
  472. // eCSSUnit_Font_Format. Blocks of eCSSUnit_Font_Format may appear
  473. // only after one of the first two. (css3-fonts only contemplates
  474. // annotating URLs with formats, but we handle the general case.)
  475. NS_PRECONDITION(aValue.GetUnit() == eCSSUnit_Array,
  476. "improper value unit for src:");
  477. const nsCSSValue::Array& sources = *aValue.GetArrayValue();
  478. size_t i = 0;
  479. while (i < sources.Count()) {
  480. nsAutoString formats;
  481. if (sources[i].GetUnit() == eCSSUnit_URL) {
  482. aResult.AppendLiteral("url(");
  483. nsDependentString url(sources[i].GetOriginalURLValue());
  484. nsStyleUtil::AppendEscapedCSSString(url, aResult);
  485. aResult.Append(')');
  486. } else if (sources[i].GetUnit() == eCSSUnit_Local_Font) {
  487. aResult.AppendLiteral("local(");
  488. nsDependentString local(sources[i].GetStringBufferValue());
  489. nsStyleUtil::AppendEscapedCSSString(local, aResult);
  490. aResult.Append(')');
  491. } else {
  492. NS_NOTREACHED("entry in src: descriptor with improper unit");
  493. i++;
  494. continue;
  495. }
  496. i++;
  497. formats.Truncate();
  498. while (i < sources.Count() &&
  499. sources[i].GetUnit() == eCSSUnit_Font_Format) {
  500. formats.Append('"');
  501. formats.Append(sources[i].GetStringBufferValue());
  502. formats.AppendLiteral("\", ");
  503. i++;
  504. }
  505. if (formats.Length() > 0) {
  506. formats.Truncate(formats.Length() - 2); // remove the last comma
  507. aResult.AppendLiteral(" format(");
  508. aResult.Append(formats);
  509. aResult.Append(')');
  510. }
  511. aResult.AppendLiteral(", ");
  512. }
  513. aResult.Truncate(aResult.Length() - 2); // remove the last comma-space
  514. }
  515. /* static */ void
  516. nsStyleUtil::AppendStepsTimingFunction(nsTimingFunction::Type aType,
  517. uint32_t aSteps,
  518. nsAString& aResult)
  519. {
  520. MOZ_ASSERT(aType == nsTimingFunction::Type::StepStart ||
  521. aType == nsTimingFunction::Type::StepEnd);
  522. aResult.AppendLiteral("steps(");
  523. aResult.AppendInt(aSteps);
  524. if (aType == nsTimingFunction::Type::StepStart) {
  525. aResult.AppendLiteral(", start)");
  526. } else {
  527. aResult.AppendLiteral(")");
  528. }
  529. }
  530. /* static */ void
  531. nsStyleUtil::AppendCubicBezierTimingFunction(float aX1, float aY1,
  532. float aX2, float aY2,
  533. nsAString& aResult)
  534. {
  535. // set the value from the cubic-bezier control points
  536. // (We could try to regenerate the keywords if we want.)
  537. aResult.AppendLiteral("cubic-bezier(");
  538. aResult.AppendFloat(aX1);
  539. aResult.AppendLiteral(", ");
  540. aResult.AppendFloat(aY1);
  541. aResult.AppendLiteral(", ");
  542. aResult.AppendFloat(aX2);
  543. aResult.AppendLiteral(", ");
  544. aResult.AppendFloat(aY2);
  545. aResult.Append(')');
  546. }
  547. /* static */ void
  548. nsStyleUtil::AppendCubicBezierKeywordTimingFunction(
  549. nsTimingFunction::Type aType,
  550. nsAString& aResult)
  551. {
  552. switch (aType) {
  553. case nsTimingFunction::Type::Ease:
  554. case nsTimingFunction::Type::Linear:
  555. case nsTimingFunction::Type::EaseIn:
  556. case nsTimingFunction::Type::EaseOut:
  557. case nsTimingFunction::Type::EaseInOut: {
  558. nsCSSKeyword keyword = nsCSSProps::ValueToKeywordEnum(
  559. static_cast<int32_t>(aType),
  560. nsCSSProps::kTransitionTimingFunctionKTable);
  561. AppendASCIItoUTF16(nsCSSKeywords::GetStringValue(keyword),
  562. aResult);
  563. break;
  564. }
  565. default:
  566. MOZ_ASSERT_UNREACHABLE("unexpected aType");
  567. break;
  568. }
  569. }
  570. /* static */ float
  571. nsStyleUtil::ColorComponentToFloat(uint8_t aAlpha)
  572. {
  573. // Alpha values are expressed as decimals, so we should convert
  574. // back, using as few decimal places as possible for
  575. // round-tripping.
  576. // First try two decimal places:
  577. float rounded = NS_roundf(float(aAlpha) * 100.0f / 255.0f) / 100.0f;
  578. if (FloatToColorComponent(rounded) != aAlpha) {
  579. // Use three decimal places.
  580. rounded = NS_roundf(float(aAlpha) * 1000.0f / 255.0f) / 1000.0f;
  581. }
  582. return rounded;
  583. }
  584. /* static */ bool
  585. nsStyleUtil::IsSignificantChild(nsIContent* aChild, bool aTextIsSignificant,
  586. bool aWhitespaceIsSignificant)
  587. {
  588. NS_ASSERTION(!aWhitespaceIsSignificant || aTextIsSignificant,
  589. "Nonsensical arguments");
  590. bool isText = aChild->IsNodeOfType(nsINode::eTEXT);
  591. if (!isText && !aChild->IsNodeOfType(nsINode::eCOMMENT) &&
  592. !aChild->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
  593. return true;
  594. }
  595. return aTextIsSignificant && isText && aChild->TextLength() != 0 &&
  596. (aWhitespaceIsSignificant ||
  597. !aChild->TextIsOnlyWhitespace());
  598. }
  599. // For a replaced element whose concrete object size is no larger than the
  600. // element's content-box, this method checks whether the given
  601. // "object-position" coordinate might cause overflow in its dimension.
  602. static bool
  603. ObjectPositionCoordMightCauseOverflow(const Position::Coord& aCoord)
  604. {
  605. // Any nonzero length in "object-position" can push us to overflow
  606. // (particularly if our concrete object size is exactly the same size as the
  607. // replaced element's content-box).
  608. if (aCoord.mLength != 0) {
  609. return true;
  610. }
  611. // Percentages are interpreted as a fraction of the extra space. So,
  612. // percentages in the 0-100% range are safe, but values outside of that
  613. // range could cause overflow.
  614. if (aCoord.mHasPercent &&
  615. (aCoord.mPercent < 0.0f || aCoord.mPercent > 1.0f)) {
  616. return true;
  617. }
  618. return false;
  619. }
  620. /* static */ bool
  621. nsStyleUtil::ObjectPropsMightCauseOverflow(const nsStylePosition* aStylePos)
  622. {
  623. auto objectFit = aStylePos->mObjectFit;
  624. // "object-fit: cover" & "object-fit: none" can give us a render rect that's
  625. // larger than our container element's content-box.
  626. if (objectFit == NS_STYLE_OBJECT_FIT_COVER ||
  627. objectFit == NS_STYLE_OBJECT_FIT_NONE) {
  628. return true;
  629. }
  630. // (All other object-fit values produce a concrete object size that's no larger
  631. // than the constraint region.)
  632. // Check each of our "object-position" coords to see if it could cause
  633. // overflow in its dimension:
  634. const Position& objectPosistion = aStylePos->mObjectPosition;
  635. if (ObjectPositionCoordMightCauseOverflow(objectPosistion.mXPosition) ||
  636. ObjectPositionCoordMightCauseOverflow(objectPosistion.mYPosition)) {
  637. return true;
  638. }
  639. return false;
  640. }
  641. /* static */ bool
  642. nsStyleUtil::CSPAllowsInlineStyle(nsIContent* aContent,
  643. nsIPrincipal* aPrincipal,
  644. nsIURI* aSourceURI,
  645. uint32_t aLineNumber,
  646. const nsSubstring& aStyleText,
  647. nsresult* aRv)
  648. {
  649. nsresult rv;
  650. if (aRv) {
  651. *aRv = NS_OK;
  652. }
  653. MOZ_ASSERT(!aContent || aContent->NodeInfo()->NameAtom() == nsGkAtoms::style,
  654. "aContent passed to CSPAllowsInlineStyle "
  655. "for an element that is not <style>");
  656. nsCOMPtr<nsIContentSecurityPolicy> csp;
  657. rv = aPrincipal->GetCsp(getter_AddRefs(csp));
  658. if (NS_FAILED(rv)) {
  659. if (aRv)
  660. *aRv = rv;
  661. return false;
  662. }
  663. if (!csp) {
  664. // No CSP --> the style is allowed
  665. return true;
  666. }
  667. // query the nonce
  668. nsAutoString nonce;
  669. if (aContent) {
  670. aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::nonce, nonce);
  671. }
  672. bool allowInlineStyle = true;
  673. rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_STYLESHEET,
  674. nonce,
  675. false, // aParserCreated only applies to scripts
  676. aStyleText, aLineNumber,
  677. &allowInlineStyle);
  678. NS_ENSURE_SUCCESS(rv, false);
  679. return allowInlineStyle;
  680. }