1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=78: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ImportScanner.h"
8 #include "nsContentUtils.h"
12 static inline bool IsWhitespace(char16_t aChar
) {
13 return nsContentUtils::IsHTMLWhitespace(aChar
);
16 void ImportScanner::Start() {
21 void ImportScanner::EmitUrl() {
22 MOZ_ASSERT(mState
== State::AfterRuleValue
);
24 // Trim trailing whitespace from an unquoted URL.
25 if (mUrlValueDelimiterClosingChar
== ')') {
26 // FIXME: Add a convenience function in nsContentUtils or something?
27 mRuleValue
.Trim(" \t\n\r\f", false);
29 mUrlsFound
.AppendElement(std::move(mRuleValue
));
31 mInImportRule
= false;
32 // We try to avoid freeing the buffers here.
33 mRuleName
.Truncate(0);
34 mRuleValue
.Truncate(0);
35 MOZ_ASSERT(mRuleValue
.IsEmpty());
38 nsTArray
<nsString
> ImportScanner::Stop() {
39 if (mState
== State::AfterRuleValue
) {
42 mState
= State::OutsideOfStyleElement
;
43 mInImportRule
= false;
44 mRuleName
.Truncate(0);
45 mRuleValue
.Truncate(0);
46 return std::move(mUrlsFound
);
49 nsTArray
<nsString
> ImportScanner::Scan(Span
<const char16_t
> aFragment
) {
50 MOZ_ASSERT(ShouldScan());
52 for (char16_t c
: aFragment
) {
54 if (mState
== State::Done
) {
59 return std::move(mUrlsFound
);
62 auto ImportScanner::Scan(char16_t aChar
) -> State
{
64 case State::OutsideOfStyleElement
:
66 MOZ_ASSERT_UNREACHABLE("How?");
69 // TODO(emilio): Maybe worth caring about html-style comments like:
72 // @import url(stuff);
75 if (IsWhitespace(aChar
)) {
79 return State::MaybeAtCommentStart
;
82 MOZ_ASSERT(mRuleName
.IsEmpty());
83 return State::AtRuleName
;
87 case State::MaybeAtCommentStart
: {
88 return aChar
== '*' ? State::AtComment
: State::Done
;
90 case State::AtComment
: {
91 return aChar
== '*' ? State::MaybeAtCommentEnd
: mState
;
93 case State::MaybeAtCommentEnd
: {
94 return aChar
== '/' ? State::Idle
: State::AtComment
;
96 case State::AtRuleName
: {
97 if (IsAsciiAlpha(aChar
)) {
98 if (mRuleName
.Length() > kMaxRuleNameLength
- 1) {
101 mRuleName
.Append(aChar
);
104 if (IsWhitespace(aChar
)) {
105 mInImportRule
= mRuleName
.LowerCaseEqualsLiteral("import");
106 if (mInImportRule
|| mRuleName
.LowerCaseEqualsLiteral("charset")) {
107 MOZ_ASSERT(mRuleValue
.IsEmpty());
108 return State::AtRuleValue
;
113 case State::AtRuleValue
: {
114 if (mRuleValue
.IsEmpty()) {
115 if (IsWhitespace(aChar
)) {
118 if (aChar
== '"' || aChar
== '\'') {
119 mUrlValueDelimiterClosingChar
= aChar
;
120 return State::AtRuleValueDelimited
;
122 if (!mInImportRule
) {
125 if (aChar
== 'u' || aChar
== 'U') {
126 mRuleValue
.Append('u');
131 if (mRuleValue
.Length() == 1) {
132 MOZ_ASSERT(mRuleValue
.EqualsLiteral("u"));
133 if (aChar
== 'r' || aChar
== 'R') {
134 mRuleValue
.Append('r');
139 if (mRuleValue
.Length() == 2) {
140 MOZ_ASSERT(mRuleValue
.EqualsLiteral("ur"));
141 if (aChar
== 'l' || aChar
== 'L') {
142 mRuleValue
.Append('l');
146 if (mRuleValue
.Length() == 3) {
147 MOZ_ASSERT(mRuleValue
.EqualsLiteral("url"));
149 mUrlValueDelimiterClosingChar
= ')';
150 mRuleValue
.Truncate(0);
151 return State::AtRuleValueDelimited
;
155 MOZ_ASSERT_UNREACHABLE(
156 "How? We should find a paren or a string delimiter");
159 case State::AtRuleValueDelimited
: {
160 if (aChar
== mUrlValueDelimiterClosingChar
) {
161 return State::AfterRuleValue
;
163 if (!mInImportRule
) {
166 if (mUrlValueDelimiterClosingChar
== ')' && mRuleValue
.IsEmpty()) {
167 if (IsWhitespace(aChar
)) {
170 if (aChar
== '"' || aChar
== '\'') {
171 // Handle url("") and url('').
172 mUrlValueDelimiterClosingChar
= aChar
;
176 if (!mRuleValue
.Append(aChar
, mozilla::fallible
)) {
177 mRuleValue
.Truncate(0);
182 case State::AfterRuleValue
: {
187 // If there's a selector here and the import was unterminated, just give
192 return mState
; // There can be all sorts of stuff here like media
193 // queries or what not.
196 MOZ_ASSERT_UNREACHABLE("Forgot to handle a state?");
200 } // namespace mozilla