Fix <rdar://problem/
5378214>
Mail crashes at RenderLayer::paintLayer() when dragging a selection over To Do text
ObjC interface does not guarantee that Document::updateRendering() gets called after
modification are made to document. This can lead to situation where paint()
is invoked with document still dirty which can then crash in number of interesting ways.
- add hasChangedChild() as needsLayout() condition. layout() will then call recalcStyle()
catching most cases and making sure document is not dirty when entering painting.
- protect recalcStyle() and layout() from being executed during painting. There are some
cases needsLayout() protection does not cover.
No layout test, these states are very hard or impossible to reach using Javascript interface
(which generally guarantees that updateRendering() is done right after execution).
* dom/Document.cpp:
(WebCore::Document::recalcStyle):
* page/Frame.cpp:
(WebCore::Frame::paint):
(WebCore::Frame::setPaintRestriction):
(WebCore::Frame::isPainting):
(WebCore::FramePrivate::FramePrivate):
* page/Frame.h:
* page/FramePrivate.h:
* page/FrameView.cpp:
(WebCore::FrameView::layout):
(WebCore::FrameView::needsLayout):
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@24878
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2007-08-06 Antti <antti@apple.com>
+
+ Reviewed by Darin.
+
+ Fix <rdar://problem/5378214>
+ Mail crashes at RenderLayer::paintLayer() when dragging a selection over To Do text
+
+ ObjC interface does not guarantee that Document::updateRendering() gets called after
+ modification are made to document. This can lead to situation where paint()
+ is invoked with document still dirty which can then crash in number of interesting ways.
+
+ - add hasChangedChild() as needsLayout() condition. layout() will then call recalcStyle()
+ catching most cases and making sure document is not dirty when entering painting.
+ - protect recalcStyle() and layout() from being executed during painting. There are some
+ cases needsLayout() protection does not cover.
+
+ No layout test, these states are very hard or impossible to reach using Javascript interface
+ (which generally guarantees that updateRendering() is done right after execution).
+
+ * dom/Document.cpp:
+ (WebCore::Document::recalcStyle):
+ * page/Frame.cpp:
+ (WebCore::Frame::paint):
+ (WebCore::Frame::setPaintRestriction):
+ (WebCore::Frame::isPainting):
+ (WebCore::FramePrivate::FramePrivate):
+ * page/Frame.h:
+ * page/FramePrivate.h:
+ * page/FrameView.cpp:
+ (WebCore::FrameView::layout):
+ (WebCore::FrameView::needsLayout):
+
2007-08-05 Maciej Stachowiak <mjs@apple.com>
Reviewed by Darin Adler.
void Document::recalcStyle(StyleChange change)
{
+ // we should not enter style recalc while painting
+ if (frame() && frame()->isPainting()) {
+ ASSERT(!frame()->isPainting());
+ return;
+ }
+
if (m_inStyleRecalc)
return; // Guard against re-entrancy. -dwh
#endif
if (renderer()) {
+ ASSERT(d->m_view && !d->m_view->needsLayout());
+ ASSERT(!d->m_isPainting);
+
+ d->m_isPainting = true;
+
// d->m_elementToDraw is used to draw only one element
RenderObject *eltRenderer = d->m_elementToDraw ? d->m_elementToDraw->renderer() : 0;
if (d->m_paintRestriction == PaintRestrictionNone)
renderer()->document()->invalidateRenderedRectsForMarkersInRect(rect);
renderer()->layer()->paint(p, rect, d->m_paintRestriction, eltRenderer);
+
+ d->m_isPainting = false;
// Regions may have changed as a result of the visibility/z-index of element changing.
if (renderer()->document()->dashboardRegionsDirty())
void Frame::setPaintRestriction(PaintRestriction pr)
{
- d->m_paintRestriction = pr;
+ d->m_paintRestriction = pr;
+}
+
+bool Frame::isPainting() const
+{
+ return d->m_isPainting;
}
void Frame::adjustPageHeight(float *newBottom, float oldTop, float oldBottom, float bottomLimit)
, m_caretVisible(false)
, m_caretPaint(true)
, m_isActive(false)
+ , m_isPainting(false)
, m_lifeSupportTimer(thisFrame, &Frame::lifeSupportTimerFired)
, m_loader(new FrameLoader(thisFrame, frameLoaderClient))
, m_userStyleSheetLoader(0)
// should move to FrameView
void paint(GraphicsContext*, const IntRect&);
void setPaintRestriction(PaintRestriction);
+ bool isPainting() const;
void setUserStyleSheetLocation(const KURL&);
void setUserStyleSheet(const String& styleSheetData);
bool m_caretVisible : 1;
bool m_caretPaint : 1;
bool m_isActive : 1;
+ bool m_isPainting : 1;
RefPtr<CSSMutableStyleDeclaration> m_typingStyle;
m_size.setWidth(visibleWidth());
return;
}
+
+ // we shouldn't enter layout() while painting
+ ASSERT(!m_frame->isPainting());
+ if (m_frame->isPainting())
+ return;
if (!allowSubtree && d->layoutRoot) {
if (d->layoutRoot->renderer())
if (!m_frame)
return false;
RenderView* root = static_cast<RenderView*>(m_frame->renderer());
- return layoutPending() || (root && root->needsLayout()) || d->layoutRoot;
+ Document * doc = m_frame->document();
+ // doc->hasChangedChild() condition can occur when using WebKit ObjC interface
+ return layoutPending() || (root && root->needsLayout()) || d->layoutRoot || (doc && doc->hasChangedChild());
}
void FrameView::setNeedsLayout()