2008-11-04 Anders Carlsson <andersca@apple.com>
[webkit/qt.git] / WebCore / dom / ProcessingInstruction.cpp
blob3d1a608257e23e58f48221979858b315b2bd4c70
1 /*
2 * Copyright (C) 2000 Peter Kelly (pmk@post.com)
3 * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
21 #include "config.h"
22 #include "ProcessingInstruction.h"
24 #include "CSSStyleSheet.h"
25 #include "CachedCSSStyleSheet.h"
26 #include "CachedXSLStyleSheet.h"
27 #include "Document.h"
28 #include "DocLoader.h"
29 #include "ExceptionCode.h"
30 #include "Frame.h"
31 #include "FrameLoader.h"
32 #include "XSLStyleSheet.h"
33 #include "XMLTokenizer.h" // for parseAttributes()
34 #include "MediaList.h"
36 namespace WebCore {
38 ProcessingInstruction::ProcessingInstruction(Document* doc)
39 : ContainerNode(doc)
40 , m_cachedSheet(0)
41 , m_loading(false)
42 , m_alternate(false)
43 #if ENABLE(XSLT)
44 , m_isXSL(false)
45 #endif
49 ProcessingInstruction::ProcessingInstruction(Document* doc, const String& target, const String& data)
50 : ContainerNode(doc)
51 , m_target(target)
52 , m_data(data)
53 , m_cachedSheet(0)
54 , m_loading(false)
55 , m_alternate(false)
56 #if ENABLE(XSLT)
57 , m_isXSL(false)
58 #endif
62 ProcessingInstruction::~ProcessingInstruction()
64 if (m_cachedSheet)
65 m_cachedSheet->removeClient(this);
68 void ProcessingInstruction::setData(const String& data, ExceptionCode&)
70 int oldLength = m_data.length();
71 m_data = data;
72 document()->textRemoved(this, 0, oldLength);
75 String ProcessingInstruction::nodeName() const
77 return m_target;
80 Node::NodeType ProcessingInstruction::nodeType() const
82 return PROCESSING_INSTRUCTION_NODE;
85 String ProcessingInstruction::nodeValue() const
87 return m_data;
90 void ProcessingInstruction::setNodeValue(const String& nodeValue, ExceptionCode& ec)
92 // NO_MODIFICATION_ALLOWED_ERR: taken care of by setData()
93 setData(nodeValue, ec);
96 PassRefPtr<Node> ProcessingInstruction::cloneNode(bool /*deep*/)
98 // ### copy m_localHref
99 return new ProcessingInstruction(document(), m_target, m_data);
102 // DOM Section 1.1.1
103 bool ProcessingInstruction::childTypeAllowed(NodeType)
105 return false;
108 void ProcessingInstruction::checkStyleSheet()
110 if (m_target == "xml-stylesheet" && document()->frame() && parentNode() == document()) {
111 // see http://www.w3.org/TR/xml-stylesheet/
112 // ### support stylesheet included in a fragment of this (or another) document
113 // ### make sure this gets called when adding from javascript
114 bool attrsOk;
115 const HashMap<String, String> attrs = parseAttributes(m_data, attrsOk);
116 if (!attrsOk)
117 return;
118 HashMap<String, String>::const_iterator i = attrs.find("type");
119 String type;
120 if (i != attrs.end())
121 type = i->second;
123 bool isCSS = type.isEmpty() || type == "text/css";
124 #if ENABLE(XSLT)
125 m_isXSL = (type == "text/xml" || type == "text/xsl" || type == "application/xml" ||
126 type == "application/xhtml+xml" || type == "application/rss+xml" || type == "application/atom=xml");
127 if (!isCSS && !m_isXSL)
128 #else
129 if (!isCSS)
130 #endif
131 return;
133 String href = attrs.get("href");
134 String alternate = attrs.get("alternate");
135 m_alternate = alternate == "yes";
136 m_title = attrs.get("title");
137 m_media = attrs.get("media");
139 if (href.length() > 1) {
140 if (href[0] == '#') {
141 m_localHref = href.substring(1);
142 #if ENABLE(XSLT)
143 // We need to make a synthetic XSLStyleSheet that is embedded. It needs to be able
144 // to kick off import/include loads that can hang off some parent sheet.
145 if (m_isXSL) {
146 m_sheet = XSLStyleSheet::createEmbedded(this, m_localHref);
147 m_loading = false;
149 #endif
151 else
153 m_loading = true;
154 document()->addPendingSheet();
155 if (m_cachedSheet)
156 m_cachedSheet->removeClient(this);
157 #if ENABLE(XSLT)
158 if (m_isXSL)
159 m_cachedSheet = document()->docLoader()->requestXSLStyleSheet(document()->completeURL(href).string());
160 else
161 #endif
163 String charset = attrs.get("charset");
164 if (charset.isEmpty())
165 charset = document()->frame()->loader()->encoding();
167 m_cachedSheet = document()->docLoader()->requestCSSStyleSheet(document()->completeURL(href).string(), charset);
169 if (m_cachedSheet)
170 m_cachedSheet->addClient(this);
176 bool ProcessingInstruction::isLoading() const
178 if (m_loading)
179 return true;
180 if (!m_sheet)
181 return false;
182 return m_sheet->isLoading();
185 bool ProcessingInstruction::sheetLoaded()
187 if (!isLoading()) {
188 document()->removePendingSheet();
189 return true;
191 return false;
194 void ProcessingInstruction::setCSSStyleSheet(const String& url, const String& charset, const CachedCSSStyleSheet* sheet)
196 #if ENABLE(XSLT)
197 ASSERT(!m_isXSL);
198 #endif
199 RefPtr<CSSStyleSheet> newSheet = CSSStyleSheet::create(this, url, charset);
200 m_sheet = newSheet;
201 parseStyleSheet(sheet->sheetText());
202 newSheet->setTitle(m_title);
203 newSheet->setMedia(MediaList::create(newSheet.get(), m_media));
204 newSheet->setDisabled(m_alternate);
207 #if ENABLE(XSLT)
208 void ProcessingInstruction::setXSLStyleSheet(const String& url, const String& sheet)
210 ASSERT(m_isXSL);
211 m_sheet = XSLStyleSheet::create(this, url);
212 parseStyleSheet(sheet);
214 #endif
216 void ProcessingInstruction::parseStyleSheet(const String& sheet)
218 m_sheet->parseString(sheet, true);
219 if (m_cachedSheet)
220 m_cachedSheet->removeClient(this);
221 m_cachedSheet = 0;
223 m_loading = false;
224 m_sheet->checkLoaded();
227 void ProcessingInstruction::setCSSStyleSheet(PassRefPtr<CSSStyleSheet> sheet)
229 ASSERT(!m_cachedSheet);
230 ASSERT(!m_loading);
231 m_sheet = sheet;
232 m_sheet->setTitle(m_title);
233 m_sheet->setDisabled(m_alternate);
236 bool ProcessingInstruction::offsetInCharacters() const
238 return true;
241 int ProcessingInstruction::maxCharacterOffset() const
243 return static_cast<int>(m_data.length());
246 void ProcessingInstruction::getSubresourceAttributeStrings(Vector<String>& urls) const
248 if (!sheet())
249 return;
251 urls.append(sheet()->href());
254 void ProcessingInstruction::insertedIntoDocument()
256 ContainerNode::insertedIntoDocument();
257 document()->addStyleSheetCandidateNode(this, m_createdByParser);
258 checkStyleSheet();
261 void ProcessingInstruction::removedFromDocument()
263 ContainerNode::removedFromDocument();
265 if (document()->renderer())
266 document()->removeStyleSheetCandidateNode(this);
268 // FIXME: It's terrible to do a synchronous update of the style selector just because a <style> or <link> element got removed.
269 if (m_cachedSheet)
270 document()->updateStyleSelector();
273 void ProcessingInstruction::finishParsingChildren()
275 m_createdByParser = false;
276 ContainerNode::finishParsingChildren();
279 } // namespace