Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / dom / ProcessingInstruction.cpp
1 /*
2  * Copyright (C) 2000 Peter Kelly (pmk@post.com)
3  * Copyright (C) 2006, 2008, 2009 Apple Inc. All rights reserved.
4  * Copyright (C) 2013 Samsung Electronics. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23 #include "ProcessingInstruction.h"
24
25 #include "AuthorStyleSheets.h"
26 #include "CSSStyleSheet.h"
27 #include "CachedCSSStyleSheet.h"
28 #include "CachedResourceLoader.h"
29 #include "CachedResourceRequest.h"
30 #include "CachedXSLStyleSheet.h"
31 #include "Document.h"
32 #include "ExceptionCode.h"
33 #include "Frame.h"
34 #include "FrameLoader.h"
35 #include "XSLStyleSheet.h"
36 #include "XMLDocumentParser.h" // for parseAttributes()
37 #include "MediaList.h"
38 #include "StyleSheetContents.h"
39
40 namespace WebCore {
41
42 inline ProcessingInstruction::ProcessingInstruction(Document& document, const String& target, const String& data)
43     : CharacterData(document, data, CreateOther)
44     , m_target(target)
45 {
46 }
47
48 Ref<ProcessingInstruction> ProcessingInstruction::create(Document& document, const String& target, const String& data)
49 {
50     return adoptRef(*new ProcessingInstruction(document, target, data));
51 }
52
53 ProcessingInstruction::~ProcessingInstruction()
54 {
55     if (m_sheet)
56         m_sheet->clearOwnerNode();
57
58     if (m_cachedSheet)
59         m_cachedSheet->removeClient(this);
60
61     if (inDocument())
62         document().authorStyleSheets().removeStyleSheetCandidateNode(*this);
63 }
64
65 String ProcessingInstruction::nodeName() const
66 {
67     return m_target;
68 }
69
70 Node::NodeType ProcessingInstruction::nodeType() const
71 {
72     return PROCESSING_INSTRUCTION_NODE;
73 }
74
75 Ref<Node> ProcessingInstruction::cloneNodeInternal(Document& targetDocument, CloningOperation)
76 {
77     // FIXME: Is it a problem that this does not copy m_localHref?
78     // What about other data members?
79     return create(targetDocument, m_target, data());
80 }
81
82 void ProcessingInstruction::checkStyleSheet()
83 {
84     if (m_target == "xml-stylesheet" && document().frame() && parentNode() == &document()) {
85         // see http://www.w3.org/TR/xml-stylesheet/
86         // ### support stylesheet included in a fragment of this (or another) document
87         // ### make sure this gets called when adding from javascript
88         bool attrsOk;
89         const HashMap<String, String> attrs = parseAttributes(data(), attrsOk);
90         if (!attrsOk)
91             return;
92         HashMap<String, String>::const_iterator i = attrs.find("type");
93         String type;
94         if (i != attrs.end())
95             type = i->value;
96
97         m_isCSS = type.isEmpty() || type == "text/css";
98 #if ENABLE(XSLT)
99         m_isXSL = (type == "text/xml" || type == "text/xsl" || type == "application/xml" ||
100                    type == "application/xhtml+xml" || type == "application/rss+xml" || type == "application/atom+xml");
101         if (!m_isCSS && !m_isXSL)
102 #else
103         if (!m_isCSS)
104 #endif
105             return;
106
107         String href = attrs.get("href");
108         String alternate = attrs.get("alternate");
109         m_alternate = alternate == "yes";
110         m_title = attrs.get("title");
111         m_media = attrs.get("media");
112
113         if (m_alternate && m_title.isEmpty())
114             return;
115
116         if (href.length() > 1 && href[0] == '#') {
117             m_localHref = href.substring(1);
118 #if ENABLE(XSLT)
119             // We need to make a synthetic XSLStyleSheet that is embedded.  It needs to be able
120             // to kick off import/include loads that can hang off some parent sheet.
121             if (m_isXSL) {
122                 URL finalURL(ParsedURLString, m_localHref);
123                 m_sheet = XSLStyleSheet::createEmbedded(this, finalURL);
124                 m_loading = false;
125             }
126 #endif
127         } else {
128             if (m_cachedSheet) {
129                 m_cachedSheet->removeClient(this);
130                 m_cachedSheet = nullptr;
131             }
132             
133             String url = document().completeURL(href).string();
134             if (!dispatchBeforeLoadEvent(url))
135                 return;
136             
137             m_loading = true;
138             document().authorStyleSheets().addPendingSheet();
139             
140             CachedResourceRequest request(ResourceRequest(document().completeURL(href)));
141 #if ENABLE(XSLT)
142             if (m_isXSL)
143                 m_cachedSheet = document().cachedResourceLoader().requestXSLStyleSheet(request);
144             else
145 #endif
146             {
147                 String charset = attrs.get("charset");
148                 if (charset.isEmpty())
149                     charset = document().charset();
150                 request.setCharset(charset);
151
152                 m_cachedSheet = document().cachedResourceLoader().requestCSSStyleSheet(request);
153             }
154             if (m_cachedSheet)
155                 m_cachedSheet->addClient(this);
156             else {
157                 // The request may have been denied if (for example) the stylesheet is local and the document is remote.
158                 m_loading = false;
159                 document().authorStyleSheets().removePendingSheet();
160             }
161         }
162     }
163 }
164
165 bool ProcessingInstruction::isLoading() const
166 {
167     if (m_loading)
168         return true;
169     if (!m_sheet)
170         return false;
171     return m_sheet->isLoading();
172 }
173
174 bool ProcessingInstruction::sheetLoaded()
175 {
176     if (!isLoading()) {
177         document().authorStyleSheets().removePendingSheet();
178         return true;
179     }
180     return false;
181 }
182
183 void ProcessingInstruction::setCSSStyleSheet(const String& href, const URL& baseURL, const String& charset, const CachedCSSStyleSheet* sheet)
184 {
185     if (!inDocument()) {
186         ASSERT(!m_sheet);
187         return;
188     }
189
190     ASSERT(m_isCSS);
191     CSSParserContext parserContext(document(), baseURL, charset);
192
193     auto cssSheet = CSSStyleSheet::create(StyleSheetContents::create(href, parserContext), this);
194     cssSheet.get().setDisabled(m_alternate);
195     cssSheet.get().setTitle(m_title);
196     cssSheet.get().setMediaQueries(MediaQuerySet::create(m_media));
197
198     m_sheet = WTFMove(cssSheet);
199
200     // We don't need the cross-origin security check here because we are
201     // getting the sheet text in "strict" mode. This enforces a valid CSS MIME
202     // type.
203     parseStyleSheet(sheet->sheetText());
204 }
205
206 #if ENABLE(XSLT)
207 void ProcessingInstruction::setXSLStyleSheet(const String& href, const URL& baseURL, const String& sheet)
208 {
209     ASSERT(m_isXSL);
210     m_sheet = XSLStyleSheet::create(this, href, baseURL);
211     Ref<Document> protect(document());
212     parseStyleSheet(sheet);
213 }
214 #endif
215
216 void ProcessingInstruction::parseStyleSheet(const String& sheet)
217 {
218     if (m_isCSS)
219         downcast<CSSStyleSheet>(*m_sheet).contents().parseString(sheet);
220 #if ENABLE(XSLT)
221     else if (m_isXSL)
222         downcast<XSLStyleSheet>(*m_sheet).parseString(sheet);
223 #endif
224
225     if (m_cachedSheet)
226         m_cachedSheet->removeClient(this);
227     m_cachedSheet = nullptr;
228
229     m_loading = false;
230
231     if (m_isCSS)
232         downcast<CSSStyleSheet>(*m_sheet).contents().checkLoaded();
233 #if ENABLE(XSLT)
234     else if (m_isXSL)
235         downcast<XSLStyleSheet>(*m_sheet).checkLoaded();
236 #endif
237 }
238
239 void ProcessingInstruction::setCSSStyleSheet(PassRefPtr<CSSStyleSheet> sheet)
240 {
241     ASSERT(!m_cachedSheet);
242     ASSERT(!m_loading);
243     m_sheet = sheet;
244     sheet->setTitle(m_title);
245     sheet->setDisabled(m_alternate);
246 }
247
248 void ProcessingInstruction::addSubresourceAttributeURLs(ListHashSet<URL>& urls) const
249 {
250     if (!sheet())
251         return;
252     
253     addSubresourceURL(urls, sheet()->baseURL());
254 }
255
256 Node::InsertionNotificationRequest ProcessingInstruction::insertedInto(ContainerNode& insertionPoint)
257 {
258     CharacterData::insertedInto(insertionPoint);
259     if (!insertionPoint.inDocument())
260         return InsertionDone;
261     document().authorStyleSheets().addStyleSheetCandidateNode(*this, m_createdByParser);
262     checkStyleSheet();
263     return InsertionDone;
264 }
265
266 void ProcessingInstruction::removedFrom(ContainerNode& insertionPoint)
267 {
268     CharacterData::removedFrom(insertionPoint);
269     if (!insertionPoint.inDocument())
270         return;
271     
272     document().authorStyleSheets().removeStyleSheetCandidateNode(*this);
273
274     if (m_sheet) {
275         ASSERT(m_sheet->ownerNode() == this);
276         m_sheet->clearOwnerNode();
277         m_sheet = nullptr;
278     }
279
280     // If we're in document teardown, then we don't need to do any notification of our sheet's removal.
281     if (document().hasLivingRenderTree())
282         document().styleResolverChanged(DeferRecalcStyle);
283 }
284
285 void ProcessingInstruction::finishParsingChildren()
286 {
287     m_createdByParser = false;
288     CharacterData::finishParsingChildren();
289 }
290
291 } // namespace