mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Draw the caret in the normal path of frame painting instead of doing it directly to the current view. bug 287813, r+sr=roc
This commit is contained in:
parent
f15a96ed13
commit
e27b36efcc
@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=4 sw=2 et tw=78: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
@ -530,6 +531,8 @@ nsTextEditorDragListener::DragEnter(nsIDOMEvent* aDragEvent)
|
||||
{
|
||||
mCaret->Init(presShell);
|
||||
mCaret->SetCaretReadOnly(PR_TRUE);
|
||||
|
||||
mOtherCaret = presShell->SetCaret(mCaret);
|
||||
}
|
||||
mCaretDrawn = PR_FALSE;
|
||||
}
|
||||
@ -631,7 +634,15 @@ nsTextEditorDragListener::DragDrop(nsIDOMEvent* aMouseEvent)
|
||||
mCaretDrawn = PR_FALSE;
|
||||
}
|
||||
mCaret->SetCaretVisible(PR_FALSE); // hide it, so that it turns off its timer
|
||||
mCaret = nsnull; // release it
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
|
||||
if (presShell)
|
||||
{
|
||||
NS_ASSERTION(mOtherCaret, "Where'd my other caret go?");
|
||||
mCaret = presShell->SetCaret(mOtherCaret);
|
||||
}
|
||||
|
||||
mOtherCaret = mCaret = nsnull;
|
||||
}
|
||||
|
||||
if (!mEditor)
|
||||
|
@ -235,8 +235,8 @@ protected:
|
||||
nsWeakPtr mPresShell;
|
||||
|
||||
nsCOMPtr<nsICaret> mCaret;
|
||||
nsCOMPtr<nsICaret> mOtherCaret;
|
||||
PRBool mCaretDrawn;
|
||||
|
||||
};
|
||||
|
||||
/** editor Implementation of the FocusListener interface
|
||||
|
@ -670,28 +670,15 @@ nsThebesRenderingContext::FillRect(nscoord aX, nscoord aY, nscoord aWidth, nscoo
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* XXX awful invert rect hack
|
||||
* idea by mrbkap
|
||||
*/
|
||||
static unsigned int gInvertRect = 0;
|
||||
NS_IMETHODIMP
|
||||
nsThebesRenderingContext::InvertRect(const nsRect& aRect)
|
||||
{
|
||||
gfxContext::GraphicsOperator lastOp = mThebes->CurrentOperator();
|
||||
|
||||
gfxRGBA newColor(0,0,0,1);
|
||||
if (gInvertRect++ % 2)
|
||||
newColor = gfxRGBA(1,1,1,1);
|
||||
mThebes->Save();
|
||||
|
||||
mThebes->SetColor(newColor);
|
||||
mThebes->SetOperator(gfxContext::OPERATOR_OVER);
|
||||
mThebes->SetOperator(gfxContext::OPERATOR_XOR);
|
||||
nsresult rv = FillRect(aRect);
|
||||
mThebes->SetOperator(lastOp);
|
||||
|
||||
mThebes->Restore();
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sw=2 et tw=78: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
@ -64,7 +65,7 @@
|
||||
#include "nsILookAndFeel.h"
|
||||
#include "nsBlockFrame.h"
|
||||
#include "nsISelectionController.h"
|
||||
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsCaret.h"
|
||||
|
||||
// The bidi indicator hangs off the caret to one side, to show which
|
||||
@ -72,15 +73,6 @@
|
||||
// an insignificant dot
|
||||
static const PRUint32 kMinBidiIndicatorPixels = 2;
|
||||
|
||||
#if !defined(MOZ_WIDGET_GTK2)
|
||||
// Because of drawing issues, we currently always make a new RC. See bug 28068
|
||||
// Before removing this, stuff will need to be fixed and tested on all platforms.
|
||||
// For example, turning this off on Mac right now causes drawing problems on pages
|
||||
// with form elements.
|
||||
// Also turning this off caused problems on GTK1. See bug 254049.
|
||||
#define DONT_REUSE_RENDERING_CONTEXT
|
||||
#endif
|
||||
|
||||
#ifdef IBMBIDI
|
||||
//-------------------------------IBM BIDI--------------------------------------
|
||||
// Mamdouh : Modifiaction of the caret to work with Bidi in the LTR and RTL
|
||||
@ -97,7 +89,6 @@ nsCaret::nsCaret()
|
||||
, mDrawn(PR_FALSE)
|
||||
, mReadOnly(PR_FALSE)
|
||||
, mShowDuringSelection(PR_FALSE)
|
||||
, mLastCaretView(nsnull)
|
||||
, mLastContentOffset(0)
|
||||
, mLastHint(nsIFrameSelection::HINTLEFT)
|
||||
#ifdef IBMBIDI
|
||||
@ -107,7 +98,6 @@ nsCaret::nsCaret()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
nsCaret::~nsCaret()
|
||||
{
|
||||
@ -153,7 +143,8 @@ NS_IMETHODIMP nsCaret::Init(nsIPresShell *inPresShell)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsISelection> domSelection;
|
||||
nsresult rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSelection));
|
||||
nsresult rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
|
||||
getter_AddRefs(domSelection));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
if (!domSelection)
|
||||
@ -187,13 +178,11 @@ NS_IMETHODIMP nsCaret::Init(nsIPresShell *inPresShell)
|
||||
//-----------------------------------------------------------------------------
|
||||
NS_IMETHODIMP nsCaret::Terminate()
|
||||
{
|
||||
// this doesn't erase the caret if it's drawn. Should it? We might not have a good
|
||||
// drawing environment during teardown.
|
||||
// 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);
|
||||
@ -204,7 +193,6 @@ NS_IMETHODIMP nsCaret::Terminate()
|
||||
mPresShell = nsnull;
|
||||
|
||||
mLastContent = nsnull;
|
||||
mLastCaretView = nsnull;
|
||||
|
||||
#ifdef IBMBIDI
|
||||
mBidiKeyboard = nsnull;
|
||||
@ -276,7 +264,11 @@ NS_IMETHODIMP nsCaret::SetCaretReadOnly(PRBool inMakeReadonly)
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
NS_IMETHODIMP nsCaret::GetCaretCoordinates(EViewCoordinates aRelativeToType, nsISelection *aDOMSel, nsRect *outCoordinates, PRBool *outIsCollapsed, nsIView **outView)
|
||||
NS_IMETHODIMP nsCaret::GetCaretCoordinates(EViewCoordinates aRelativeToType,
|
||||
nsISelection *aDOMSel,
|
||||
nsRect *outCoordinates,
|
||||
PRBool *outIsCollapsed,
|
||||
nsIView **outView)
|
||||
{
|
||||
if (!mPresShell)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
@ -315,15 +307,7 @@ NS_IMETHODIMP nsCaret::GetCaretCoordinates(EViewCoordinates aRelativeToType, nsI
|
||||
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);
|
||||
nsCOMPtr<nsIContent> contentNode = do_QueryInterface(focusNode);
|
||||
if (!contentNode)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
@ -350,10 +334,9 @@ NS_IMETHODIMP nsCaret::GetCaretCoordinates(EViewCoordinates aRelativeToType, nsI
|
||||
return err;
|
||||
|
||||
nsPoint viewOffset(0, 0);
|
||||
nsRect clipRect;
|
||||
nsIView *drawingView; // views are not refcounted
|
||||
|
||||
GetViewForRendering(theFrame, aRelativeToType, viewOffset, clipRect, &drawingView, outView);
|
||||
GetViewForRendering(theFrame, aRelativeToType, viewOffset, &drawingView, outView);
|
||||
if (!drawingView)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
// ramp up to make a rendering context for measuring text.
|
||||
@ -434,10 +417,55 @@ NS_IMETHODIMP nsCaret::DrawAtPosition(nsIDOMNode* aNode, PRInt32 aOffset)
|
||||
presShell->GetCaretBidiLevel(&bidiLevel);
|
||||
|
||||
// XXX we need to do more work here to get the correct hint.
|
||||
return DrawAtPositionWithHint(aNode, aOffset, nsIFrameSelection::HINTLEFT, bidiLevel) ?
|
||||
nsresult rv = DrawAtPositionWithHint(aNode, aOffset, nsIFrameSelection::HINTLEFT, bidiLevel) ?
|
||||
NS_OK : NS_ERROR_FAILURE;
|
||||
ToggleDrawnStatus();
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsIFrame * nsCaret::GetCaretFrame()
|
||||
{
|
||||
// Return null if we're not drawn to prevent anybody from trying to draw us.
|
||||
if (!mDrawn)
|
||||
return nsnull;
|
||||
|
||||
// Recompute the frame that we're supposed to draw in to guarantee that
|
||||
// we're not going to try to draw into a stale (dead) frame.
|
||||
PRInt32 unused;
|
||||
nsIFrame *frame = nsnull;
|
||||
nsresult rv = GetCaretFrameForNodeOffset(mLastContent, mLastContentOffset,
|
||||
mLastHint, mLastBidiLevel, &frame,
|
||||
&unused);
|
||||
if (NS_FAILED(rv))
|
||||
return nsnull;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
void nsCaret::InvalidateOutsideCaret()
|
||||
{
|
||||
nsIFrame *frame = GetCaretFrame();
|
||||
|
||||
// Only invalidate if we are not fully contained by our frame's rect.
|
||||
if (frame && !frame->GetOverflowRect().Contains(GetCaretRect()))
|
||||
InvalidateRects(mCaretRect, GetHookRect(), frame);
|
||||
}
|
||||
|
||||
void nsCaret::PaintCaret(nsDisplayListBuilder *aBuilder,
|
||||
nsIRenderingContext *aCtx,
|
||||
const nsPoint &aOffset)
|
||||
{
|
||||
NS_ASSERTION(mDrawn, "The caret shouldn't be drawing");
|
||||
|
||||
if (mReadOnly)
|
||||
aCtx->SetColor(NS_RGBA(0x85, 0x85, 0x85, 0xff));
|
||||
else
|
||||
aCtx->SetColor(NS_RGBA(0x00, 0x00, 0x00, 0xff));
|
||||
|
||||
aCtx->InvertRect(mCaretRect + aOffset);
|
||||
if (!GetHookRect().IsEmpty())
|
||||
aCtx->InvertRect(GetHookRect() + aOffset);
|
||||
}
|
||||
|
||||
#ifdef XP_MAC
|
||||
#pragma mark -
|
||||
@ -543,11 +571,11 @@ nsCaret::DrawAtPositionWithHint(nsIDOMNode* aNode,
|
||||
PRInt32 aOffset,
|
||||
nsIFrameSelection::HINT aFrameHint,
|
||||
PRUint8 aBidiLevel)
|
||||
{
|
||||
{
|
||||
nsCOMPtr<nsIContent> contentNode = do_QueryInterface(aNode);
|
||||
if (!contentNode)
|
||||
return PR_FALSE;
|
||||
|
||||
|
||||
nsIFrame* theFrame = nsnull;
|
||||
PRInt32 theFrameOffset = 0;
|
||||
|
||||
@ -569,32 +597,35 @@ nsCaret::DrawAtPositionWithHint(nsIDOMNode* aNode,
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
|
||||
if (!mDrawn)
|
||||
{
|
||||
// save stuff so we can erase the caret later
|
||||
// save stuff so we can figure out what frame we're in 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 (aBidiLevel & BIDI_LEVEL_UNDEFINED)
|
||||
presShell->SetCaretBidiLevel(NS_GET_EMBEDDING_LEVEL(theFrame));
|
||||
}
|
||||
|
||||
GetCaretRectAndInvert(theFrame, theFrameOffset);
|
||||
rv = UpdateCaretRects(theFrame, theFrameOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return PR_FALSE;
|
||||
InvalidateRects(mCaretRect, mHookRect, theFrame);
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCaret::GetCaretFrameForNodeOffset (nsIContent* aContentNode,
|
||||
PRInt32 aOffset,
|
||||
nsIFrameSelection::HINT aFrameHint,
|
||||
PRUint8 aBidiLevel,
|
||||
nsIFrame** aReturnFrame,
|
||||
PRInt32* aReturnOffset)
|
||||
nsCaret::GetCaretFrameForNodeOffset(nsIContent* aContentNode,
|
||||
PRInt32 aOffset,
|
||||
nsIFrameSelection::HINT aFrameHint,
|
||||
PRUint8 aBidiLevel,
|
||||
nsIFrame** aReturnFrame,
|
||||
PRInt32* aReturnOffset)
|
||||
{
|
||||
|
||||
//get frame selection and find out what frame to use...
|
||||
@ -612,7 +643,9 @@ nsCaret::GetCaretFrameForNodeOffset (nsIContent* aContentNode,
|
||||
nsIFrame* theFrame = nsnull;
|
||||
PRInt32 theFrameOffset = 0;
|
||||
|
||||
nsresult rv = frameSelection->GetFrameForNodeOffset(aContentNode, aOffset, aFrameHint, &theFrame, &theFrameOffset);
|
||||
nsresult rv = frameSelection->GetFrameForNodeOffset(aContentNode, aOffset,
|
||||
aFrameHint, &theFrame,
|
||||
&theFrameOffset);
|
||||
if (NS_FAILED(rv) || !theFrame)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
@ -762,17 +795,20 @@ nsCaret::GetCaretFrameForNodeOffset (nsIContent* aContentNode,
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void nsCaret::GetViewForRendering(nsIFrame *caretFrame, EViewCoordinates coordType, nsPoint &viewOffset, nsRect& outClipRect, nsIView **outRenderingView, nsIView **outRelativeView)
|
||||
void nsCaret::GetViewForRendering(nsIFrame *caretFrame,
|
||||
EViewCoordinates coordType,
|
||||
nsPoint &viewOffset,
|
||||
nsIView **outRenderingView,
|
||||
nsIView **outRelativeView)
|
||||
{
|
||||
|
||||
if (!caretFrame || !outRenderingView)
|
||||
return;
|
||||
|
||||
// XXX by Masayuki Nakano:
|
||||
// Our this code is not good. This is adhoc approach.
|
||||
// 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 (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.
|
||||
@ -782,91 +818,63 @@ void nsCaret::GetViewForRendering(nsIFrame *caretFrame, EViewCoordinates coordTy
|
||||
// (nearest native window) related.
|
||||
coordType = eRenderingViewCoordinates;
|
||||
#endif
|
||||
}
|
||||
|
||||
*outRenderingView = nsnull;
|
||||
if (outRelativeView)
|
||||
*outRelativeView = nsnull;
|
||||
|
||||
NS_ASSERTION(caretFrame, "Should have frame here");
|
||||
NS_ASSERTION(caretFrame, "Should have a frame here");
|
||||
|
||||
viewOffset.x = 0;
|
||||
viewOffset.y = 0;
|
||||
|
||||
nsPoint withinViewOffset(0, 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 (!theView)
|
||||
return;
|
||||
|
||||
if (outRelativeView && coordType == eClosestViewCoordinates)
|
||||
*outRelativeView = theView;
|
||||
|
||||
nsIView* returnView = nsnull; // views are not refcounted
|
||||
// Note: views are not refcounted.
|
||||
nsIView* returnView = nsIView::GetViewFor(theView->GetNearestWidget(nsnull));
|
||||
|
||||
// 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();
|
||||
// This gets uses the first view with a widget
|
||||
if (coordType == eRenderingViewCoordinates) {
|
||||
if (returnView) {
|
||||
// Now adjust the view offset for this view.
|
||||
withinViewOffset += theView->GetOffsetTo(returnView);
|
||||
|
||||
// Account for the view's origin not lining up with the widget's
|
||||
// (bug 190290)
|
||||
withinViewOffset += returnView->GetPosition() -
|
||||
returnView->GetBounds().TopLeft();
|
||||
viewOffset = withinViewOffset;
|
||||
|
||||
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;
|
||||
if (outRelativeView)
|
||||
*outRelativeView = returnView;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// window-relative coordinates. Done for us by the view.
|
||||
withinViewOffset += theView->GetOffsetTo(nsnull);
|
||||
viewOffset = withinViewOffset;
|
||||
|
||||
// Get the relative view for top level window coordinates
|
||||
if (outRelativeView && coordType == eTopLevelWindowCoordinates) {
|
||||
nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
|
||||
if (presShell) {
|
||||
nsIViewManager* vm = presShell->GetViewManager();
|
||||
if (vm) {
|
||||
vm->GetRootView(*outRelativeView);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -972,215 +980,132 @@ void nsCaret::DrawCaret()
|
||||
}
|
||||
|
||||
DrawAtPositionWithHint(node, offset, hint, bidiLevel);
|
||||
ToggleDrawnStatus();
|
||||
}
|
||||
|
||||
void nsCaret::GetCaretRectAndInvert(nsIFrame* aFrame, PRInt32 aFrameOffset)
|
||||
nsresult nsCaret::UpdateCaretRects(nsIFrame* aFrame, PRInt32 aFrameOffset)
|
||||
{
|
||||
NS_ASSERTION(aFrame, "Should have a frame here");
|
||||
|
||||
nsRect frameRect = aFrame->GetRect();
|
||||
frameRect.x = 0; // the origin is accounted for in GetViewForRendering()
|
||||
frameRect.x = 0;
|
||||
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;
|
||||
|
||||
if (!presShell) return NS_ERROR_FAILURE;
|
||||
|
||||
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);
|
||||
nsIWidget *widget = aFrame->GetWindow();
|
||||
if (!widget)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
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.
|
||||
}
|
||||
nsCOMPtr<nsIRenderingContext> rendContext;
|
||||
nsresult rv = presContext->DeviceContext()->
|
||||
CreateRenderingContext(widget, *getter_AddRefs(rendContext));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!rendContext)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
const nsStyleFont* fontStyle = aFrame->GetStyleFont();
|
||||
const nsStyleVisibility* vis = aFrame->GetStyleVisibility();
|
||||
rendContext->SetFont(fontStyle->mFont, vis->mLangGroup);
|
||||
|
||||
nsCOMPtr<nsIFontMetrics> fm;
|
||||
rendContext->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);
|
||||
mCaretRect = 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);
|
||||
nsPoint framePos;
|
||||
|
||||
caretRect += framePos;
|
||||
// if cache in selection is available, apply it, else refresh it
|
||||
privateSelection->GetCachedFrameOffset(aFrame, aFrameOffset, framePos);
|
||||
|
||||
caretRect.width = mCaretTwipsWidth;
|
||||
mCaretRect += framePos;
|
||||
mCaretRect.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.
|
||||
return UpdateHookRect(presContext);
|
||||
}
|
||||
|
||||
nscoord caretXMost = caretRect.XMost();
|
||||
nscoord frameXMost = frameRect.XMost();
|
||||
nsresult nsCaret::UpdateHookRect(nsPresContext* aPresContext)
|
||||
{
|
||||
mHookRect.Empty();
|
||||
|
||||
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)
|
||||
// Simon -- make a hook to draw to the left or right of the caret to show keyboard language direction
|
||||
PRBool bidiEnabled;
|
||||
PRBool isCaretRTL=PR_FALSE;
|
||||
if (mBidiKeyboard)
|
||||
mBidiKeyboard->IsLangRTL(&isCaretRTL);
|
||||
if (isCaretRTL)
|
||||
{
|
||||
bidiEnabled = PR_TRUE;
|
||||
aPresContext->SetBidiEnabled(bidiEnabled);
|
||||
}
|
||||
else
|
||||
bidiEnabled = aPresContext->BidiEnabled();
|
||||
if (bidiEnabled)
|
||||
{
|
||||
if (isCaretRTL != mKeyboardRTL)
|
||||
{
|
||||
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 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)))
|
||||
{
|
||||
if (NS_SUCCEEDED(domSelection->SelectionLanguageChange(mKeyboardRTL)))
|
||||
{
|
||||
mRendContext->PopState();
|
||||
#ifdef DONT_REUSE_RENDERING_CONTEXT
|
||||
mRendContext = nsnull;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
// 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.
|
||||
mHookRect.SetRect(mCaretRect.x + ((isCaretRTL) ?
|
||||
mBidiIndicatorTwipsSize * -1 :
|
||||
mCaretRect.width),
|
||||
mCaretRect.y + mBidiIndicatorTwipsSize,
|
||||
mBidiIndicatorTwipsSize,
|
||||
mCaretRect.width);
|
||||
}
|
||||
#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);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// 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
|
||||
// static
|
||||
void nsCaret::InvalidateRects(const nsRect &aRect, const nsRect &aHook,
|
||||
nsIFrame *aFrame)
|
||||
{
|
||||
NS_ASSERTION(aFrame, "Must have a frame to invalidate");
|
||||
nsRect rect;
|
||||
rect.UnionRect(aRect, aHook);
|
||||
aFrame->Invalidate(rect, PR_FALSE);
|
||||
}
|
||||
|
||||
#ifdef XP_MAC
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=2 sw=2 et tw=78:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
@ -73,34 +74,84 @@ class nsCaret : public nsICaret,
|
||||
NS_IMETHOD GetCaretVisible(PRBool *outMakeVisible);
|
||||
NS_IMETHOD SetCaretVisible(PRBool intMakeVisible);
|
||||
NS_IMETHOD SetCaretReadOnly(PRBool inMakeReadonly);
|
||||
NS_IMETHOD GetCaretCoordinates(EViewCoordinates aRelativeToType, nsISelection *inDOMSel, nsRect* outCoordinates, PRBool* outIsCollapsed, nsIView **outView);
|
||||
virtual PRBool GetCaretReadOnly()
|
||||
{
|
||||
return mReadOnly;
|
||||
}
|
||||
NS_IMETHOD GetCaretCoordinates(EViewCoordinates aRelativeToType,
|
||||
nsISelection *inDOMSel,
|
||||
nsRect* outCoordinates,
|
||||
PRBool* outIsCollapsed,
|
||||
nsIView **outView);
|
||||
NS_IMETHOD EraseCaret();
|
||||
|
||||
NS_IMETHOD SetVisibilityDuringSelection(PRBool aVisibility);
|
||||
NS_IMETHOD DrawAtPosition(nsIDOMNode* aNode, PRInt32 aOffset);
|
||||
nsIFrame* GetCaretFrame();
|
||||
nsRect GetCaretRect()
|
||||
{
|
||||
nsRect r;
|
||||
r.UnionRect(mCaretRect, GetHookRect());
|
||||
return r;
|
||||
}
|
||||
nsIContent* GetCaretContent()
|
||||
{
|
||||
if (mDrawn)
|
||||
return mLastContent;
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
void InvalidateOutsideCaret();
|
||||
|
||||
void PaintCaret(nsDisplayListBuilder *aBuilder,
|
||||
nsIRenderingContext *aCtx,
|
||||
const nsPoint &aOffset);
|
||||
|
||||
//nsISelectionListener interface
|
||||
NS_DECL_NSISELECTIONLISTENER
|
||||
|
||||
|
||||
static void CaretBlinkCallback(nsITimer *aTimer, void *aClosure);
|
||||
|
||||
NS_IMETHOD GetCaretFrameForNodeOffset (nsIContent* aContentNode, PRInt32 aOffset, nsIFrameSelection::HINT aFrameHint, PRUint8 aBidiLevel,
|
||||
nsIFrame** aReturnFrame, PRInt32* aReturnOffset);
|
||||
NS_IMETHOD GetCaretFrameForNodeOffset(nsIContent* aContentNode,
|
||||
PRInt32 aOffset,
|
||||
nsIFrameSelection::HINT aFrameHint,
|
||||
PRUint8 aBidiLevel,
|
||||
nsIFrame** aReturnFrame,
|
||||
PRInt32* aReturnOffset);
|
||||
protected:
|
||||
|
||||
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);
|
||||
void GetViewForRendering(nsIFrame *caretFrame,
|
||||
EViewCoordinates coordType,
|
||||
nsPoint &viewOffset,
|
||||
nsIView **outRenderingView,
|
||||
nsIView **outRelativeView);
|
||||
PRBool DrawAtPositionWithHint(nsIDOMNode* aNode,
|
||||
PRInt32 aOffset,
|
||||
nsIFrameSelection::HINT aFrameHint,
|
||||
PRUint8 aBidiLevel);
|
||||
PRBool MustDrawCaret();
|
||||
void DrawCaret();
|
||||
void DrawCaretAfterBriefDelay();
|
||||
void GetCaretRectAndInvert(nsIFrame* aFrame, PRInt32 aFrameOffset);
|
||||
void ToggleDrawnStatus() { mDrawn = !mDrawn; }
|
||||
nsresult UpdateCaretRects(nsIFrame* aFrame, PRInt32 aFrameOffset);
|
||||
nsresult UpdateHookRect(nsPresContext* aPresContext);
|
||||
static void InvalidateRects(const nsRect &aRect, const nsRect &aHook,
|
||||
nsIFrame *aFrame);
|
||||
nsRect GetHookRect()
|
||||
{
|
||||
#ifdef IBMBIDI
|
||||
return mHookRect;
|
||||
#else
|
||||
return nsRect();
|
||||
#endif
|
||||
}
|
||||
void ToggleDrawnStatus() { mDrawn = !mDrawn; }
|
||||
|
||||
protected:
|
||||
|
||||
@ -120,12 +171,17 @@ protected:
|
||||
PRPackedBool mReadOnly; // it the caret in readonly state (draws differently)
|
||||
PRPackedBool mShowDuringSelection; // show when text is selected
|
||||
|
||||
nsRect mCaretRect; // the last caret rect
|
||||
nsIView* mLastCaretView; // last view that we used for drawing. Cached so we can tell when we need to make a new RC
|
||||
nsCOMPtr<nsIContent> mLastContent; // store the content the caret was last requested to be drawn in (by DrawAtPosition()/DrawCaret()),
|
||||
// note that this can be different than where it was actually drawn (anon <BR> in text control)
|
||||
nsRect mCaretRect; // the last caret rect, in the coodinates of the last frame.
|
||||
|
||||
nsCOMPtr<nsIContent> mLastContent; // store the content the caret was last requested to be drawn
|
||||
// in (by DrawAtPosition()/DrawCaret()),
|
||||
// note that this can be different than where it was
|
||||
// actually drawn (anon <BR> in text control)
|
||||
PRInt32 mLastContentOffset; // the offset for the last request
|
||||
nsIFrameSelection::HINT mLastHint; // the hint associated with the last request, see also mLastBidiLevel below
|
||||
|
||||
nsIFrameSelection::HINT mLastHint; // the hint associated with the last request, see also
|
||||
// mLastBidiLevel below
|
||||
|
||||
#ifdef IBMBIDI
|
||||
nsRect mHookRect; // directional hook on the caret
|
||||
nsCOMPtr<nsIBidiKeyboard> mBidiKeyboard; // Bidi keyboard object to set and query keyboard language
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=2 sw=2 et tw=78:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
@ -55,10 +56,11 @@
|
||||
#endif
|
||||
|
||||
nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
||||
PRBool aIsForEvents, nsIFrame* aMovingFrame)
|
||||
PRBool aIsForEvents, PRBool aBuildCaret, nsIFrame* aMovingFrame)
|
||||
: mReferenceFrame(aReferenceFrame),
|
||||
mMovingFrame(aMovingFrame),
|
||||
mIgnoreScrollFrame(nsnull),
|
||||
mBuildCaret(aBuildCaret),
|
||||
mEventDelivery(aIsForEvents),
|
||||
mIsAtRootOfPseudoStackingContext(PR_FALSE) {
|
||||
PL_InitArenaPool(&mPool, "displayListArena", 1024, sizeof(void*)-1);
|
||||
@ -75,6 +77,10 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
||||
getter_AddRefs(mBoundingSelection));
|
||||
}
|
||||
}
|
||||
|
||||
if (mIsBackgroundOnly) {
|
||||
mBuildCaret = PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
nsDisplayListBuilder::~nsDisplayListBuilder() {
|
||||
@ -82,6 +88,64 @@ nsDisplayListBuilder::~nsDisplayListBuilder() {
|
||||
PL_FinishArenaPool(&mPool);
|
||||
}
|
||||
|
||||
nsICaret *
|
||||
nsDisplayListBuilder::GetCaret() {
|
||||
NS_ASSERTION(mCaretStates.Length() > 0, "Not enough presshells");
|
||||
|
||||
nsIFrame* frame = GetCaretFrame();
|
||||
if (!frame) {
|
||||
return nsnull;
|
||||
}
|
||||
nsIPresShell* shell = frame->GetPresContext()->PresShell();
|
||||
nsCOMPtr<nsICaret> caret;
|
||||
shell->GetCaret(getter_AddRefs(caret));
|
||||
|
||||
return caret;
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayListBuilder::EnterPresShell(nsIFrame* aReferenceFrame,
|
||||
const nsRect& aDirtyRect) {
|
||||
if (!mBuildCaret) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsIPresShell* shell = aReferenceFrame->GetPresContext()->PresShell();
|
||||
nsCOMPtr<nsICaret> caret;
|
||||
shell->GetCaret(getter_AddRefs(caret));
|
||||
nsIFrame* frame = caret->GetCaretFrame();
|
||||
|
||||
nsLayoutUtils::MarkCaretSubtreeForPainting(this, aReferenceFrame,
|
||||
frame, caret->GetCaretRect(),
|
||||
aDirtyRect, PR_TRUE);
|
||||
|
||||
mCaretStates.AppendElement(frame);
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayListBuilder::LeavePresShell(nsIFrame* aReferenceFrame,
|
||||
const nsRect& aDirtyRect)
|
||||
{
|
||||
if (!mBuildCaret) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Pop the state off.
|
||||
NS_ASSERTION(mCaretStates.Length() > 0, "Leaving too many PresShell");
|
||||
nsICaret* caret = GetCaret();
|
||||
if (caret) {
|
||||
nsLayoutUtils::MarkCaretSubtreeForPainting(this, aReferenceFrame,
|
||||
GetCaretFrame(),
|
||||
caret->GetCaretRect(),
|
||||
aDirtyRect, PR_FALSE);
|
||||
} else {
|
||||
NS_ASSERTION(GetCaretFrame() == nsnull,
|
||||
"GetCaret and LeavePresShell diagree");
|
||||
}
|
||||
|
||||
mCaretStates.SetLength(mCaretStates.Length() - 1);
|
||||
}
|
||||
|
||||
void*
|
||||
nsDisplayListBuilder::Allocate(size_t aSize) {
|
||||
void *tmp;
|
||||
@ -455,6 +519,14 @@ nsDisplayOutline::Paint(nsDisplayListBuilder* aBuilder,
|
||||
mFrame->GetStyleContext(), 0);
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayCaret::Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsIRenderingContext* aCtx, const nsRect& aDirtyRect) {
|
||||
// Note: Because we exist, we know that the caret is visible, so we don't
|
||||
// need to check for the caret's visibility.
|
||||
mCaret->PaintCaret(aBuilder, aCtx, aBuilder->ToReferenceFrame(mFrame));
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayBorder::Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsIRenderingContext* aCtx, const nsRect& aDirtyRect) {
|
||||
@ -622,7 +694,6 @@ void nsDisplayOpacity::Paint(nsDisplayListBuilder* aBuilder,
|
||||
// depth of nested translucent elements. This will be fixed when we move to
|
||||
// cairo with support for real alpha channels in surfaces, so we don't have
|
||||
// to do this white/black hack anymore.
|
||||
nsIViewManager* vm = mFrame->GetPresContext()->GetViewManager();
|
||||
float opacity = mFrame->GetStyleDisplay()->mOpacity;
|
||||
|
||||
nsRect bounds;
|
||||
@ -661,6 +732,7 @@ void nsDisplayOpacity::Paint(nsDisplayListBuilder* aBuilder,
|
||||
|
||||
#elif !defined(XP_MACOSX)
|
||||
|
||||
nsIViewManager* vm = mFrame->GetPresContext()->GetViewManager();
|
||||
nsIViewManager::BlendingBuffers* buffers =
|
||||
vm->CreateBlendingBuffers(aCtx, PR_FALSE, nsnull, mNeedAlpha, bounds);
|
||||
if (!buffers) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=2 sw=2 et tw=78:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
@ -50,6 +51,8 @@
|
||||
#include "nsISelection.h"
|
||||
#include "plarena.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsICaret.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
@ -119,6 +122,8 @@ public:
|
||||
* is the origin of the reference coordinate system for this display list
|
||||
* @param aIsForEvents PR_TRUE if we're creating this list in order to
|
||||
* determine which frame is under the mouse position
|
||||
* @param aBuildCaret whether or not we should include the caret in any
|
||||
* display lists that we make.
|
||||
* @param aMovingFrame a frame whose subtree should be regarded as
|
||||
* moving; moving frames are not allowed to clip or cover (during
|
||||
* OptimizeVisibility) non-moving frames. E.g. when we're constructing
|
||||
@ -126,7 +131,7 @@ public:
|
||||
* operation, we specify the scrolled frame as the moving frame.
|
||||
*/
|
||||
nsDisplayListBuilder(nsIFrame* aReferenceFrame, PRBool aIsForEvents,
|
||||
nsIFrame* aMovingFrame = nsnull);
|
||||
PRBool aBuildCaret, nsIFrame* aMovingFrame = nsnull);
|
||||
~nsDisplayListBuilder();
|
||||
|
||||
/**
|
||||
@ -193,6 +198,42 @@ public:
|
||||
* Get the scrollframe to ignore, if any.
|
||||
*/
|
||||
nsIFrame* GetIgnoreScrollFrame() { return mIgnoreScrollFrame; }
|
||||
/**
|
||||
* Display the caret if needed.
|
||||
*/
|
||||
nsresult DisplayCaret(nsIFrame* aFrame, const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists) {
|
||||
nsIFrame* frame = GetCaretFrame();
|
||||
if (aFrame != frame) {
|
||||
return NS_OK;
|
||||
}
|
||||
return frame->DisplayCaret(this, aDirtyRect, aLists);
|
||||
}
|
||||
/**
|
||||
* Get the frame that the caret is supposed to draw in.
|
||||
* If the caret is currently invisible, this will be null.
|
||||
*/
|
||||
nsIFrame* GetCaretFrame() {
|
||||
if (mBuildCaret) {
|
||||
NS_ASSERTION(mCaretStates.Length() > 0, "Not enough presshells");
|
||||
return mCaretStates[mCaretStates.Length() - 1];
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
/**
|
||||
* Get the caret associated with the current presshell.
|
||||
*/
|
||||
nsICaret* GetCaret();
|
||||
/**
|
||||
* Notify the display list builder that we're entering a presshell.
|
||||
* aReferenceFrame should be a frame in the new presshell and aDirtyRect
|
||||
* should be the current dirty rect in aReferenceFrame's coordinate space.
|
||||
*/
|
||||
void EnterPresShell(nsIFrame* aReferenceFrame, const nsRect& aDirtyRect);
|
||||
/**
|
||||
* Notify the display list builder that we're leaving a presshell.
|
||||
*/
|
||||
void LeavePresShell(nsIFrame* aReferenceFrame, const nsRect& aDirtyRect);
|
||||
|
||||
/**
|
||||
* Allocate memory in our arena. It will only be freed when this display list
|
||||
@ -231,6 +272,8 @@ private:
|
||||
nsIFrame* mIgnoreScrollFrame;
|
||||
PLArenaPool mPool;
|
||||
nsCOMPtr<nsISelection> mBoundingSelection;
|
||||
nsTArray<nsIFrame *> mCaretStates;
|
||||
PRPackedBool mBuildCaret;
|
||||
PRPackedBool mEventDelivery;
|
||||
PRPackedBool mIsBackgroundOnly;
|
||||
PRPackedBool mIsAtRootOfPseudoStackingContext;
|
||||
@ -757,6 +800,30 @@ protected:
|
||||
#endif
|
||||
};
|
||||
|
||||
MOZ_DECL_CTOR_COUNTER(nsDisplayCaret)
|
||||
class nsDisplayCaret : public nsDisplayItem {
|
||||
public:
|
||||
nsDisplayCaret(nsIFrame* aCaretFrame, nsICaret *aCaret)
|
||||
: nsDisplayItem(aCaretFrame), mCaret(aCaret) {
|
||||
MOZ_COUNT_CTOR(nsDisplayCaret);
|
||||
}
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
virtual ~nsDisplayCaret() {
|
||||
MOZ_COUNT_DTOR(nsDisplayCaret);
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) {
|
||||
// The caret returns a rect in the coordinates of mFrame.
|
||||
return mCaret->GetCaretRect() + aBuilder->ToReferenceFrame(mFrame);
|
||||
}
|
||||
virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx,
|
||||
const nsRect& aDirtyRect);
|
||||
NS_DISPLAY_DECL_NAME("Caret");
|
||||
protected:
|
||||
nsCOMPtr<nsICaret> mCaret;
|
||||
};
|
||||
|
||||
/**
|
||||
* The standard display item to paint the CSS borders of a frame.
|
||||
*/
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sw=2 et tw=78: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
@ -56,10 +57,10 @@ class nsISelection;
|
||||
class nsIDOMNode;
|
||||
|
||||
// IID for the nsICaret interface
|
||||
// dcb01833-509d-4fcb-8f7f-6beb006261b9
|
||||
// 89ce0f4b-17c0-4362-b641-12ef696134d6
|
||||
#define NS_ICARET_IID \
|
||||
{ 0xdcb01833, 0x509d, 0x4fcb, \
|
||||
{ 0x8f, 0x7f, 0x6b, 0xeb, 0x00, 0x62, 0x61, 0xb9 } }
|
||||
{ 0x89ce0f4b, 0x17c0, 0x4362, \
|
||||
{ 0xb6, 0x41, 0x12, 0xef, 0x69, 0x61, 0x34, 0xd6 } }
|
||||
|
||||
class nsICaret: public nsISupports
|
||||
{
|
||||
@ -95,14 +96,21 @@ public:
|
||||
*/
|
||||
NS_IMETHOD SetCaretReadOnly(PRBool inMakeReadonly) = 0;
|
||||
|
||||
virtual PRBool GetCaretReadOnly() = 0;
|
||||
|
||||
/** GetCaretCoordinates
|
||||
* Get the position of the caret in coordinates relative to the typed specified (aRelativeToType).
|
||||
* 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.
|
||||
*/
|
||||
NS_IMETHOD GetCaretCoordinates(EViewCoordinates aRelativeToType, nsISelection *aDOMSel, nsRect *outCoordinates, PRBool *outIsCollapsed, nsIView **outView) = 0;
|
||||
NS_IMETHOD GetCaretCoordinates(EViewCoordinates aRelativeToType,
|
||||
nsISelection *aDOMSel,
|
||||
nsRect *outCoordinates,
|
||||
PRBool *outIsCollapsed,
|
||||
nsIView **outView) = 0;
|
||||
|
||||
/** Erase Caret
|
||||
* this will erase the caret if its drawn and reset drawn status
|
||||
@ -121,12 +129,47 @@ public:
|
||||
NS_IMETHOD DrawAtPosition(nsIDOMNode* aNode, PRInt32 aOffset) = 0;
|
||||
|
||||
/** GetCaretFrameForNodeOffset
|
||||
* Get the frame and content offset at which the caret is drawn,
|
||||
* invoking the bidi caret positioning algorithm if necessary
|
||||
**/
|
||||
NS_IMETHOD GetCaretFrameForNodeOffset (nsIContent* aContentNode, PRInt32 aOffset, nsIFrameSelection::HINT aFrameHint, PRUint8 aBidiLevel,
|
||||
nsIFrame** aReturnFrame, PRInt32* aReturnOffset) = 0;
|
||||
|
||||
* Get the frame and content offset at which the caret is drawn,
|
||||
* invoking the bidi caret positioning algorithm if necessary
|
||||
**/
|
||||
NS_IMETHOD GetCaretFrameForNodeOffset(nsIContent* aContentNode,
|
||||
PRInt32 aOffset,
|
||||
nsIFrameSelection::HINT aFrameHint,
|
||||
PRUint8 aBidiLevel,
|
||||
nsIFrame** aReturnFrame,
|
||||
PRInt32* aReturnOffset) = 0;
|
||||
|
||||
/** GetCaretFrame
|
||||
* Get the current frame that the caret should be drawn in. If the caret is
|
||||
* not currently visible (i.e., it is between blinks), then this will
|
||||
* return null.
|
||||
*/
|
||||
virtual nsIFrame *GetCaretFrame() = 0;
|
||||
|
||||
/** GetCaretRect
|
||||
* Get the current caret rect. Only call this when GetCaretFrame returns
|
||||
* non-null.
|
||||
*/
|
||||
virtual nsRect GetCaretRect() = 0;
|
||||
|
||||
/** GetCaretContent
|
||||
* Get the content that the caret was last drawn in.
|
||||
*/
|
||||
virtual nsIContent* GetCaretContent() = 0;
|
||||
|
||||
/** InvalidateOutsideCaret
|
||||
* Invalidate the area that the caret currently occupies if the caret is
|
||||
* outside of its frame's overflow area. This is used when the content that
|
||||
* the caret is currently drawn is is being deleted or reflowed.
|
||||
*/
|
||||
virtual void InvalidateOutsideCaret() = 0;
|
||||
|
||||
/** PaintCaret
|
||||
* Actually paint the caret onto the given rendering context.
|
||||
*/
|
||||
virtual void PaintCaret(nsDisplayListBuilder *aBuilder,
|
||||
nsIRenderingContext *aCtx,
|
||||
const nsPoint &aOffset) = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsICaret, NS_ICARET_IID)
|
||||
|
@ -96,9 +96,8 @@ class nsISelection;
|
||||
template<class E> class nsCOMArray;
|
||||
|
||||
#define NS_IPRESSHELL_IID \
|
||||
{ 0x998cde06, 0x5fa4, 0x4c8b, \
|
||||
{ 0x94, 0x8d, 0xc7, 0x15, 0x74, 0x75, 0xab, 0x6f } }
|
||||
|
||||
{ 0xa736d2fd, 0x0191, 0x42ea, \
|
||||
{ 0xb1, 0xb0, 0x80, 0x45, 0x1d, 0xfa, 0x03, 0x53 } }
|
||||
|
||||
// Constants uses for ScrollFrameIntoView() function
|
||||
#define NS_PRESSHELL_SCROLL_TOP 0
|
||||
@ -485,6 +484,11 @@ public:
|
||||
*/
|
||||
NS_IMETHOD GetCaret(nsICaret **aOutCaret) = 0;
|
||||
|
||||
/**
|
||||
* Set the current caret to a new caret. Returns the old caret.
|
||||
*/
|
||||
virtual already_AddRefed<nsICaret> SetCaret(nsICaret *aNewCaret) = 0;
|
||||
|
||||
/**
|
||||
* Should the images have borders etc. Actual visual effects are determined
|
||||
* by the frames. Visual effects may not effect layout, only display.
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sw=2 et tw=78: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
@ -617,10 +618,16 @@ static PRBool gDumpRepaintRegionForCopy = PR_FALSE;
|
||||
nsIFrame*
|
||||
nsLayoutUtils::GetFrameForPoint(nsIFrame* aFrame, nsPoint aPt)
|
||||
{
|
||||
nsDisplayListBuilder builder(aFrame, PR_TRUE);
|
||||
nsDisplayListBuilder builder(aFrame, PR_TRUE, PR_FALSE);
|
||||
nsDisplayList list;
|
||||
nsRect target(aPt, nsSize(1, 1));
|
||||
|
||||
builder.EnterPresShell(aFrame, target);
|
||||
|
||||
nsresult rv =
|
||||
aFrame->BuildDisplayListForStackingContext(&builder, nsRect(aPt, nsSize(1, 1)), &list);
|
||||
aFrame->BuildDisplayListForStackingContext(&builder, target, &list);
|
||||
|
||||
builder.LeavePresShell(aFrame, target);
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -669,11 +676,16 @@ nsresult
|
||||
nsLayoutUtils::PaintFrame(nsIRenderingContext* aRenderingContext, nsIFrame* aFrame,
|
||||
const nsRegion& aDirtyRegion, nscolor aBackground)
|
||||
{
|
||||
nsDisplayListBuilder builder(aFrame, PR_FALSE);
|
||||
nsDisplayListBuilder builder(aFrame, PR_FALSE, PR_TRUE);
|
||||
nsDisplayList list;
|
||||
nsRect dirtyRect = aDirtyRegion.GetBounds();
|
||||
|
||||
builder.EnterPresShell(aFrame, dirtyRect);
|
||||
|
||||
nsresult rv =
|
||||
aFrame->BuildDisplayListForStackingContext(&builder, dirtyRect, &list);
|
||||
|
||||
builder.LeavePresShell(aFrame, dirtyRect);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (NS_GET_A(aBackground) > 0) {
|
||||
@ -791,10 +803,15 @@ nsLayoutUtils::ComputeRepaintRegionForCopy(nsIFrame* aRootFrame,
|
||||
// hierarchy has already been updated for the move.)
|
||||
nsRect rect;
|
||||
rect.UnionRect(aCopyRect, aCopyRect + aDelta);
|
||||
nsDisplayListBuilder builder(aRootFrame, PR_FALSE, aMovingFrame);
|
||||
nsDisplayListBuilder builder(aRootFrame, PR_FALSE, PR_TRUE, aMovingFrame);
|
||||
nsDisplayList list;
|
||||
|
||||
builder.EnterPresShell(aRootFrame, rect);
|
||||
|
||||
nsresult rv =
|
||||
aRootFrame->BuildDisplayListForStackingContext(&builder, rect, &list);
|
||||
|
||||
builder.LeavePresShell(aRootFrame, rect);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -943,3 +960,40 @@ nsLayoutUtils::ScrollIntoView(nsIFormControlFrame* aFormFrame)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsLayoutUtils::MarkCaretSubtreeForPainting(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aReferenceFrame,
|
||||
nsIFrame* aCaretFrame,
|
||||
const nsRect& aCaretRect,
|
||||
const nsRect& aRealDirtyRect,
|
||||
PRBool aMark)
|
||||
{
|
||||
// Easy test: If there is no caret, we don't have anything to do.
|
||||
if (!aCaretFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
NS_ASSERTION(aReferenceFrame, "We must have a reference frame");
|
||||
|
||||
// Check if the dirty rect intersects with the caret's dirty rect.
|
||||
nsRect caretRect = aCaretRect + aCaretFrame->GetOffsetTo(aReferenceFrame);
|
||||
if (!caretRect.Intersects(aRealDirtyRect)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aMark) {
|
||||
// Okay, our rects intersect, let's mark the frame and all of its ancestors.
|
||||
do {
|
||||
aCaretFrame->AddStateBits(NS_FRAME_HAS_DESCENDANT_PLACEHOLDER);
|
||||
aCaretFrame = aCaretFrame->GetParent();
|
||||
} while (aCaretFrame);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
aCaretFrame->RemoveStateBits(NS_FRAME_HAS_DESCENDANT_PLACEHOLDER);
|
||||
aCaretFrame = aCaretFrame->GetParent();
|
||||
} while (aCaretFrame);
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ class nsIScrollableView;
|
||||
class nsIScrollableFrame;
|
||||
class nsIDOMEvent;
|
||||
class nsRegion;
|
||||
class nsDisplayListBuilder;
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "nsStyleContext.h"
|
||||
@ -412,6 +413,26 @@ public:
|
||||
* @param aFormFrame Frame to scroll into view.
|
||||
*/
|
||||
static void ScrollIntoView(nsIFormControlFrame* aFormFrame);
|
||||
|
||||
/**
|
||||
* Ensure that the caret frame's subtree is painted by the next paint.
|
||||
* @param aBuilder The display list builder that we're going to be painting
|
||||
* with.
|
||||
* @param aCaretFrame The frame that the caret is currently in.
|
||||
* @param aReferenceFrame The frame whose coodinate space aRealDirtyRect is
|
||||
* in.
|
||||
* @param aCaretRect The rect (in aCaretFrame's coordinates) that the caret
|
||||
* wants to be in.
|
||||
* @param aRealDirtyRect The rect (in aReferenceFrame's coordinates) that is
|
||||
* the original dirty rect.
|
||||
* @param aMark Whether we're marking or unmarking the frames.
|
||||
*/
|
||||
static void MarkCaretSubtreeForPainting(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aReferenceFrame,
|
||||
nsIFrame* aCaretFrame,
|
||||
const nsRect& aCaretRect,
|
||||
const nsRect& aRealDirtyRect,
|
||||
PRBool aMark);
|
||||
};
|
||||
|
||||
#endif // nsLayoutUtils_h__
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=2 sw=2 et tw=78:
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
@ -1200,6 +1201,7 @@ public:
|
||||
NS_IMETHOD SetCaretReadOnly(PRBool aReadOnly);
|
||||
NS_IMETHOD GetCaretEnabled(PRBool *aOutEnabled);
|
||||
NS_IMETHOD SetCaretVisibilityDuringSelection(PRBool aVisibility);
|
||||
virtual already_AddRefed<nsICaret> SetCaret(nsICaret *aNewCaret);
|
||||
|
||||
NS_IMETHOD SetSelectionFlags(PRInt16 aInEnable);
|
||||
NS_IMETHOD GetSelectionFlags(PRInt16 *aOutEnable);
|
||||
@ -3093,6 +3095,14 @@ NS_IMETHODIMP PresShell::GetCaret(nsICaret **outCaret)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<nsICaret> PresShell::SetCaret(nsICaret *aNewCaret)
|
||||
{
|
||||
nsICaret *oldCaret = nsnull;
|
||||
mCaret.swap(oldCaret);
|
||||
mCaret = aNewCaret;
|
||||
return oldCaret;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP PresShell::SetCaretEnabled(PRBool aInEnable)
|
||||
{
|
||||
nsresult result = NS_OK;
|
||||
@ -3362,9 +3372,12 @@ static void UpdateViewProperties(nsPresContext* aPresContext, nsIViewManager* aV
|
||||
NS_IMETHODIMP
|
||||
PresShell::StyleChangeReflow()
|
||||
{
|
||||
|
||||
WillCauseReflow();
|
||||
|
||||
if (mCaret) {
|
||||
mCaret->InvalidateOutsideCaret();
|
||||
}
|
||||
|
||||
nsIFrame* rootFrame = FrameManager()->GetRootFrame();
|
||||
if (rootFrame) {
|
||||
// Kick off a top-down reflow
|
||||
@ -5136,6 +5149,9 @@ PresShell::CharacterDataChanged(nsIDocument *aDocument,
|
||||
NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
|
||||
|
||||
WillCauseReflow();
|
||||
if (mCaret) {
|
||||
mCaret->InvalidateOutsideCaret();
|
||||
}
|
||||
mFrameConstructor->CharacterDataChanged(aContent, aAppend);
|
||||
VERIFY_STYLE_TREE;
|
||||
DidCauseReflow();
|
||||
@ -5232,11 +5248,10 @@ PresShell::ContentRemoved(nsIDocument *aDocument,
|
||||
NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentRemoved");
|
||||
NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
|
||||
|
||||
// XXX fix for bug 304383. Remove when bug 287813 is fixed?
|
||||
// Make sure that the caret doesn't leave a turd where the child used to be.
|
||||
if (mCaret) {
|
||||
nsIFrame* frame = GetPrimaryFrameFor(aChild);
|
||||
if (frame && (frame->GetStateBits() & NS_FRAME_EXTERNAL_REFERENCE)) {
|
||||
mCaret->EraseCaret();
|
||||
if (mCaret->GetCaretContent() == aChild) {
|
||||
mCaret->InvalidateOutsideCaret();
|
||||
}
|
||||
}
|
||||
|
||||
@ -5505,7 +5520,7 @@ PresShell::RenderOffscreen(nsRect aRect, PRBool aUntrusted,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsDisplayListBuilder builder(rootFrame, PR_FALSE);
|
||||
nsDisplayListBuilder builder(rootFrame, PR_FALSE, PR_FALSE);
|
||||
nsDisplayList list;
|
||||
nsIScrollableView* scrollingView = nsnull;
|
||||
mViewManager->GetRootScrollableView(&scrollingView);
|
||||
@ -5518,7 +5533,11 @@ PresShell::RenderOffscreen(nsRect aRect, PRBool aUntrusted,
|
||||
builder.SetIgnoreScrollFrame(GetRootScrollFrame());
|
||||
}
|
||||
|
||||
builder.EnterPresShell(rootFrame, r);
|
||||
|
||||
rv = rootFrame->BuildDisplayListForStackingContext(&builder, r, &list);
|
||||
|
||||
builder.LeavePresShell(rootFrame, r);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsRegion region(r);
|
||||
@ -5566,9 +5585,6 @@ PresShell::Paint(nsIView* aView,
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mCaret)
|
||||
mCaret->EraseCaret();
|
||||
|
||||
nsLayoutUtils::PaintFrame(aRenderingContext, frame, aDirtyRegion,
|
||||
backgroundColor);
|
||||
@ -5810,7 +5826,7 @@ PresShell::HandleEvent(nsIView *aView,
|
||||
nsPoint eventPoint
|
||||
= nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, frame);
|
||||
nsIFrame* targetFrame =
|
||||
targetFrame = nsLayoutUtils::GetFrameForPoint(frame, eventPoint);
|
||||
nsLayoutUtils::GetFrameForPoint(frame, eventPoint);
|
||||
if (targetFrame) {
|
||||
PresShell* shell =
|
||||
NS_STATIC_CAST(PresShell*, targetFrame->GetPresContext()->PresShell());
|
||||
@ -7421,7 +7437,7 @@ PresShellViewEventListener::WillRefreshRegion(nsIViewManager *aViewManager,
|
||||
nsIRegion *aRegion,
|
||||
PRUint32 aUpdateFlags)
|
||||
{
|
||||
return HideCaret();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -7433,7 +7449,7 @@ PresShellViewEventListener::DidRefreshRegion(nsIViewManager *aViewManager,
|
||||
{
|
||||
nsCSSRendering::DidPaint();
|
||||
|
||||
return RestoreCaretVisibility();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -7443,7 +7459,7 @@ PresShellViewEventListener::WillRefreshRect(nsIViewManager *aViewManager,
|
||||
const nsRect *aRect,
|
||||
PRUint32 aUpdateFlags)
|
||||
{
|
||||
return HideCaret();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -7455,7 +7471,7 @@ PresShellViewEventListener::DidRefreshRect(nsIViewManager *aViewManager,
|
||||
{
|
||||
nsCSSRendering::DidPaint();
|
||||
|
||||
return RestoreCaretVisibility();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -915,6 +915,17 @@ nsFrame::DisplayOutline(nsDisplayListBuilder* aBuilder,
|
||||
return DisplayOutlineUnconditional(aBuilder, aLists);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsIFrame::DisplayCaret(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect, const nsDisplayListSet& aLists)
|
||||
{
|
||||
if (!IsVisibleForPainting(aBuilder))
|
||||
return NS_OK;
|
||||
|
||||
return aLists.Content()->AppendNewToTop(
|
||||
new (aBuilder) nsDisplayCaret(this, aBuilder->GetCaret()));
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFrame::DisplayBorderBackgroundOutline(nsDisplayListBuilder* aBuilder,
|
||||
const nsDisplayListSet& aLists,
|
||||
@ -1118,6 +1129,8 @@ BuildDisplayListWithOverflowClip(nsDisplayListBuilder* aBuilder, nsIFrame* aFram
|
||||
nsDisplayListCollection set;
|
||||
nsresult rv = aFrame->BuildDisplayList(aBuilder, aDirtyRect, set);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = aBuilder->DisplayCaret(aFrame, aDirtyRect, aSet);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return aFrame->OverflowClip(aBuilder, set, aSet, aClipRect);
|
||||
}
|
||||
@ -1439,9 +1452,12 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
overflowClip);
|
||||
} else {
|
||||
rv = aChild->BuildDisplayList(aBuilder, dirty, aLists);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = aBuilder->DisplayCaret(aChild, dirty, aLists);
|
||||
}
|
||||
}
|
||||
aChild->RemoveStateBits(NS_FRAME_HAS_DESCENDANT_PLACEHOLDER);
|
||||
return NS_OK;
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsDisplayList list;
|
||||
@ -1451,6 +1467,9 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
isComposited) {
|
||||
// True stacking context
|
||||
rv = aChild->BuildDisplayListForStackingContext(aBuilder, dirty, &list);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = aBuilder->DisplayCaret(aChild, dirty, aLists);
|
||||
}
|
||||
} else {
|
||||
nsRect clipRect;
|
||||
PRBool applyAbsPosClipping =
|
||||
@ -1473,6 +1492,9 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
pseudoStack, overflowClip);
|
||||
} else {
|
||||
rv = aChild->BuildDisplayList(aBuilder, clippedDirtyRect, pseudoStack);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = aBuilder->DisplayCaret(aChild, dirty, aLists);
|
||||
}
|
||||
}
|
||||
aChild->RemoveStateBits(NS_FRAME_HAS_DESCENDANT_PLACEHOLDER);
|
||||
|
||||
|
@ -303,7 +303,13 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
return NS_OK;
|
||||
|
||||
nsRect dirty = aDirtyRect - f->GetOffsetTo(this);
|
||||
return f->BuildDisplayListForStackingContext(aBuilder, dirty, aLists.Content());
|
||||
|
||||
aBuilder->EnterPresShell(f, dirty);
|
||||
|
||||
rv = f->BuildDisplayListForStackingContext(aBuilder, dirty, aLists.Content());
|
||||
|
||||
aBuilder->LeavePresShell(f, dirty);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sw=2 et tw=78: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
@ -99,10 +100,10 @@ struct nsMargin;
|
||||
typedef class nsIFrame nsIBox;
|
||||
|
||||
// IID for the nsIFrame interface
|
||||
// bdf02423-88d6-41ca-818a-54d7b51328c3
|
||||
// 4742c112-3577-4d90-aeb8-833729f14033
|
||||
#define NS_IFRAME_IID \
|
||||
{ 0xbdf02423, 0x88d6, 0x41ca, \
|
||||
{ 0x81, 0x8a, 0x54, 0xd7, 0xb5, 0x13, 0x28, 0xc3 } }
|
||||
{ 0x4742c112, 0x3577, 0x4d90, \
|
||||
{ 0xae, 0xb8, 0x83, 0x37, 0x29, 0xf1, 0x40, 0x33 } }
|
||||
|
||||
/**
|
||||
* Indication of how the frame can be split. This is used when doing runaround
|
||||
@ -695,6 +696,15 @@ public:
|
||||
NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists) { return NS_OK; }
|
||||
/**
|
||||
* Displays the caret onto the given display list builder. The caret is
|
||||
* painted on top of the rest of the display list items.
|
||||
*
|
||||
* @param aDirtyRect is the dirty rectangle that we're repainting.
|
||||
*/
|
||||
nsresult DisplayCaret(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists);
|
||||
|
||||
PRBool IsThemed() {
|
||||
return IsThemed(GetStyleDisplay());
|
||||
|
Loading…
Reference in New Issue
Block a user