webengine/osswebengine/WebCore/html/HTMLLinkElement.cpp
changeset 0 dd21522fd290
child 27 6297cdf66332
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /**
       
     2  * This file is part of the DOM implementation for KDE.
       
     3  *
       
     4  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
       
     5  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
       
     6  *           (C) 2001 Dirk Mueller (mueller@kde.org)
       
     7  * Copyright (C) 2003 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 #include "config.h"
       
    25 #include "HTMLLinkElement.h"
       
    26 
       
    27 #include "CSSHelper.h"
       
    28 #include "CachedCSSStyleSheet.h"
       
    29 #include "DocLoader.h"
       
    30 #include "Document.h"
       
    31 #include "Frame.h"
       
    32 #include "FrameLoader.h"
       
    33 #include "FrameTree.h"
       
    34 #include "HTMLNames.h"
       
    35 #include "MediaList.h"
       
    36 #include "MediaQueryEvaluator.h"
       
    37 
       
    38 namespace WebCore {
       
    39 
       
    40 using namespace HTMLNames;
       
    41 
       
    42 HTMLLinkElement::HTMLLinkElement(Document *doc)
       
    43     : HTMLElement(linkTag, doc)
       
    44     , m_cachedSheet(0)
       
    45     , m_disabledState(0)
       
    46     , m_loading(false)
       
    47     , m_alternate(false)
       
    48     , m_isStyleSheet(false)
       
    49     , m_isIcon(false)
       
    50 {
       
    51 }
       
    52 
       
    53 HTMLLinkElement::~HTMLLinkElement()
       
    54 {
       
    55     if (m_cachedSheet) {
       
    56         m_cachedSheet->deref(this);
       
    57         if (m_loading && !isDisabled() && !isAlternate())
       
    58             document()->removePendingSheet();
       
    59     }
       
    60 }
       
    61 
       
    62 void HTMLLinkElement::setDisabledState(bool _disabled)
       
    63 {
       
    64     int oldDisabledState = m_disabledState;
       
    65     m_disabledState = _disabled ? 2 : 1;
       
    66     if (oldDisabledState != m_disabledState) {
       
    67         // If we change the disabled state while the sheet is still loading, then we have to
       
    68         // perform three checks:
       
    69         if (isLoading()) {
       
    70             // Check #1: If the sheet becomes disabled while it was loading, and if it was either
       
    71             // a main sheet or a sheet that was previously enabled via script, then we need
       
    72             // to remove it from the list of pending sheets.
       
    73             if (m_disabledState == 2 && (!m_alternate || oldDisabledState == 1))
       
    74                 document()->removePendingSheet();
       
    75 
       
    76             // Check #2: An alternate sheet becomes enabled while it is still loading.
       
    77             if (m_alternate && m_disabledState == 1)
       
    78                 document()->addPendingSheet();
       
    79 
       
    80             // Check #3: A main sheet becomes enabled while it was still loading and
       
    81             // after it was disabled via script.  It takes really terrible code to make this
       
    82             // happen (a double toggle for no reason essentially).  This happens on
       
    83             // virtualplastic.net, which manages to do about 12 enable/disables on only 3
       
    84             // sheets. :)
       
    85             if (!m_alternate && m_disabledState == 1 && oldDisabledState == 2)
       
    86                 document()->addPendingSheet();
       
    87 
       
    88             // If the sheet is already loading just bail.
       
    89             return;
       
    90         }
       
    91 
       
    92         // Load the sheet, since it's never been loaded before.
       
    93         if (!m_sheet && m_disabledState == 1)
       
    94             process();
       
    95         else
       
    96             document()->updateStyleSelector(); // Update the style selector.
       
    97     }
       
    98 }
       
    99 
       
   100 StyleSheet* HTMLLinkElement::sheet() const
       
   101 {
       
   102     return m_sheet.get();
       
   103 }
       
   104 
       
   105 void HTMLLinkElement::parseMappedAttribute(MappedAttribute *attr)
       
   106 {
       
   107     if (attr->name() == relAttr) {
       
   108 #if PRELOAD_SCANNER_ENABLED
       
   109         tokenizeRelAttribute(attr->value(), m_isStyleSheet, m_alternate, m_isIcon);
       
   110 #else
       
   111         tokenizeRelAttribute(attr->value());
       
   112 #endif
       
   113         process();
       
   114     } else if (attr->name() == hrefAttr) {
       
   115         m_url = document()->completeURL(parseURL(attr->value()));
       
   116         process();
       
   117     } else if (attr->name() == typeAttr) {
       
   118         m_type = attr->value();
       
   119         process();
       
   120     } else if (attr->name() == mediaAttr) {
       
   121         m_media = attr->value().domString().lower();
       
   122         process();
       
   123     } else if (attr->name() == disabledAttr) {
       
   124         setDisabledState(!attr->isNull());
       
   125     } else {
       
   126         if (attr->name() == titleAttr && m_sheet)
       
   127             m_sheet->setTitle(attr->value());
       
   128         HTMLElement::parseMappedAttribute(attr);
       
   129     }
       
   130 }
       
   131 
       
   132 #if PRELOAD_SCANNER_ENABLED
       
   133 void HTMLLinkElement::tokenizeRelAttribute(const AtomicString& relStr, bool& styleSheet, bool& alternate, bool& icon)
       
   134 {
       
   135     styleSheet = false;
       
   136     icon = false; 
       
   137     alternate = false;
       
   138     String rel = relStr.domString().lower();
       
   139     if (rel == "stylesheet")
       
   140         styleSheet = true;
       
   141     else if (rel == "icon" || rel == "shortcut icon")
       
   142         icon = true;
       
   143     else if (rel == "alternate stylesheet" || rel == "stylesheet alternate") {
       
   144         styleSheet = true;
       
   145         alternate = true;
       
   146     } else {
       
   147         // Tokenize the rel attribute and set bits based on specific keywords that we find.
       
   148         rel.replace('\n', ' ');
       
   149         Vector<String> list = rel.split(' ');
       
   150         Vector<String>::const_iterator end = list.end();
       
   151         for (Vector<String>::const_iterator it = list.begin(); it != end; ++it) {
       
   152             if (*it == "stylesheet")
       
   153                 styleSheet = true;
       
   154             else if (*it == "alternate")
       
   155                 alternate = true;
       
   156             else if (*it == "icon")
       
   157                 icon = true;
       
   158 #else
       
   159 void HTMLLinkElement::tokenizeRelAttribute(const AtomicString& relStr)
       
   160 {
       
   161     m_isStyleSheet = m_isIcon = m_alternate = false;
       
   162     String rel = relStr.domString().lower();
       
   163     if (rel == "stylesheet")
       
   164         m_isStyleSheet = true;
       
   165     else if (rel == "icon" || rel == "shortcut icon")
       
   166         m_isIcon = true;
       
   167     else if (rel == "alternate stylesheet" || rel == "stylesheet alternate")
       
   168         m_isStyleSheet = m_alternate = true;
       
   169     else {
       
   170         // Tokenize the rel attribute and set bits based on specific keywords that we find.
       
   171         rel.replace('\n', ' ');
       
   172         Vector<String> list = rel.split(' ');
       
   173         Vector<String>::const_iterator end = list.end();
       
   174         for (Vector<String>::const_iterator it = list.begin(); it != end; ++it) {
       
   175             if (*it == "stylesheet")
       
   176                 m_isStyleSheet = true;
       
   177             else if (*it == "alternate")
       
   178                 m_alternate = true;
       
   179             else if (*it == "icon")
       
   180                 m_isIcon = true;
       
   181 #endif
       
   182         }
       
   183     }
       
   184 }
       
   185 
       
   186 void HTMLLinkElement::process()
       
   187 {
       
   188     if (!inDocument())
       
   189         return;
       
   190 
       
   191     String type = m_type.lower();
       
   192 
       
   193     // IE extension: location of small icon for locationbar / bookmarks
       
   194     // We'll record this URL per document, even if we later only use it in top level frames
       
   195     if (m_isIcon && !m_url.isEmpty())
       
   196         document()->setIconURL(m_url, type);
       
   197 
       
   198     // Stylesheet
       
   199     // This was buggy and would incorrectly match <link rel="alternate">, which has a different specified meaning. -dwh
       
   200     if (m_disabledState != 2 && (type.contains("text/css") || m_isStyleSheet) && document()->frame()) {
       
   201         // no need to load style sheets which aren't for the screen output
       
   202         // ### there may be in some situations e.g. for an editor or script to manipulate
       
   203         // also, don't load style sheets for standalone documents
       
   204         MediaQueryEvaluator allEval(true);
       
   205         MediaQueryEvaluator screenEval("screen", true);
       
   206         MediaQueryEvaluator printEval("print", true);
       
   207         RefPtr<MediaList> media = new MediaList((CSSStyleSheet*)0, m_media, true);
       
   208         if (allEval.eval(media.get()) || screenEval.eval(media.get()) || printEval.eval(media.get())) {
       
   209 
       
   210             // Add ourselves as a pending sheet, but only if we aren't an alternate 
       
   211             // stylesheet.  Alternate stylesheets don't hold up render tree construction.
       
   212             if (!isAlternate())
       
   213                 document()->addPendingSheet();
       
   214 
       
   215             String chset = getAttribute(charsetAttr);
       
   216             if (chset.isEmpty() && document()->frame())
       
   217                 chset = document()->frame()->loader()->encoding();
       
   218             
       
   219             if (m_cachedSheet) {
       
   220                 if (m_loading)
       
   221                     document()->removePendingSheet();
       
   222                 m_cachedSheet->deref(this);
       
   223             }
       
   224             m_loading = true;
       
   225             m_cachedSheet = document()->docLoader()->requestCSSStyleSheet(m_url, chset);
       
   226             if (m_cachedSheet)
       
   227                 m_cachedSheet->ref(this);
       
   228             else if (!isAlternate()) { // request may have been denied if stylesheet is local and document is remote.
       
   229                 m_loading = false;
       
   230                 document()->removePendingSheet();
       
   231             }
       
   232         }
       
   233     } else if (m_sheet) {
       
   234         // we no longer contain a stylesheet, e.g. perhaps rel or type was changed
       
   235         m_sheet = 0;
       
   236         document()->updateStyleSelector();
       
   237     }
       
   238 }
       
   239 
       
   240 void HTMLLinkElement::insertedIntoDocument()
       
   241 {
       
   242     HTMLElement::insertedIntoDocument();
       
   243     process();
       
   244 }
       
   245 
       
   246 void HTMLLinkElement::removedFromDocument()
       
   247 {
       
   248     HTMLElement::removedFromDocument();
       
   249     process();
       
   250 }
       
   251 
       
   252 void HTMLLinkElement::setCSSStyleSheet(const String& url, const String& charset, const String& sheetStr)
       
   253 {
       
   254     m_sheet = new CSSStyleSheet(this, url, charset);
       
   255     m_sheet->parseString(sheetStr, !document()->inCompatMode());
       
   256     m_sheet->setTitle(title());
       
   257 
       
   258     RefPtr<MediaList> media = new MediaList((CSSStyleSheet*)0, m_media, true);
       
   259     m_sheet->setMedia(media.get());
       
   260 
       
   261     m_loading = false;
       
   262     m_sheet->checkLoaded();
       
   263 }
       
   264 
       
   265 bool HTMLLinkElement::isLoading() const
       
   266 {
       
   267     if (m_loading)
       
   268         return true;
       
   269     if (!m_sheet)
       
   270         return false;
       
   271     return static_cast<CSSStyleSheet *>(m_sheet.get())->isLoading();
       
   272 }
       
   273 
       
   274 bool HTMLLinkElement::sheetLoaded()
       
   275 {
       
   276     if (!isLoading() && !isDisabled() && !isAlternate()) {
       
   277         document()->removePendingSheet();
       
   278         return true;
       
   279     }
       
   280     return false;
       
   281 }
       
   282 
       
   283 bool HTMLLinkElement::isURLAttribute(Attribute *attr) const
       
   284 {
       
   285     return attr->name() == hrefAttr;
       
   286 }
       
   287 
       
   288 bool HTMLLinkElement::disabled() const
       
   289 {
       
   290     return !getAttribute(disabledAttr).isNull();
       
   291 }
       
   292 
       
   293 void HTMLLinkElement::setDisabled(bool disabled)
       
   294 {
       
   295     setAttribute(disabledAttr, disabled ? "" : 0);
       
   296 }
       
   297 
       
   298 String HTMLLinkElement::charset() const
       
   299 {
       
   300     return getAttribute(charsetAttr);
       
   301 }
       
   302 
       
   303 void HTMLLinkElement::setCharset(const String& value)
       
   304 {
       
   305     setAttribute(charsetAttr, value);
       
   306 }
       
   307 
       
   308 String HTMLLinkElement::href() const
       
   309 {
       
   310     return document()->completeURL(getAttribute(hrefAttr));
       
   311 }
       
   312 
       
   313 void HTMLLinkElement::setHref(const String& value)
       
   314 {
       
   315     setAttribute(hrefAttr, value);
       
   316 }
       
   317 
       
   318 String HTMLLinkElement::hreflang() const
       
   319 {
       
   320     return getAttribute(hreflangAttr);
       
   321 }
       
   322 
       
   323 void HTMLLinkElement::setHreflang(const String& value)
       
   324 {
       
   325     setAttribute(hreflangAttr, value);
       
   326 }
       
   327 
       
   328 String HTMLLinkElement::media() const
       
   329 {
       
   330     return getAttribute(mediaAttr);
       
   331 }
       
   332 
       
   333 void HTMLLinkElement::setMedia(const String& value)
       
   334 {
       
   335     setAttribute(mediaAttr, value);
       
   336 }
       
   337 
       
   338 String HTMLLinkElement::rel() const
       
   339 {
       
   340     return getAttribute(relAttr);
       
   341 }
       
   342 
       
   343 void HTMLLinkElement::setRel(const String& value)
       
   344 {
       
   345     setAttribute(relAttr, value);
       
   346 }
       
   347 
       
   348 String HTMLLinkElement::rev() const
       
   349 {
       
   350     return getAttribute(revAttr);
       
   351 }
       
   352 
       
   353 void HTMLLinkElement::setRev(const String& value)
       
   354 {
       
   355     setAttribute(revAttr, value);
       
   356 }
       
   357 
       
   358 String HTMLLinkElement::target() const
       
   359 {
       
   360     return getAttribute(targetAttr);
       
   361 }
       
   362 
       
   363 void HTMLLinkElement::setTarget(const String& value)
       
   364 {
       
   365     setAttribute(targetAttr, value);
       
   366 }
       
   367 
       
   368 String HTMLLinkElement::type() const
       
   369 {
       
   370     return getAttribute(typeAttr);
       
   371 }
       
   372 
       
   373 void HTMLLinkElement::setType(const String& value)
       
   374 {
       
   375     setAttribute(typeAttr, value);
       
   376 }
       
   377 
       
   378 }