Back to index

lightning-sunbird  0.9+nobinonly
Public Types | Public Member Functions | Static Public Member Functions | Public Attributes | Protected Member Functions | Protected Attributes
nsCaret Class Reference

#include <nsCaret.h>

Inheritance diagram for nsCaret:
Inheritance graph
[legend]
Collaboration diagram for nsCaret:
Collaboration graph
[legend]

List of all members.

Public Types

enum  EViewCoordinates { eTopLevelWindowCoordinates, eRenderingViewCoordinates, eClosestViewCoordinates, eIMECoordinates }

Public Member Functions

 nsCaret ()
virtual ~nsCaret ()
NS_IMETHOD Init (nsIPresShell *inPresShell)
NS_IMETHOD Terminate ()
NS_IMETHOD GetCaretDOMSelection (nsISelection **outDOMSel)
NS_IMETHOD SetCaretDOMSelection (nsISelection *inDOMSel)
NS_IMETHOD GetCaretVisible (PRBool *outMakeVisible)
 GetCaretVisible will get the visibility of the caret.
NS_IMETHOD SetCaretVisible (PRBool intMakeVisible)
 SetCaretVisible will set the visibility of the caret.
NS_IMETHOD SetCaretReadOnly (PRBool inMakeReadonly)
 SetCaretReadOnly set the appearance of the caret.
NS_IMETHOD GetCaretCoordinates (EViewCoordinates aRelativeToType, nsISelection *inDOMSel, nsRect *outCoordinates, PRBool *outIsCollapsed, nsIView **outView)
 GetCaretCoordinates Get the position of the caret in coordinates relative to the typed specified (aRelativeToType).
NS_IMETHOD EraseCaret ()
 Erase Caret this will erase the caret if its drawn and reset drawn status.
NS_IMETHOD SetVisibilityDuringSelection (PRBool aVisibility)
NS_IMETHOD DrawAtPosition (nsIDOMNode *aNode, PRInt32 aOffset)
 DrawAtPosition.
NS_IMETHOD GetCaretFrameForNodeOffset (nsIContent *aContentNode, PRInt32 aOffset, nsIFrameSelection::HINT aFrameHint, PRUint8 aBidiLevel, nsIFrame **aReturnFrame, PRInt32 *aReturnOffset)
 GetCaretFrameForNodeOffset Get the frame and content offset at which the caret is drawn, invoking the bidi caret positioning algorithm if necessary.
void notifySelectionChanged (in nsIDOMDocument doc, in nsISelection sel, in short reason)

Static Public Member Functions

static
NS_DECL_NSISELECTIONLISTENER
void 
CaretBlinkCallback (nsITimer *aTimer, void *aClosure)

Public Attributes

const short NO_REASON = 0
const short DRAG_REASON = 1
const short MOUSEDOWN_REASON = 2
const short MOUSEUP_REASON = 4
const short KEYPRESS_REASON = 8
const short SELECTALL_REASON = 16

Protected Member Functions

void KillTimer ()
nsresult PrimeTimer ()
nsresult StartBlinking ()
nsresult StopBlinking ()
void GetViewForRendering (nsIFrame *caretFrame, EViewCoordinates coordType, nsPoint &viewOffset, nsRect &outClipRect, nsIView **outRenderingView, nsIView **outRelativeView)
PRBool DrawAtPositionWithHint (nsIDOMNode *aNode, PRInt32 aOffset, nsIFrameSelection::HINT aFrameHint, PRUint8 aBidiLevel)
PRBool MustDrawCaret ()
void DrawCaret ()
void GetCaretRectAndInvert (nsIFrame *aFrame, PRInt32 aFrameOffset)
void ToggleDrawnStatus ()

Protected Attributes

nsWeakPtr mPresShell
nsWeakPtr mDomSelectionWeak
nsCOMPtr< nsITimermBlinkTimer
nsCOMPtr< nsIRenderingContextmRendContext
PRUint32 mBlinkRate
nscoord mCaretTwipsWidth
nscoord mBidiIndicatorTwipsSize
PRPackedBool mVisible
PRPackedBool mDrawn
PRPackedBool mReadOnly
PRPackedBool mShowDuringSelection
nsRect mCaretRect
nsIViewmLastCaretView
nsCOMPtr< nsIContentmLastContent
PRInt32 mLastContentOffset
nsIFrameSelection::HINT mLastHint

Detailed Description

Definition at line 54 of file nsCaret.h.


Member Enumeration Documentation

enum nsICaret::EViewCoordinates [inherited]
Enumerator:
eTopLevelWindowCoordinates 
eRenderingViewCoordinates 
eClosestViewCoordinates 
eIMECoordinates 

Definition at line 67 of file nsICaret.h.


Constructor & Destructor Documentation

Definition at line 92 of file nsCaret.cpp.

nsCaret::~nsCaret ( ) [virtual]

Definition at line 111 of file nsCaret.cpp.

{
  KillTimer();
}

Here is the call graph for this function:


Member Function Documentation

void nsCaret::CaretBlinkCallback ( nsITimer aTimer,
void aClosure 
) [static]

Definition at line 1171 of file nsCaret.cpp.

{
  nsCaret   *theCaret = NS_REINTERPRET_CAST(nsCaret*, aClosure);
  if (!theCaret) return;
  
  theCaret->DrawCaret();
}

Here is the call graph for this function:

Here is the caller graph for this function:

NS_IMETHODIMP nsCaret::DrawAtPosition ( nsIDOMNode aNode,
PRInt32  aOffset 
) [virtual]

DrawAtPosition.

Draw the caret explicitly, at the specified node and offset. To avoid drawing glitches, you should call EraseCaret() after each call to DrawAtPosition().

Implements nsICaret.

Definition at line 407 of file nsCaret.cpp.

{
  NS_ENSURE_ARG(aNode);

  PRUint8 bidiLevel;
  nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
  if (!presShell)
    return NS_ERROR_FAILURE;
  presShell->GetCaretBidiLevel(&bidiLevel);
  
  // XXX we need to do more work here to get the correct hint.
  return DrawAtPositionWithHint(aNode, aOffset, nsIFrameSelection::HINTLEFT, bidiLevel) ?
    NS_OK : NS_ERROR_FAILURE;
}

Here is the call graph for this function:

PRBool nsCaret::DrawAtPositionWithHint ( nsIDOMNode aNode,
PRInt32  aOffset,
nsIFrameSelection::HINT  aFrameHint,
PRUint8  aBidiLevel 
) [protected]

Definition at line 517 of file nsCaret.cpp.

{  
  nsCOMPtr<nsIContent> contentNode = do_QueryInterface(aNode);
  if (!contentNode)
    return PR_FALSE;
      
  nsIFrame* theFrame = nsnull;
  PRInt32   theFrameOffset = 0;

  nsresult rv = GetCaretFrameForNodeOffset(contentNode, aOffset, aFrameHint, aBidiLevel,
                                           &theFrame, &theFrameOffset);
  if (NS_FAILED(rv) || !theFrame)
    return PR_FALSE;
  
  // now we have a frame, check whether it's appropriate to show the caret here
  const nsStyleUserInterface* userinterface = theFrame->GetStyleUserInterface();
  if (
#ifdef SUPPORT_USER_MODIFY
        // editable content still defaults to NS_STYLE_USER_MODIFY_READ_ONLY at present. See bug 15284
      (userinterface->mUserModify == NS_STYLE_USER_MODIFY_READ_ONLY) ||
#endif          
      (userinterface->mUserInput == NS_STYLE_USER_INPUT_NONE) ||
      (userinterface->mUserInput == NS_STYLE_USER_INPUT_DISABLED))
  {
    return PR_FALSE;
  }  

  if (!mDrawn)
  {
    // save stuff so we can erase the caret later
    mLastContent = contentNode;
    mLastContentOffset = aOffset;
    mLastHint = aFrameHint;
    mLastBidiLevel = aBidiLevel;

    // If there has been a reflow, set the caret Bidi level to the level of the current frame
    nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
    if (!presShell)
      return PR_FALSE;
    if (aBidiLevel & BIDI_LEVEL_UNDEFINED)
      presShell->SetCaretBidiLevel(NS_GET_EMBEDDING_LEVEL(theFrame));
  }

  GetCaretRectAndInvert(theFrame, theFrameOffset);

  return PR_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsCaret::DrawCaret ( ) [protected]

Definition at line 895 of file nsCaret.cpp.

{
  // do we need to draw the caret at all?
  if (!MustDrawCaret())
    return;
  
  nsCOMPtr<nsIDOMNode> node;
  PRInt32 offset;
  nsIFrameSelection::HINT hint;
  PRUint8 bidiLevel;

  if (!mDrawn)
  {
    nsCOMPtr<nsISelection> domSelection = do_QueryReferent(mDomSelectionWeak);
    nsCOMPtr<nsISelectionPrivate> privateSelection(do_QueryInterface(domSelection));
    if (!privateSelection) return;
    
    PRBool isCollapsed = PR_FALSE;
    domSelection->GetIsCollapsed(&isCollapsed);
    if (!mShowDuringSelection && !isCollapsed)
      return;

    PRBool hintRight;
    privateSelection->GetInterlinePosition(&hintRight);//translate hint.
    hint = hintRight ? nsIFrameSelection::HINTRIGHT : nsIFrameSelection::HINTLEFT;

    // get the node and offset, which is where we want the caret to draw
    domSelection->GetFocusNode(getter_AddRefs(node));
    if (!node)
      return;
    
    if (NS_FAILED(domSelection->GetFocusOffset(&offset)))
      return;

    nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
    if (!presShell)
      return;
    presShell->GetCaretBidiLevel(&bidiLevel);
  }
  else
  {
    if (!mLastContent)
    {
      mDrawn = PR_FALSE;
      return;
    }
    if (!mLastContent->IsInDoc())
    {
      mLastContent = nsnull;
      mDrawn = PR_FALSE;
      return;
    }
    node = do_QueryInterface(mLastContent);
    offset = mLastContentOffset;
    hint = mLastHint;
    bidiLevel = mLastBidiLevel;
  }

  DrawAtPositionWithHint(node, offset, hint, bidiLevel);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Erase Caret this will erase the caret if its drawn and reset drawn status.

Implements nsICaret.

Definition at line 394 of file nsCaret.cpp.

{
  if (mDrawn)
    DrawCaret();
  return NS_OK;
}

Here is the call graph for this function:

NS_IMETHODIMP nsCaret::GetCaretCoordinates ( EViewCoordinates  aRelativeToType,
nsISelection aDOMSel,
nsRect outCoordinates,
PRBool outIsCollapsed,
nsIView **  outView 
) [virtual]

GetCaretCoordinates Get the position of the caret in coordinates relative to the typed specified (aRelativeToType).

If the selection is collapsed, this returns the caret location and true in outIsCollapsed. If the selection is not collapsed, this returns the location of the focus pos, and false in outIsCollapsed.

Implements nsICaret.

Definition at line 278 of file nsCaret.cpp.

{
  if (!mPresShell)
    return NS_ERROR_NOT_INITIALIZED;
  if (!outCoordinates || !outIsCollapsed)
    return NS_ERROR_NULL_POINTER;

  nsCOMPtr<nsISelection> domSelection = aDOMSel;
  nsCOMPtr<nsISelectionPrivate> privateSelection(do_QueryInterface(domSelection));
  if (!privateSelection)
    return NS_ERROR_NOT_INITIALIZED;    // no selection

  if (outView)
    *outView = nsnull;

  // fill in defaults for failure
  outCoordinates->x = -1;
  outCoordinates->y = -1;
  outCoordinates->width = -1;
  outCoordinates->height = -1;
  *outIsCollapsed = PR_FALSE;
  
  nsresult err = domSelection->GetIsCollapsed(outIsCollapsed);
  if (NS_FAILED(err)) 
    return err;
    
  nsCOMPtr<nsIDOMNode>  focusNode;
  
  err = domSelection->GetFocusNode(getter_AddRefs(focusNode));
  if (NS_FAILED(err))
    return err;
  if (!focusNode)
    return NS_ERROR_FAILURE;
  
  PRInt32 focusOffset;
  err = domSelection->GetFocusOffset(&focusOffset);
  if (NS_FAILED(err))
    return err;
    
/*
  // is this a text node?
  nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(focusNode);
  // note that we only work with text nodes here, unlike when drawing the caret.
  // this is because this routine is intended for IME support, which only cares about text.
  if (!nodeAsText)
    return NS_ERROR_UNEXPECTED;
*/  
  nsCOMPtr<nsIContent>contentNode = do_QueryInterface(focusNode);
  if (!contentNode)
    return NS_ERROR_FAILURE;

  // find the frame that contains the content node that has focus
  nsIFrame*       theFrame = nsnull;
  PRInt32         theFrameOffset = 0;

  nsCOMPtr<nsIFrameSelection> frameSelection;
  privateSelection->GetFrameSelection(getter_AddRefs(frameSelection));

  nsIFrameSelection::HINT hint;
  frameSelection->GetHint(&hint);

  PRUint8 bidiLevel;
  nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
  if (!presShell)
    return NS_ERROR_FAILURE;
  presShell->GetCaretBidiLevel(&bidiLevel);
  
  err = GetCaretFrameForNodeOffset(contentNode,
                                   focusOffset, hint,
                                   bidiLevel,
                                   &theFrame,
                                   &theFrameOffset);
  if (NS_FAILED(err) || !theFrame)
    return err;
  
  nsPoint   viewOffset(0, 0);
  nsRect    clipRect;
  nsIView   *drawingView;     // views are not refcounted

  GetViewForRendering(theFrame, aRelativeToType, viewOffset, clipRect, &drawingView, outView);
  if (!drawingView)
    return NS_ERROR_UNEXPECTED;
  // ramp up to make a rendering context for measuring text.
  // First, we get the pres context ...
  nsPresContext *presContext = presShell->GetPresContext();

  // ... then tell it to make a rendering context
  nsCOMPtr<nsIRenderingContext> rendContext;  
  err = presContext->DeviceContext()->
    CreateRenderingContext(drawingView, *getter_AddRefs(rendContext));
  if (NS_FAILED(err))
    return err;
  if (!rendContext)
    return NS_ERROR_UNEXPECTED;

  // now we can measure the offset into the frame.
  nsPoint   framePos(0, 0);
  theFrame->GetPointFromOffset(presContext, rendContext, theFrameOffset, &framePos);

  // we don't need drawingView anymore so reuse that; reset viewOffset values for our purposes
  if (aRelativeToType == eClosestViewCoordinates)
  {
    theFrame->GetOffsetFromView(viewOffset, &drawingView);
    if (outView)
      *outView = drawingView;
  }
  // now add the frame offset to the view offset, and we're done
  viewOffset += framePos;
  outCoordinates->x = viewOffset.x;
  outCoordinates->y = viewOffset.y;
  outCoordinates->height = theFrame->GetSize().height;
  outCoordinates->width  = mCaretTwipsWidth;
  
  return NS_OK;
}

Here is the call graph for this function:

Implements nsICaret.

Definition at line 220 of file nsCaret.cpp.

Here is the call graph for this function:

NS_IMETHODIMP nsCaret::GetCaretFrameForNodeOffset ( nsIContent aContentNode,
PRInt32  aOffset,
nsIFrameSelection::HINT  aFrameHint,
PRUint8  aBidiLevel,
nsIFrame **  aReturnFrame,
PRInt32 aReturnOffset 
) [virtual]

GetCaretFrameForNodeOffset Get the frame and content offset at which the caret is drawn, invoking the bidi caret positioning algorithm if necessary.

Implements nsICaret.

Definition at line 569 of file nsCaret.cpp.

{

  //get frame selection and find out what frame to use...
  nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
  if (!presShell)
    return NS_ERROR_FAILURE;

  nsCOMPtr<nsISelectionPrivate> privateSelection(do_QueryReferent(mDomSelectionWeak));
  if (!privateSelection)
    return NS_ERROR_FAILURE;

  nsCOMPtr<nsIFrameSelection> frameSelection;
  privateSelection->GetFrameSelection(getter_AddRefs(frameSelection));

  nsIFrame* theFrame = nsnull;
  PRInt32   theFrameOffset = 0;

  nsresult rv = frameSelection->GetFrameForNodeOffset(aContentNode, aOffset, aFrameHint, &theFrame, &theFrameOffset);
  if (NS_FAILED(rv) || !theFrame)
    return NS_ERROR_FAILURE;

  // Mamdouh : modification of the caret to work at rtl and ltr with Bidi
  //
  // Direction Style from this->GetStyleData()
  // now in (visibility->mDirection)
  // ------------------
  // NS_STYLE_DIRECTION_LTR : LTR or Default
  // NS_STYLE_DIRECTION_RTL
  // NS_STYLE_DIRECTION_INHERIT
  nsPresContext *presContext = presShell->GetPresContext();
  if (presContext && presContext->BidiEnabled())
  {
    // If there has been a reflow, take the caret Bidi level to be the level of the current frame
    if (aBidiLevel & BIDI_LEVEL_UNDEFINED)
      aBidiLevel = NS_GET_EMBEDDING_LEVEL(theFrame);

    PRInt32 start;
    PRInt32 end;
    nsIFrame* frameBefore;
    nsIFrame* frameAfter;
    PRUint8 levelBefore;     // Bidi level of the character before the caret
    PRUint8 levelAfter;      // Bidi level of the character after the caret

    theFrame->GetOffsets(start, end);
    if (start == 0 || end == 0 || start == theFrameOffset || end == theFrameOffset)
    {
      /* Boundary condition, we need to know the Bidi levels of the characters before and after the caret */
      if (NS_SUCCEEDED(frameSelection->GetPrevNextBidiLevels(presContext, aContentNode, aOffset,
                                                             &frameBefore, &frameAfter,
                                                             &levelBefore, &levelAfter)))
      {
        if ((levelBefore != levelAfter) || (aBidiLevel != levelBefore))
        {
          aBidiLevel = PR_MAX(aBidiLevel, PR_MIN(levelBefore, levelAfter));                                  // rule c3
          aBidiLevel = PR_MIN(aBidiLevel, PR_MAX(levelBefore, levelAfter));                                  // rule c4
          if (aBidiLevel == levelBefore                                                                      // rule c1
              || aBidiLevel > levelBefore && aBidiLevel < levelAfter && !((aBidiLevel ^ levelBefore) & 1)    // rule c5
              || aBidiLevel < levelBefore && aBidiLevel > levelAfter && !((aBidiLevel ^ levelBefore) & 1))   // rule c9
          {
            if (theFrame != frameBefore)
            {
              if (frameBefore) // if there is a frameBefore, move into it
              {
                theFrame = frameBefore;
                theFrame->GetOffsets(start, end);
                theFrameOffset = end;
              }
              else 
              {
                // if there is no frameBefore, we must be at the beginning of the line
                // so we stay with the current frame.
                // Exception: when the first frame on the line has a different Bidi level from the paragraph level, there is no
                // real frame for the caret to be in. We have to find the first frame whose level is the same as the
                // paragraph level, and put the caret at the end of the frame before that.
                PRUint8 baseLevel = NS_GET_BASE_LEVEL(frameAfter);
                if (baseLevel != levelAfter)
                {
                  if (NS_SUCCEEDED(frameSelection->GetFrameFromLevel(presContext, frameAfter, eDirNext, baseLevel, &theFrame)))
                  {
                    theFrame->GetOffsets(start, end);
                    levelAfter = NS_GET_EMBEDDING_LEVEL(theFrame);
                    if (baseLevel & 1) // RTL paragraph: caret to the right of the rightmost character
                      theFrameOffset = (levelAfter & 1) ? start : end;
                    else               // LTR paragraph: caret to the left of the leftmost character
                      theFrameOffset = (levelAfter & 1) ? end : start;
                  }
                }
              }
            }
          }
          else if (aBidiLevel == levelAfter                                                                     // rule c2
                   || aBidiLevel > levelBefore && aBidiLevel < levelAfter && !((aBidiLevel ^ levelAfter) & 1)   // rule c6  
                   || aBidiLevel < levelBefore && aBidiLevel > levelAfter && !((aBidiLevel ^ levelAfter) & 1))  // rule c10
          {
            if (theFrame != frameAfter)
            {
              if (frameAfter)
              {
                // if there is a frameAfter, move into it
                theFrame = frameAfter;
                theFrame->GetOffsets(start, end);
                theFrameOffset = start;
              }
              else 
              {
                // if there is no frameAfter, we must be at the end of the line
                // so we stay with the current frame.
                //
                // Exception: when the last frame on the line has a different Bidi level from the paragraph level, there is no
                // real frame for the caret to be in. We have to find the last frame whose level is the same as the
                // paragraph level, and put the caret at the end of the frame after that.

                PRUint8 baseLevel = NS_GET_BASE_LEVEL(frameBefore);
                if (baseLevel != levelBefore)
                {
                  if (NS_SUCCEEDED(frameSelection->GetFrameFromLevel(presContext, frameBefore, eDirPrevious, baseLevel, &theFrame)))
                  {
                    theFrame->GetOffsets(start, end);
                    levelBefore = NS_GET_EMBEDDING_LEVEL(theFrame);
                    if (baseLevel & 1) // RTL paragraph: caret to the left of the leftmost character
                      theFrameOffset = (levelBefore & 1) ? end : start;
                    else               // RTL paragraph: caret to the right of the rightmost character
                      theFrameOffset = (levelBefore & 1) ? start : end;
                  }
                }
              }
            }
          }
          else if (aBidiLevel > levelBefore && aBidiLevel < levelAfter  // rule c7/8
                   && !((levelBefore ^ levelAfter) & 1)                 // before and after have the same parity
                   && ((aBidiLevel ^ levelAfter) & 1))                  // caret has different parity
          {
            if (NS_SUCCEEDED(frameSelection->GetFrameFromLevel(presContext, frameAfter, eDirNext, aBidiLevel, &theFrame)))
            {
              theFrame->GetOffsets(start, end);
              levelAfter = NS_GET_EMBEDDING_LEVEL(theFrame);
              if (aBidiLevel & 1) // c8: caret to the right of the rightmost character
                theFrameOffset = (levelAfter & 1) ? start : end;
              else               // c7: caret to the left of the leftmost character
                theFrameOffset = (levelAfter & 1) ? end : start;
            }
          }
          else if (aBidiLevel < levelBefore && aBidiLevel > levelAfter  // rule c11/12
                   && !((levelBefore ^ levelAfter) & 1)                 // before and after have the same parity
                   && ((aBidiLevel ^ levelAfter) & 1))                  // caret has different parity
          {
            if (NS_SUCCEEDED(frameSelection->GetFrameFromLevel(presContext, frameBefore, eDirPrevious, aBidiLevel, &theFrame)))
            {
              theFrame->GetOffsets(start, end);
              levelBefore = NS_GET_EMBEDDING_LEVEL(theFrame);
              if (aBidiLevel & 1) // c12: caret to the left of the leftmost character
                theFrameOffset = (levelBefore & 1) ? end : start;
              else               // c11: caret to the right of the rightmost character
                theFrameOffset = (levelBefore & 1) ? start : end;
            }
          }   
        }
      }
    }
  }
  *aReturnFrame = theFrame;
  *aReturnOffset = theFrameOffset;
  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsCaret::GetCaretRectAndInvert ( nsIFrame aFrame,
PRInt32  aFrameOffset 
) [protected]

Definition at line 956 of file nsCaret.cpp.

{
  NS_ASSERTION(aFrame, "Should have a frame here");

  nsRect frameRect = aFrame->GetRect();
  frameRect.x = 0;      // the origin is accounted for in GetViewForRendering()
  frameRect.y = 0;
  
  nsPoint   viewOffset(0, 0);
  nsRect    clipRect;
  nsIView   *drawingView;
  GetViewForRendering(aFrame, eRenderingViewCoordinates, viewOffset, clipRect, &drawingView, nsnull);
  
  if (!drawingView)
    return;
  
  frameRect += viewOffset;

  nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
  if (!presShell) return;
  
  nsPresContext *presContext = presShell->GetPresContext();

  // if the view changed, or we don't have a rendering context, make one
  // because of drawing issues, always make a new RC at the moment. See bug 28068
  if (
#ifdef DONT_REUSE_RENDERING_CONTEXT
      PR_TRUE ||
#endif
      (mLastCaretView != drawingView) || !mRendContext)
  {
    mRendContext = nsnull;    // free existing one if we have one
    
    nsresult rv = presContext->DeviceContext()->
      CreateRenderingContext(drawingView, *getter_AddRefs(mRendContext));

    if (NS_FAILED(rv) || !mRendContext)
      return;      
  }

  // push a known good state
  mRendContext->PushState();

  // if we got a zero-height frame, it's probably a BR frame at the end of a non-empty line
  // (see BRFrame::Reflow). In that case, figure out a height. We have to do this
  // after we've got an RC.
  if (frameRect.height == 0)
  {
      const nsStyleFont* fontStyle = aFrame->GetStyleFont();
      const nsStyleVisibility* vis = aFrame->GetStyleVisibility();
      mRendContext->SetFont(fontStyle->mFont, vis->mLangGroup);

      nsCOMPtr<nsIFontMetrics> fm;
      mRendContext->GetFontMetrics(*getter_AddRefs(fm));
      if (fm)
      {
        nscoord ascent, descent;
        fm->GetMaxAscent(ascent);
        fm->GetMaxDescent(descent);
        frameRect.height = ascent + descent;
        frameRect.y -= ascent; // BR frames sit on the baseline of the text, so we need to subtract
                               // the ascent to account for the frame height.
      }
  }
  
  // views are not refcounted
  mLastCaretView = drawingView;

  if (!mDrawn)
  {
    nsPoint   framePos(0, 0);
    nsRect    caretRect = frameRect;
    nsCOMPtr<nsISelection> domSelection = do_QueryReferent(mDomSelectionWeak);
    nsCOMPtr<nsISelectionPrivate> privateSelection = do_QueryInterface(domSelection);

    // if cache in selection is available, apply it, else refresh it
    privateSelection->GetCachedFrameOffset(aFrame, aFrameOffset, framePos);

    caretRect += framePos;

    caretRect.width = mCaretTwipsWidth;

    // Check if the caret intersects with the right edge
    // of the frame. If it does, and the frame's right edge
    // is close to the right edge of the clipRect, we may
    // need to adjust the caret's x position so that it
    // remains visible.

    nscoord caretXMost = caretRect.XMost();
    nscoord frameXMost = frameRect.XMost();

    if (caretXMost > frameXMost)
    {
      nscoord clipXMost  = clipRect.XMost();

      if (caretRect.x == frameRect.x && caretRect.x <= clipXMost &&
          caretXMost > clipXMost)
      {
        // The left side of the caret is attached to the left edge of
        // the frame, and it is wider than the frame itself. It also
        // overlaps the right edge of the clipRect so we need to nudge
        // it to the left so that it remains visible.
        //
        // We usually hit this case when the caret is attached to a
        // br frame (which is about 1 twip in width) that is positioned
        // at the right edge of the content area because it is right aligned
        // or the right margin pushed it beyond the width of the view port.

        caretRect.x = clipXMost - caretRect.width;
      }
      else if (caretRect.x == frameXMost && frameXMost == clipXMost)
      {
        // The left side of the caret is attached to the right edge of
        // the frame, but it's going to get clipped because it's positioned
        // on the  right edge of the clipRect, so nudge it to the
        // left so it remains visible.
        //
        // We usually hit this case when the caret is after the last
        // character on the line, and the line exceeds the width of the
        // view port.

        caretRect.x = clipXMost - caretRect.width;
      }
    }

    mCaretRect.IntersectRect(clipRect, caretRect);
#ifdef IBMBIDI
    // Simon -- make a hook to draw to the left or right of the caret to show keyboard language direction
    PRBool bidiEnabled;
    nsRect hookRect;
    PRBool isCaretRTL=PR_FALSE;
    if (mBidiKeyboard)
      mBidiKeyboard->IsLangRTL(&isCaretRTL);
    if (isCaretRTL)
    {
      bidiEnabled = PR_TRUE;
      presContext->SetBidiEnabled(bidiEnabled);
    }
    else
      bidiEnabled = presContext->BidiEnabled();
    if (bidiEnabled)
    {
      if (isCaretRTL != mKeyboardRTL)
      {
        /* if the caret bidi level and the keyboard language direction are not in
         * synch, the keyboard language must have been changed by the
         * user, and if the caret is in a boundary condition (between left-to-right and
         * right-to-left characters) it may have to change position to
         * reflect the location in which the next character typed will
         * appear. We will call |SelectionLanguageChange| and exit
         * without drawing the caret in the old position.
         */ 
        mKeyboardRTL = isCaretRTL;
        nsCOMPtr<nsISelection> domSelection = do_QueryReferent(mDomSelectionWeak);
        if (domSelection)
        {
          if (NS_SUCCEEDED(domSelection->SelectionLanguageChange(mKeyboardRTL)))
          {
            mRendContext->PopState();
#ifdef DONT_REUSE_RENDERING_CONTEXT
            mRendContext = nsnull;
#endif
            return;
          }
        }
      }
      // If keyboard language is RTL, draw the hook on the left; if LTR, to the right
      // The height of the hook rectangle is the same as the width of the caret
      // rectangle.
      hookRect.SetRect(caretRect.x + ((isCaretRTL) ?
                                       mBidiIndicatorTwipsSize * -1 :
                                       caretRect.width),
                       caretRect.y + mBidiIndicatorTwipsSize,
                       mBidiIndicatorTwipsSize,
                       caretRect.width);
      mHookRect.IntersectRect(clipRect, hookRect);
    }
#endif //IBMBIDI
  }
  
  if (mReadOnly)
    mRendContext->SetColor(NS_RGB(85, 85, 85));   // we are drawing it; gray
  else
    mRendContext->SetColor(NS_RGB(255,255,255));

  mRendContext->InvertRect(mCaretRect);

  // Ensure the buffer is flushed (Cocoa needs this), since we're drawing
  // outside the normal painting process.
  mRendContext->FlushRect(mCaretRect);

#ifdef IBMBIDI
  if (!mHookRect.IsEmpty()) // if Bidi support is disabled, the rectangle remains empty and won't be drawn
    mRendContext->InvertRect(mHookRect);
#endif

  mRendContext->PopState();
  
  ToggleDrawnStatus();

  if (mDrawn) {
    aFrame->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE);
  }

#ifdef DONT_REUSE_RENDERING_CONTEXT
  mRendContext = nsnull;
#endif
}

Here is the call graph for this function:

Here is the caller graph for this function:

NS_IMETHODIMP nsCaret::GetCaretVisible ( PRBool outMakeVisible) [virtual]

GetCaretVisible will get the visibility of the caret.

Parameters:
inMakeVisiblePR_TRUE it is shown, PR_FALSE it is hidden

Implements nsICaret.

Definition at line 261 of file nsCaret.cpp.

{
  NS_ENSURE_ARG_POINTER(outMakeVisible);
  *outMakeVisible = mVisible;
  return NS_OK;
}
void nsCaret::GetViewForRendering ( nsIFrame caretFrame,
EViewCoordinates  coordType,
nsPoint viewOffset,
nsRect outClipRect,
nsIView **  outRenderingView,
nsIView **  outRelativeView 
) [protected]

Definition at line 742 of file nsCaret.cpp.

{

  if (!caretFrame || !outRenderingView)
    return;

  // XXX by Masayuki Nakano:
  // Our this code is not good. This is adhoc approach.
  // Our best approach is to use the event fired widget related view.
  // But if we do so, we need large change for editor and this.
  if (coordType == eIMECoordinates)
#if defined(XP_MAC) || defined(XP_MACOSX) || defined(XP_WIN)
   // #59405 and #313918, on Mac and Windows, the coordinate for IME need to be
   // root view related.
   coordType = eTopLevelWindowCoordinates; 
#else
   // #59405, on unix, the coordinate for IME need to be view
   // (nearest native window) related.
   coordType = eRenderingViewCoordinates; 
#endif

  *outRenderingView = nsnull;
  if (outRelativeView)
    *outRelativeView = nsnull;
  
  NS_ASSERTION(caretFrame, "Should have frame here");
 
  viewOffset.x = 0;
  viewOffset.y = 0;
  
  nsPoint   withinViewOffset(0, 0);
  // get the offset of this frame from its parent view (walks up frame hierarchy)
  nsIView* theView = nsnull;
  caretFrame->GetOffsetFromView(withinViewOffset, &theView);
  if (theView == nsnull) return;

  if (outRelativeView && coordType == eClosestViewCoordinates)
    *outRelativeView = theView;

  nsIView*    returnView = nsnull;    // views are not refcounted
  
  // coorinates relative to the view we are going to use for drawing
  if (coordType == eRenderingViewCoordinates)
  {
    nsIScrollableView*  scrollableView = nsnull;
  
    nsPoint             drawViewOffset(0, 0);         // offset to the view we are using to draw
    
    // walk up to the first view with a widget
    do {
      //is this a scrollable view?
      if (!scrollableView)
        scrollableView = theView->ToScrollableView();

      if (theView->HasWidget())
      {
        returnView = theView;
        // account for the view's origin not lining up with the widget's (bug 190290)
        drawViewOffset += theView->GetPosition() - theView->GetBounds().TopLeft();
        break;
      }
      drawViewOffset += theView->GetPosition();
      theView = theView->GetParent();
    } while (theView);
    
    viewOffset = withinViewOffset;
    viewOffset += drawViewOffset;
    
    if (scrollableView)
    {
      nsRect  bounds = scrollableView->View()->GetBounds();
      scrollableView->GetScrollPosition(bounds.x, bounds.y);
      
      bounds += drawViewOffset;   // offset to coords of returned view
      outClipRect = bounds;
    }
    else
    {
      NS_ASSERTION(returnView, "bulletproofing, see bug #24329");
      if (returnView)
        outClipRect = returnView->GetBounds();
    }

    if (outRelativeView)
      *outRelativeView = returnView;
  }
  else
  {
    // window-relative coordinates (walk right to the top of the view hierarchy)
    // we don't do anything with clipping here
    viewOffset = withinViewOffset;

    do {
      if (!returnView && theView->HasWidget())
        returnView = theView;
      // is this right?
      viewOffset += theView->GetPosition();
      
      if (outRelativeView && coordType == eTopLevelWindowCoordinates)
        *outRelativeView = theView;

      theView = theView->GetParent();
    } while (theView);
  }
  
  *outRenderingView = returnView;
}

Here is the call graph for this function:

Here is the caller graph for this function:

NS_IMETHODIMP nsCaret::Init ( nsIPresShell inPresShell) [virtual]

Implements nsICaret.

Definition at line 117 of file nsCaret.cpp.

{
  NS_ENSURE_ARG(inPresShell);
  
  mPresShell = do_GetWeakReference(inPresShell);    // the presshell owns us, so no addref
  NS_ASSERTION(mPresShell, "Hey, pres shell should support weak refs");

  // get nsILookAndFeel from the pres context, which has one cached.
  nsILookAndFeel *lookAndFeel = nsnull;
  nsPresContext *presContext = inPresShell->GetPresContext();
  
  PRInt32 caretPixelsWidth = 1;
  if (presContext && (lookAndFeel = presContext->LookAndFeel())) {
    PRInt32 tempInt;
    if (NS_SUCCEEDED(lookAndFeel->GetMetric(nsILookAndFeel::eMetric_CaretWidth, tempInt)))
      caretPixelsWidth = (nscoord)tempInt;
    if (NS_SUCCEEDED(lookAndFeel->GetMetric(nsILookAndFeel::eMetric_CaretBlinkTime, tempInt)))
      mBlinkRate = (PRUint32)tempInt;
    if (NS_SUCCEEDED(lookAndFeel->GetMetric(nsILookAndFeel::eMetric_ShowCaretDuringSelection, tempInt)))
      mShowDuringSelection = tempInt ? PR_TRUE : PR_FALSE;
  }
  
  float tDevUnitsToTwips;
  tDevUnitsToTwips = presContext->DeviceContext()->DevUnitsToTwips();
  mCaretTwipsWidth = (nscoord)(tDevUnitsToTwips * (float)caretPixelsWidth);
  mBidiIndicatorTwipsSize = (nscoord)(tDevUnitsToTwips * (float)kMinBidiIndicatorPixels);
  if (mBidiIndicatorTwipsSize < mCaretTwipsWidth) {
    mBidiIndicatorTwipsSize = mCaretTwipsWidth;
  }

  // get the selection from the pres shell, and set ourselves up as a selection
  // listener

  nsCOMPtr<nsISelectionController> selCon = do_QueryReferent(mPresShell);
  if (!selCon)
    return NS_ERROR_FAILURE;

  nsCOMPtr<nsISelection> domSelection;
  nsresult rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSelection));
  if (NS_FAILED(rv))
    return rv;
  if (!domSelection)
    return NS_ERROR_FAILURE;

  nsCOMPtr<nsISelectionPrivate> privateSelection = do_QueryInterface(domSelection);
  if (privateSelection)
    privateSelection->AddSelectionListener(this);
  mDomSelectionWeak = do_GetWeakReference(domSelection);
  
  // set up the blink timer
  if (mVisible)
  {
    rv = StartBlinking();
    if (NS_FAILED(rv))
      return rv;
  }

#ifdef IBMBIDI
  PRBool isRTL = PR_FALSE;
  mBidiKeyboard = do_GetService("@mozilla.org/widget/bidikeyboard;1");
  if (mBidiKeyboard)
       mBidiKeyboard->IsLangRTL(&isRTL);
  mKeyboardRTL = isRTL;
#endif
  
  return NS_OK;
}

Here is the call graph for this function:

void nsCaret::KillTimer ( ) [protected]

Definition at line 463 of file nsCaret.cpp.

{
  if (mBlinkTimer)
  {
    mBlinkTimer->Cancel();
  }
}

Here is the caller graph for this function:

PRBool nsCaret::MustDrawCaret ( ) [protected]

Definition at line 861 of file nsCaret.cpp.

{
  nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
  if (presShell) {
    PRBool isPaintingSuppressed;
    presShell->IsPaintingSuppressed(&isPaintingSuppressed);
    if (isPaintingSuppressed)
      return PR_FALSE;
  }

  if (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

  return isCollapsed;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsISelectionListener::notifySelectionChanged ( in nsIDOMDocument  doc,
in nsISelection  sel,
in short  reason 
) [inherited]
nsresult nsCaret::PrimeTimer ( ) [protected]

Definition at line 473 of file nsCaret.cpp.

{
  // set up the blink timer
  if (!mReadOnly && mBlinkRate > 0)
  {
    if (!mBlinkTimer) {
      nsresult  err;
      mBlinkTimer = do_CreateInstance("@mozilla.org/timer;1", &err);    
      if (NS_FAILED(err))
        return err;
    }    

    mBlinkTimer->InitWithFuncCallback(CaretBlinkCallback, this, mBlinkRate,
                                      nsITimer::TYPE_REPEATING_SLACK);
  }

  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Implements nsICaret.

Definition at line 231 of file nsCaret.cpp.

{
  NS_ENSURE_ARG_POINTER(aDOMSel);
  mDomSelectionWeak = do_GetWeakReference(aDOMSel);   // weak reference to pres shell
  if (mVisible)
  {
    // Stop the caret from blinking in its previous location.
    StopBlinking();
    // Start the caret blinking in the new location.
    StartBlinking();
  }
  return NS_OK;
}

Here is the call graph for this function:

NS_IMETHODIMP nsCaret::SetCaretReadOnly ( PRBool  inMakeReadonly) [virtual]

SetCaretReadOnly set the appearance of the caret.

Parameters:
inMakeReadonlyPR_TRUE to show the caret in a 'read only' state, PR_FALSE to show the caret in normal, editing state

Implements nsICaret.

Definition at line 270 of file nsCaret.cpp.

{
  mReadOnly = inMakeReadonly;
  return NS_OK;
}
NS_IMETHODIMP nsCaret::SetCaretVisible ( PRBool  inMakeVisible) [virtual]

SetCaretVisible will set the visibility of the caret.

Parameters:
inMakeVisiblePR_TRUE to show the caret, PR_FALSE to hide it

Implements nsICaret.

Definition at line 247 of file nsCaret.cpp.

{
  mVisible = inMakeVisible;
  nsresult  err = NS_OK;
  if (mVisible)
    err = StartBlinking();
  else
    err = StopBlinking();
    
  return err;
}

Here is the call graph for this function:

Implements nsICaret.

Definition at line 401 of file nsCaret.cpp.

{
  mShowDuringSelection = aVisibility;
  return NS_OK;
}

Definition at line 494 of file nsCaret.cpp.

{
  PrimeTimer();

  //NS_ASSERTION(!mDrawn, "Caret should not be drawn here");
  DrawCaret();    // draw it right away
  
  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 506 of file nsCaret.cpp.

{
  if (mDrawn)     // erase the caret if necessary
    DrawCaret();
    
  KillTimer();
  
  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Implements nsICaret.

Definition at line 187 of file nsCaret.cpp.

{
  // this doesn't erase the caret if it's drawn. Should it? We might not have a good
  // drawing environment during teardown.
  
  KillTimer();
  mBlinkTimer = nsnull;
  
  mRendContext = nsnull;

  // unregiser ourselves as a selection listener
  nsCOMPtr<nsISelection> domSelection = do_QueryReferent(mDomSelectionWeak);
  nsCOMPtr<nsISelectionPrivate> privateSelection(do_QueryInterface(domSelection));
  if (privateSelection)
    privateSelection->RemoveSelectionListener(this);
  mDomSelectionWeak = nsnull;
  mPresShell = nsnull;

  mLastContent = nsnull;
  mLastCaretView = nsnull;
  
#ifdef IBMBIDI
  mBidiKeyboard = nsnull;
#endif

  return NS_OK;
}

Here is the call graph for this function:

void nsCaret::ToggleDrawnStatus ( ) [inline, protected]

Definition at line 101 of file nsCaret.h.

{   mDrawn = !mDrawn; }

Here is the caller graph for this function:


Member Data Documentation

Definition at line 47 of file nsISelectionListener.idl.

Definition at line 50 of file nsISelectionListener.idl.

Definition at line 114 of file nsCaret.h.

Definition at line 111 of file nsCaret.h.

Definition at line 108 of file nsCaret.h.

Definition at line 121 of file nsCaret.h.

Definition at line 113 of file nsCaret.h.

Definition at line 106 of file nsCaret.h.

Definition at line 117 of file nsCaret.h.

Definition at line 122 of file nsCaret.h.

Definition at line 123 of file nsCaret.h.

Definition at line 125 of file nsCaret.h.

Definition at line 126 of file nsCaret.h.

Definition at line 48 of file nsISelectionListener.idl.

Definition at line 49 of file nsISelectionListener.idl.

Definition at line 105 of file nsCaret.h.

Definition at line 118 of file nsCaret.h.

Definition at line 109 of file nsCaret.h.

Definition at line 119 of file nsCaret.h.

Definition at line 116 of file nsCaret.h.

const short nsISelectionListener::NO_REASON = 0 [inherited]

Definition at line 46 of file nsISelectionListener.idl.

Definition at line 51 of file nsISelectionListener.idl.


The documentation for this class was generated from the following files: