f6b32180303795da9e43251800cc176a5d5e536a
[WebKit-https.git] / Source / WebCore / css / CSSImportRule.cpp
1 /*
2  * (C) 1999-2003 Lars Knoll (knoll@kde.org)
3  * (C) 2002-2003 Dirk Mueller (mueller@kde.org)
4  * Copyright (C) 2002, 2005, 2006, 2008, 2009, 2010 Apple Inc. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23 #include "CSSImportRule.h"
24
25 #include "CachedCSSStyleSheet.h"
26 #include "CachedResourceLoader.h"
27 #include "Document.h"
28 #include "MediaList.h"
29 #include "SecurityOrigin.h"
30 #include "Settings.h"
31 #include <wtf/StdLibExtras.h>
32 #include <wtf/text/StringBuilder.h>
33
34 namespace WebCore {
35
36 PassRefPtr<CSSImportRule> CSSImportRule::create(CSSStyleSheet* parent, const String& href, PassRefPtr<MediaQuerySet> media)
37 {
38     return adoptRef(new CSSImportRule(parent, href, media));
39 }
40
41 CSSImportRule::CSSImportRule(CSSStyleSheet* parent, const String& href, PassRefPtr<MediaQuerySet> media)
42     : CSSRule(parent, CSSRule::IMPORT_RULE)
43     , m_styleSheetClient(this)
44     , m_strHref(href)
45     , m_mediaQueries(media)
46     , m_cachedSheet(0)
47     , m_loading(false)
48 {
49     ASSERT(parent);
50     if (!m_mediaQueries)
51         m_mediaQueries = MediaQuerySet::create(String());
52 }
53
54 CSSImportRule::~CSSImportRule()
55 {
56     if (m_styleSheet)
57         m_styleSheet->clearOwnerRule();
58     if (m_cachedSheet)
59         m_cachedSheet->removeClient(&m_styleSheetClient);
60 }
61
62 void CSSImportRule::setCSSStyleSheet(const String& href, const KURL& baseURL, const String& charset, const CachedCSSStyleSheet* sheet)
63 {
64     if (m_styleSheet)
65         m_styleSheet->clearOwnerRule();
66     m_styleSheet = CSSStyleSheet::create(this, href, baseURL, charset);
67
68     bool crossOriginCSS = false;
69     bool validMIMEType = false;
70     CSSStyleSheet* parent = parentStyleSheet();
71     CSSParserMode cssParserMode = parent ? parent->cssParserMode() : CSSStrictMode;
72     bool enforceMIMEType = isStrictParserMode(cssParserMode);
73     Document* document = parent ? parent->findDocument() : 0;
74     bool needsSiteSpecificQuirks = document && document->settings() && document->settings()->needsSiteSpecificQuirks();
75
76 #ifdef BUILDING_ON_LEOPARD
77     if (enforceMIMEType && needsSiteSpecificQuirks) {
78         // Covers both http and https, with or without "www."
79         if (baseURL.string().contains("mcafee.com/japan/", false))
80             enforceMIMEType = false;
81     }
82 #endif
83
84     String sheetText = sheet->sheetText(enforceMIMEType, &validMIMEType);
85     m_styleSheet->parseString(sheetText, cssParserMode);
86
87     if (!document || !document->securityOrigin()->canRequest(baseURL))
88         crossOriginCSS = true;
89
90     if (crossOriginCSS && !validMIMEType && !m_styleSheet->hasSyntacticallyValidCSSHeader())
91         m_styleSheet = CSSStyleSheet::create(this, href, baseURL, charset);
92
93     if (isStrictParserMode(cssParserMode) && needsSiteSpecificQuirks) {
94         // Work around <https://bugs.webkit.org/show_bug.cgi?id=28350>.
95         DEFINE_STATIC_LOCAL(const String, slashKHTMLFixesDotCss, ("/KHTMLFixes.css"));
96         DEFINE_STATIC_LOCAL(const String, mediaWikiKHTMLFixesStyleSheet, ("/* KHTML fix stylesheet */\n/* work around the horizontal scrollbars */\n#column-content { margin-left: 0; }\n\n"));
97         // There are two variants of KHTMLFixes.css. One is equal to mediaWikiKHTMLFixesStyleSheet,
98         // while the other lacks the second trailing newline.
99         if (baseURL.string().endsWith(slashKHTMLFixesDotCss) && !sheetText.isNull() && mediaWikiKHTMLFixesStyleSheet.startsWith(sheetText)
100                 && sheetText.length() >= mediaWikiKHTMLFixesStyleSheet.length() - 1) {
101             ASSERT(m_styleSheet->length() == 1);
102             ExceptionCode ec;
103             m_styleSheet->deleteRule(0, ec);
104         }
105     }
106
107     m_loading = false;
108
109     if (parent) {
110         parent->notifyLoadedSheet(sheet);
111         parent->checkLoaded();
112     }
113 }
114
115 bool CSSImportRule::isLoading() const
116 {
117     return m_loading || (m_styleSheet && m_styleSheet->isLoading());
118 }
119
120 void CSSImportRule::requestStyleSheet()
121 {
122     CSSStyleSheet* parentSheet = parentStyleSheet();
123     if (!parentSheet)
124         return;
125     Document* document = parentSheet->findDocument();
126     if (!document)
127         return;
128
129     CachedResourceLoader* cachedResourceLoader = document->cachedResourceLoader();
130     if (!cachedResourceLoader)
131         return;
132
133     String absHref = m_strHref;
134     if (!parentSheet->finalURL().isNull())
135         // use parent styleheet's URL as the base URL
136         absHref = KURL(parentSheet->finalURL(), m_strHref).string();
137
138     // Check for a cycle in our import chain.  If we encounter a stylesheet
139     // in our parent chain with the same URL, then just bail.
140     CSSStyleSheet* rootSheet = parentSheet;
141     for (CSSStyleSheet* sheet = parentSheet; sheet; sheet = sheet->parentStyleSheet()) {
142         // FIXME: This is wrong if the finalURL was updated via document::updateBaseURL.
143         if (absHref == sheet->finalURL().string())
144             return;
145         rootSheet = sheet;
146     }
147
148     ResourceRequest request(document->completeURL(absHref));
149     if (parentSheet->isUserStyleSheet())
150         m_cachedSheet = cachedResourceLoader->requestUserCSSStyleSheet(request, parentSheet->charset());
151     else
152         m_cachedSheet = cachedResourceLoader->requestCSSStyleSheet(request, parentSheet->charset());
153     if (m_cachedSheet) {
154         // if the import rule is issued dynamically, the sheet may be
155         // removed from the pending sheet count, so let the doc know
156         // the sheet being imported is pending.
157         if (parentSheet && parentSheet->loadCompleted() && rootSheet == parentSheet)
158             parentSheet->startLoadingDynamicSheet();
159         m_loading = true;
160         m_cachedSheet->addClient(&m_styleSheetClient);
161     }
162 }
163
164 MediaList* CSSImportRule::media()
165 {
166     return m_mediaQueries->ensureMediaList(parentStyleSheet());
167 }
168
169 String CSSImportRule::cssText() const
170 {
171     StringBuilder result;
172     result.append("@import url(\"");
173     result.append(m_strHref);
174     result.append("\")");
175
176     if (m_mediaQueries) {
177         result.append(' ');
178         result.append(m_mediaQueries->mediaText());
179     }
180     result.append(';');
181
182     return result.toString();
183 }
184
185 void CSSImportRule::addSubresourceStyleURLs(ListHashSet<KURL>& urls)
186 {
187     if (m_styleSheet)
188         addSubresourceURL(urls, m_styleSheet->baseURL());
189 }
190
191 } // namespace WebCore