1 /**
2 * This file is part of the DOM implementation for KDE.
3 *
4 * Copyright 1999-2003 Lars Knoll (knoll@kde.org)
5 * Copyright 2002-2003 Dirk Mueller (mueller@kde.org)
6 * Copyright 2002-2008 Apple Computer, Inc.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24 #include "css_ruleimpl.h"
25 #include "css_stylesheetimpl.h"
26 #include "css_valueimpl.h"
27 #include "cssparser.h"
28
29 #include <dom/css_rule.h>
30 #include <dom/css_stylesheet.h>
31 #include <dom/dom_exception.h>
32 #include <dom/dom_string.h>
33
34 #include <xml/dom_docimpl.h>
35
36 using namespace DOM;
37
parentStyleSheet() const38 CSSStyleSheetImpl *CSSRuleImpl::parentStyleSheet() const
39 {
40 return (m_parent && m_parent->isCSSStyleSheet()) ?
41 static_cast<CSSStyleSheetImpl *>(m_parent) : nullptr;
42 }
43
parentRule() const44 CSSRuleImpl *CSSRuleImpl::parentRule() const
45 {
46 return (m_parent && m_parent->isRule()) ?
47 static_cast<CSSRuleImpl *>(m_parent) : nullptr;
48 }
49
cssText() const50 DOM::DOMString CSSRuleImpl::cssText() const
51 {
52 // ###
53 return DOMString();
54 }
55
setCssText(DOM::DOMString)56 void CSSRuleImpl::setCssText(DOM::DOMString /*str*/)
57 {
58 // ###
59 }
60
61 // ---------------------------------------------------------------------------
62
CSSFontFaceRuleImpl(StyleBaseImpl * parent)63 CSSFontFaceRuleImpl::CSSFontFaceRuleImpl(StyleBaseImpl *parent)
64 : CSSRuleImpl(parent)
65 {
66 m_type = CSSRule::FONT_FACE_RULE;
67 m_style = nullptr;
68 }
69
~CSSFontFaceRuleImpl()70 CSSFontFaceRuleImpl::~CSSFontFaceRuleImpl()
71 {
72 if (m_style) {
73 m_style->deref();
74 }
75 }
76
setDeclaration(CSSStyleDeclarationImpl * decl)77 void CSSFontFaceRuleImpl::setDeclaration(CSSStyleDeclarationImpl *decl)
78 {
79 assert(!m_style);
80 m_style = decl;
81 if (m_style) {
82 m_style->ref();
83 }
84 }
85
cssText() const86 DOMString CSSFontFaceRuleImpl::cssText() const
87 {
88 DOMString result("@font-face");
89
90 result += " { ";
91 result += m_style->cssText();
92 result += "}";
93
94 return result;
95 }
96
97 // --------------------------------------------------------------------------
98
CSSImportRuleImpl(StyleBaseImpl * parent,const DOM::DOMString & href,MediaListImpl * media)99 CSSImportRuleImpl::CSSImportRuleImpl(StyleBaseImpl *parent,
100 const DOM::DOMString &href,
101 MediaListImpl *media)
102 : CSSRuleImpl(parent)
103 {
104 m_type = CSSRule::IMPORT_RULE;
105
106 m_lstMedia = media;
107 if (!m_lstMedia) {
108 m_lstMedia = new MediaListImpl(this, DOMString());
109 }
110 m_lstMedia->setParent(this);
111 m_lstMedia->ref();
112
113 m_strHref = href;
114 m_styleSheet = nullptr;
115
116 m_cachedSheet = nullptr;
117
118 init();
119 }
CSSImportRuleImpl(StyleBaseImpl * parent,const DOM::DOMString & href,const DOM::DOMString & media)120 CSSImportRuleImpl::CSSImportRuleImpl(StyleBaseImpl *parent,
121 const DOM::DOMString &href,
122 const DOM::DOMString &media)
123 : CSSRuleImpl(parent)
124 {
125 m_type = CSSRule::IMPORT_RULE;
126
127 m_lstMedia = new MediaListImpl(this, media);
128 m_lstMedia->ref();
129
130 m_strHref = href;
131 m_styleSheet = nullptr;
132
133 m_cachedSheet = nullptr;
134
135 init();
136 }
137
~CSSImportRuleImpl()138 CSSImportRuleImpl::~CSSImportRuleImpl()
139 {
140 if (m_lstMedia) {
141 m_lstMedia->setParent(nullptr);
142 m_lstMedia->deref();
143 }
144 if (m_styleSheet) {
145 m_styleSheet->setParent(nullptr);
146 m_styleSheet->deref();
147 }
148
149 if (m_cachedSheet) {
150 m_cachedSheet->deref(this);
151 }
152 }
153
checkLoaded() const154 void CSSImportRuleImpl::checkLoaded() const
155 {
156 if (isLoading()) {
157 return;
158 }
159 CSSRuleImpl::checkLoaded();
160 }
161
setStyleSheet(const DOM::DOMString & url,const DOM::DOMString & sheetStr,const DOM::DOMString & charset,const DOM::DOMString & mimetype)162 void CSSImportRuleImpl::setStyleSheet(const DOM::DOMString &url, const DOM::DOMString &sheetStr, const DOM::DOMString &charset, const DOM::DOMString &mimetype)
163 {
164 if (m_styleSheet) {
165 m_styleSheet->setParent(nullptr);
166 m_styleSheet->deref();
167 }
168 m_styleSheet = new CSSStyleSheetImpl(this, url);
169 m_styleSheet->setCharset(charset);
170 m_styleSheet->ref();
171
172 CSSStyleSheetImpl *parent = parentStyleSheet();
173 bool strict = parent ? parent->useStrictParsing() : true;
174 DOMString sheet = sheetStr;
175 if (strict && !khtml::isAcceptableCSSMimetype(mimetype)) {
176 sheet = "";
177 }
178 m_styleSheet->parseString(sheet, strict);
179 m_loading = false;
180 m_done = true;
181
182 checkLoaded();
183 }
184
error(int,const QString &)185 void CSSImportRuleImpl::error(int /*err*/, const QString &/*text*/)
186 {
187 if (m_styleSheet) {
188 m_styleSheet->setParent(nullptr);
189 m_styleSheet->deref();
190 }
191 m_styleSheet = nullptr;
192
193 m_loading = false;
194 m_done = true;
195
196 checkLoaded();
197 }
198
isLoading() const199 bool CSSImportRuleImpl::isLoading() const
200 {
201 return (m_loading || (m_styleSheet && m_styleSheet->isLoading()));
202 }
203
init()204 void CSSImportRuleImpl::init()
205 {
206 m_loading = 0;
207 m_done = false;
208 khtml::DocLoader *docLoader = nullptr;
209 StyleBaseImpl *root = this;
210 StyleBaseImpl *parent;
211 while ((parent = root->parent())) {
212 root = parent;
213 }
214 if (root->isCSSStyleSheet()) {
215 docLoader = static_cast<CSSStyleSheetImpl *>(root)->docLoader();
216 }
217
218 DOMString absHref = m_strHref;
219 CSSStyleSheetImpl *parentSheet = parentStyleSheet();
220 if (!parentSheet->href().isNull()) {
221 // use parent styleheet's URL as the base URL
222 absHref = QUrl(parentSheet->href().string()).resolved(QUrl(m_strHref.string())).toString();
223 }
224 /*
225 else {
226 // use documents's URL as the base URL
227 DocumentImpl *doc = static_cast<CSSStyleSheetImpl*>(root)->doc();
228 absHref = QUrl(doc->URL()).resolved(QUrl(m_strHref.string())).toString();
229 }
230 */
231 // Check for a cycle in our import chain. If we encounter a stylesheet
232 // in our parent chain with the same URL, then just bail.
233 for (parent = static_cast<StyleBaseImpl *>(this)->parent();
234 parent;
235 parent = parent->parent())
236 if (absHref == parent->baseURL().url()) {
237 return;
238 }
239
240 m_cachedSheet = docLoader->requestStyleSheet(absHref, parentStyleSheet()->charset().string());
241
242 if (m_cachedSheet) {
243 // if the import rule is issued dynamically, the sheet may have already been
244 // removed from the pending sheet count, so let the doc know
245 // the sheet being imported is pending.
246 checkPending();
247
248 m_loading = true;
249 m_cachedSheet->ref(this);
250 }
251 }
252
cssText() const253 DOMString CSSImportRuleImpl::cssText() const
254 {
255 DOMString result = "@import url(\"";
256 result += m_strHref;
257 result += "\")";
258
259 if (m_lstMedia) {
260 result += " ";
261 result += m_lstMedia->mediaText();
262 }
263 result += ";";
264
265 return result;
266 }
267
268 // --------------------------------------------------------------------------
CSSMediaRuleImpl(StyleBaseImpl * parent,MediaListImpl * mediaList,CSSRuleListImpl * ruleList)269 CSSMediaRuleImpl::CSSMediaRuleImpl(StyleBaseImpl *parent, MediaListImpl *mediaList, CSSRuleListImpl *ruleList)
270 : CSSRuleImpl(parent)
271 {
272 m_type = CSSRule::MEDIA_RULE;
273 m_lstMedia = mediaList;
274 if (m_lstMedia) {
275 m_lstMedia->ref();
276 }
277 m_lstCSSRules = ruleList;
278 m_lstCSSRules->ref();
279 }
280
CSSMediaRuleImpl(StyleBaseImpl * parent)281 CSSMediaRuleImpl::CSSMediaRuleImpl(StyleBaseImpl *parent)
282 : CSSRuleImpl(parent)
283 {
284 m_type = CSSRule::MEDIA_RULE;
285 m_lstMedia = nullptr;
286 m_lstCSSRules = new CSSRuleListImpl();
287 m_lstCSSRules->ref();
288 }
289
CSSMediaRuleImpl(StyleBaseImpl * parent,const DOM::DOMString & media)290 CSSMediaRuleImpl::CSSMediaRuleImpl(StyleBaseImpl *parent, const DOM::DOMString &media)
291 : CSSRuleImpl(parent)
292 {
293 m_type = CSSRule::MEDIA_RULE;
294 m_lstMedia = new MediaListImpl(this, media);
295 m_lstMedia->ref();
296 m_lstCSSRules = new CSSRuleListImpl();
297 m_lstCSSRules->ref();
298 }
299
~CSSMediaRuleImpl()300 CSSMediaRuleImpl::~CSSMediaRuleImpl()
301 {
302 if (m_lstMedia) {
303 m_lstMedia->setParent(nullptr);
304 m_lstMedia->deref();
305 }
306 for (unsigned int i = 0; i < m_lstCSSRules->length(); ++i) {
307 m_lstCSSRules->item(i)->setParent(nullptr);
308 }
309 m_lstCSSRules->deref();
310 }
311
append(CSSRuleImpl * rule)312 unsigned long CSSMediaRuleImpl::append(CSSRuleImpl *rule)
313 {
314 return rule ? m_lstCSSRules->insertRule(rule, m_lstCSSRules->length()) : 0;
315 }
316
insertRule(const DOMString & rule,unsigned long index)317 unsigned long CSSMediaRuleImpl::insertRule(const DOMString &rule,
318 unsigned long index)
319 {
320 CSSParser p(strictParsing);
321 CSSRuleImpl *newRule = p.parseRule(parentStyleSheet(), rule);
322
323 return newRule ? m_lstCSSRules->insertRule(newRule, index) : 0;
324 }
325
cssText() const326 DOM::DOMString CSSMediaRuleImpl::cssText() const
327 {
328 DOMString result("@media ");
329 if (m_lstMedia) {
330 result += m_lstMedia->mediaText();
331 result += " ";
332 }
333 result += "{ \n";
334
335 if (m_lstCSSRules) {
336 unsigned len = m_lstCSSRules->length();
337 for (unsigned i = 0; i < len; i++) {
338 result += " ";
339 result += m_lstCSSRules->item(i)->cssText();
340 result += "\n";
341 }
342 }
343
344 result += "}";
345 return result;
346 }
347
348 // ---------------------------------------------------------------------------
349
CSSPageRuleImpl(StyleBaseImpl * parent)350 CSSPageRuleImpl::CSSPageRuleImpl(StyleBaseImpl *parent)
351 : CSSRuleImpl(parent)
352 {
353 m_type = CSSRule::PAGE_RULE;
354 m_style = nullptr;
355 }
356
~CSSPageRuleImpl()357 CSSPageRuleImpl::~CSSPageRuleImpl()
358 {
359 if (m_style) {
360 m_style->deref();
361 }
362 }
363
selectorText() const364 DOM::DOMString CSSPageRuleImpl::selectorText() const
365 {
366 // ###
367 return DOMString();
368 }
369
setSelectorText(DOM::DOMString)370 void CSSPageRuleImpl::setSelectorText(DOM::DOMString /*str*/)
371 {
372 // ###
373 }
374
375 // --------------------------------------------------------------------------
376
CSSStyleRuleImpl(StyleBaseImpl * parent)377 CSSStyleRuleImpl::CSSStyleRuleImpl(StyleBaseImpl *parent)
378 : CSSRuleImpl(parent)
379 {
380 m_type = CSSRule::STYLE_RULE;
381 m_style = nullptr;
382 m_selector = nullptr;
383 }
384
~CSSStyleRuleImpl()385 CSSStyleRuleImpl::~CSSStyleRuleImpl()
386 {
387 if (m_style) {
388 m_style->setParent(nullptr);
389 m_style->deref();
390 }
391 qDeleteAll(*m_selector);
392 delete m_selector;
393 }
394
cssText() const395 DOMString CSSStyleRuleImpl::cssText() const
396 {
397 DOMString result(selectorText());
398
399 result += " { ";
400 result += m_style->cssText();
401 result += "}";
402
403 return result;
404 }
405
selectorText() const406 DOM::DOMString CSSStyleRuleImpl::selectorText() const
407 {
408 if (m_selector) {
409 DOMString str;
410 foreach (CSSSelector *s, *m_selector) {
411 if (s != m_selector->at(0)) {
412 str += ", ";
413 }
414 str += s->selectorText();
415 }
416 return str;
417 }
418 return DOMString();
419 }
420
setSelectorText(DOM::DOMString)421 void CSSStyleRuleImpl::setSelectorText(DOM::DOMString /*str*/)
422 {
423 // ###
424 }
425
parseString(const DOMString &,bool)426 bool CSSStyleRuleImpl::parseString(const DOMString &/*string*/, bool)
427 {
428 // ###
429 return false;
430 }
431
setDeclaration(CSSStyleDeclarationImpl * style)432 void CSSStyleRuleImpl::setDeclaration(CSSStyleDeclarationImpl *style)
433 {
434 if (m_style != style) {
435 if (m_style) {
436 m_style->deref();
437 }
438 m_style = style;
439 if (m_style) {
440 m_style->ref();
441 }
442 }
443 }
444
445 // --------------------------------------------------------------------
446
CSSNamespaceRuleImpl(StyleBaseImpl * parent,const DOMString & prefix,const DOMString & ns)447 CSSNamespaceRuleImpl::CSSNamespaceRuleImpl(StyleBaseImpl *parent, const DOMString &prefix, const DOMString &ns)
448 : CSSRuleImpl(parent)
449 {
450 m_type = CSSRule::NAMESPACE_RULE;
451 m_prefix = prefix;
452 m_namespace = ns;
453 }
454
455 // --------------------------------------------------------------------
456
CSSRuleListImpl(StyleListImpl * const list,bool omitCharsetRules)457 CSSRuleListImpl::CSSRuleListImpl(StyleListImpl *const list, bool omitCharsetRules)
458 {
459 m_list = list;
460 if (list && omitCharsetRules) {
461 m_list = nullptr;
462 unsigned len = list->length();
463 for (unsigned i = 0; i < len; ++i) {
464 StyleBaseImpl *rule = list->item(i);
465 if (rule->isRule() && !rule->isCharsetRule()) {
466 append(static_cast<CSSRuleImpl *>(rule));
467 }
468 }
469 } else if (m_list) {
470 m_list->ref();
471 }
472 }
473
~CSSRuleListImpl()474 CSSRuleListImpl::~CSSRuleListImpl()
475 {
476 CSSRuleImpl *rule;
477 while (!m_lstCSSRules.isEmpty() && (rule = m_lstCSSRules.takeFirst())) {
478 rule->deref();
479 }
480 if (m_list) {
481 m_list->deref();
482 }
483 }
484
length() const485 unsigned long CSSRuleListImpl::length() const
486 {
487 return m_list ? m_list->length() : m_lstCSSRules.count();
488 }
489
item(unsigned long index)490 CSSRuleImpl *CSSRuleListImpl::item(unsigned long index)
491 {
492 if (m_list) {
493 StyleBaseImpl *rule = m_list->item(index);
494 assert(!rule || rule->isRule());
495 return static_cast<CSSRuleImpl *>(rule);
496 }
497 return index < length() ? m_lstCSSRules.at(index) : nullptr;
498 }
499
deleteRule(unsigned long index)500 void CSSRuleListImpl::deleteRule(unsigned long index)
501 {
502 assert(!m_list);
503 if (index + 1 > (unsigned) m_lstCSSRules.size()) {
504 return;
505 // ### Throw INDEX_SIZE_ERR exception here (TODO)
506 }
507 CSSRuleImpl *rule = m_lstCSSRules.takeAt(index);
508 rule->deref();
509 }
510
append(CSSRuleImpl * rule)511 void CSSRuleListImpl::append(CSSRuleImpl *rule)
512 {
513 assert(!m_list);
514 rule->ref();
515 m_lstCSSRules.append(rule);
516 }
517
insertRule(CSSRuleImpl * rule,unsigned long index)518 unsigned long CSSRuleListImpl::insertRule(CSSRuleImpl *rule,
519 unsigned long index)
520 {
521 assert(!m_list);
522 if (index > (unsigned) m_lstCSSRules.size()) {
523 return 0;
524 // ### Throw INDEX_SIZE_ERR exception here (TODO)
525 }
526
527 if (rule) {
528 m_lstCSSRules.insert(index, rule);
529 rule->ref();
530 return index;
531 }
532
533 return 0;
534 }
535
536