|
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., 51 Franklin Street, Fifth Floor, |
|
20 * Boston, MA 02110-1301, 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 "FrameLoader.h" |
|
33 #include "XSLStyleSheet.h" |
|
34 #include "XMLTokenizer.h" // for parseAttributes() |
|
35 |
|
36 namespace WebCore { |
|
37 |
|
38 ProcessingInstruction::ProcessingInstruction(Document* doc) |
|
39 : ContainerNode(doc) |
|
40 , m_cachedSheet(0) |
|
41 , m_loading(false) |
|
42 #if ENABLE(XSLT) |
|
43 , m_isXSL(false) |
|
44 #endif |
|
45 { |
|
46 } |
|
47 |
|
48 ProcessingInstruction::ProcessingInstruction(Document* doc, const String& target, const String& data) |
|
49 : ContainerNode(doc) |
|
50 , m_target(target) |
|
51 , m_data(data) |
|
52 , m_cachedSheet(0) |
|
53 , m_loading(false) |
|
54 #if ENABLE(XSLT) |
|
55 , m_isXSL(false) |
|
56 #endif |
|
57 { |
|
58 } |
|
59 |
|
60 ProcessingInstruction::~ProcessingInstruction() |
|
61 { |
|
62 if (m_cachedSheet) |
|
63 m_cachedSheet->deref(this); |
|
64 } |
|
65 |
|
66 void ProcessingInstruction::setData(const String& data, ExceptionCode& ec) |
|
67 { |
|
68 // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly. |
|
69 if (isReadOnlyNode()) { |
|
70 ec = NO_MODIFICATION_ALLOWED_ERR; |
|
71 return; |
|
72 } |
|
73 m_data = data; |
|
74 } |
|
75 |
|
76 String ProcessingInstruction::nodeName() const |
|
77 { |
|
78 return m_target; |
|
79 } |
|
80 |
|
81 Node::NodeType ProcessingInstruction::nodeType() const |
|
82 { |
|
83 return PROCESSING_INSTRUCTION_NODE; |
|
84 } |
|
85 |
|
86 String ProcessingInstruction::nodeValue() const |
|
87 { |
|
88 return m_data; |
|
89 } |
|
90 |
|
91 void ProcessingInstruction::setNodeValue(const String& nodeValue, ExceptionCode& ec) |
|
92 { |
|
93 // NO_MODIFICATION_ALLOWED_ERR: taken care of by setData() |
|
94 setData(nodeValue, ec); |
|
95 } |
|
96 |
|
97 PassRefPtr<Node> ProcessingInstruction::cloneNode(bool /*deep*/) |
|
98 { |
|
99 // ### copy m_localHref |
|
100 return new ProcessingInstruction(document(), m_target, m_data); |
|
101 } |
|
102 |
|
103 // DOM Section 1.1.1 |
|
104 bool ProcessingInstruction::childTypeAllowed(NodeType) |
|
105 { |
|
106 return false; |
|
107 } |
|
108 |
|
109 bool ProcessingInstruction::checkStyleSheet() |
|
110 { |
|
111 if (m_target == "xml-stylesheet") { |
|
112 // see http://www.w3.org/TR/xml-stylesheet/ |
|
113 // ### support stylesheet included in a fragment of this (or another) document |
|
114 // ### make sure this gets called when adding from javascript |
|
115 bool attrsOk; |
|
116 const HashMap<String, String> attrs = parseAttributes(m_data, attrsOk); |
|
117 if (!attrsOk) |
|
118 return true; |
|
119 HashMap<String, String>::const_iterator i = attrs.find("type"); |
|
120 String type; |
|
121 if (i != attrs.end()) |
|
122 type = i->second; |
|
123 |
|
124 bool isCSS = type.isEmpty() || type == "text/css"; |
|
125 #if ENABLE(XSLT) |
|
126 m_isXSL = (type == "text/xml" || type == "text/xsl" || type == "application/xml" || |
|
127 type == "application/xhtml+xml" || type == "application/rss+xml" || type == "application/atom=xml"); |
|
128 if (!isCSS && !m_isXSL) |
|
129 #else |
|
130 if (!isCSS) |
|
131 #endif |
|
132 return true; |
|
133 |
|
134 String href = attrs.get("href"); |
|
135 |
|
136 if (href.length() > 1) { |
|
137 if (href[0] == '#') { |
|
138 m_localHref = href.substring(1); |
|
139 #if ENABLE(XSLT) |
|
140 // We need to make a synthetic XSLStyleSheet that is embedded. It needs to be able |
|
141 // to kick off import/include loads that can hang off some parent sheet. |
|
142 if (m_isXSL) { |
|
143 m_sheet = new XSLStyleSheet(this, m_localHref, true); |
|
144 m_loading = false; |
|
145 } |
|
146 return !m_isXSL; |
|
147 #endif |
|
148 } |
|
149 else |
|
150 { |
|
151 // FIXME: some validation on the URL? |
|
152 if (document()->frame()) { |
|
153 m_loading = true; |
|
154 document()->addPendingSheet(); |
|
155 if (m_cachedSheet) |
|
156 m_cachedSheet->deref(this); |
|
157 #if ENABLE(XSLT) |
|
158 if (m_isXSL) |
|
159 m_cachedSheet = document()->docLoader()->requestXSLStyleSheet(document()->completeURL(href)); |
|
160 else |
|
161 #endif |
|
162 { |
|
163 String charset = attrs.get("charset"); |
|
164 if (charset.isEmpty()) |
|
165 charset = document()->frame()->loader()->encoding(); |
|
166 |
|
167 m_cachedSheet = document()->docLoader()->requestCSSStyleSheet(document()->completeURL(href), charset); |
|
168 } |
|
169 if (m_cachedSheet) |
|
170 m_cachedSheet->ref(this); |
|
171 #if ENABLE(XSLT) |
|
172 return !m_isXSL; |
|
173 #endif |
|
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 bool ProcessingInstruction::sheetLoaded() |
|
192 { |
|
193 if (!isLoading()) { |
|
194 document()->removePendingSheet(); |
|
195 return true; |
|
196 } |
|
197 return false; |
|
198 } |
|
199 |
|
200 void ProcessingInstruction::setCSSStyleSheet(const String& url, const String& charset, const String& sheet) |
|
201 { |
|
202 #if ENABLE(XSLT) |
|
203 ASSERT(!m_isXSL); |
|
204 #endif |
|
205 m_sheet = new CSSStyleSheet(this, url, charset); |
|
206 parseStyleSheet(sheet); |
|
207 } |
|
208 |
|
209 #if ENABLE(XSLT) |
|
210 void ProcessingInstruction::setXSLStyleSheet(const String& url, const String& sheet) |
|
211 { |
|
212 ASSERT(m_isXSL); |
|
213 m_sheet = new XSLStyleSheet(this, url); |
|
214 parseStyleSheet(sheet); |
|
215 } |
|
216 #endif |
|
217 |
|
218 void ProcessingInstruction::parseStyleSheet(const String& sheet) |
|
219 { |
|
220 m_sheet->parseString(sheet, true); |
|
221 if (m_cachedSheet) |
|
222 m_cachedSheet->deref(this); |
|
223 m_cachedSheet = 0; |
|
224 |
|
225 m_loading = false; |
|
226 m_sheet->checkLoaded(); |
|
227 } |
|
228 |
|
229 String ProcessingInstruction::toString() const |
|
230 { |
|
231 String result = "<?"; |
|
232 result += m_target; |
|
233 result += " "; |
|
234 result += m_data; |
|
235 result += "?>"; |
|
236 return result; |
|
237 } |
|
238 |
|
239 void ProcessingInstruction::setCSSStyleSheet(CSSStyleSheet* sheet) |
|
240 { |
|
241 ASSERT(!m_cachedSheet); |
|
242 ASSERT(!m_loading); |
|
243 m_sheet = sheet; |
|
244 } |
|
245 |
|
246 bool ProcessingInstruction::offsetInCharacters() const |
|
247 { |
|
248 return true; |
|
249 } |
|
250 |
|
251 } // namespace |