Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / core / html / parser / CSSPreloadScanner.cpp
blobd7fad12fa695d98da79499de7832e7176e07d912
1 /*
2 * Copyright (C) 2008, 2010 Apple Inc. All Rights Reserved.
3 * Copyright (C) 2009 Torch Mobile, Inc. http://www.torchmobile.com/
4 * Copyright (C) 2010 Google Inc. All Rights Reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "config.h"
29 #include "core/html/parser/CSSPreloadScanner.h"
31 #include "core/fetch/FetchInitiatorTypeNames.h"
32 #include "core/html/parser/HTMLParserIdioms.h"
33 #include "platform/text/SegmentedString.h"
35 namespace blink {
37 CSSPreloadScanner::CSSPreloadScanner()
38 : m_state(Initial)
39 , m_requests(0)
40 , m_referrerPolicy(ReferrerPolicyDefault)
44 CSSPreloadScanner::~CSSPreloadScanner()
48 void CSSPreloadScanner::reset()
50 m_state = Initial;
51 m_rule.clear();
52 m_ruleValue.clear();
55 template<typename Char>
56 void CSSPreloadScanner::scanCommon(const Char* begin, const Char* end, const SegmentedString& source, PreloadRequestStream& requests)
58 m_requests = &requests;
59 for (const Char* it = begin; it != end && m_state != DoneParsingImportRules; ++it)
60 tokenize(*it, source);
61 m_requests = 0;
64 void CSSPreloadScanner::scan(const HTMLToken::DataVector& data, const SegmentedString& source, PreloadRequestStream& requests)
66 scanCommon(data.data(), data.data() + data.size(), source, requests);
69 void CSSPreloadScanner::scan(const String& tagName, const SegmentedString& source, PreloadRequestStream& requests)
71 if (tagName.is8Bit()) {
72 const LChar* begin = tagName.characters8();
73 scanCommon(begin, begin + tagName.length(), source, requests);
74 return;
76 const UChar* begin = tagName.characters16();
77 scanCommon(begin, begin + tagName.length(), source, requests);
80 void CSSPreloadScanner::setReferrerPolicy(const ReferrerPolicy policy)
82 m_referrerPolicy = policy;
85 inline void CSSPreloadScanner::tokenize(UChar c, const SegmentedString& source)
87 // We are just interested in @import rules, no need for real tokenization here
88 // Searching for other types of resources is probably low payoff.
89 switch (m_state) {
90 case Initial:
91 if (isHTMLSpace<UChar>(c))
92 break;
93 if (c == '@')
94 m_state = RuleStart;
95 else if (c == '/')
96 m_state = MaybeComment;
97 else
98 m_state = DoneParsingImportRules;
99 break;
100 case MaybeComment:
101 if (c == '*')
102 m_state = Comment;
103 else
104 m_state = Initial;
105 break;
106 case Comment:
107 if (c == '*')
108 m_state = MaybeCommentEnd;
109 break;
110 case MaybeCommentEnd:
111 if (c == '*')
112 break;
113 if (c == '/')
114 m_state = Initial;
115 else
116 m_state = Comment;
117 break;
118 case RuleStart:
119 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
120 m_rule.clear();
121 m_ruleValue.clear();
122 m_rule.append(c);
123 m_state = Rule;
124 } else
125 m_state = Initial;
126 break;
127 case Rule:
128 if (isHTMLSpace<UChar>(c))
129 m_state = AfterRule;
130 else if (c == ';')
131 m_state = Initial;
132 else
133 m_rule.append(c);
134 break;
135 case AfterRule:
136 if (isHTMLSpace<UChar>(c))
137 break;
138 if (c == ';')
139 m_state = Initial;
140 else if (c == '{')
141 m_state = DoneParsingImportRules;
142 else {
143 m_state = RuleValue;
144 m_ruleValue.append(c);
146 break;
147 case RuleValue:
148 if (isHTMLSpace<UChar>(c))
149 m_state = AfterRuleValue;
150 else if (c == ';')
151 emitRule(source);
152 else
153 m_ruleValue.append(c);
154 break;
155 case AfterRuleValue:
156 if (isHTMLSpace<UChar>(c))
157 break;
158 if (c == ';')
159 emitRule(source);
160 else if (c == '{')
161 m_state = DoneParsingImportRules;
162 else {
163 // FIXME: media rules
164 m_state = Initial;
166 break;
167 case DoneParsingImportRules:
168 ASSERT_NOT_REACHED();
169 break;
173 static String parseCSSStringOrURL(const String& string)
175 size_t offset = 0;
176 size_t reducedLength = string.length();
178 while (reducedLength && isHTMLSpace<UChar>(string[offset])) {
179 ++offset;
180 --reducedLength;
182 while (reducedLength && isHTMLSpace<UChar>(string[offset + reducedLength - 1]))
183 --reducedLength;
185 if (reducedLength >= 5
186 && (string[offset] == 'u' || string[offset] == 'U')
187 && (string[offset + 1] == 'r' || string[offset + 1] == 'R')
188 && (string[offset + 2] == 'l' || string[offset + 2] == 'L')
189 && string[offset + 3] == '('
190 && string[offset + reducedLength - 1] == ')') {
191 offset += 4;
192 reducedLength -= 5;
195 while (reducedLength && isHTMLSpace<UChar>(string[offset])) {
196 ++offset;
197 --reducedLength;
199 while (reducedLength && isHTMLSpace<UChar>(string[offset + reducedLength - 1]))
200 --reducedLength;
202 if (reducedLength < 2 || string[offset] != string[offset + reducedLength - 1] || !(string[offset] == '\'' || string[offset] == '"'))
203 return String();
204 offset++;
205 reducedLength -= 2;
207 while (reducedLength && isHTMLSpace<UChar>(string[offset])) {
208 ++offset;
209 --reducedLength;
211 while (reducedLength && isHTMLSpace<UChar>(string[offset + reducedLength - 1]))
212 --reducedLength;
214 return string.substring(offset, reducedLength);
217 void CSSPreloadScanner::emitRule(const SegmentedString& source)
219 if (equalIgnoringCase(m_rule, "import")) {
220 String url = parseCSSStringOrURL(m_ruleValue.toString());
221 if (!url.isEmpty()) {
222 KURL baseElementURL; // FIXME: This should be passed in from the HTMLPreloadScaner via scan()!
223 TextPosition position = TextPosition(source.currentLine(), source.currentColumn());
224 OwnPtr<PreloadRequest> request = PreloadRequest::create(FetchInitiatorTypeNames::css, position, url, baseElementURL, Resource::CSSStyleSheet, m_referrerPolicy);
225 // FIXME: Should this be including the charset in the preload request?
226 m_requests->append(request.release());
228 m_state = Initial;
229 } else if (equalIgnoringCase(m_rule, "charset"))
230 m_state = Initial;
231 else
232 m_state = DoneParsingImportRules;
233 m_rule.clear();
234 m_ruleValue.clear();