Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / dom / StyleEngine.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2001 Dirk Mueller (mueller@kde.org)
5  *           (C) 2006 Alexey Proskuryakov (ap@webkit.org)
6  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012 Apple Inc. All rights reserved.
7  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
8  * Copyright (C) 2008, 2009, 2011, 2012 Google Inc. All rights reserved.
9  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
10  * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved.
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Library General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public License
23  * along with this library; see the file COPYING.LIB.  If not, write to
24  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25  * Boston, MA 02110-1301, USA.
26  */
27
28 #include "config.h"
29 #include "core/dom/StyleEngine.h"
30
31 #include "HTMLNames.h"
32 #include "SVGNames.h"
33 #include "core/css/CSSFontSelector.h"
34 #include "core/css/CSSStyleSheet.h"
35 #include "core/css/FontFaceCache.h"
36 #include "core/css/StyleInvalidationAnalysis.h"
37 #include "core/css/StyleSheetContents.h"
38 #include "core/dom/DocumentStyleSheetCollector.h"
39 #include "core/dom/Element.h"
40 #include "core/dom/ProcessingInstruction.h"
41 #include "core/dom/ShadowTreeStyleSheetCollection.h"
42 #include "core/dom/shadow/ShadowRoot.h"
43 #include "core/html/HTMLIFrameElement.h"
44 #include "core/html/HTMLImport.h"
45 #include "core/html/HTMLLinkElement.h"
46 #include "core/inspector/InspectorInstrumentation.h"
47 #include "core/page/Page.h"
48 #include "core/page/PageGroup.h"
49 #include "core/frame/Settings.h"
50 #include "core/svg/SVGStyleElement.h"
51 #include "platform/URLPatternMatcher.h"
52
53 namespace WebCore {
54
55 using namespace HTMLNames;
56
57 static HashMap<AtomicString, StyleSheetContents*>& textToSheetCache()
58 {
59     typedef HashMap<AtomicString, StyleSheetContents*> TextToSheetCache;
60     DEFINE_STATIC_LOCAL(TextToSheetCache, cache, ());
61     return cache;
62 }
63
64 static HashMap<StyleSheetContents*, AtomicString>& sheetToTextCache()
65 {
66     typedef HashMap<StyleSheetContents*, AtomicString> SheetToTextCache;
67     DEFINE_STATIC_LOCAL(SheetToTextCache, cache, ());
68     return cache;
69 }
70
71 StyleEngine::StyleEngine(Document& document)
72     : m_document(document)
73     , m_isMaster(HTMLImport::isMaster(&document))
74     , m_pendingStylesheets(0)
75     , m_injectedStyleSheetCacheValid(false)
76     , m_documentStyleSheetCollection(document)
77     , m_documentScopeDirty(true)
78     , m_usesSiblingRules(false)
79     , m_usesSiblingRulesOverride(false)
80     , m_usesFirstLineRules(false)
81     , m_usesFirstLetterRules(false)
82     , m_usesRemUnits(false)
83     , m_maxDirectAdjacentSelectors(0)
84     , m_ignorePendingStylesheets(false)
85     , m_didCalculateResolver(false)
86     // We don't need to create CSSFontSelector for imported document or
87     // HTMLTemplateElement's document, because those documents have no frame.
88     , m_fontSelector(document.frame() ? CSSFontSelector::create(&document) : 0)
89 {
90 }
91
92 StyleEngine::~StyleEngine()
93 {
94     for (unsigned i = 0; i < m_injectedAuthorStyleSheets.size(); ++i)
95         m_injectedAuthorStyleSheets[i]->clearOwnerNode();
96     for (unsigned i = 0; i < m_authorStyleSheets.size(); ++i)
97         m_authorStyleSheets[i]->clearOwnerNode();
98
99     if (m_fontSelector) {
100         m_fontSelector->clearDocument();
101         if (m_resolver)
102             m_fontSelector->unregisterForInvalidationCallbacks(m_resolver.get());
103     }
104 }
105
106 inline Document* StyleEngine::master()
107 {
108     if (isMaster())
109         return &m_document;
110     HTMLImport* import = m_document.import();
111     if (!import) // Document::import() can return null while executing its destructor.
112         return 0;
113     return import->master();
114 }
115
116 void StyleEngine::insertTreeScopeInDocumentOrder(TreeScopeSet& treeScopes, TreeScope* treeScope)
117 {
118     if (treeScopes.isEmpty()) {
119         treeScopes.add(treeScope);
120         return;
121     }
122     if (treeScopes.contains(treeScope))
123         return;
124
125     TreeScopeSet::iterator begin = treeScopes.begin();
126     TreeScopeSet::iterator end = treeScopes.end();
127     TreeScopeSet::iterator it = end;
128     TreeScope* followingTreeScope = 0;
129     do {
130         --it;
131         TreeScope* n = *it;
132         unsigned short position = n->comparePosition(*treeScope);
133         if (position & Node::DOCUMENT_POSITION_FOLLOWING) {
134             treeScopes.insertBefore(followingTreeScope, treeScope);
135             return;
136         }
137         followingTreeScope = n;
138     } while (it != begin);
139
140     treeScopes.insertBefore(followingTreeScope, treeScope);
141 }
142
143 TreeScopeStyleSheetCollection* StyleEngine::ensureStyleSheetCollectionFor(TreeScope& treeScope)
144 {
145     if (treeScope == m_document)
146         return &m_documentStyleSheetCollection;
147
148     HashMap<TreeScope*, OwnPtr<TreeScopeStyleSheetCollection> >::AddResult result = m_styleSheetCollectionMap.add(&treeScope, nullptr);
149     if (result.isNewEntry)
150         result.storedValue->value = adoptPtr(new ShadowTreeStyleSheetCollection(toShadowRoot(treeScope)));
151     return result.storedValue->value.get();
152 }
153
154 TreeScopeStyleSheetCollection* StyleEngine::styleSheetCollectionFor(TreeScope& treeScope)
155 {
156     if (treeScope == m_document)
157         return &m_documentStyleSheetCollection;
158
159     HashMap<TreeScope*, OwnPtr<TreeScopeStyleSheetCollection> >::iterator it = m_styleSheetCollectionMap.find(&treeScope);
160     if (it == m_styleSheetCollectionMap.end())
161         return 0;
162     return it->value.get();
163 }
164
165 const Vector<RefPtr<StyleSheet> >& StyleEngine::styleSheetsForStyleSheetList(TreeScope& treeScope)
166 {
167     if (treeScope == m_document)
168         return m_documentStyleSheetCollection.styleSheetsForStyleSheetList();
169
170     return ensureStyleSheetCollectionFor(treeScope)->styleSheetsForStyleSheetList();
171 }
172
173 const Vector<RefPtr<CSSStyleSheet> >& StyleEngine::activeAuthorStyleSheets() const
174 {
175     return m_documentStyleSheetCollection.activeAuthorStyleSheets();
176 }
177
178 void StyleEngine::combineCSSFeatureFlags(const RuleFeatureSet& features)
179 {
180     // Delay resetting the flags until after next style recalc since unapplying the style may not work without these set (this is true at least with before/after).
181     m_usesSiblingRules = m_usesSiblingRules || features.usesSiblingRules();
182     m_usesFirstLineRules = m_usesFirstLineRules || features.usesFirstLineRules();
183     m_maxDirectAdjacentSelectors = max(m_maxDirectAdjacentSelectors, features.maxDirectAdjacentSelectors());
184 }
185
186 void StyleEngine::resetCSSFeatureFlags(const RuleFeatureSet& features)
187 {
188     m_usesSiblingRules = features.usesSiblingRules();
189     m_usesFirstLineRules = features.usesFirstLineRules();
190     m_maxDirectAdjacentSelectors = features.maxDirectAdjacentSelectors();
191 }
192
193 const Vector<RefPtr<CSSStyleSheet> >& StyleEngine::injectedAuthorStyleSheets() const
194 {
195     updateInjectedStyleSheetCache();
196     return m_injectedAuthorStyleSheets;
197 }
198
199 void StyleEngine::updateInjectedStyleSheetCache() const
200 {
201     if (m_injectedStyleSheetCacheValid)
202         return;
203     m_injectedStyleSheetCacheValid = true;
204     m_injectedAuthorStyleSheets.clear();
205
206     Page* owningPage = m_document.page();
207     if (!owningPage)
208         return;
209
210     const InjectedStyleSheetEntryVector& entries = InjectedStyleSheets::instance().entries();
211     for (unsigned i = 0; i < entries.size(); ++i) {
212         const InjectedStyleSheetEntry* entry = entries[i].get();
213         if (entry->injectedFrames() == InjectStyleInTopFrameOnly && m_document.ownerElement())
214             continue;
215         if (!URLPatternMatcher::matchesPatterns(m_document.url(), entry->whitelist()))
216             continue;
217         RefPtr<CSSStyleSheet> groupSheet = CSSStyleSheet::createInline(const_cast<Document*>(&m_document), KURL());
218         m_injectedAuthorStyleSheets.append(groupSheet);
219         groupSheet->contents()->parseString(entry->source());
220     }
221 }
222
223 void StyleEngine::invalidateInjectedStyleSheetCache()
224 {
225     m_injectedStyleSheetCacheValid = false;
226     markDocumentDirty();
227     // FIXME: updateInjectedStyleSheetCache is called inside StyleSheetCollection::updateActiveStyleSheets
228     // and batch updates lots of sheets so we can't call addedStyleSheet() or removedStyleSheet().
229     m_document.styleResolverChanged(RecalcStyleDeferred);
230 }
231
232 void StyleEngine::addAuthorSheet(PassRefPtr<StyleSheetContents> authorSheet)
233 {
234     m_authorStyleSheets.append(CSSStyleSheet::create(authorSheet, &m_document));
235     m_document.addedStyleSheet(m_authorStyleSheets.last().get(), RecalcStyleImmediately);
236     markDocumentDirty();
237 }
238
239 void StyleEngine::addPendingSheet()
240 {
241     master()->styleEngine()->notifyPendingStyleSheetAdded();
242 }
243
244 // This method is called whenever a top-level stylesheet has finished loading.
245 void StyleEngine::removePendingSheet(Node* styleSheetCandidateNode, RemovePendingSheetNotificationType notification)
246 {
247     TreeScope* treeScope = styleSheetCandidateNode->hasTagName(styleTag) ? &styleSheetCandidateNode->treeScope() : &m_document;
248     markTreeScopeDirty(*treeScope);
249     master()->styleEngine()->notifyPendingStyleSheetRemoved(notification);
250 }
251
252 void StyleEngine::notifyPendingStyleSheetAdded()
253 {
254     ASSERT(isMaster());
255     m_pendingStylesheets++;
256 }
257
258 void StyleEngine::notifyPendingStyleSheetRemoved(RemovePendingSheetNotificationType notification)
259 {
260     ASSERT(isMaster());
261     // Make sure we knew this sheet was pending, and that our count isn't out of sync.
262     ASSERT(m_pendingStylesheets > 0);
263
264     m_pendingStylesheets--;
265     if (m_pendingStylesheets)
266         return;
267
268     if (notification == RemovePendingSheetNotifyLater) {
269         m_document.setNeedsNotifyRemoveAllPendingStylesheet();
270         return;
271     }
272
273     // FIXME: We can't call addedStyleSheet or removedStyleSheet here because we don't know
274     // what's new. We should track that to tell the style system what changed.
275     m_document.didRemoveAllPendingStylesheet();
276 }
277
278 void StyleEngine::modifiedStyleSheet(StyleSheet* sheet)
279 {
280     if (!sheet)
281         return;
282
283     Node* node = sheet->ownerNode();
284     if (!node || !node->inDocument())
285         return;
286
287     TreeScope& treeScope = node->hasTagName(styleTag) ? node->treeScope() : m_document;
288     ASSERT(node->hasTagName(styleTag) || treeScope == m_document);
289
290     markTreeScopeDirty(treeScope);
291 }
292
293 void StyleEngine::addStyleSheetCandidateNode(Node* node, bool createdByParser)
294 {
295     if (!node->inDocument())
296         return;
297
298     TreeScope& treeScope = node->hasTagName(styleTag) ? node->treeScope() : m_document;
299     ASSERT(node->hasTagName(styleTag) || treeScope == m_document);
300
301     TreeScopeStyleSheetCollection* collection = ensureStyleSheetCollectionFor(treeScope);
302     ASSERT(collection);
303     collection->addStyleSheetCandidateNode(node, createdByParser);
304
305     markTreeScopeDirty(treeScope);
306     if (treeScope != m_document)
307         insertTreeScopeInDocumentOrder(m_activeTreeScopes, &treeScope);
308 }
309
310 void StyleEngine::removeStyleSheetCandidateNode(Node* node, ContainerNode* scopingNode)
311 {
312     TreeScope& treeScope = scopingNode ? scopingNode->treeScope() : m_document;
313     ASSERT(node->hasTagName(styleTag) || treeScope == m_document);
314
315     TreeScopeStyleSheetCollection* collection = styleSheetCollectionFor(treeScope);
316     ASSERT(collection);
317     collection->removeStyleSheetCandidateNode(node, scopingNode);
318
319     markTreeScopeDirty(treeScope);
320     m_activeTreeScopes.remove(&treeScope);
321 }
322
323 void StyleEngine::modifiedStyleSheetCandidateNode(Node* node)
324 {
325     if (!node->inDocument())
326         return;
327
328     TreeScope& treeScope = node->hasTagName(styleTag) ? node->treeScope() : m_document;
329     ASSERT(node->hasTagName(styleTag) || treeScope == m_document);
330     markTreeScopeDirty(treeScope);
331 }
332
333 bool StyleEngine::shouldUpdateShadowTreeStyleSheetCollection(StyleResolverUpdateMode updateMode)
334 {
335     return !m_dirtyTreeScopes.isEmpty() || updateMode == FullStyleUpdate;
336 }
337
338 void StyleEngine::clearMediaQueryRuleSetOnTreeScopeStyleSheets(TreeScopeSet treeScopes)
339 {
340     for (TreeScopeSet::iterator it = treeScopes.begin(); it != treeScopes.end(); ++it) {
341         TreeScope& treeScope = **it;
342         ASSERT(treeScope != m_document);
343         ShadowTreeStyleSheetCollection* collection = static_cast<ShadowTreeStyleSheetCollection*>(styleSheetCollectionFor(treeScope));
344         ASSERT(collection);
345         collection->clearMediaQueryRuleSetStyleSheets();
346     }
347 }
348
349 void StyleEngine::clearMediaQueryRuleSetStyleSheets()
350 {
351     m_documentStyleSheetCollection.clearMediaQueryRuleSetStyleSheets();
352     clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_activeTreeScopes);
353     clearMediaQueryRuleSetOnTreeScopeStyleSheets(m_dirtyTreeScopes);
354 }
355
356 void StyleEngine::updateStyleSheetsInImport(DocumentStyleSheetCollector& parentCollector)
357 {
358     ASSERT(!isMaster());
359     Vector<RefPtr<StyleSheet> > sheetsForList;
360     ImportedDocumentStyleSheetCollector subcollector(parentCollector, sheetsForList);
361     m_documentStyleSheetCollection.collectStyleSheets(this, subcollector);
362     m_documentStyleSheetCollection.swapSheetsForSheetList(sheetsForList);
363 }
364
365 bool StyleEngine::updateActiveStyleSheets(StyleResolverUpdateMode updateMode)
366 {
367     ASSERT(isMaster());
368     ASSERT(!m_document.inStyleRecalc());
369
370     if (!m_document.isActive())
371         return false;
372
373     bool requiresFullStyleRecalc = false;
374     if (m_documentScopeDirty || updateMode == FullStyleUpdate)
375         requiresFullStyleRecalc = m_documentStyleSheetCollection.updateActiveStyleSheets(this, updateMode);
376
377     if (shouldUpdateShadowTreeStyleSheetCollection(updateMode)) {
378         TreeScopeSet treeScopes = updateMode == FullStyleUpdate ? m_activeTreeScopes : m_dirtyTreeScopes;
379         HashSet<TreeScope*> treeScopesRemoved;
380
381         for (TreeScopeSet::iterator it = treeScopes.begin(); it != treeScopes.end(); ++it) {
382             TreeScope* treeScope = *it;
383             ASSERT(treeScope != m_document);
384             ShadowTreeStyleSheetCollection* collection = static_cast<ShadowTreeStyleSheetCollection*>(styleSheetCollectionFor(*treeScope));
385             ASSERT(collection);
386             collection->updateActiveStyleSheets(this, updateMode);
387             if (!collection->hasStyleSheetCandidateNodes())
388                 treeScopesRemoved.add(treeScope);
389         }
390         if (!treeScopesRemoved.isEmpty())
391             for (HashSet<TreeScope*>::iterator it = treeScopesRemoved.begin(); it != treeScopesRemoved.end(); ++it)
392                 m_activeTreeScopes.remove(*it);
393     }
394
395     InspectorInstrumentation::activeStyleSheetsUpdated(&m_document);
396     m_usesRemUnits = m_documentStyleSheetCollection.usesRemUnits();
397
398     m_dirtyTreeScopes.clear();
399     m_documentScopeDirty = false;
400
401     return requiresFullStyleRecalc;
402 }
403
404 const Vector<RefPtr<StyleSheet> > StyleEngine::activeStyleSheetsForInspector() const
405 {
406     if (m_activeTreeScopes.isEmpty())
407         return m_documentStyleSheetCollection.styleSheetsForStyleSheetList();
408
409     Vector<RefPtr<StyleSheet> > activeStyleSheets;
410
411     activeStyleSheets.append(m_documentStyleSheetCollection.styleSheetsForStyleSheetList());
412
413     TreeScopeSet::const_iterator begin = m_activeTreeScopes.begin();
414     TreeScopeSet::const_iterator end = m_activeTreeScopes.end();
415     for (TreeScopeSet::const_iterator it = begin; it != end; ++it) {
416         if (TreeScopeStyleSheetCollection* collection = m_styleSheetCollectionMap.get(*it))
417             activeStyleSheets.append(collection->styleSheetsForStyleSheetList());
418     }
419
420     // FIXME: Inspector needs a vector which has all active stylesheets.
421     // However, creating such a large vector might cause performance regression.
422     // Need to implement some smarter solution.
423     return activeStyleSheets;
424 }
425
426 void StyleEngine::didRemoveShadowRoot(ShadowRoot* shadowRoot)
427 {
428     m_styleSheetCollectionMap.remove(shadowRoot);
429 }
430
431 void StyleEngine::appendActiveAuthorStyleSheets()
432 {
433     ASSERT(isMaster());
434
435     m_resolver->setBuildScopedStyleTreeInDocumentOrder(true);
436     m_resolver->appendAuthorStyleSheets(0, m_documentStyleSheetCollection.activeAuthorStyleSheets());
437
438     TreeScopeSet::iterator begin = m_activeTreeScopes.begin();
439     TreeScopeSet::iterator end = m_activeTreeScopes.end();
440     for (TreeScopeSet::iterator it = begin; it != end; ++it) {
441         if (TreeScopeStyleSheetCollection* collection = m_styleSheetCollectionMap.get(*it)) {
442             m_resolver->setBuildScopedStyleTreeInDocumentOrder(!collection->scopingNodesForStyleScoped());
443             m_resolver->appendAuthorStyleSheets(0, collection->activeAuthorStyleSheets());
444         }
445     }
446     m_resolver->finishAppendAuthorStyleSheets();
447     m_resolver->setBuildScopedStyleTreeInDocumentOrder(false);
448 }
449
450 void StyleEngine::createResolver()
451 {
452     // It is a programming error to attempt to resolve style on a Document
453     // which is not in a frame. Code which hits this should have checked
454     // Document::isActive() before calling into code which could get here.
455
456     ASSERT(m_document.frame());
457     ASSERT(m_fontSelector);
458
459     m_resolver = adoptPtr(new StyleResolver(m_document));
460     appendActiveAuthorStyleSheets();
461     m_fontSelector->registerForInvalidationCallbacks(m_resolver.get());
462     combineCSSFeatureFlags(m_resolver->ensureRuleFeatureSet());
463 }
464
465 void StyleEngine::clearResolver()
466 {
467     ASSERT(!m_document.inStyleRecalc());
468     ASSERT(isMaster() || !m_resolver);
469     ASSERT(m_fontSelector || !m_resolver);
470     if (m_resolver)
471         m_fontSelector->unregisterForInvalidationCallbacks(m_resolver.get());
472     m_resolver.clear();
473 }
474
475 void StyleEngine::clearMasterResolver()
476 {
477     if (Document* master = this->master())
478         master->styleEngine()->clearResolver();
479 }
480
481 unsigned StyleEngine::resolverAccessCount() const
482 {
483     return m_resolver ? m_resolver->accessCount() : 0;
484 }
485
486 void StyleEngine::didDetach()
487 {
488     clearResolver();
489 }
490
491 bool StyleEngine::shouldClearResolver() const
492 {
493     return !m_didCalculateResolver && !haveStylesheetsLoaded();
494 }
495
496 StyleResolverChange StyleEngine::resolverChanged(RecalcStyleTime time, StyleResolverUpdateMode mode)
497 {
498     StyleResolverChange change;
499
500     if (!isMaster()) {
501         if (Document* master = this->master())
502             master->styleResolverChanged(time, mode);
503         return change;
504     }
505
506     // Don't bother updating, since we haven't loaded all our style info yet
507     // and haven't calculated the style selector for the first time.
508     if (!m_document.isActive() || shouldClearResolver()) {
509         clearResolver();
510         return change;
511     }
512
513     m_didCalculateResolver = true;
514     if (m_document.didLayoutWithPendingStylesheets() && !hasPendingSheets())
515         change.setNeedsRepaint();
516
517     if (updateActiveStyleSheets(mode))
518         change.setNeedsStyleRecalc();
519
520     return change;
521 }
522
523 void StyleEngine::clearFontCache()
524 {
525     // We should not recreate FontSelector. Instead, clear fontFaceCache.
526     if (m_fontSelector)
527         m_fontSelector->fontFaceCache()->clear();
528     if (m_resolver)
529         m_resolver->invalidateMatchedPropertiesCache();
530 }
531
532 void StyleEngine::updateGenericFontFamilySettings()
533 {
534     if (!m_fontSelector)
535         return;
536
537     m_fontSelector->updateGenericFontFamilySettings(m_document);
538     if (m_resolver)
539         m_resolver->invalidateMatchedPropertiesCache();
540 }
541
542 void StyleEngine::removeFontFaceRules(const Vector<const StyleRuleFontFace*>& fontFaceRules)
543 {
544     if (!m_fontSelector)
545         return;
546
547     FontFaceCache* cache = m_fontSelector->fontFaceCache();
548     for (unsigned i = 0; i < fontFaceRules.size(); ++i)
549         cache->remove(fontFaceRules[i]);
550     if (m_resolver)
551         m_resolver->invalidateMatchedPropertiesCache();
552 }
553
554 void StyleEngine::markTreeScopeDirty(TreeScope& scope)
555 {
556     if (scope == m_document) {
557         markDocumentDirty();
558         return;
559     }
560
561     m_dirtyTreeScopes.add(&scope);
562 }
563
564 void StyleEngine::markDocumentDirty()
565 {
566     m_documentScopeDirty = true;
567     if (!HTMLImport::isMaster(&m_document))
568         m_document.import()->master()->styleEngine()->markDocumentDirty();
569 }
570
571 PassRefPtr<CSSStyleSheet> StyleEngine::createSheet(Element* e, const String& text, TextPosition startPosition, bool createdByParser)
572 {
573     RefPtr<CSSStyleSheet> styleSheet;
574
575     e->document().styleEngine()->addPendingSheet();
576
577     if (!e->document().inQuirksMode()) {
578         AtomicString textContent(text);
579
580         HashMap<AtomicString, StyleSheetContents*>::AddResult result = textToSheetCache().add(textContent, 0);
581         if (result.isNewEntry || !result.storedValue->value) {
582             styleSheet = StyleEngine::parseSheet(e, text, startPosition, createdByParser);
583             if (result.isNewEntry && styleSheet->contents()->maybeCacheable()) {
584                 result.storedValue->value = styleSheet->contents();
585                 sheetToTextCache().add(styleSheet->contents(), textContent);
586             }
587         } else {
588             ASSERT(result.storedValue->value->maybeCacheable());
589             styleSheet = CSSStyleSheet::createInline(result.storedValue->value, e, startPosition);
590         }
591     } else {
592         // FIXME: currently we don't cache StyleSheetContents inQuirksMode.
593         styleSheet = StyleEngine::parseSheet(e, text, startPosition, createdByParser);
594     }
595
596     ASSERT(styleSheet);
597     styleSheet->setTitle(e->title());
598     return styleSheet;
599 }
600
601 PassRefPtr<CSSStyleSheet> StyleEngine::parseSheet(Element* e, const String& text, TextPosition startPosition, bool createdByParser)
602 {
603     RefPtr<CSSStyleSheet> styleSheet;
604     styleSheet = CSSStyleSheet::createInline(e, KURL(), startPosition, e->document().inputEncoding());
605     styleSheet->contents()->parseStringAtPosition(text, startPosition, createdByParser);
606     return styleSheet;
607 }
608
609 void StyleEngine::removeSheet(StyleSheetContents* contents)
610 {
611     HashMap<StyleSheetContents*, AtomicString>::iterator it = sheetToTextCache().find(contents);
612     if (it == sheetToTextCache().end())
613         return;
614
615     textToSheetCache().remove(it->value);
616     sheetToTextCache().remove(contents);
617 }
618
619 }