KHtml

html_headimpl.cpp
1 /**
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright (C) 1999 Lars Knoll ([email protected])
5  * (C) 1999 Antti Koivisto ([email protected])
6  * (C) 2001 Dirk Mueller ([email protected])
7  * (C) 2003, 2004, 2005, 2006, 2007 Apple Computer, Inc.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB. If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24 // -------------------------------------------------------------------------
25 
26 #include "html/html_headimpl.h"
27 #include "html/html_documentimpl.h"
28 #include "xml/dom_textimpl.h"
29 #include "xml/dom2_eventsimpl.h"
30 
31 #include "khtmlview.h"
32 #include "khtml_part.h"
33 
34 #include "misc/loader.h"
35 
36 #include "css/cssstyleselector.h"
37 #include "css/css_mediaquery.h"
38 
39 #include "ecma/kjs_proxy.h"
40 
41 #include <QUrl>
42 #include "khtml_debug.h"
43 
44 using namespace khtml;
45 using namespace DOM;
46 
47 NodeImpl::Id HTMLBaseElementImpl::id() const
48 {
49  return ID_BASE;
50 }
51 
52 void HTMLBaseElementImpl::parseAttribute(AttributeImpl *attr)
53 {
54  switch (attr->id()) {
55  case ATTR_HREF:
56  m_href = attr->value().trimSpaces().string();
57  process();
58  break;
59  case ATTR_TARGET:
60  m_target = attr->value();
61  process();
62  break;
63  default:
64  HTMLElementImpl::parseAttribute(attr);
65  }
66 }
67 
68 void HTMLBaseElementImpl::insertedIntoDocument()
69 {
70  HTMLElementImpl::insertedIntoDocument();
71  process();
72 }
73 
74 void HTMLBaseElementImpl::removedFromDocument()
75 {
76  HTMLElementImpl::removedFromDocument();
77 
78  // Since the document doesn't have a base element...
79  // (This will break in the case of multiple base elements, but that's not valid anyway (?))
80  document()->setBaseURL(QUrl());
81  document()->setBaseTarget(QString());
82 }
83 
84 void HTMLBaseElementImpl::process()
85 {
86  if (!inDocument()) {
87  return;
88  }
89 
90  if (!m_href.isEmpty() && document()->part()) {
91  document()->setBaseURL(QUrl(document()->part()->url()).resolved(QUrl(m_href)));
92  }
93 
94  if (!m_target.isEmpty()) {
95  document()->setBaseTarget(m_target.string());
96  }
97 
98  // ### should changing a document's base URL dynamically automatically update all images, stylesheets etc?
99 }
100 
101 // -------------------------------------------------------------------------
102 
103 HTMLLinkElementImpl::~HTMLLinkElementImpl()
104 {
105  if (m_sheet) {
106  m_sheet->deref();
107  }
108  if (m_cachedSheet) {
109  m_cachedSheet->deref(this);
110  }
111 }
112 
113 NodeImpl::Id HTMLLinkElementImpl::id() const
114 {
115  return ID_LINK;
116 }
117 
118 void HTMLLinkElementImpl::parseAttribute(AttributeImpl *attr)
119 {
120  switch (attr->id()) {
121  case ATTR_HREF: {
122  const DOMString hrefUrl = attr->value().trimSpaces();
123  if (!hrefUrl.isEmpty()) {
124  m_url = document()->completeURL(hrefUrl.string());
125  }
126  process();
127  break;
128  }
129  case ATTR_REL:
130  case ATTR_TYPE:
131  process();
132  break;
133  case ATTR_TITLE:
134  // ### when title changes we have to reconsider our alternative
135  // stylesheet choice
136  if (m_sheet) {
137  m_sheet->setTitle(attr->value());
138  }
139  break;
140  case ATTR_MEDIA:
141  m_media = attr->value().string().toLower();
142  process();
143  break;
144  case ATTR_DISABLED: {
145  bool m_oldisDisabled = m_isDisabled;
146  m_isDisabled = attr->val();
147  if (m_oldisDisabled != m_isDisabled) {
148  if (isLoading()) {
149  if (m_oldisDisabled) {
150  document()->addPendingSheet();
151  } else if (!m_alternate) {
152  document()->styleSheetLoaded();
153  }
154  }
155  if (m_oldisDisabled) {
156  // enabling: if it's an alternate sheet, pretend it's not.
157  m_alternate = false;
158  } else if (!m_alternate) {
159  // disabling: recheck alternate status
160  QString rel = getAttribute(ATTR_REL).string().toLower();
161  QString type = getAttribute(ATTR_TYPE).string().toLower();
162  m_alternate = (type.contains("text/css") || rel.contains("stylesheet")) && rel.contains("alternate");
163  }
164  if (isLoading()) {
165  break;
166  }
167  if (!m_sheet && !m_isDisabled) {
168  process();
169  if (isLoading() && m_alternate) {
170  document()->addPendingSheet();
171  }
172  m_alternate = false;
173  } else {
174  document()->updateStyleSelector(); // Update the style selector.
175  }
176  }
177  break;
178  }
179  default:
180  HTMLElementImpl::parseAttribute(attr);
181  }
182 }
183 
184 static inline bool isIconLink(const QString &relAttribute)
185 {
186  // https://www.w3.org/TR/html5/links.html#linkTypes:
187  // split rel attribute on spaces and search for "icon" keyword.
188  // note: relAttribute is supposed to be a lower case string
189  const QLatin1String icon("icon");
190  int iconPos = relAttribute.indexOf(icon);
191  while (iconPos != -1) {
192  const bool found = (iconPos == 0 || relAttribute.at(iconPos - 1).isSpace()) &&
193  (((iconPos + 4) == relAttribute.length()) || relAttribute.at(iconPos + 4).isSpace());
194  if (found) {
195  return true;
196  }
197  iconPos = relAttribute.indexOf(icon, iconPos + 5);
198  }
199 
200  return false;
201 }
202 
203 void HTMLLinkElementImpl::process()
204 {
205  if (!inDocument()) {
206  return;
207  }
208 
209  //QString type = getAttribute(ATTR_TYPE).string().toLower();
210  const QString rel = getAttribute(ATTR_REL).string().toLower();
211 
212  KHTMLPart *part = document()->part();
213 
214  // Location of small icon for locationbar / bookmarks (aka "favicon")
215  if (isIconLink(rel) && !m_url.isEmpty() && part && !part->parentPart()) {
216  part->browserExtension()->setIconUrl(QUrl(m_url.string()));
217  } // Stylesheet
218  else if (rel.contains("stylesheet") && !m_url.isEmpty() && !m_isDisabled) {
219  // no need to load style sheets which aren't for the screen output
220  // ### there may be in some situations e.g. for an editor or script to manipulate
221  khtml::MediaQueryEvaluator allEval(true);
222  khtml::MediaQueryEvaluator screenEval("screen", true);
223  khtml::MediaQueryEvaluator printEval("print", true);
224  MediaListImpl *media = new MediaListImpl((CSSStyleSheetImpl *)nullptr, m_media, true);
225  media->ref();
226  if (allEval.eval(media) || screenEval.eval(media) || printEval.eval(media)) {
227  // Add ourselves as a pending sheet, but only if we aren't an alternate
228  // stylesheet. Alternate stylesheets don't hold up render tree construction.
229  m_alternate = rel.contains("alternate");
230  if (!isAlternate()) {
231  document()->addPendingSheet();
232  }
233 
234  QString chset = getAttribute(ATTR_CHARSET).string();
235  // set chset to charset of referring document when attribute CHARSET is absent.
236  // https://www.w3.org/TR/CSS21/syndata.html(4.4)
237  if (chset.isEmpty() && part) {
238  chset = part->encoding();
239  }
240  if (m_cachedSheet) {
241  if (m_loading) {
242  document()->styleSheetLoaded();
243  }
244  m_cachedSheet->deref(this);
245  }
246  m_loading = true;
247  m_cachedSheet = document()->docLoader()->requestStyleSheet(m_url, chset);
248  if (m_cachedSheet) {
249  m_isCSSSheet = true;
250  m_cachedSheet->ref(this);
251  } else if (!isAlternate()) {
252  // Error requesting sheet; decrement pending sheet count
253  m_loading = false;
254  document()->styleSheetLoaded();
255  }
256  }
257  media->deref();
258  } else if (m_sheet) {
259  // we no longer contain a stylesheet, e.g. perhaps rel or type was changed
260  m_sheet->deref();
261  m_sheet = nullptr;
262  m_isCSSSheet = false;
263  document()->updateStyleSelector();
264  }
265 }
266 
267 void HTMLLinkElementImpl::insertedIntoDocument()
268 {
269  HTMLElementImpl::insertedIntoDocument();
270  process();
271 }
272 
273 void HTMLLinkElementImpl::removedFromDocument()
274 {
275  HTMLElementImpl::removedFromDocument();
276  document()->updateStyleSelector();
277 }
278 
279 void HTMLLinkElementImpl::setStyleSheet(const DOM::DOMString &url, const DOM::DOMString &sheetStr, const DOM::DOMString &charset, const DOM::DOMString &mimetype)
280 {
281  if (m_sheet) {
282  m_sheet->deref();
283  }
284  bool strict = !document()->inCompatMode();
285  DOMString sheet = sheetStr;
286  if (strict && !khtml::isAcceptableCSSMimetype(mimetype)) {
287  sheet = "";
288  }
289  m_sheet = new CSSStyleSheetImpl(this, url);
290  m_sheet->ref();
291  m_sheet->setCharset(charset);
292  m_sheet->parseString(sheet, strict);
293  m_sheet->setTitle(getAttribute(ATTR_TITLE));
294 
295  MediaListImpl *media = new MediaListImpl((CSSStyleSheetImpl *)nullptr, m_media);
296  m_sheet->setMedia(media);
297 
298  finished();
299 }
300 
301 void HTMLLinkElementImpl::finished()
302 {
303  m_loading = false;
304 
305  // Tell the doc about the sheet.
306  if (!isLoading() && !isDisabled() && !isAlternate()) {
307  document()->styleSheetLoaded();
308  }
309 
310  // ### major inefficiency, but currently necessary for proper
311  // alternate styles support. don't recalc the styleselector
312  // when nothing actually changed!
313  if (isAlternate() && m_sheet && !isDisabled()) {
314  document()->updateStyleSelector();
315  }
316 }
317 
318 void HTMLLinkElementImpl::error(int, const QString &)
319 {
320  finished();
321 }
322 
323 bool HTMLLinkElementImpl::isLoading() const
324 {
325 // qCDebug(KHTML_LOG) << "link: checking if loading!";
326  if (m_loading) {
327  return true;
328  }
329  if (!m_sheet) {
330  return false;
331  }
332  //if(!m_sheet->isCSSStyleSheet()) return false;
333  return static_cast<CSSStyleSheetImpl *>(m_sheet)->isLoading();
334 }
335 
336 bool HTMLLinkElementImpl::checkAddPendingSheet()
337 {
338  if (!isLoading() && !isDisabled() && !isAlternate()) {
339  document()->addPendingSheet();
340  return true;
341  }
342  return false;
343 }
344 
345 bool HTMLLinkElementImpl::checkRemovePendingSheet()
346 {
347  if (!isLoading() && !isDisabled() && !isAlternate()) {
348  document()->styleSheetLoaded();
349  return true;
350  }
351  return false;
352 }
353 
354 // -------------------------------------------------------------------------
355 
356 NodeImpl::Id HTMLMetaElementImpl::id() const
357 {
358  return ID_META;
359 }
360 
361 void HTMLMetaElementImpl::parseAttribute(AttributeImpl *attr)
362 {
363  switch (attr->id()) {
364  case ATTR_HTTP_EQUIV:
365  m_equiv = attr->value();
366  process();
367  break;
368  case ATTR_CONTENT:
369  m_content = attr->value();
370  process();
371  break;
372  default:
373  HTMLElementImpl::parseAttribute(attr);
374  }
375 }
376 
377 void HTMLMetaElementImpl::insertedIntoDocument()
378 {
379  HTMLElementImpl::insertedIntoDocument();
380  process();
381 }
382 
383 void HTMLMetaElementImpl::process()
384 {
385  // Get the document to process the tag, but only if we're actually part of DOM tree (changing a meta tag while
386  // it's not in the tree shouldn't have any effect on the document)
387  if (inDocument() && !m_equiv.isNull() && !m_content.isNull()) {
388  document()->processHttpEquiv(m_equiv, m_content);
389  }
390 }
391 
392 // -------------------------------------------------------------------------
393 
394 HTMLScriptElementImpl::HTMLScriptElementImpl(DocumentImpl *doc)
395  : HTMLElementImpl(doc), m_cachedScript(nullptr), m_createdByParser(false), m_evaluated(false), m_hasNonEmptyForAttribute(false)
396 {
397 }
398 
399 HTMLScriptElementImpl::~HTMLScriptElementImpl()
400 {
401  if (m_cachedScript) {
402  m_cachedScript->deref(this);
403  }
404 }
405 
406 NodeImpl::Id HTMLScriptElementImpl::id() const
407 {
408  return ID_SCRIPT;
409 }
410 
411 void HTMLScriptElementImpl::parseAttribute(AttributeImpl *attr)
412 {
413  switch (attr->id()) {
414  case ATTR_ONLOAD:
415  setHTMLEventListener(EventImpl::LOAD_EVENT,
416  document()->createHTMLEventListener(attr->value().string(), "onload", this));
417  break;
418  case ATTR_SRC: {
419  // We want to evaluate scripts on src attr change when a fresh script element
420  // is inserted into document, and then has its source changed -after-.
421  // If the source is manipulated while we're outside the document,
422  // we'll only start doing things once we get insertedIntoDocument()
423  if (m_evaluated || m_cachedScript || m_createdByParser || !inDocument()) {
424  return;
425  }
426  const DOMString url = attr->value().trimSpaces();
427  if (!url.isEmpty()) {
428  loadFromUrl(url);
429  }
430  break;
431  }
432  case ATTR_FOR: {
433  m_hasNonEmptyForAttribute = !attr->value().isEmpty();
434  break;
435  }
436  default:
437  HTMLElementImpl::parseAttribute(attr);
438  }
439 }
440 
441 bool HTMLScriptElementImpl::isURLAttribute(AttributeImpl *attr) const
442 {
443  return attr->id() == ATTR_SRC;
444 }
445 
446 bool HTMLScriptElementImpl::isValidScript() const
447 {
448  // HTML5 draft 4.3.1 : script elements with non-empty for attribute
449  // must not be executed.
450  if (m_hasNonEmptyForAttribute) {
451  return false;
452  }
453 
454  // Check type before language, since language is deprecated
455  /*
456  Mozilla 1.5 doesn't accept the text/javascript1.x formats, but WinIE 6 does.
457  Mozilla 1.5 doesn't accept text/jscript, text/ecmascript, and text/livescript, but WinIE 6 does.
458  Mozilla 1.5 accepts application/x-javascript, WinIE 6 doesn't.
459  Mozilla 1.5 allows leading and trailing whitespace, but WinIE 6 doesn't.
460  Mozilla 1.5 and WinIE 6 both accept the empty string, but neither accept a whitespace-only string.
461  We want to accept all the values that either of these browsers accept, but not other values.
462  */
463  QString type = getAttribute(ATTR_TYPE).string().toLower();
464 
465  // Gecko accepts initial/trailing whitespace around the mimetype.
466  // Whitespace only, however, musn't trigger execution.
467  int length = type.length();
468  type = type.trimmed();
469  if (length)
470  return !(type.compare("text/javascript") != 0 &&
471  type.compare("text/javascript1.0") != 0 &&
472  type.compare("text/javascript1.1") != 0 &&
473  type.compare("text/javascript1.2") != 0 &&
474  type.compare("text/javascript1.3") != 0 &&
475  type.compare("text/javascript1.4") != 0 &&
476  type.compare("text/javascript1.5") != 0 &&
477  type.compare("text/jscript") != 0 &&
478  type.compare("text/ecmascript") != 0 &&
479  type.compare("text/livescript") != 0 &&
480  type.compare("application/x-javascript") != 0 &&
481  type.compare("application/x-ecmascript") != 0 &&
482  type.compare("application/javascript") != 0 &&
483  type.compare("application/ecmascript") != 0);
484 
485  /*
486  Mozilla 1.5 doesn't accept jscript or ecmascript, but WinIE 6 does.
487  Mozilla 1.5 accepts javascript1.0, javascript1.4, and javascript1.5, but WinIE 6 accepts only 1.1 - 1.3.
488  Neither Mozilla 1.5 nor WinIE 6 accept leading or trailing whitespace.
489  We want to accept all the values that either of these browsers accept, but not other values.
490  */
491  QString lang = getAttribute(ATTR_LANGUAGE).string().toLower();
492  if (!lang.isEmpty())
493  return !(lang.compare("javascript") != 0 &&
494  lang.compare("javascript1.0") != 0 &&
495  lang.compare("javascript1.1") != 0 &&
496  lang.compare("javascript1.2") != 0 &&
497  lang.compare("javascript1.3") != 0 &&
498  lang.compare("javascript1.4") != 0 &&
499  lang.compare("javascript1.5") != 0 &&
500  lang.compare("ecmascript") != 0 &&
501  lang.compare("livescript") != 0 &&
502  lang.compare("jscript"));
503 
504  return true;
505 }
506 
507 void HTMLScriptElementImpl::childrenChanged()
508 {
509  // If a node is inserted as a child of the script element
510  // and the script element has been inserted in the document
511  // we evaluate the script.
512  if (!m_createdByParser && inDocument() && firstChild()) {
513  evaluateScript(document()->URL().url(), text());
514  }
515 }
516 
517 void HTMLScriptElementImpl::loadFromUrl(const DOMString &url)
518 {
519  QString charset = getAttribute(ATTR_CHARSET).string();
520  m_cachedScript = document()->docLoader()->requestScript(url, charset);
521  if (m_cachedScript) {
522  m_cachedScript->ref(this);
523  }
524 }
525 
526 void HTMLScriptElementImpl::insertedIntoDocument()
527 {
528  HTMLElementImpl::insertedIntoDocument();
529 
530  assert(!m_cachedScript);
531 
532  if (m_createdByParser) {
533  return;
534  }
535 
536  const DOMString url = getAttribute(ATTR_SRC).trimSpaces();
537  if (!url.isEmpty()) {
538  loadFromUrl(url);
539  return;
540  }
541 
542  // If there's an empty script node, we shouldn't evaluate the script
543  // because if a script is inserted afterwards (by setting text or innerText)
544  // it should be evaluated, and evaluateScript only evaluates a script once.
545  DOMString scriptString = text();
546  if (!scriptString.isEmpty()) {
547  evaluateScript(document()->URL().url(), scriptString);
548  }
549 }
550 
551 void HTMLScriptElementImpl::removedFromDocument()
552 {
553  HTMLElementImpl::removedFromDocument();
554 
555  if (m_cachedScript) {
556  m_cachedScript->deref(this);
557  m_cachedScript = nullptr;
558  }
559 }
560 
561 void HTMLScriptElementImpl::notifyFinished(CachedObject *o)
562 {
563  CachedScript *cs = static_cast<CachedScript *>(o);
564 
565  assert(cs == m_cachedScript);
566 
567  QString URL = cs->url().string();
568  DOMString script = cs->script();
569  cs->deref(this);
570  m_cachedScript = nullptr;
571 
572  ref(); // Pin so we don't destroy oursleves.
573  if (!cs->hadError()) {
574  evaluateScript(URL, script);
575  dispatchHTMLEvent(EventImpl::LOAD_EVENT, false, false);
576  }
577  deref();
578 }
579 
580 void HTMLScriptElementImpl::evaluateScript(const QString &URL, const DOMString &script)
581 {
582  if (m_evaluated || !isValidScript()) {
583  return;
584  }
585 
586  KHTMLPart *part = document()->part();
587  if (part) {
588  KJSProxy *proxy = KJSProxy::proxy(part);
589  if (proxy) {
590  m_evaluated = true;
591  proxy->evaluate(URL, 0, script.string(), nullptr);
592  DocumentImpl::updateDocumentsRendering();
593  }
594  }
595 }
596 
597 DOMString HTMLScriptElementImpl::text() const
598 {
599  DOMString val = "";
600 
601  for (NodeImpl *n = firstChild(); n; n = n->nextSibling()) {
602  if (n->isTextNode()) {
603  val += static_cast<TextImpl *>(n)->data();
604  }
605  }
606 
607  return val;
608 }
609 
610 void HTMLScriptElementImpl::setText(const DOMString &value)
611 {
612  int exceptioncode = 0;
613  int numChildren = childNodeCount();
614 
615  if (numChildren == 1 && firstChild()->isTextNode()) {
616  static_cast<DOM::TextImpl *>(firstChild())->setData(value, exceptioncode);
617  return;
618  }
619 
620  if (numChildren > 0) {
621  removeChildren();
622  }
623 
624  appendChild(document()->createTextNode(value.implementation()), exceptioncode);
625 }
626 
627 DOMString HTMLScriptElementImpl::htmlFor() const
628 {
629  // DOM Level 1 says: reserved for future use.
630  return DOMString();
631 }
632 
633 void HTMLScriptElementImpl::setHtmlFor(const DOMString &/*value*/)
634 {
635  // DOM Level 1 says: reserved for future use.
636 }
637 
638 DOMString HTMLScriptElementImpl::event() const
639 {
640  // DOM Level 1 says: reserved for future use.
641  return DOMString();
642 }
643 
644 void HTMLScriptElementImpl::setEvent(const DOMString &/*value*/)
645 {
646  // DOM Level 1 says: reserved for future use.
647 }
648 
649 DOMString HTMLScriptElementImpl::charset() const
650 {
651  return getAttribute(ATTR_CHARSET);
652 }
653 
654 void HTMLScriptElementImpl::setCharset(const DOMString &value)
655 {
656  setAttribute(ATTR_CHARSET, value);
657 }
658 
659 bool HTMLScriptElementImpl::defer() const
660 {
661  return !getAttribute(ATTR_DEFER).isNull();
662 }
663 
664 void HTMLScriptElementImpl::setDefer(bool defer)
665 {
666  setAttribute(ATTR_DEFER, defer ? "" : nullptr);
667 }
668 
669 DOMString HTMLScriptElementImpl::src() const
670 {
671  return document()->completeURL(getAttribute(ATTR_SRC).trimSpaces().string());
672 }
673 
674 void HTMLScriptElementImpl::setSrc(const DOMString &value)
675 {
676  setAttribute(ATTR_SRC, value);
677 }
678 
679 DOMString HTMLScriptElementImpl::type() const
680 {
681  return getAttribute(ATTR_TYPE);
682 }
683 
684 void HTMLScriptElementImpl::setType(const DOMString &value)
685 {
686  setAttribute(ATTR_TYPE, value);
687 }
688 
689 // -------------------------------------------------------------------------
690 
691 HTMLStyleElementImpl::~HTMLStyleElementImpl()
692 {
693  if (m_sheet) {
694  m_sheet->deref();
695  }
696 }
697 
698 NodeImpl::Id HTMLStyleElementImpl::id() const
699 {
700  return ID_STYLE;
701 }
702 
703 // other stuff...
704 void HTMLStyleElementImpl::parseAttribute(AttributeImpl *attr)
705 {
706  switch (attr->id()) {
707  case ATTR_TYPE:
708  m_type = attr->value().lower();
709  break;
710  case ATTR_MEDIA:
711  m_media = attr->value().string().toLower();
712  break;
713  case ATTR_TITLE:
714  if (m_sheet) {
715  m_sheet->setTitle(attr->value());
716  }
717  break;
718  default:
719  HTMLElementImpl::parseAttribute(attr);
720  }
721 }
722 
723 void HTMLStyleElementImpl::insertedIntoDocument()
724 {
725  HTMLElementImpl::insertedIntoDocument();
726 
727  // If we're empty, we have to call parseText here, since we won't get childrenChanged();
728  // but we still want a CSSOM object
729  if (!firstChild()) {
730  parseText();
731  }
732 
733  if (m_sheet) {
734  document()->updateStyleSelector();
735  }
736 }
737 
738 void HTMLStyleElementImpl::removedFromDocument()
739 {
740  HTMLElementImpl::removedFromDocument();
741  if (m_sheet) {
742  document()->updateStyleSelector();
743  }
744 }
745 
746 void HTMLStyleElementImpl::childrenChanged()
747 {
748  HTMLElementImpl::childrenChanged();
749 
750  parseText();
751 }
752 
753 void HTMLStyleElementImpl::parseText()
754 {
755  DOMString text = "";
756 
757  for (NodeImpl *c = firstChild(); c != nullptr; c = c->nextSibling()) {
758  if ((c->nodeType() == Node::TEXT_NODE) ||
759  (c->nodeType() == Node::CDATA_SECTION_NODE) ||
760  (c->nodeType() == Node::COMMENT_NODE)) {
761  text += c->nodeValue();
762  }
763  }
764 
765  if (m_sheet) {
766  m_sheet->deref();
767  m_sheet = nullptr;
768  }
769 
770  m_loading = false;
771  if (m_type.isEmpty() || m_type == "text/css") { // Type must be empty or CSS
772  MediaListImpl *media = new MediaListImpl((CSSStyleSheetImpl *)nullptr, m_media, true);
773  media->ref();
774  khtml::MediaQueryEvaluator screenEval("screen", true);
775  khtml::MediaQueryEvaluator printEval("print", true);
776  if (screenEval.eval(media) || printEval.eval(media)) {
777  document()->addPendingSheet();
778  m_loading = true;
779  m_sheet = new CSSStyleSheetImpl(this);
780  m_sheet->ref();
781  m_sheet->parseString(text, !document()->inCompatMode());
782  m_sheet->setMedia(media);
783  m_sheet->setTitle(getAttribute(ATTR_TITLE));
784  m_loading = false;
785  }
786  media->deref();
787  }
788 
789  if (!isLoading() && m_sheet) {
790  document()->styleSheetLoaded();
791  }
792 }
793 
794 bool HTMLStyleElementImpl::isLoading() const
795 {
796  if (m_loading) {
797  return true;
798  }
799  if (!m_sheet) {
800  return false;
801  }
802  return static_cast<CSSStyleSheetImpl *>(m_sheet)->isLoading();
803 }
804 
805 bool HTMLStyleElementImpl::checkRemovePendingSheet()
806 {
807  if (!isLoading()) {
808  document()->styleSheetLoaded();
809  return true;
810  }
811  return false;
812 }
813 
814 bool HTMLStyleElementImpl::checkAddPendingSheet()
815 {
816  if (!isLoading()) {
817  document()->addPendingSheet();
818  return true;
819  }
820  return false;
821 }
822 
823 // -------------------------------------------------------------------------
824 
825 NodeImpl::Id HTMLTitleElementImpl::id() const
826 {
827  return ID_TITLE;
828 }
829 
830 void HTMLTitleElementImpl::childrenChanged()
831 {
832  HTMLElementImpl::childrenChanged();
833 
834  m_title = "";
835  for (NodeImpl *c = firstChild(); c != nullptr; c = c->nextSibling()) {
836  if ((c->nodeType() == Node::TEXT_NODE) || (c->nodeType() == Node::CDATA_SECTION_NODE)) {
837  m_title += c->nodeValue();
838  }
839  }
840  if (!m_title.isEmpty() && inDocument()) {
841  document()->setTitle(m_title);
842  }
843 }
844 
845 DOMString HTMLTitleElementImpl::text()
846 {
847  if (firstChild() && firstChild()->nodeType() == Node::TEXT_NODE) {
848  return firstChild()->nodeValue();
849  }
850  return "";
851 }
852 
853 void HTMLTitleElementImpl::setText(const DOMString &str)
854 {
855  int exceptioncode = 0;
856  RefPtr<DOM::NodeListImpl> nl = childNodes();
857  const unsigned int length = nl->length();
858  for (unsigned int i = 0; i < length; ++i) {
859  if (nl->item(i)->nodeType() == DOM::Node::TEXT_NODE) {
860  static_cast<DOM::TextImpl *>(nl->item(i))->setData(str, exceptioncode);
861  return;
862  }
863  }
864 
865  // No child text node found, creating one
866  DOM::TextImpl *t = document()->createTextNode(str.implementation());
867  appendChild(t, exceptioncode);
868 }
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
void setIconUrl(const QUrl &url)
Node appendChild(const Node &newChild)
Adds the node newChild to the end of the list of children of this node.
Definition: dom_node.cpp:354
DOMString lang() const
Language code defined in RFC 1766.
This file is part of the HTML rendering engine for KDE.
Proxy class serving as interface when being dlopen&#39;ed.
Definition: kjs_proxy.h:61
This class is khtml&#39;s main class.
Definition: khtml_part.h:208
void ref()
NodeList childNodes() const
A NodeList that contains all children of this node.
Definition: dom_node.cpp:258
void setAttribute(const DOMString &name, const DOMString &value)
Adds a new attribute.
bool isSpace() const const
void deref()
Type type(const QSqlDatabase &db)
DOMString text() const
The specified title as a string.
Definition: html_head.cpp:596
KParts::BrowserExtension * browserExtension() const
Returns a pointer to the KParts::BrowserExtension.
bool isEmpty() const const
QString trimmed() const const
This class implements the basic string we use in the DOM.
Definition: dom_string.h:44
DOMString nodeValue() const
The value of this node, depending on its type; see the table above.
Definition: dom_node.cpp:218
QString toLower() const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
Node firstChild() const
The first child of this node.
Definition: dom_node.cpp:266
This library provides a full-featured HTML parser and widget.
Class that evaluates css media queries as defined in CSS3 Module "Media Queries" (https://www.w3.org/TR/css3-mediaqueries/) Special constructors are needed, if simple media queries are to be evaluated without knowledge of the medium features.
DOMString getAttribute(const DOMString &name)
Retrieves an attribute value by name.
const QChar at(int position) const const
int length() const const
DOMStringImpl * implementation() const
Definition: dom_string.h:145
int compare(const QString &other, Qt::CaseSensitivity cs) const const
a cached script
Definition: loader.h:322
Node nextSibling() const
The node immediately following this node.
Definition: dom_node.cpp:290
KHTMLPart * parentPart()
Returns a pointer to the parent KHTMLPart if the part is a frame in an HTML frameset.
DOMString trimSpaces() const
Returns a string with Space Characters removed from the start and the end.
Definition: dom_string.cpp:345
unsigned short nodeType() const
A code representing the type of the underlying object, as defined above.
Definition: dom_node.cpp:242
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Oct 26 2021 22:48:02 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.