Flag nsCaret::mPendingDraw if the on-cycle draw was suppressed; update the caret when the pres shell tells us that painting is unsuppressed. b=520720 r=roc
authorMats Palmgren <matspal@gmail.com>
Fri, 16 Oct 2009 12:55:32 +0200
changeset 33905 53f1a647625c8831e4482033dc47b0de4b9c8901
parent 33904 66c1213056bdb7a20bbf5ab7b08715e65e91aac0
child 33906 9603902c1e8f4687037292e1f5f421c4944342c4
push idunknown
push userunknown
push dateunknown
reviewersroc
bugs520720
milestone1.9.3a1pre
Flag nsCaret::mPendingDraw if the on-cycle draw was suppressed; update the caret when the pres shell tells us that painting is unsuppressed. b=520720 r=roc
layout/base/nsCaret.cpp
layout/base/nsCaret.h
layout/base/nsPresShell.cpp
--- a/layout/base/nsCaret.cpp
+++ b/layout/base/nsCaret.cpp
@@ -86,16 +86,17 @@ static const PRInt32 kMinBidiIndicatorPi
 
 //-----------------------------------------------------------------------------
 
 nsCaret::nsCaret()
 : mPresShell(nsnull)
 , mBlinkRate(500)
 , mVisible(PR_FALSE)
 , mDrawn(PR_FALSE)
+, mPendingDraw(PR_FALSE)
 , mReadOnly(PR_FALSE)
 , mShowDuringSelection(PR_FALSE)
 , mIgnoreUserModify(PR_TRUE)
 #ifdef IBMBIDI
 , mKeyboardRTL(PR_FALSE)
 , mLastBidiLevel(0)
 #endif
 , mLastContentOffset(0)
@@ -956,21 +957,29 @@ void nsCaret::GetViewForRendering(nsIFra
         }
       }
     }
   }
 
   *outRenderingView = returnView;
 }
 
-nsresult nsCaret::CheckCaretDrawingState() 
+nsresult nsCaret::CheckCaretDrawingState()
 {
-  // If the caret's drawn when it shouldn't be, erase it.
-  if (mDrawn && (!mVisible || !MustDrawCaret(PR_TRUE)))
-    EraseCaret();
+  if (mDrawn) {
+    // The caret is drawn; if it shouldn't be, erase it.
+    if (!mVisible || !MustDrawCaret(PR_TRUE))
+      EraseCaret();
+  }
+  else
+  {
+    // The caret is not drawn; if it should be, draw it.
+    if (mPendingDraw && (mVisible && MustDrawCaret(PR_TRUE)))
+      DrawCaret(PR_TRUE);
+  }
   return NS_OK;
 }
 
 /*-----------------------------------------------------------------------------
 
   MustDrawCaret
   
   Find out if we need to do any caret drawing. This returns true if
@@ -978,32 +987,24 @@ nsresult nsCaret::CheckCaretDrawingState
   a) The caret has been drawn, and we need to erase it.
   b) The caret is not drawn, and the selection is collapsed.
   c) The caret is not hidden due to open XUL popups
      (see IsMenuPopupHidingCaret()).
   
 ----------------------------------------------------------------------------- */
 PRBool nsCaret::MustDrawCaret(PRBool aIgnoreDrawnState)
 {
-  nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
-  if (presShell) {
-    PRBool isPaintingSuppressed;
-    presShell->IsPaintingSuppressed(&isPaintingSuppressed);
-    if (isPaintingSuppressed)
-      return PR_FALSE;
-  }
-
   if (!aIgnoreDrawnState && mDrawn)
     return PR_TRUE;
 
   nsCOMPtr<nsISelection> domSelection = do_QueryReferent(mDomSelectionWeak);
   if (!domSelection)
     return PR_FALSE;
+
   PRBool isCollapsed;
-
   if (NS_FAILED(domSelection->GetIsCollapsed(&isCollapsed)))
     return PR_FALSE;
 
   if (mShowDuringSelection)
     return PR_TRUE;      // show the caret even in selections
 
   if (IsMenuPopupHidingCaret())
     return PR_FALSE;
@@ -1054,28 +1055,39 @@ PRBool nsCaret::IsMenuPopupHidingCaret()
     }
   }
 #endif
 
   // There are no open menu popups, no need to hide the caret.
   return PR_FALSE;
 }
 
-/*-----------------------------------------------------------------------------
-
-  DrawCaret
-    
------------------------------------------------------------------------------ */
-
 void nsCaret::DrawCaret(PRBool aInvalidate)
 {
-  // do we need to draw the caret at all?
+  // Do we need to draw the caret at all?
   if (!MustDrawCaret(PR_FALSE))
     return;
   
+  // Can we draw the caret now?
+  nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
+  NS_ENSURE_TRUE(presShell, /**/);
+  {
+    PRBool isPaintingSuppressed;
+    presShell->IsPaintingSuppressed(&isPaintingSuppressed);
+    if (isPaintingSuppressed)
+    {
+      if (!mDrawn)
+        mPendingDraw = PR_TRUE;
+
+      // PresShell::UnsuppressAndInvalidate() will call CheckCaretDrawingState()
+      // to get us drawn.
+      return;
+    }
+  }
+
   nsCOMPtr<nsIDOMNode> node;
   PRInt32 offset;
   nsFrameSelection::HINT hint;
   PRUint8 bidiLevel;
 
   if (!mDrawn)
   {
     nsCOMPtr<nsISelection> domSelection = do_QueryReferent(mDomSelectionWeak);
@@ -1097,17 +1109,19 @@ void nsCaret::DrawCaret(PRBool aInvalida
       return;
     
     if (NS_FAILED(domSelection->GetFocusOffset(&offset)))
       return;
 
     nsCOMPtr<nsFrameSelection> frameSelection = GetFrameSelection();
     if (!frameSelection)
       return;
+
     bidiLevel = frameSelection->GetCaretBidiLevel();
+    mPendingDraw = PR_FALSE;
   }
   else
   {
     if (!mLastContent)
     {
       mDrawn = PR_FALSE;
       return;
     }
--- a/layout/base/nsCaret.h
+++ b/layout/base/nsCaret.h
@@ -276,23 +276,24 @@ protected:
     nsWeakPtr             mPresShell;
     nsWeakPtr             mDomSelectionWeak;
 
     nsCOMPtr<nsITimer>              mBlinkTimer;
     nsCOMPtr<nsIRenderingContext>   mRendContext;
 
     // XXX these fields should go away and the values be acquired as needed,
     // probably by ComputeMetrics.
-    PRUint32              mBlinkRate;         // time for one cyle (off then on), in milliseconds
+    PRUint32              mBlinkRate;         // time for one cyle (on then off), in milliseconds
     nscoord               mCaretWidthCSSPx;   // caret width in CSS pixels
     float                 mCaretAspectRatio;  // caret width/height aspect ratio
     
     PRPackedBool          mVisible;           // is the caret blinking
 
     PRPackedBool          mDrawn;             // Denotes when the caret is physically drawn on the screen.
+    PRPackedBool          mPendingDraw;       // True when the last on-state draw was suppressed.
 
     PRPackedBool          mReadOnly;          // it the caret in readonly state (draws differently)      
     PRPackedBool          mShowDuringSelection; // show when text is selected
 
     PRPackedBool          mIgnoreUserModify;
 
 #ifdef IBMBIDI
     PRPackedBool          mKeyboardRTL;       // is the keyboard language right-to-left
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -4636,16 +4636,20 @@ PresShell::UnsuppressAndInvalidate()
   
   mPaintingSuppressed = PR_FALSE;
   nsIFrame* rootFrame = FrameManager()->GetRootFrame();
   if (rootFrame) {
     // let's assume that outline on a root frame is not supported
     nsRect rect(nsPoint(0, 0), rootFrame->GetSize());
     rootFrame->Invalidate(rect);
 
+    if (mCaretEnabled && mCaret) {
+      mCaret->CheckCaretDrawingState();
+    }
+
     mPresContext->RootPresContext()->UpdatePluginGeometry(rootFrame);
   }
 
   // now that painting is unsuppressed, focus may be set on the document
   nsPIDOMWindow *win = mDocument->GetWindow();
   if (win)
     win->SetReadyForFocus();