Split remaining CSSRules into internal and CSSOM types
[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<StyleRuleImport> StyleRuleImport::create(CSSStyleSheet* parent, const String& href, PassRefPtr<MediaQuerySet> media)
37 {
38     return adoptRef(new StyleRuleImport(parent, href, media));
39 }
40
41 StyleRuleImport::StyleRuleImport(CSSStyleSheet* parent, const String& href, PassRefPtr<MediaQuerySet> media)
42     : StyleRuleBase(Import, 0)
43     , m_parentStyleSheet(parent)
44     , m_styleSheetClient(this)
45     , m_strHref(href)
46     , m_mediaQueries(media)
47     , m_cachedSheet(0)
48     , m_loading(false)
49 {
50     ASSERT(parent);
51     if (!m_mediaQueries)
52         m_mediaQueries = MediaQuerySet::create(String());
53 }
54
55 StyleRuleImport::~StyleRuleImport()
56 {
57     if (m_styleSheet)
58         m_styleSheet->clearOwnerRule();
59     if (m_cachedSheet)
60         m_cachedSheet->removeClient(&m_styleSheetClient);
61 }
62
63 void StyleRuleImport::setCSSStyleSheet(const String& href, const KURL& baseURL, const String& charset, const CachedCSSStyleSheet* sheet)
64 {
65     if (m_styleSheet)
66         m_styleSheet->clearOwnerRule();
67     m_styleSheet = CSSStyleSheet::create(this, href, baseURL, charset);
68
69     bool crossOriginCSS = false;
70     bool validMIMEType = false;
71     CSSParserMode cssParserMode = m_parentStyleSheet ? m_parentStyleSheet->cssParserMode() : CSSStrictMode;
72     bool enforceMIMEType = isStrictParserMode(cssParserMode);
73     Document* document = m_parentStyleSheet ? m_parentStyleSheet->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 (m_parentStyleSheet) {
110         m_parentStyleSheet->notifyLoadedSheet(sheet);
111         m_parentStyleSheet->checkLoaded();
112     }
113 }
114
115 bool StyleRuleImport::isLoading() const
116 {
117     return m_loading || (m_styleSheet && m_styleSheet->isLoading());
118 }
119
120 void StyleRuleImport::requestStyleSheet()
121 {
122     if (!m_parentStyleSheet)
123         return;
124     Document* document = m_parentStyleSheet->findDocument();
125     if (!document)
126         return;
127
128     CachedResourceLoader* cachedResourceLoader = document->cachedResourceLoader();
129     if (!cachedResourceLoader)
130         return;
131
132     String absHref = m_strHref;
133     if (!m_parentStyleSheet->finalURL().isNull())
134         // use parent styleheet's URL as the base URL
135         absHref = KURL(m_parentStyleSheet->finalURL(), m_strHref).string();
136
137     // Check for a cycle in our import chain.  If we encounter a stylesheet
138     // in our parent chain with the same URL, then just bail.
139     CSSStyleSheet* rootSheet = m_parentStyleSheet;
140     for (CSSStyleSheet* sheet = m_parentStyleSheet; sheet; sheet = sheet->parentStyleSheet()) {
141         // FIXME: This is wrong if the finalURL was updated via document::updateBaseURL.
142         if (absHref == sheet->finalURL().string())
143             return;
144         rootSheet = sheet;
145     }
146
147     ResourceRequest request(document->completeURL(absHref));
148     if (m_parentStyleSheet->isUserStyleSheet())
149         m_cachedSheet = cachedResourceLoader->requestUserCSSStyleSheet(request, m_parentStyleSheet->charset());
150     else
151         m_cachedSheet = cachedResourceLoader->requestCSSStyleSheet(request, m_parentStyleSheet->charset());
152     if (m_cachedSheet) {
153         // if the import rule is issued dynamically, the sheet may be
154         // removed from the pending sheet count, so let the doc know
155         // the sheet being imported is pending.
156         if (m_parentStyleSheet && m_parentStyleSheet->loadCompleted() && rootSheet == m_parentStyleSheet)
157             m_parentStyleSheet->startLoadingDynamicSheet();
158         m_loading = true;
159         m_cachedSheet->addClient(&m_styleSheetClient);
160     }
161 }
162
163 CSSImportRule::CSSImportRule(StyleRuleImport* importRule, CSSStyleSheet* parent)
164     : CSSRule(parent, CSSRule::IMPORT_RULE)
165     , m_importRule(importRule)
166 {
167 }
168
169 MediaList* CSSImportRule::media()
170 {
171     return m_importRule->mediaQueries()->ensureMediaList(parentStyleSheet());
172 }
173
174 String CSSImportRule::cssText() const
175 {
176     StringBuilder result;
177     result.append("@import url(\"");
178     result.append(m_importRule->href());
179     result.append("\")");
180
181     if (m_importRule->mediaQueries()) {
182         result.append(' ');
183         result.append(m_importRule->mediaQueries()->mediaText());
184     }
185     result.append(';');
186     
187     return result.toString();
188 }
189
190 } // namespace WebCore