2006-10-07 Anders Carlsson <acarlsson@apple.com>
[WebKit-https.git] / WebCore / dom / ProcessingInstruction.cpp
1 /**
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright (C) 2000 Peter Kelly (pmk@post.com)
5  * Copyright (C) 2006 Apple Computer, Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22 #include "config.h"
23 #include "ProcessingInstruction.h"
24
25 #include "CSSStyleSheet.h"
26 #include "CachedCSSStyleSheet.h"
27 #include "CachedXSLStyleSheet.h"
28 #include "Document.h"
29 #include "DocLoader.h"
30 #include "ExceptionCode.h"
31 #include "Frame.h"
32 #include "XSLStyleSheet.h"
33 #include "XMLTokenizer.h" // for parseAttributes()
34
35 namespace WebCore {
36
37 ProcessingInstruction::ProcessingInstruction(Document* doc)
38     : ContainerNode(doc)
39     , m_cachedSheet(0)
40     , m_loading(false)
41 #if XSLT_SUPPORT
42     , m_isXSL(false)
43 #endif
44 {
45 }
46
47 ProcessingInstruction::ProcessingInstruction(Document* doc, const String& target, const String& data)
48     : ContainerNode(doc)
49     , m_target(target)
50     , m_data(data)
51     , m_cachedSheet(0)
52     , m_loading(false)
53 #if XSLT_SUPPORT
54     , m_isXSL(false)
55 #endif
56 {
57 }
58
59 ProcessingInstruction::~ProcessingInstruction()
60 {
61     if (m_cachedSheet)
62         m_cachedSheet->deref(this);
63 }
64
65 void ProcessingInstruction::setData(const String& data, ExceptionCode& ec)
66 {
67     // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
68     if (isReadOnlyNode()) {
69         ec = NO_MODIFICATION_ALLOWED_ERR;
70         return;
71     }
72     m_data = data;
73 }
74
75 String ProcessingInstruction::nodeName() const
76 {
77     return m_target;
78 }
79
80 Node::NodeType ProcessingInstruction::nodeType() const
81 {
82     return PROCESSING_INSTRUCTION_NODE;
83 }
84
85 String ProcessingInstruction::nodeValue() const
86 {
87     return m_data;
88 }
89
90 void ProcessingInstruction::setNodeValue(const String& nodeValue, ExceptionCode& ec)
91 {
92     // NO_MODIFICATION_ALLOWED_ERR: taken care of by setData()
93     setData(nodeValue, ec);
94 }
95
96 PassRefPtr<Node> ProcessingInstruction::cloneNode(bool /*deep*/)
97 {
98     // ### copy m_localHref
99     return new ProcessingInstruction(document(), m_target, m_data);
100 }
101
102 // DOM Section 1.1.1
103 bool ProcessingInstruction::childTypeAllowed(NodeType)
104 {
105     return false;
106 }
107
108 bool ProcessingInstruction::checkStyleSheet()
109 {
110     if (m_target == "xml-stylesheet") {
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 true;
118         HashMap<String, String>::const_iterator i = attrs.find("type");
119         String type;
120         if (i != attrs.end())
121             type = i->second;
122         
123         bool isCSS = type.isEmpty() || type == "text/css";
124 #if XSLT_SUPPORT
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 true;
132
133         String href = attrs.get("href");
134
135         if (href.length() > 1) {
136             if (href[0] == '#') {
137                 m_localHref = href.substring(1).impl();
138 #if XSLT_SUPPORT
139                 // We need to make a synthetic XSLStyleSheet that is embedded.  It needs to be able
140                 // to kick off import/include loads that can hang off some parent sheet.
141                 if (m_isXSL) {
142                     m_sheet = new XSLStyleSheet(this, m_localHref, true);
143                     m_loading = false;
144                 }                    
145                 return !m_isXSL;
146 #endif
147             }
148             else
149             {
150                 // FIXME: some validation on the URL?
151                 if (document()->frame()) {
152                     m_loading = true;
153                     document()->addPendingSheet();
154                     if (m_cachedSheet)
155                         m_cachedSheet->deref(this);
156 #if XSLT_SUPPORT
157                     if (m_isXSL)
158                         m_cachedSheet = document()->docLoader()->requestXSLStyleSheet(document()->completeURL(href));
159                     else
160 #endif
161                     {
162                         String charset = attrs.get("charset");
163                         if (charset.isEmpty())
164                             charset = document()->frame()->encoding();
165
166                         m_cachedSheet = document()->docLoader()->requestCSSStyleSheet(document()->completeURL(href), charset);
167                     }
168                     if (m_cachedSheet)
169                         m_cachedSheet->ref( this );
170 #if XSLT_SUPPORT
171                     return !m_isXSL;
172 #endif
173                 }
174             }
175
176         }
177     }
178     
179     return true;
180 }
181
182 bool ProcessingInstruction::isLoading() const
183 {
184     if (m_loading)
185         return true;
186     if (!m_sheet)
187         return false;
188     return m_sheet->isLoading();
189 }
190
191 void ProcessingInstruction::sheetLoaded()
192 {
193     if (!isLoading())
194         document()->stylesheetLoaded();
195 }
196
197 void ProcessingInstruction::setCSSStyleSheet(const String &url, const String& charset, const String &sheet)
198 {
199     ASSERT(!m_isXSL);
200     m_sheet = new CSSStyleSheet(this, url, charset);
201     parseStyleSheet(sheet);
202 }
203
204 #if XSLT_SUPPORT
205 void ProcessingInstruction::setXSLStyleSheet(const String &url, const String &sheet)
206 {
207     ASSERT(m_isXSL);
208     m_sheet = new XSLStyleSheet(this, url);
209     parseStyleSheet(sheet);
210 }
211 #endif
212
213 void ProcessingInstruction::parseStyleSheet(const String &sheet)
214 {
215     m_sheet->parseString(sheet);
216     if (m_cachedSheet)
217         m_cachedSheet->deref(this);
218     m_cachedSheet = 0;
219
220     m_loading = false;
221
222     // Tell the doc about the sheet.
223     if (!isLoading() && m_sheet)
224         document()->stylesheetLoaded();
225 }
226
227 String ProcessingInstruction::toString() const
228 {
229     String result = "<?";
230     result += m_target;
231     result += " ";
232     result += m_data;
233     result += "?>";
234     return result;
235 }
236
237 void ProcessingInstruction::setCSSStyleSheet(CSSStyleSheet* sheet)
238 {
239     ASSERT(!m_cachedSheet);
240     ASSERT(!m_loading);
241     m_sheet = sheet;
242 }
243
244 bool ProcessingInstruction::offsetInCharacters() const
245 {
246     return true;
247 }
248
249 } // namespace