1999-02-11 23:49:08 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
*
|
1999-11-06 03:40:37 +00:00
|
|
|
* The contents of this file are subject to the Netscape Public
|
|
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
|
|
* except in compliance with the License. You may obtain a copy of
|
|
|
|
* the License at http://www.mozilla.org/NPL/
|
1999-02-11 23:49:08 +00:00
|
|
|
*
|
1999-11-06 03:40:37 +00:00
|
|
|
* Software distributed under the License is distributed on an "AS
|
|
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
|
|
* implied. See the License for the specific language governing
|
|
|
|
* rights and limitations under the License.
|
1999-02-11 23:49:08 +00:00
|
|
|
*
|
1999-11-06 03:40:37 +00:00
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is Netscape
|
1999-02-11 23:49:08 +00:00
|
|
|
* Communications Corporation. Portions created by Netscape are
|
1999-11-06 03:40:37 +00:00
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
|
|
* Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
2000-02-02 22:24:56 +00:00
|
|
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
1999-02-11 23:49:08 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
|
|
|
|
#include "nsITimer.h"
|
|
|
|
#include "nsITimerCallback.h"
|
|
|
|
|
1999-07-14 22:18:29 +00:00
|
|
|
#include "nsIComponentManager.h"
|
1999-02-12 00:55:46 +00:00
|
|
|
#include "nsIFrameSelection.h"
|
1999-02-11 23:49:08 +00:00
|
|
|
#include "nsIFrame.h"
|
|
|
|
#include "nsIDOMNode.h"
|
|
|
|
#include "nsIDOMRange.h"
|
|
|
|
#include "nsIDOMSelection.h"
|
|
|
|
#include "nsIDOMCharacterData.h"
|
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsIPresShell.h"
|
|
|
|
#include "nsIRenderingContext.h"
|
1999-03-02 04:26:49 +00:00
|
|
|
#include "nsIDeviceContext.h"
|
1999-02-11 23:49:08 +00:00
|
|
|
#include "nsIView.h"
|
1999-03-02 04:26:49 +00:00
|
|
|
#include "nsIViewManager.h"
|
1999-02-11 23:49:08 +00:00
|
|
|
#include "nsIPresContext.h"
|
1999-07-14 22:18:29 +00:00
|
|
|
#include "nsILookAndFeel.h"
|
|
|
|
#include "nsWidgetsCID.h" // for NS_LOOKANDFEEL_CID
|
1999-09-14 23:41:19 +00:00
|
|
|
#include "nsBlockFrame.h"
|
2000-04-27 07:37:12 +00:00
|
|
|
#include "nsISelectionController.h"
|
1999-02-11 23:49:08 +00:00
|
|
|
|
|
|
|
#include "nsCaret.h"
|
|
|
|
|
|
|
|
|
1999-07-14 22:18:29 +00:00
|
|
|
static NS_DEFINE_IID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
|
|
|
|
|
1999-02-11 23:49:08 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
1999-10-08 20:41:19 +00:00
|
|
|
|
1999-02-11 23:49:08 +00:00
|
|
|
nsCaret::nsCaret()
|
|
|
|
: mPresShell(nsnull)
|
1999-02-12 18:24:53 +00:00
|
|
|
, mBlinkRate(500)
|
1999-07-14 22:18:29 +00:00
|
|
|
, mCaretWidth(20)
|
1999-03-02 04:26:49 +00:00
|
|
|
, mVisible(PR_FALSE)
|
|
|
|
, mReadOnly(PR_TRUE)
|
|
|
|
, mDrawn(PR_FALSE)
|
1999-04-01 23:57:35 +00:00
|
|
|
, mLastCaretFrame(nsnull)
|
|
|
|
, mLastContentOffset(0)
|
1999-02-11 23:49:08 +00:00
|
|
|
{
|
|
|
|
NS_INIT_REFCNT();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
nsCaret::~nsCaret()
|
|
|
|
{
|
1999-03-02 04:26:49 +00:00
|
|
|
KillTimer();
|
1999-02-11 23:49:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
1999-07-14 22:18:29 +00:00
|
|
|
NS_IMETHODIMP nsCaret::Init(nsIPresShell *inPresShell)
|
1999-02-11 23:49:08 +00:00
|
|
|
{
|
|
|
|
if (!inPresShell)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
2000-04-27 07:37:12 +00:00
|
|
|
mPresShell = getter_AddRefs(NS_GetWeakReference(inPresShell)); // the presshell owns us, so no addref
|
|
|
|
|
1999-07-14 22:18:29 +00:00
|
|
|
nsILookAndFeel* touchyFeely;
|
2000-02-02 22:24:56 +00:00
|
|
|
if (NS_SUCCEEDED(nsComponentManager::CreateInstance(kLookAndFeelCID, nsnull, NS_GET_IID(nsILookAndFeel), (void**)&touchyFeely)))
|
1999-07-14 22:18:29 +00:00
|
|
|
{
|
|
|
|
PRInt32 tempInt;
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(touchyFeely->GetMetric(nsILookAndFeel::eMetric_CaretWidthTwips, tempInt)))
|
|
|
|
mCaretWidth = (nscoord)tempInt;
|
|
|
|
if (NS_SUCCEEDED(touchyFeely->GetMetric(nsILookAndFeel::eMetric_CaretBlinkTime, tempInt)))
|
|
|
|
mBlinkRate = (PRUint32)tempInt;
|
|
|
|
|
|
|
|
NS_RELEASE(touchyFeely);
|
|
|
|
}
|
|
|
|
|
1999-02-11 23:49:08 +00:00
|
|
|
// get the selection from the pres shell, and set ourselves up as a selection
|
|
|
|
// listener
|
|
|
|
|
1999-02-12 00:55:46 +00:00
|
|
|
nsCOMPtr<nsIDOMSelection> domSelection;
|
2000-04-27 07:37:12 +00:00
|
|
|
nsCOMPtr<nsISelectionController> selCon = do_QueryReferent(mPresShell);
|
|
|
|
if (selCon)
|
1999-02-11 23:49:08 +00:00
|
|
|
{
|
2000-04-27 07:37:12 +00:00
|
|
|
if (NS_SUCCEEDED(selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSelection))))
|
|
|
|
{
|
|
|
|
domSelection->AddSelectionListener(this);
|
2000-05-04 08:35:42 +00:00
|
|
|
mDomSelectionWeak = getter_AddRefs( NS_GetWeakReference(domSelection) );
|
2000-04-27 07:37:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return NS_ERROR_FAILURE;
|
1999-02-11 23:49:08 +00:00
|
|
|
|
|
|
|
// set up the blink timer
|
|
|
|
if (mVisible)
|
|
|
|
{
|
|
|
|
nsresult err = StartBlinking();
|
|
|
|
if (NS_FAILED(err))
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NS_IMPL_ADDREF(nsCaret);
|
|
|
|
NS_IMPL_RELEASE(nsCaret);
|
|
|
|
//-----------------------------------------------------------------------------
|
1999-04-01 23:57:35 +00:00
|
|
|
NS_IMETHODIMP nsCaret::QueryInterface(const nsIID& aIID,
|
1999-02-11 23:49:08 +00:00
|
|
|
void** aInstancePtrResult)
|
|
|
|
{
|
1999-09-14 23:41:19 +00:00
|
|
|
NS_PRECONDITION(aInstancePtrResult, "null pointer");
|
|
|
|
if (!aInstancePtrResult)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
nsISupports* foundInterface;
|
|
|
|
|
|
|
|
if (aIID.Equals(NS_GET_IID(nsISupports)))
|
|
|
|
foundInterface = (nsISupports*)(nsICaret*)this; // whoo boy
|
|
|
|
else if (aIID.Equals(NS_GET_IID(nsICaret)))
|
|
|
|
foundInterface = (nsICaret*)this;
|
|
|
|
else if (aIID.Equals(NS_GET_IID(nsIDOMSelectionListener)))
|
|
|
|
foundInterface = (nsIDOMSelectionListener*)this;
|
|
|
|
else
|
|
|
|
foundInterface = nsnull;
|
|
|
|
|
|
|
|
nsresult status;
|
|
|
|
if (! foundInterface)
|
|
|
|
status = NS_NOINTERFACE;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NS_ADDREF(foundInterface);
|
|
|
|
status = NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
*aInstancePtrResult = foundInterface;
|
|
|
|
return status;
|
1999-02-11 23:49:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2000-05-11 04:25:43 +00:00
|
|
|
NS_IMETHODIMP nsCaret::SetCaretVisible(PRBool inMakeVisible, nsIDOMSelection *aDOMSel)
|
1999-02-11 23:49:08 +00:00
|
|
|
{
|
2000-05-11 04:25:43 +00:00
|
|
|
mDomSelectionWeak = getter_AddRefs( NS_GetWeakReference(aDOMSel) ); // weak reference to pres shell
|
1999-02-11 23:49:08 +00:00
|
|
|
mVisible = inMakeVisible;
|
|
|
|
nsresult err = NS_OK;
|
|
|
|
if (mVisible)
|
|
|
|
err = StartBlinking();
|
|
|
|
else
|
|
|
|
err = StopBlinking();
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2000-05-11 04:25:43 +00:00
|
|
|
NS_IMETHODIMP nsCaret::SetCaretReadOnly(PRBool inMakeReadonly, nsIDOMSelection *aDOMSel)
|
1999-02-11 23:49:08 +00:00
|
|
|
{
|
2000-05-11 04:25:43 +00:00
|
|
|
mDomSelectionWeak = getter_AddRefs( NS_GetWeakReference(aDOMSel) ); // weak reference to pres shell
|
|
|
|
|
1999-02-11 23:49:08 +00:00
|
|
|
mReadOnly = inMakeReadonly;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-02-13 04:47:45 +00:00
|
|
|
|
1999-04-27 21:59:18 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
2000-05-04 08:35:42 +00:00
|
|
|
NS_IMETHODIMP nsCaret::GetWindowRelativeCoordinates(nsRect& outCoordinates, PRBool& outIsCollapsed, nsIDOMSelection *aDOMSel)
|
1999-04-27 21:59:18 +00:00
|
|
|
{
|
|
|
|
if (!mPresShell)
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
2000-05-11 04:25:43 +00:00
|
|
|
|
|
|
|
mDomSelectionWeak = getter_AddRefs( NS_GetWeakReference(aDOMSel) ); // weak reference to pres shell
|
1999-04-27 21:59:18 +00:00
|
|
|
|
2000-05-04 08:35:42 +00:00
|
|
|
nsCOMPtr<nsIDOMSelection> domSelection = aDOMSel;
|
2000-04-27 07:37:12 +00:00
|
|
|
nsresult err;
|
1999-04-27 21:59:18 +00:00
|
|
|
if (!domSelection)
|
|
|
|
return NS_ERROR_NOT_INITIALIZED; // no selection
|
|
|
|
|
|
|
|
// fill in defaults for failure
|
|
|
|
outCoordinates.x = -1;
|
|
|
|
outCoordinates.y = -1;
|
1999-12-22 07:56:40 +00:00
|
|
|
outCoordinates.width = -1;
|
|
|
|
outCoordinates.height = -1;
|
1999-04-27 21:59:18 +00:00
|
|
|
outIsCollapsed = PR_FALSE;
|
|
|
|
|
1999-07-18 02:27:19 +00:00
|
|
|
err = domSelection->GetIsCollapsed(&outIsCollapsed);
|
1999-04-27 21:59:18 +00:00
|
|
|
if (NS_FAILED(err))
|
|
|
|
return err;
|
|
|
|
|
|
|
|
// code in progress
|
|
|
|
nsCOMPtr<nsIDOMNode> focusNode;
|
1999-05-18 22:24:55 +00:00
|
|
|
|
1999-07-18 02:27:19 +00:00
|
|
|
err = domSelection->GetFocusNode(getter_AddRefs(focusNode));
|
1999-05-18 22:24:55 +00:00
|
|
|
if (NS_FAILED(err))
|
|
|
|
return err;
|
|
|
|
if (!focusNode)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
1999-04-27 21:59:18 +00:00
|
|
|
PRInt32 focusOffset;
|
1999-07-18 02:27:19 +00:00
|
|
|
err = domSelection->GetFocusOffset(&focusOffset);
|
1999-05-18 22:24:55 +00:00
|
|
|
if (NS_FAILED(err))
|
|
|
|
return err;
|
|
|
|
|
1999-11-23 20:30:21 +00:00
|
|
|
/*
|
1999-05-18 22:24:55 +00:00
|
|
|
// 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;
|
1999-11-23 20:30:21 +00:00
|
|
|
*/
|
1999-05-18 22:24:55 +00:00
|
|
|
nsCOMPtr<nsIContent>contentNode = do_QueryInterface(focusNode);
|
|
|
|
if (!contentNode)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
1999-09-11 00:18:02 +00:00
|
|
|
//get frame selection and find out what frame to use...
|
|
|
|
nsCOMPtr<nsIFrameSelection> frameSelection;
|
2000-04-27 07:37:12 +00:00
|
|
|
nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
|
|
|
|
if (presShell)
|
|
|
|
err = presShell->GetFrameSelection(getter_AddRefs(frameSelection));
|
|
|
|
else
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
if (NS_FAILED(err) || !frameSelection)
|
|
|
|
return err?err : NS_ERROR_FAILURE;
|
1999-11-10 23:47:56 +00:00
|
|
|
|
|
|
|
// find the frame that contains the content node that has focus
|
|
|
|
nsIFrame* theFrame = nsnull;
|
2000-01-10 15:32:42 +00:00
|
|
|
PRInt32 theFrameOffset = 0;
|
|
|
|
err = frameSelection->GetFrameForNodeOffset(contentNode, focusOffset, &theFrame, &theFrameOffset);
|
1999-11-10 23:47:56 +00:00
|
|
|
if (NS_FAILED(err) || !theFrame)
|
1999-05-18 22:24:55 +00:00
|
|
|
return err;
|
|
|
|
|
|
|
|
nsPoint viewOffset(0, 0);
|
|
|
|
nsIView *drawingView; // views are not refcounted
|
|
|
|
GetViewForRendering(theFrame, eTopLevelWindowCoordinates, viewOffset, drawingView);
|
|
|
|
if (!drawingView)
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
1999-04-27 21:59:18 +00:00
|
|
|
|
1999-05-18 22:24:55 +00:00
|
|
|
// ramp up to make a rendering context for measuring text.
|
|
|
|
// First, we get the pres context ...
|
|
|
|
nsCOMPtr<nsIPresContext> presContext;
|
2000-04-27 07:37:12 +00:00
|
|
|
err = presShell->GetPresContext(getter_AddRefs(presContext));
|
1999-05-18 22:24:55 +00:00
|
|
|
if (NS_FAILED(err))
|
|
|
|
return err;
|
|
|
|
|
|
|
|
// ... then get a device context
|
|
|
|
nsCOMPtr<nsIDeviceContext> dx;
|
|
|
|
err = presContext->GetDeviceContext(getter_AddRefs(dx));
|
|
|
|
if (NS_FAILED(err))
|
|
|
|
return err;
|
|
|
|
if (!dx)
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
|
|
|
|
// ... then tell it to make a rendering context
|
|
|
|
nsCOMPtr<nsIRenderingContext> rendContext;
|
|
|
|
err = dx->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);
|
2000-01-10 15:32:42 +00:00
|
|
|
theFrame->GetPointFromOffset(presContext, rendContext, theFrameOffset, &framePos);
|
1999-04-27 21:59:18 +00:00
|
|
|
|
1999-11-10 23:47:56 +00:00
|
|
|
nsRect frameRect;
|
|
|
|
theFrame->GetRect(frameRect);
|
|
|
|
|
1999-05-18 22:24:55 +00:00
|
|
|
// now add the frame offset to the view offset, and we're done
|
|
|
|
viewOffset += framePos;
|
1999-12-22 07:56:40 +00:00
|
|
|
outCoordinates.x = viewOffset.x;
|
|
|
|
outCoordinates.y = viewOffset.y;
|
|
|
|
outCoordinates.height = frameRect.height;
|
|
|
|
outCoordinates.width = frameRect.width;
|
1999-05-18 22:24:55 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
1999-04-27 21:59:18 +00:00
|
|
|
}
|
|
|
|
|
1999-04-01 23:57:35 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NS_IMETHODIMP nsCaret::ClearFrameRefs(nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (mLastCaretFrame == aFrame)
|
|
|
|
{
|
|
|
|
mLastCaretFrame = nsnull; // frames are not refcounted.
|
|
|
|
mLastContentOffset = 0;
|
|
|
|
}
|
|
|
|
|
1999-09-14 23:41:19 +00:00
|
|
|
mDrawn = PR_FALSE; // assume that the view has been cleared, and ensure
|
|
|
|
// that we don't try to use the frame.
|
|
|
|
|
1999-04-01 23:57:35 +00:00
|
|
|
// should we just call StopBlinking() here?
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-03-02 04:26:49 +00:00
|
|
|
#ifdef XP_MAC
|
1999-02-11 23:49:08 +00:00
|
|
|
#pragma mark -
|
1999-03-02 04:26:49 +00:00
|
|
|
#endif
|
1999-02-11 23:49:08 +00:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2000-05-04 08:35:42 +00:00
|
|
|
NS_IMETHODIMP nsCaret::NotifySelectionChanged(nsIDOMDocument *, nsIDOMSelection *aDomSel, short)
|
1999-02-11 23:49:08 +00:00
|
|
|
{
|
2000-05-04 08:35:42 +00:00
|
|
|
mDomSelectionWeak = getter_AddRefs( NS_GetWeakReference(aDomSel) ); // weak reference to pres shell
|
1999-02-13 04:47:45 +00:00
|
|
|
if (mVisible)
|
|
|
|
{
|
|
|
|
StopBlinking();
|
|
|
|
StartBlinking();
|
|
|
|
}
|
|
|
|
|
1999-02-11 23:49:08 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-03-02 04:26:49 +00:00
|
|
|
#ifdef XP_MAC
|
1999-02-11 23:49:08 +00:00
|
|
|
#pragma mark -
|
1999-03-02 04:26:49 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void nsCaret::KillTimer()
|
|
|
|
{
|
|
|
|
if (mBlinkTimer)
|
|
|
|
{
|
|
|
|
mBlinkTimer->Cancel();
|
|
|
|
}
|
|
|
|
}
|
1999-02-11 23:49:08 +00:00
|
|
|
|
1999-02-17 02:08:01 +00:00
|
|
|
|
1999-02-11 23:49:08 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
1999-02-17 02:08:01 +00:00
|
|
|
nsresult nsCaret::PrimeTimer()
|
1999-02-11 23:49:08 +00:00
|
|
|
{
|
1999-03-02 04:26:49 +00:00
|
|
|
KillTimer();
|
1999-02-11 23:49:08 +00:00
|
|
|
|
|
|
|
// set up the blink timer
|
1999-04-01 23:57:35 +00:00
|
|
|
if (!mReadOnly && mBlinkRate > 0)
|
1999-02-13 04:47:45 +00:00
|
|
|
{
|
2000-05-17 02:49:35 +00:00
|
|
|
nsresult err;
|
|
|
|
mBlinkTimer = do_CreateInstance("component://netscape/timer", &err);
|
1999-02-13 04:47:45 +00:00
|
|
|
|
|
|
|
if (NS_FAILED(err))
|
|
|
|
return err;
|
|
|
|
|
2000-01-21 21:56:09 +00:00
|
|
|
mBlinkTimer->Init(CaretBlinkCallback, this, mBlinkRate, NS_PRIORITY_HIGH, NS_TYPE_REPEATING_PRECISE);
|
1999-02-13 04:47:45 +00:00
|
|
|
}
|
1999-02-17 02:08:01 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
nsresult nsCaret::StartBlinking()
|
|
|
|
{
|
|
|
|
PrimeTimer();
|
1999-03-03 01:11:28 +00:00
|
|
|
|
1999-09-14 23:41:19 +00:00
|
|
|
//NS_ASSERTION(!mDrawn, "Caret should not be drawn here");
|
1999-02-11 23:49:08 +00:00
|
|
|
DrawCaret(); // draw it right away
|
1999-03-02 04:26:49 +00:00
|
|
|
|
1999-02-13 04:47:45 +00:00
|
|
|
return NS_OK;
|
1999-02-11 23:49:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
nsresult nsCaret::StopBlinking()
|
|
|
|
{
|
|
|
|
if (mDrawn) // erase the caret if necessary
|
|
|
|
DrawCaret();
|
1999-09-14 23:41:19 +00:00
|
|
|
|
1999-03-02 04:26:49 +00:00
|
|
|
KillTimer();
|
1999-02-11 23:49:08 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
1999-04-01 23:57:35 +00:00
|
|
|
// Get the nsIFrame and the content offset for the current caret position.
|
1999-04-27 21:59:18 +00:00
|
|
|
// Returns PR_TRUE if we should go ahead and draw, PR_FALSE otherwise.
|
1999-04-01 23:57:35 +00:00
|
|
|
//
|
|
|
|
PRBool nsCaret::SetupDrawingFrameAndOffset()
|
1999-02-11 23:49:08 +00:00
|
|
|
{
|
2000-05-04 08:35:42 +00:00
|
|
|
if (!mDomSelectionWeak)
|
|
|
|
return PR_FALSE;
|
|
|
|
nsCOMPtr<nsIDOMSelection> domSelection = do_QueryReferent(mDomSelectionWeak);
|
1999-04-01 23:57:35 +00:00
|
|
|
PRBool isCollapsed;
|
|
|
|
|
1999-07-18 02:27:19 +00:00
|
|
|
if (domSelection && NS_SUCCEEDED(domSelection->GetIsCollapsed(&isCollapsed)) && isCollapsed)
|
1999-04-01 23:57:35 +00:00
|
|
|
{
|
1999-03-02 04:26:49 +00:00
|
|
|
// start and end parent should be the same since we are collapsed
|
|
|
|
nsCOMPtr<nsIDOMNode> focusNode;
|
1999-07-07 01:11:49 +00:00
|
|
|
PRInt32 contentOffset;
|
1999-03-02 04:26:49 +00:00
|
|
|
|
1999-07-18 02:27:19 +00:00
|
|
|
if (NS_SUCCEEDED(domSelection->GetFocusNode(getter_AddRefs(focusNode))) && focusNode &&
|
|
|
|
NS_SUCCEEDED(domSelection->GetFocusOffset(&contentOffset)))
|
1999-03-02 04:26:49 +00:00
|
|
|
{
|
1999-07-07 01:11:49 +00:00
|
|
|
nsCOMPtr<nsIContent>contentNode = do_QueryInterface(focusNode);
|
|
|
|
|
|
|
|
if (contentNode)
|
1999-02-11 23:49:08 +00:00
|
|
|
{
|
1999-09-11 06:00:00 +00:00
|
|
|
// see if we have an offset between child nodes, or an offset into a text
|
|
|
|
// node.
|
1999-10-22 00:19:18 +00:00
|
|
|
#if NOT_NEEDED
|
1999-10-22 14:51:41 +00:00
|
|
|
PRBool canContainChildren;
|
1999-09-11 06:00:00 +00:00
|
|
|
if (NS_SUCCEEDED(contentNode->CanContainChildren(canContainChildren)) && canContainChildren)
|
|
|
|
{
|
|
|
|
// point the caret to the start of the child node
|
|
|
|
nsCOMPtr<nsIContent> childNode;
|
|
|
|
contentNode->ChildAt(contentOffset, *getter_AddRefs(childNode));
|
|
|
|
if (childNode)
|
|
|
|
{
|
|
|
|
contentNode = childNode;
|
|
|
|
contentOffset = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-09-14 23:41:19 +00:00
|
|
|
// are we in a text node?
|
|
|
|
//nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(focusNode);
|
1999-09-11 06:00:00 +00:00
|
|
|
|
1999-09-14 23:41:19 +00:00
|
|
|
// we can be in a text node, or a BR node here.
|
1999-09-11 06:00:00 +00:00
|
|
|
}
|
1999-10-22 00:19:18 +00:00
|
|
|
#endif // NOT_NEEDED
|
1999-07-07 01:11:49 +00:00
|
|
|
nsIFrame* theFrame = nsnull;
|
2000-01-10 15:32:42 +00:00
|
|
|
PRInt32 theFrameOffset = 0;
|
2000-05-04 08:35:42 +00:00
|
|
|
nsresult err;
|
1999-09-11 06:00:00 +00:00
|
|
|
//get frame selection and find out what frame to use...
|
|
|
|
nsCOMPtr<nsIFrameSelection> frameSelection;
|
2000-04-27 07:37:12 +00:00
|
|
|
nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
|
|
|
|
if (presShell)
|
|
|
|
err = presShell->GetFrameSelection(getter_AddRefs(frameSelection));
|
|
|
|
else
|
|
|
|
return NS_ERROR_FAILURE;
|
1999-09-11 06:00:00 +00:00
|
|
|
if (NS_FAILED(err) || !frameSelection)
|
|
|
|
return PR_FALSE;
|
1999-07-07 01:11:49 +00:00
|
|
|
|
2000-01-10 15:32:42 +00:00
|
|
|
err = frameSelection->GetFrameForNodeOffset(contentNode, contentOffset, &theFrame, &theFrameOffset);
|
1999-09-11 06:00:00 +00:00
|
|
|
if (NS_FAILED(err))
|
|
|
|
return PR_FALSE;
|
|
|
|
else
|
1999-02-11 23:49:08 +00:00
|
|
|
{
|
1999-07-07 01:11:49 +00:00
|
|
|
|
|
|
|
// mark the frame, so we get notified on deletion.
|
|
|
|
// frames are never unmarked, which means that we'll touch every frame we visit.
|
|
|
|
// this is not ideal.
|
|
|
|
nsFrameState state;
|
|
|
|
theFrame->GetFrameState(&state);
|
|
|
|
state |= NS_FRAME_EXTERNAL_REFERENCE;
|
|
|
|
theFrame->SetFrameState(state);
|
1999-03-02 04:26:49 +00:00
|
|
|
|
1999-07-07 01:11:49 +00:00
|
|
|
mLastCaretFrame = theFrame;
|
2000-01-10 15:32:42 +00:00
|
|
|
mLastContentOffset = theFrameOffset;
|
1999-07-07 01:11:49 +00:00
|
|
|
return PR_TRUE;
|
1999-04-01 23:57:35 +00:00
|
|
|
}
|
|
|
|
}
|
1999-03-02 04:26:49 +00:00
|
|
|
}
|
1999-04-01 23:57:35 +00:00
|
|
|
}
|
1999-02-11 23:49:08 +00:00
|
|
|
|
1999-04-01 23:57:35 +00:00
|
|
|
return PR_FALSE;
|
1999-02-11 23:49:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-04-01 23:57:35 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
1999-05-18 22:24:55 +00:00
|
|
|
void nsCaret::GetViewForRendering(nsIFrame *caretFrame, EViewCoordinates coordType, nsPoint &viewOffset, nsIView* &outView)
|
1999-04-01 23:57:35 +00:00
|
|
|
{
|
1999-09-11 19:11:53 +00:00
|
|
|
if (!caretFrame) return;
|
1999-04-01 23:57:35 +00:00
|
|
|
outView = nsnull;
|
|
|
|
|
1999-09-14 23:41:19 +00:00
|
|
|
NS_ASSERTION(caretFrame, "Should have a frame here");
|
|
|
|
if (!caretFrame)
|
|
|
|
return;
|
|
|
|
|
1999-04-01 23:57:35 +00:00
|
|
|
nsIView* theView = nsnull;
|
1999-09-11 06:00:00 +00:00
|
|
|
NS_ASSERTION(caretFrame, "Should have frame here");
|
1999-10-26 04:44:41 +00:00
|
|
|
nsCOMPtr<nsIPresContext> presContext;
|
2000-04-27 07:37:12 +00:00
|
|
|
nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
|
|
|
|
if (presShell)
|
|
|
|
presShell->GetPresContext(getter_AddRefs(presContext));
|
|
|
|
else
|
|
|
|
return;
|
1999-10-26 04:44:41 +00:00
|
|
|
caretFrame->GetOffsetFromView(presContext, viewOffset, &theView);
|
1999-04-01 23:57:35 +00:00
|
|
|
if (theView == nsnull) return;
|
|
|
|
|
1999-06-15 23:54:26 +00:00
|
|
|
nsIView* returnView = nsnull;
|
|
|
|
|
1999-04-01 23:57:35 +00:00
|
|
|
nscoord x, y;
|
|
|
|
|
|
|
|
do {
|
|
|
|
theView->GetPosition(&x, &y);
|
|
|
|
|
1999-06-15 23:54:26 +00:00
|
|
|
if (!returnView)
|
1999-05-18 22:24:55 +00:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIWidget> viewWidget;
|
|
|
|
theView->GetWidget(*getter_AddRefs(viewWidget));
|
1999-06-15 23:54:26 +00:00
|
|
|
|
|
|
|
if (viewWidget)
|
|
|
|
{
|
1999-09-11 06:00:00 +00:00
|
|
|
returnView = theView;
|
1999-06-15 23:54:26 +00:00
|
|
|
|
1999-09-11 06:00:00 +00:00
|
|
|
if (coordType == eViewCoordinates)
|
|
|
|
break;
|
1999-06-15 23:54:26 +00:00
|
|
|
}
|
2000-05-11 04:25:43 +00:00
|
|
|
viewOffset.x += x;
|
|
|
|
viewOffset.y += y;
|
1999-06-15 23:54:26 +00:00
|
|
|
}
|
1999-04-01 23:57:35 +00:00
|
|
|
|
|
|
|
theView->GetParent(theView);
|
|
|
|
} while (theView);
|
|
|
|
|
1999-06-15 23:54:26 +00:00
|
|
|
outView = returnView;
|
1999-04-01 23:57:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-09-14 23:41:19 +00:00
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
MustDrawCaret
|
|
|
|
|
|
|
|
FInd out if we need to do any caret drawing. This returns true if
|
|
|
|
either a) or b)
|
|
|
|
a) caret has been drawn, and we need to erase it.
|
|
|
|
b) caret is not drawn, and selection is collapsed
|
|
|
|
|
|
|
|
----------------------------------------------------------------------------- */
|
|
|
|
PRBool nsCaret::MustDrawCaret()
|
|
|
|
{
|
|
|
|
if (mDrawn)
|
|
|
|
return PR_TRUE;
|
|
|
|
|
2000-05-04 08:35:42 +00:00
|
|
|
nsCOMPtr<nsIDOMSelection> domSelection = do_QueryReferent(mDomSelectionWeak);
|
1999-09-14 23:41:19 +00:00
|
|
|
PRBool isCollapsed;
|
|
|
|
|
|
|
|
if (NS_FAILED(domSelection->GetIsCollapsed(&isCollapsed)))
|
|
|
|
return PR_FALSE;
|
|
|
|
|
|
|
|
return isCollapsed;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
DrawCaretWithContext
|
|
|
|
|
|
|
|
By this point, the caret rect should have been set up.
|
|
|
|
|
|
|
|
----------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
void nsCaret::DrawCaretWithContext(nsIRenderingContext* inRendContext)
|
1999-04-01 23:57:35 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
NS_ASSERTION(mLastCaretFrame != nsnull, "Should have a frame here");
|
|
|
|
|
|
|
|
nsRect frameRect;
|
|
|
|
mLastCaretFrame->GetRect(frameRect);
|
|
|
|
frameRect.x = 0; // the origin is accounted for in GetViewForRendering()
|
|
|
|
frameRect.y = 0;
|
|
|
|
|
1999-09-14 23:41:19 +00:00
|
|
|
if (frameRect.height == 0) // we're in a BR frame which has zero height.
|
1999-04-01 23:57:35 +00:00
|
|
|
{
|
1999-09-14 23:41:19 +00:00
|
|
|
frameRect.height = 200;
|
|
|
|
frameRect.y -= 200;
|
1999-04-01 23:57:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsPoint viewOffset(0, 0);
|
|
|
|
nsIView *drawingView;
|
1999-05-18 22:24:55 +00:00
|
|
|
GetViewForRendering(mLastCaretFrame, eViewCoordinates, viewOffset, drawingView);
|
1999-04-01 23:57:35 +00:00
|
|
|
|
|
|
|
if (drawingView == nsnull)
|
|
|
|
return;
|
|
|
|
|
|
|
|
frameRect += viewOffset;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIPresContext> presContext;
|
2000-04-27 07:37:12 +00:00
|
|
|
nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
|
|
|
|
if (presShell)
|
|
|
|
{
|
|
|
|
if (NS_FAILED(presShell->GetPresContext(getter_AddRefs(presContext))))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return;
|
1999-09-14 23:41:19 +00:00
|
|
|
|
|
|
|
// make a rendering context, if we didn't get passed one
|
|
|
|
nsCOMPtr<nsIRenderingContext> localRC = do_QueryInterface(inRendContext); // OK if inRendContext is null
|
|
|
|
if (!localRC)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDeviceContext> dx;
|
|
|
|
|
|
|
|
if (NS_FAILED(presContext->GetDeviceContext(getter_AddRefs(dx))) || !dx)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (NS_FAILED(dx->CreateRenderingContext(drawingView, *getter_AddRefs(localRC))) || !localRC)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mDrawn)
|
1999-04-01 23:57:35 +00:00
|
|
|
{
|
|
|
|
nsPoint framePos(0, 0);
|
1999-10-01 13:16:30 +00:00
|
|
|
nsRect caretRect = frameRect;
|
1999-04-01 23:57:35 +00:00
|
|
|
|
1999-09-14 23:41:19 +00:00
|
|
|
mLastCaretFrame->GetPointFromOffset(presContext, localRC, mLastContentOffset, &framePos);
|
1999-10-01 13:16:30 +00:00
|
|
|
caretRect += framePos;
|
2000-04-14 23:00:30 +00:00
|
|
|
|
1999-04-01 23:57:35 +00:00
|
|
|
|
|
|
|
//printf("Content offset %ld, frame offset %ld\n", focusOffset, framePos.x);
|
|
|
|
|
1999-10-01 13:16:30 +00:00
|
|
|
caretRect.width = mCaretWidth;
|
|
|
|
|
|
|
|
// Avoid view redraw problems by making sure the
|
|
|
|
// caret doesn't hang outside the right edge of
|
1999-10-29 13:43:11 +00:00
|
|
|
// the frame. This ensures that the caret gets
|
1999-10-01 13:16:30 +00:00
|
|
|
// erased properly if the frame's right edge gets
|
|
|
|
// invalidated.
|
|
|
|
|
|
|
|
nscoord cX = caretRect.x + caretRect.width;
|
|
|
|
nscoord fX = frameRect.x + frameRect.width;
|
|
|
|
|
1999-10-29 13:43:11 +00:00
|
|
|
if (caretRect.x <= fX && cX > fX)
|
1999-10-01 13:16:30 +00:00
|
|
|
{
|
|
|
|
caretRect.x -= cX - fX;
|
|
|
|
|
|
|
|
if (caretRect.x < frameRect.x)
|
|
|
|
caretRect.x = frameRect.x;
|
|
|
|
}
|
|
|
|
|
|
|
|
mCaretRect = caretRect;
|
1999-09-14 23:41:19 +00:00
|
|
|
}
|
1999-08-09 19:14:43 +00:00
|
|
|
/*
|
1999-04-01 23:57:35 +00:00
|
|
|
if (mReadOnly)
|
|
|
|
inRendContext.SetColor(NS_RGB(85, 85, 85)); // we are drawing it; gray
|
1999-08-09 19:14:43 +00:00
|
|
|
*/
|
|
|
|
|
1999-09-14 23:41:19 +00:00
|
|
|
localRC->SetColor(NS_RGB(255,255,255));
|
|
|
|
localRC->InvertRect(mCaretRect);
|
|
|
|
ToggleDrawnStatus();
|
1999-04-01 23:57:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void nsCaret::DrawCaret()
|
|
|
|
{
|
1999-09-14 23:41:19 +00:00
|
|
|
// do we need to draw the caret at all?
|
|
|
|
if (!MustDrawCaret())
|
1999-04-01 23:57:35 +00:00
|
|
|
return;
|
|
|
|
|
1999-09-14 23:41:19 +00:00
|
|
|
// if we are drawing, not erasing, then set up the frame etc.
|
|
|
|
if (!mDrawn)
|
1999-04-01 23:57:35 +00:00
|
|
|
{
|
1999-09-14 23:41:19 +00:00
|
|
|
if (! SetupDrawingFrameAndOffset())
|
|
|
|
return;
|
1999-04-01 23:57:35 +00:00
|
|
|
}
|
1999-09-14 23:41:19 +00:00
|
|
|
|
|
|
|
DrawCaretWithContext(nsnull);
|
1999-04-01 23:57:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void nsCaret::RefreshDrawCaret(nsIView *aView, nsIRenderingContext& inRendContext, const nsRect& aDirtyRect)
|
|
|
|
{
|
1999-09-14 23:41:19 +00:00
|
|
|
/*
|
1999-04-01 23:57:35 +00:00
|
|
|
if (! SetupDrawingFrameAndOffset())
|
|
|
|
return;
|
|
|
|
|
|
|
|
NS_ASSERTION(mLastCaretFrame != nsnull, "Should have a frame here");
|
|
|
|
|
|
|
|
nsPoint viewOffset(0, 0);
|
|
|
|
nsIView *drawingView;
|
|
|
|
//GetViewForRendering(viewOffset, drawingView);
|
|
|
|
|
|
|
|
mLastCaretFrame->GetOffsetFromView(viewOffset, &drawingView);
|
|
|
|
|
|
|
|
// are we in the view that is being painted?
|
|
|
|
if (drawingView == nsnull || drawingView != aView)
|
|
|
|
return;
|
1999-09-14 23:41:19 +00:00
|
|
|
|
|
|
|
mDrawn = PR_FALSE; // we're rendering to a view that is being redrawn
|
1999-04-01 23:57:35 +00:00
|
|
|
DrawCaretWithContext(inRendContext);
|
1999-09-14 23:41:19 +00:00
|
|
|
*/
|
1999-04-01 23:57:35 +00:00
|
|
|
}
|
|
|
|
|
1999-03-02 04:26:49 +00:00
|
|
|
#ifdef XP_MAC
|
1999-02-11 23:49:08 +00:00
|
|
|
#pragma mark -
|
1999-03-02 04:26:49 +00:00
|
|
|
#endif
|
1999-02-11 23:49:08 +00:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/* static */
|
|
|
|
void nsCaret::CaretBlinkCallback(nsITimer *aTimer, void *aClosure)
|
|
|
|
{
|
|
|
|
nsCaret *theCaret = NS_REINTERPRET_CAST(nsCaret*, aClosure);
|
|
|
|
if (!theCaret) return;
|
|
|
|
|
|
|
|
theCaret->DrawCaret();
|
2000-01-21 21:56:09 +00:00
|
|
|
|
|
|
|
#ifndef REPEATING_TIMERS
|
1999-03-02 04:26:49 +00:00
|
|
|
theCaret->PrimeTimer();
|
2000-01-21 21:56:09 +00:00
|
|
|
#endif
|
1999-02-11 23:49:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
nsresult NS_NewCaret(nsICaret** aInstancePtrResult)
|
|
|
|
{
|
1999-09-14 23:41:19 +00:00
|
|
|
NS_PRECONDITION(aInstancePtrResult, "null ptr");
|
1999-02-11 23:49:08 +00:00
|
|
|
|
|
|
|
nsCaret* caret = new nsCaret();
|
|
|
|
if (nsnull == caret)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
1999-09-14 23:41:19 +00:00
|
|
|
return caret->QueryInterface(NS_GET_IID(nsICaret), (void**) aInstancePtrResult);
|
1999-02-11 23:49:08 +00:00
|
|
|
}
|
|
|
|
|