<rdar://problem/10071256> Retain retired custom fonts until the next style recalc
authormitz@apple.com <mitz@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 5 Sep 2011 00:01:40 +0000 (00:01 +0000)
committermitz@apple.com <mitz@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 5 Sep 2011 00:01:40 +0000 (00:01 +0000)
Reviewed by Darin Adler.

Source/WebCore:

Test: fast/css/font-face-used-after-retired.html

During style recalc, existing renderers may reference their old style, including font data.
Allow them to do so safely by keeping retired custom font data around until after style recalc.

* css/CSSFontFace.cpp:
(WebCore::CSSFontFace::retireCustomFont): Added. Calls through to CSSFontSelector, if the font
face is still part of any segmented font face. Otherwise, deletes the custom font data.
* css/CSSFontFace.h:
* css/CSSFontFaceSource.cpp:
(WebCore::CSSFontFaceSource::pruneTable): Changed to call retireCustomFont() instead of deleting
retired font data.
* css/CSSFontSelector.cpp:
(WebCore::CSSFontSelector::retireCustomFont): Added. Calls through to the Document, if this is
still the active font selector for a document. Otherwise, deletes the custom font data.
* css/CSSFontSelector.h:
* css/CSSSegmentedFontFace.cpp:
(WebCore::CSSSegmentedFontFace::pruneTable): Changed to call retireCustomFont() instead of
deleting retired font data.
* dom/Document.cpp:
(WebCore::Document::~Document): Added a call to deleteRetiredCustomFonts(), in case the Document
is destroyed before getting a chance to recalc style after custom fonts have been retired.
(WebCore::Document::recalcStyle): Added a call to deleteRetiredCustomFonts() after style recalc.
(WebCore::Document::deleteRetiredCustomFonts): Added. Deletes all previously-retired custom font
data.
* dom/Document.h:
(WebCore::Document::retireCustomFont): Added.

LayoutTests:

* fast/css/font-face-used-after-retired-expected.txt: Added.
* fast/css/font-face-used-after-retired.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@94508 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/css/font-face-used-after-retired-expected.txt [new file with mode: 0644]
LayoutTests/fast/css/font-face-used-after-retired.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/css/CSSFontFace.cpp
Source/WebCore/css/CSSFontFace.h
Source/WebCore/css/CSSFontFaceSource.cpp
Source/WebCore/css/CSSFontSelector.cpp
Source/WebCore/css/CSSFontSelector.h
Source/WebCore/css/CSSSegmentedFontFace.cpp
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h

index c8f00c5d103bf46535026c30bd824fbc8db8939f..4bf305c44fce2138d9b41368ed70ec7eb79adf11 100644 (file)
@@ -1,3 +1,12 @@
+2011-09-04  Dan Bernstein  <mitz@apple.com>
+
+        <rdar://problem/10071256> Retain retired custom fonts until the next style recalc
+
+        Reviewed by Darin Adler.
+
+        * fast/css/font-face-used-after-retired-expected.txt: Added.
+        * fast/css/font-face-used-after-retired.html: Added.
+
 2011-09-04  Sam Weinig  <sam@webkit.org>
 
         Forgot to check in new results for fast/events/event-creation.html
diff --git a/LayoutTests/fast/css/font-face-used-after-retired-expected.txt b/LayoutTests/fast/css/font-face-used-after-retired-expected.txt
new file mode 100644 (file)
index 0000000..aa44e7c
--- /dev/null
@@ -0,0 +1,2 @@
+
+PASS
diff --git a/LayoutTests/fast/css/font-face-used-after-retired.html b/LayoutTests/fast/css/font-face-used-after-retired.html
new file mode 100644 (file)
index 0000000..47b62c0
--- /dev/null
@@ -0,0 +1,20 @@
+<style>
+    @font-face {
+        font-family: custom;
+        src: url(no-such-file.ttf);
+    }
+</style>
+<!-- content: counter(page) causes the style diff to be "detach" -->
+<div style="font-family: custom; content: counter(page);">
+    <br>PASS
+</div>
+<script>
+    if (window.layoutTestController) {
+        layoutTestController.dumpAsText();
+        layoutTestController.waitUntilDone();
+        // Must wait for the font to fail to load.
+        setTimeout(function() { layoutTestController.notifyDone() }, 100);
+    }
+
+    document.execCommand("SelectAll");
+</script>
index 50431ae586c84aafaa35f211cfed4492188d62fc..3f5252ee20bee4a1bf363e32ad48f7bd939a6441 100644 (file)
@@ -1,3 +1,37 @@
+2011-09-04  Dan Bernstein  <mitz@apple.com>
+
+        <rdar://problem/10071256> Retain retired custom fonts until the next style recalc
+
+        Reviewed by Darin Adler.
+
+        Test: fast/css/font-face-used-after-retired.html
+
+        During style recalc, existing renderers may reference their old style, including font data.
+        Allow them to do so safely by keeping retired custom font data around until after style recalc.
+
+        * css/CSSFontFace.cpp:
+        (WebCore::CSSFontFace::retireCustomFont): Added. Calls through to CSSFontSelector, if the font
+        face is still part of any segmented font face. Otherwise, deletes the custom font data.
+        * css/CSSFontFace.h:
+        * css/CSSFontFaceSource.cpp:
+        (WebCore::CSSFontFaceSource::pruneTable): Changed to call retireCustomFont() instead of deleting
+        retired font data.
+        * css/CSSFontSelector.cpp:
+        (WebCore::CSSFontSelector::retireCustomFont): Added. Calls through to the Document, if this is
+        still the active font selector for a document. Otherwise, deletes the custom font data.
+        * css/CSSFontSelector.h:
+        * css/CSSSegmentedFontFace.cpp:
+        (WebCore::CSSSegmentedFontFace::pruneTable): Changed to call retireCustomFont() instead of
+        deleting retired font data.
+        * dom/Document.cpp:
+        (WebCore::Document::~Document): Added a call to deleteRetiredCustomFonts(), in case the Document
+        is destroyed before getting a chance to recalc style after custom fonts have been retired.
+        (WebCore::Document::recalcStyle): Added a call to deleteRetiredCustomFonts() after style recalc.
+        (WebCore::Document::deleteRetiredCustomFonts): Added. Deletes all previously-retired custom font
+        data.
+        * dom/Document.h:
+        (WebCore::Document::retireCustomFont): Added.
+
 2011-09-04  Sam Weinig  <sam@webkit.org>
 
         Document.createEvent should support all the interfaces of Event we got
index 2c50a0472a19f047651d8f58f231ef270d05c679..3b6dea40bc37c6a91fc46dc9dcc0cbdfa2d31de8 100644 (file)
@@ -118,6 +118,19 @@ SimpleFontData* CSSFontFace::getFontData(const FontDescription& fontDescription,
     return 0;
 }
 
+void CSSFontFace::retireCustomFont(SimpleFontData* fontData)
+{
+    if (m_segmentedFontFaces.isEmpty()) {
+        GlyphPageTreeNode::pruneTreeCustomFontData(fontData);
+        delete fontData;
+        return;
+    }
+
+    // Use one of the CSSSegmentedFontFaces' font selector. They all have
+    // the same font selector.
+    (*m_segmentedFontFaces.begin())->fontSelector()->retireCustomFont(fontData);
+}
+
 #if ENABLE(SVG_FONTS)
 bool CSSFontFace::hasSVGFontFaceSource() const
 {
index 55e048c9e144c8f8c9ee863903bfa6cde2b3fce7..45f8f13b8eb6d81633ecab9213aafb24b10ed091 100644 (file)
@@ -63,6 +63,7 @@ public:
     void addSource(CSSFontFaceSource*);
 
     void fontLoaded(CSSFontFaceSource*);
+    void retireCustomFont(SimpleFontData*);
 
     SimpleFontData* getFontData(const FontDescription&, bool syntheticBold, bool syntheticItalic);
 
index 1a98dde9d91903cbd448a1b873cb9c718f0cc4fd..3cf4e67744935bffb88e9bcb5b1a70ad446ed231 100644 (file)
@@ -71,10 +71,11 @@ void CSSFontFaceSource::pruneTable()
 {
     if (m_fontDataTable.isEmpty())
         return;
+
     HashMap<unsigned, SimpleFontData*>::iterator end = m_fontDataTable.end();
     for (HashMap<unsigned, SimpleFontData*>::iterator it = m_fontDataTable.begin(); it != end; ++it)
-        GlyphPageTreeNode::pruneTreeCustomFontData(it->second);
-    deleteAllValues(m_fontDataTable);
+        m_face->retireCustomFont(it->second);
+
     m_fontDataTable.clear();
 }
 
index 5665f1dec3006352edfad5caa66dfbbf5117304f..713d928884161057471f83755df50207a68aec26 100644 (file)
@@ -383,6 +383,16 @@ void CSSFontSelector::fontCacheInvalidated()
     dispatchInvalidationCallbacks();
 }
 
+void CSSFontSelector::retireCustomFont(FontData* fontData)
+{
+    if (m_document)
+        m_document->retireCustomFont(fontData);
+    else {
+        GlyphPageTreeNode::pruneTreeCustomFontData(fontData);
+        delete fontData;
+    }
+}
+
 static FontData* fontDataForGenericFamily(Document* document, const FontDescription& fontDescription, const AtomicString& familyName)
 {
     if (!document || !document->frame())
index 61baa9fb812e28eba3ea7d1855e5d651d0eceb6d..20978251571b481e0006424cd9f4706d6e52c3be 100644 (file)
@@ -59,6 +59,8 @@ public:
     void fontLoaded();
     virtual void fontCacheInvalidated();
 
+    void retireCustomFont(FontData*);
+
     bool isEmpty() const;
 
     CachedResourceLoader* cachedResourceLoader() const;
index 1f6e20d6ea825b5256dbd163b480f3584932df44..6303ff83c0239f5f92b0a8b117a63f62aa37fecd 100644 (file)
@@ -52,10 +52,11 @@ void CSSSegmentedFontFace::pruneTable()
     // Make sure the glyph page tree prunes out all uses of this custom font.
     if (m_fontDataTable.isEmpty())
         return;
+
     HashMap<unsigned, SegmentedFontData*>::iterator end = m_fontDataTable.end();
     for (HashMap<unsigned, SegmentedFontData*>::iterator it = m_fontDataTable.begin(); it != end; ++it)
-        GlyphPageTreeNode::pruneTreeCustomFontData(it->second);
-    deleteAllValues(m_fontDataTable);
+        m_fontSelector->retireCustomFont(it->second);
+
     m_fontDataTable.clear();
 }
 
index 3efe13a300234dda1f7f84663b38f3753204426d..12f445b551b7b6d6d23924d6e062ba6ba017622f 100644 (file)
@@ -574,6 +574,8 @@ Document::~Document()
             (*m_userSheets)[i]->clearOwnerNode();
     }
 
+    deleteRetiredCustomFonts();
+
     m_weakReference->clear();
 
     if (m_mediaQueryMatcher)
@@ -1562,6 +1564,9 @@ void Document::recalcStyle(StyleChange change)
             element->recalcStyle(change);
     }
 
+    // Now that all RenderStyles that pointed to retired fonts have been updated, the fonts can safely be deleted.
+    deleteRetiredCustomFonts();
+
 #if USE(ACCELERATED_COMPOSITING)
     if (view()) {
         bool layoutPending = view()->layoutPending() || renderer()->needsLayout();
@@ -1698,6 +1703,20 @@ PassRefPtr<RenderStyle> Document::styleForPage(int pageIndex)
     return style.release();
 }
 
+void Document::retireCustomFont(FontData* fontData)
+{
+    m_retiredCustomFonts.append(adoptPtr(fontData));
+}
+
+void Document::deleteRetiredCustomFonts()
+{
+    size_t size = m_retiredCustomFonts.size();
+    for (size_t i = 0; i < size; ++i)
+        GlyphPageTreeNode::pruneTreeCustomFontData(m_retiredCustomFonts[i].get());
+
+    m_retiredCustomFonts.clear();
+}
+
 bool Document::isPageBoxVisible(int pageIndex)
 {
     RefPtr<RenderStyle> style = styleForPage(pageIndex);
index 83cfd204160601193465ae6cfc0f58c32b8da212..679fb94b14f1f2ca0fad331c33268d71741b6137 100644 (file)
@@ -81,6 +81,7 @@ class EntityReference;
 class Event;
 class EventListener;
 class EventQueue;
+class FontData;
 class FormAssociatedElement;
 class Frame;
 class FrameView;
@@ -547,6 +548,8 @@ public:
     PassRefPtr<RenderStyle> styleForElementIgnoringPendingStylesheets(Element*);
     PassRefPtr<RenderStyle> styleForPage(int pageIndex);
 
+    void retireCustomFont(FontData*);
+
     // Returns true if page box (margin boxes and page borders) is visible.
     bool isPageBoxVisible(int pageIndex);
 
@@ -1135,6 +1138,8 @@ private:
 
     void createStyleSelector();
 
+    void deleteRetiredCustomFonts();
+
     PassRefPtr<NodeList> handleZeroPadding(const HitTestRequest&, HitTestResult&) const;
 
     void loadEventDelayTimerFired(Timer<Document>*);
@@ -1148,7 +1153,8 @@ private:
     OwnPtr<CSSStyleSelector> m_styleSelector;
     bool m_didCalculateStyleSelector;
     bool m_hasDirtyStyleSelector;
-    
+    Vector<OwnPtr<FontData> > m_retiredCustomFonts;
+
     mutable RefPtr<CSSPrimitiveValueCache> m_cssPrimitiveValueCache;
 
     Frame* m_frame;