mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Back out 1ac4cb2e7c32 to c631f9c3e9a9 (bug 598482) for Android reftest failures
This commit is contained in:
parent
eef3a778a8
commit
2e8e3cc006
@ -1146,9 +1146,6 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
GenerateDragGesture(aPresContext, (nsMouseEvent*)aEvent);
|
||||
UpdateCursor(aPresContext, aEvent, mCurrentTarget, aStatus);
|
||||
GenerateMouseEnterExit((nsGUIEvent*)aEvent);
|
||||
// Flush pending layout changes, so that later mouse move events
|
||||
// will go to the right nodes.
|
||||
FlushPendingEvents(aPresContext);
|
||||
break;
|
||||
case NS_DRAGDROP_GESTURE:
|
||||
if (mClickHoldContextMenu) {
|
||||
|
@ -113,7 +113,6 @@ _TEST_FILES = \
|
||||
test_bug689564.html \
|
||||
test_bug698929.html \
|
||||
test_eventctors.html \
|
||||
test_bug635465.html \
|
||||
$(NULL)
|
||||
|
||||
#bug 585630
|
||||
|
@ -1,90 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=635465
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 635465</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<style type="text/css">
|
||||
#item {
|
||||
position: relative;
|
||||
}
|
||||
.s-menu-section-submenu {
|
||||
position: absolute;
|
||||
display: none;
|
||||
}
|
||||
.open .s-menu-section-submenu {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=635465">Mozilla Bug 635465</a>
|
||||
<div id="display">
|
||||
<div class="item" id="item"
|
||||
onmouseover="showSubmenu(event)" onmouseout="hideSubmenu(event)">
|
||||
<a href="#" id="firsthover">Hover me</a>
|
||||
<div class="s-menu-section-submenu" id="menu">
|
||||
<a href="#" id="secondhover">Now hover me</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.8">
|
||||
|
||||
/** Test for Bug 635465 **/
|
||||
function showSubmenu(event) {
|
||||
var item = document.getElementById('item');
|
||||
|
||||
var width = item.offsetWidth; // IT WORKS IF YOU REMOVE THIS LINE
|
||||
|
||||
item.className='open';
|
||||
}
|
||||
|
||||
function hideSubmenu(event) {
|
||||
document.getElementById('item').className='';
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function executeTests() {
|
||||
// First flush out layout of firsthover
|
||||
ok($("firsthover").getBoundingClientRect().height > 0, true,
|
||||
"Should have a nonzero height before hover");
|
||||
|
||||
// Now trigger a mouseover on firsthover
|
||||
synthesizeMouseAtCenter($("firsthover"), { type: "mousemove" });
|
||||
|
||||
ok($("secondhover").getBoundingClientRect().height > 0, true,
|
||||
"Should have a nonzero height for submenu after hover");
|
||||
|
||||
// Now determine where secondhover is hanging out
|
||||
var rect = $("secondhover").getBoundingClientRect();
|
||||
synthesizeMouseAtCenter($("secondhover"), { type: "mousemove" });
|
||||
|
||||
// And another mouseover one pixel to the right of where the center used to be
|
||||
synthesizeMouseAtPoint(rect.left + rect.width/2 + 1,
|
||||
rect.top + rect.height/2,
|
||||
{ type: "mousemove" });
|
||||
|
||||
ok($("secondhover").getBoundingClientRect().height > 0, true,
|
||||
"Should have a nonzero height for submenu after second hover");
|
||||
|
||||
// And check computed display of the menu
|
||||
is(getComputedStyle($("menu"), "").display, "block", "Should have block display");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForFocus(executeTests);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -1160,6 +1160,10 @@ nsTextEditorState::PrepareEditor(const nsAString *aValue)
|
||||
// All nsTextControlFrames are widgets
|
||||
editorFlags |= nsIPlaintextEditor::eEditorWidgetMask;
|
||||
|
||||
// Use async reflow and painting for text widgets to improve
|
||||
// performance.
|
||||
editorFlags |= nsIPlaintextEditor::eEditorUseAsyncUpdatesMask;
|
||||
|
||||
// Spell check is diabled at creation time. It is enabled once
|
||||
// the editor comes into focus.
|
||||
editorFlags |= nsIPlaintextEditor::eEditorSkipSpellCheck;
|
||||
@ -1310,7 +1314,12 @@ nsTextEditorState::PrepareEditor(const nsAString *aValue)
|
||||
// editor for us.
|
||||
|
||||
if (!defaultValue.IsEmpty()) {
|
||||
rv = newEditor->SetFlags(editorFlags);
|
||||
// Avoid causing reentrant painting and reflowing by telling the editor
|
||||
// that we don't want it to force immediate view refreshes or force
|
||||
// immediate reflows during any editor calls.
|
||||
|
||||
rv = newEditor->SetFlags(editorFlags |
|
||||
nsIPlaintextEditor::eEditorUseAsyncUpdatesMask);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Now call SetValue() which will make the necessary editor calls to set
|
||||
@ -1828,6 +1837,7 @@ nsTextEditorState::SetValue(const nsAString& aValue, bool aUserInput)
|
||||
flags = savedFlags;
|
||||
flags &= ~(nsIPlaintextEditor::eEditorDisabledMask);
|
||||
flags &= ~(nsIPlaintextEditor::eEditorReadonlyMask);
|
||||
flags |= nsIPlaintextEditor::eEditorUseAsyncUpdatesMask;
|
||||
flags |= nsIPlaintextEditor::eEditorDontEchoPassword;
|
||||
mEditor->SetFlags(flags);
|
||||
|
||||
|
@ -4732,7 +4732,8 @@ nsDocShell::Repaint(bool aForce)
|
||||
nsIViewManager* viewManager = presShell->GetViewManager();
|
||||
NS_ENSURE_TRUE(viewManager, NS_ERROR_FAILURE);
|
||||
|
||||
NS_ENSURE_SUCCESS(viewManager->InvalidateAllViews(), NS_ERROR_FAILURE);
|
||||
// what about aForce ?
|
||||
NS_ENSURE_SUCCESS(viewManager->UpdateAllViews(0), NS_ERROR_FAILURE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -7323,7 +7324,7 @@ nsDocShell::RestoreFromHistory()
|
||||
// call Thaw. So we issue the invalidate here.
|
||||
newRootView = newVM->GetRootView();
|
||||
if (newRootView) {
|
||||
newVM->InvalidateView(newRootView);
|
||||
newVM->UpdateView(newRootView, NS_VMREFRESH_NO_SYNC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -761,6 +761,27 @@ nsDOMWindowUtils::CycleCollect(nsICycleCollectorListener *aListener)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::ProcessUpdates()
|
||||
{
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
if (!presContext)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
nsIPresShell* shell = presContext->GetPresShell();
|
||||
if (!shell)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
nsIViewManager *viewManager = shell->GetViewManager();
|
||||
if (!viewManager)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
nsIViewManager::UpdateViewBatch batch;
|
||||
batch.BeginUpdateViewBatch(viewManager);
|
||||
batch.EndUpdateViewBatch(NS_VMREFRESH_IMMEDIATE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::SendSimpleGestureEvent(const nsAString& aType,
|
||||
float aX,
|
||||
|
@ -69,7 +69,7 @@ interface nsIDOMBlob;
|
||||
interface nsIDOMFile;
|
||||
interface nsIFile;
|
||||
|
||||
[scriptable, uuid(b9c1f815-c2f2-4607-a060-6a8566581927)]
|
||||
[scriptable, uuid(3af3c5ce-6f2a-47e7-acd0-555ed576fa82)]
|
||||
interface nsIDOMWindowUtils : nsISupports {
|
||||
|
||||
/**
|
||||
@ -378,6 +378,12 @@ interface nsIDOMWindowUtils : nsISupports {
|
||||
*/
|
||||
void cycleCollect([optional] in nsICycleCollectorListener aListener);
|
||||
|
||||
/**
|
||||
* Force processing of any queued paints
|
||||
*/
|
||||
|
||||
void processUpdates();
|
||||
|
||||
/** Synthesize a simple gesture event for a window. The event types
|
||||
* supported are: MozSwipeGesture, MozMagnifyGestureStart,
|
||||
* MozMagnifyGestureUpdate, MozMagnifyGesture, MozRotateGestureStart,
|
||||
|
@ -623,7 +623,8 @@ NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRect(NPRect *invalidRect)
|
||||
if (mWidget) {
|
||||
mWidget->Invalidate(nsIntRect(invalidRect->left, invalidRect->top,
|
||||
invalidRect->right - invalidRect->left,
|
||||
invalidRect->bottom - invalidRect->top));
|
||||
invalidRect->bottom - invalidRect->top),
|
||||
false);
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
@ -655,6 +656,12 @@ NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRegion(NPRegion invalidRegion)
|
||||
|
||||
NS_IMETHODIMP nsPluginInstanceOwner::ForceRedraw()
|
||||
{
|
||||
NS_ENSURE_TRUE(mObjectFrame, NS_ERROR_NULL_POINTER);
|
||||
nsIView* view = mObjectFrame->GetView();
|
||||
if (view) {
|
||||
return view->GetViewManager()->Composite();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(07b6d070-ccea-4a00-84b4-f4b94dd9eb52)]
|
||||
[scriptable, uuid(05d312ef-8914-494e-91c9-2be8ed7f8e29)]
|
||||
interface nsIPlaintextEditor : nsISupports
|
||||
{
|
||||
|
||||
@ -56,27 +56,29 @@ interface nsIPlaintextEditor : nsISupports
|
||||
const long eEditorFilterInputMask = 0x0020;
|
||||
// use mail-compose editing rules
|
||||
const long eEditorMailMask = 0x0040;
|
||||
// prevent immediate reflows and view refreshes
|
||||
const long eEditorUseAsyncUpdatesMask = 0x0080;
|
||||
// allow the editor to set font: monospace on the root node
|
||||
const long eEditorEnableWrapHackMask = 0x0080;
|
||||
const long eEditorEnableWrapHackMask = 0x0100;
|
||||
// bit for widgets (form elements)
|
||||
const long eEditorWidgetMask = 0x0100;
|
||||
const long eEditorWidgetMask = 0x0200;
|
||||
// this HTML editor should not create css styles
|
||||
const long eEditorNoCSSMask = 0x0200;
|
||||
const long eEditorNoCSSMask = 0x0400;
|
||||
// whether HTML document specific actions are executed or not.
|
||||
// e.g., if this flag is set, the editor doesn't handle Tab key.
|
||||
// besides, anchors of HTML are not clickable.
|
||||
const long eEditorAllowInteraction = 0x0400;
|
||||
const long eEditorAllowInteraction = 0x0800;
|
||||
// when this is set, the characters in password editor are always masked.
|
||||
// see bug 530367 for the detail.
|
||||
const long eEditorDontEchoPassword = 0x0800;
|
||||
const long eEditorDontEchoPassword = 0x1000;
|
||||
// when this flag is set, the internal direction of the editor is RTL.
|
||||
// if neither of the direction flags are set, the direction is determined
|
||||
// from the text control's content node.
|
||||
const long eEditorRightToLeft = 0x1000;
|
||||
const long eEditorRightToLeft = 0x2000;
|
||||
// when this flag is set, the internal direction of the editor is LTR.
|
||||
const long eEditorLeftToRight = 0x2000;
|
||||
const long eEditorLeftToRight = 0x4000;
|
||||
// when this flag is set, the editor's text content is not spell checked.
|
||||
const long eEditorSkipSpellCheck = 0x4000;
|
||||
const long eEditorSkipSpellCheck = 0x8000;
|
||||
|
||||
/*
|
||||
* The valid values for newlines handling.
|
||||
|
@ -4198,6 +4198,15 @@ nsresult nsEditor::BeginUpdateViewBatch()
|
||||
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(selection));
|
||||
selPrivate->StartBatchChanges();
|
||||
}
|
||||
|
||||
// Turn off view updating.
|
||||
nsCOMPtr<nsIPresShell> ps = GetPresShell();
|
||||
if (ps) {
|
||||
nsCOMPtr<nsIViewManager> viewManager = ps->GetViewManager();
|
||||
if (viewManager) {
|
||||
mBatch.BeginUpdateViewBatch(viewManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mUpdateCount++;
|
||||
@ -4233,6 +4242,20 @@ nsresult nsEditor::EndUpdateViewBatch()
|
||||
|
||||
StCaretHider caretHider(caret);
|
||||
|
||||
PRUint32 flags = 0;
|
||||
|
||||
GetFlags(&flags);
|
||||
|
||||
// Turn view updating back on.
|
||||
PRUint32 updateFlag = NS_VMREFRESH_IMMEDIATE;
|
||||
|
||||
// If we're doing async updates, use NS_VMREFRESH_DEFERRED here, so that
|
||||
// the reflows we caused will get processed before the invalidates.
|
||||
if (flags & nsIPlaintextEditor::eEditorUseAsyncUpdatesMask) {
|
||||
updateFlag = NS_VMREFRESH_DEFERRED;
|
||||
}
|
||||
mBatch.EndUpdateViewBatch(updateFlag);
|
||||
|
||||
// Turn selection updating and notifications back on.
|
||||
|
||||
nsCOMPtr<nsISelection>selection;
|
||||
|
@ -689,6 +689,11 @@ public:
|
||||
return (mFlags & nsIPlaintextEditor::eEditorMailMask) != 0;
|
||||
}
|
||||
|
||||
bool UseAsyncUpdate() const
|
||||
{
|
||||
return (mFlags & nsIPlaintextEditor::eEditorUseAsyncUpdatesMask) != 0;
|
||||
}
|
||||
|
||||
bool IsWrapHackEnabled() const
|
||||
{
|
||||
return (mFlags & nsIPlaintextEditor::eEditorEnableWrapHackMask) != 0;
|
||||
@ -763,6 +768,7 @@ protected:
|
||||
|
||||
nsWeakPtr mSelConWeak; // weak reference to the nsISelectionController
|
||||
PRInt32 mUpdateCount;
|
||||
nsIViewManager::UpdateViewBatch mBatch;
|
||||
|
||||
// Spellchecking
|
||||
enum Tristate {
|
||||
|
@ -7634,6 +7634,7 @@ static bool gInApplyRenderingChangeToTree = false;
|
||||
|
||||
static void
|
||||
DoApplyRenderingChangeToTree(nsIFrame* aFrame,
|
||||
nsIViewManager* aViewManager,
|
||||
nsFrameManager* aFrameManager,
|
||||
nsChangeHint aChange);
|
||||
|
||||
@ -7642,7 +7643,7 @@ DoApplyRenderingChangeToTree(nsIFrame* aFrame,
|
||||
* This rect is relative to aFrame's parent
|
||||
*/
|
||||
static void
|
||||
UpdateViewsForTree(nsIFrame* aFrame,
|
||||
UpdateViewsForTree(nsIFrame* aFrame, nsIViewManager* aViewManager,
|
||||
nsFrameManager* aFrameManager,
|
||||
nsChangeHint aChange)
|
||||
{
|
||||
@ -7669,19 +7670,19 @@ UpdateViewsForTree(nsIFrame* aFrame,
|
||||
nsIFrame* outOfFlowFrame =
|
||||
nsPlaceholderFrame::GetRealFrameForPlaceholder(child);
|
||||
do {
|
||||
DoApplyRenderingChangeToTree(outOfFlowFrame, aFrameManager,
|
||||
aChange);
|
||||
DoApplyRenderingChangeToTree(outOfFlowFrame, aViewManager,
|
||||
aFrameManager, aChange);
|
||||
} while ((outOfFlowFrame = outOfFlowFrame->GetNextContinuation()));
|
||||
} else if (lists.CurrentID() == nsIFrame::kPopupList) {
|
||||
DoApplyRenderingChangeToTree(child, aFrameManager,
|
||||
aChange);
|
||||
DoApplyRenderingChangeToTree(child, aViewManager,
|
||||
aFrameManager, aChange);
|
||||
} else { // regular frame
|
||||
if ((child->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER) &&
|
||||
(aChange & nsChangeHint_RepaintFrame)) {
|
||||
FrameLayerBuilder::InvalidateThebesLayerContents(child,
|
||||
child->GetVisualOverflowRectRelativeToSelf());
|
||||
}
|
||||
UpdateViewsForTree(child, aFrameManager, aChange);
|
||||
UpdateViewsForTree(child, aViewManager, aFrameManager, aChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7690,6 +7691,7 @@ UpdateViewsForTree(nsIFrame* aFrame,
|
||||
|
||||
static void
|
||||
DoApplyRenderingChangeToTree(nsIFrame* aFrame,
|
||||
nsIViewManager* aViewManager,
|
||||
nsFrameManager* aFrameManager,
|
||||
nsChangeHint aChange)
|
||||
{
|
||||
@ -7701,7 +7703,7 @@ DoApplyRenderingChangeToTree(nsIFrame* aFrame,
|
||||
// frame doesn't have a view, find the nearest containing view
|
||||
// (adjusting r's coordinate system to reflect the nesting) and
|
||||
// update there.
|
||||
UpdateViewsForTree(aFrame, aFrameManager, aChange);
|
||||
UpdateViewsForTree(aFrame, aViewManager, aFrameManager, aChange);
|
||||
|
||||
// if frame has view, will already be invalidated
|
||||
if (aChange & nsChangeHint_RepaintFrame) {
|
||||
@ -7764,18 +7766,25 @@ ApplyRenderingChangeToTree(nsPresContext* aPresContext,
|
||||
NS_ASSERTION(aFrame, "root frame must paint");
|
||||
}
|
||||
|
||||
nsIViewManager* viewManager = shell->GetViewManager();
|
||||
|
||||
// Trigger rendering updates by damaging this frame and any
|
||||
// continuations of this frame.
|
||||
|
||||
// XXX this needs to detect the need for a view due to an opacity change and deal with it...
|
||||
|
||||
nsIViewManager::UpdateViewBatch batch(viewManager);
|
||||
|
||||
#ifdef DEBUG
|
||||
gInApplyRenderingChangeToTree = true;
|
||||
#endif
|
||||
DoApplyRenderingChangeToTree(aFrame, shell->FrameManager(), aChange);
|
||||
DoApplyRenderingChangeToTree(aFrame, viewManager, shell->FrameManager(),
|
||||
aChange);
|
||||
#ifdef DEBUG
|
||||
gInApplyRenderingChangeToTree = false;
|
||||
#endif
|
||||
|
||||
batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -7816,8 +7825,13 @@ InvalidateCanvasIfNeeded(nsIPresShell* presShell, nsIContent* node)
|
||||
// XHTML or something), but chances are we want to. Play it safe.
|
||||
// Invalidate the viewport.
|
||||
|
||||
// Wrap this in a DEFERRED view update batch so we don't try to
|
||||
// flush out layout here
|
||||
|
||||
nsIViewManager::UpdateViewBatch batch(presShell->GetViewManager());
|
||||
nsIFrame* rootFrame = presShell->GetRootFrame();
|
||||
rootFrame->InvalidateFrameSubtree();
|
||||
batch.EndUpdateViewBatch(NS_VMREFRESH_DEFERRED);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -11584,7 +11598,7 @@ nsCSSFrameConstructor::RebuildAllStyleData(nsChangeHint aExtraHint)
|
||||
return;
|
||||
|
||||
// Make sure that the viewmanager will outlive the presshell
|
||||
nsCOMPtr<nsIViewManager> vm = mPresShell->GetViewManager();
|
||||
nsIViewManager::UpdateViewBatch batch(mPresShell->GetViewManager());
|
||||
|
||||
// Processing the style changes could cause a flush that propagates to
|
||||
// the parent frame and thus destroys the pres shell.
|
||||
@ -11600,6 +11614,7 @@ nsCSSFrameConstructor::RebuildAllStyleData(nsChangeHint aExtraHint)
|
||||
// so we can recalculate while maintaining rule tree immutability
|
||||
nsresult rv = mPresShell->StyleSet()->BeginReconstruct();
|
||||
if (NS_FAILED(rv)) {
|
||||
batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -11634,6 +11649,7 @@ nsCSSFrameConstructor::RebuildAllStyleData(nsChangeHint aExtraHint)
|
||||
// reconstructed will still have their old style context pointers
|
||||
// until they are destroyed).
|
||||
mPresShell->StyleSet()->EndReconstruct();
|
||||
batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1554,8 +1554,9 @@ DocumentViewerImpl::Destroy()
|
||||
// The invalidate that removing this view causes is dropped because
|
||||
// the Freeze call above sets painting to be suppressed for our
|
||||
// document. So we do it ourselves and make it happen.
|
||||
vm->InvalidateViewNoSuppression(rootView,
|
||||
rootView->GetBounds() - rootView->GetPosition());
|
||||
vm->UpdateViewNoSuppression(rootView,
|
||||
rootView->GetBounds() - rootView->GetPosition(),
|
||||
NS_VMREFRESH_NO_SYNC);
|
||||
|
||||
nsIView *rootViewParent = rootView->GetParent();
|
||||
if (rootViewParent) {
|
||||
@ -2808,6 +2809,8 @@ DocumentViewerImpl::SetTextZoom(float aTextZoom)
|
||||
|
||||
mTextZoom = aTextZoom;
|
||||
|
||||
nsIViewManager::UpdateViewBatch batch(GetViewManager());
|
||||
|
||||
// Set the text zoom on all children of mContainer (even if our zoom didn't
|
||||
// change, our children's zoom may be different, though it would be unusual).
|
||||
// Do this first, in case kids are auto-sizing and post reflow commands on
|
||||
@ -2824,6 +2827,8 @@ DocumentViewerImpl::SetTextZoom(float aTextZoom)
|
||||
// And do the external resources
|
||||
mDocument->EnumerateExternalResources(SetExtResourceTextZoom, &ZoomInfo);
|
||||
|
||||
batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2845,6 +2850,8 @@ DocumentViewerImpl::SetMinFontSize(PRInt32 aMinFontSize)
|
||||
|
||||
mMinFontSize = aMinFontSize;
|
||||
|
||||
nsIViewManager::UpdateViewBatch batch(GetViewManager());
|
||||
|
||||
// Set the min font on all children of mContainer (even if our min font didn't
|
||||
// change, our children's min font may be different, though it would be unusual).
|
||||
// Do this first, in case kids are auto-sizing and post reflow commands on
|
||||
@ -2861,6 +2868,8 @@ DocumentViewerImpl::SetMinFontSize(PRInt32 aMinFontSize)
|
||||
mDocument->EnumerateExternalResources(SetExtResourceMinFontSize,
|
||||
NS_INT32_TO_PTR(aMinFontSize));
|
||||
|
||||
batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2883,6 +2892,7 @@ DocumentViewerImpl::SetFullZoom(float aFullZoom)
|
||||
nsCOMPtr<nsIPresShell> shell = pc->GetPresShell();
|
||||
NS_ENSURE_TRUE(shell, NS_OK);
|
||||
|
||||
nsIViewManager::UpdateViewBatch batch(shell->GetViewManager());
|
||||
if (!mPrintPreviewZoomed) {
|
||||
mOriginalPrintPreviewScale = pc->GetPrintPreviewScale();
|
||||
mPrintPreviewZoomed = true;
|
||||
@ -2901,12 +2911,15 @@ DocumentViewerImpl::SetFullZoom(float aFullZoom)
|
||||
nsRect rect(nsPoint(0, 0), rootFrame->GetSize());
|
||||
rootFrame->Invalidate(rect);
|
||||
}
|
||||
batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
mPageZoom = aFullZoom;
|
||||
|
||||
nsIViewManager::UpdateViewBatch batch(GetViewManager());
|
||||
|
||||
struct ZoomInfo ZoomInfo = { aFullZoom };
|
||||
CallChildren(SetChildFullZoom, &ZoomInfo);
|
||||
|
||||
@ -2918,6 +2931,8 @@ DocumentViewerImpl::SetFullZoom(float aFullZoom)
|
||||
// And do the external resources
|
||||
mDocument->EnumerateExternalResources(SetExtResourceFullZoom, &ZoomInfo);
|
||||
|
||||
batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -141,8 +141,8 @@ typedef struct CapturingContentInfo {
|
||||
} CapturingContentInfo;
|
||||
|
||||
#define NS_IPRESSHELL_IID \
|
||||
{ 0x3ab5b116, 0x2d73, 0x431c, \
|
||||
{ 0x9a, 0x4b, 0x6c, 0x91, 0x9e, 0x42, 0x45, 0xc3 } }
|
||||
{ 0x4e23d557, 0x741a, 0x4fd0,\
|
||||
{ 0x91, 0x52, 0x34, 0xe2, 0xb4, 0xef, 0xe8, 0x2e } }
|
||||
|
||||
// Constants for ScrollContentIntoView() function
|
||||
#define NS_PRESSHELL_SCROLL_TOP 0
|
||||
@ -1148,7 +1148,6 @@ public:
|
||||
virtual bool ShouldIgnoreInvalidation() = 0;
|
||||
virtual void WillPaint(bool aWillSendDidPaint) = 0;
|
||||
virtual void DidPaint() = 0;
|
||||
virtual void ScheduleViewManagerFlush() = 0;
|
||||
virtual void ClearMouseCaptureOnView(nsIView* aView) = 0;
|
||||
virtual bool IsVisible() = 0;
|
||||
virtual void DispatchSynthMouseMove(nsGUIEvent *aEvent, bool aFlushOnHoverChange) = 0;
|
||||
|
@ -1056,12 +1056,6 @@ nsPresContext::SetShell(nsIPresShell* aShell)
|
||||
mAnimationManager->Disconnect();
|
||||
mAnimationManager = nsnull;
|
||||
}
|
||||
|
||||
if (IsRoot()) {
|
||||
// Have to cancel our plugin geometry timer, because the
|
||||
// callback for that depends on a non-null presshell.
|
||||
static_cast<nsRootPresContext*>(this)->CancelUpdatePluginGeometryTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2328,7 +2322,6 @@ nsRootPresContext::~nsRootPresContext()
|
||||
NS_ASSERTION(mRegisteredPlugins.Count() == 0,
|
||||
"All plugins should have been unregistered");
|
||||
CancelDidPaintTimer();
|
||||
CancelUpdatePluginGeometryTimer();
|
||||
}
|
||||
|
||||
void
|
||||
@ -2569,9 +2562,6 @@ nsRootPresContext::UpdatePluginGeometry()
|
||||
if (!mNeedsToUpdatePluginGeometry)
|
||||
return;
|
||||
mNeedsToUpdatePluginGeometry = false;
|
||||
// Cancel out mUpdatePluginGeometryTimer so it doesn't do a random
|
||||
// update when we don't actually want one.
|
||||
CancelUpdatePluginGeometryTimer();
|
||||
|
||||
nsIFrame* f = mUpdatePluginGeometryForFrame;
|
||||
if (f) {
|
||||
@ -2593,10 +2583,33 @@ nsRootPresContext::UpdatePluginGeometry()
|
||||
DidApplyPluginGeometryUpdates();
|
||||
}
|
||||
|
||||
static void
|
||||
UpdatePluginGeometryCallback(nsITimer *aTimer, void *aClosure)
|
||||
void
|
||||
nsRootPresContext::SynchronousPluginGeometryUpdate()
|
||||
{
|
||||
static_cast<nsRootPresContext*>(aClosure)->UpdatePluginGeometry();
|
||||
if (!mNeedsToUpdatePluginGeometry) {
|
||||
// Nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
// Force synchronous paint
|
||||
nsIPresShell* shell = GetPresShell();
|
||||
if (!shell)
|
||||
return;
|
||||
nsIFrame* rootFrame = shell->GetRootFrame();
|
||||
if (!rootFrame)
|
||||
return;
|
||||
nsCOMPtr<nsIWidget> widget = rootFrame->GetNearestWidget();
|
||||
if (!widget)
|
||||
return;
|
||||
// Force synchronous paint of a single pixel, just to force plugin
|
||||
// updates to be flushed. Doing plugin updates during paint is the best
|
||||
// way to ensure that plugin updates are in sync with our content.
|
||||
widget->Invalidate(nsIntRect(0,0,1,1), true);
|
||||
|
||||
// Update plugin geometry just in case that invalidate didn't work
|
||||
// (e.g. if none of the widget is visible, it might not have processed
|
||||
// a paint event). Normally this won't need to do anything.
|
||||
UpdatePluginGeometry();
|
||||
}
|
||||
|
||||
void
|
||||
@ -2606,23 +2619,15 @@ nsRootPresContext::RequestUpdatePluginGeometry(nsIFrame* aFrame)
|
||||
return;
|
||||
|
||||
if (!mNeedsToUpdatePluginGeometry) {
|
||||
// We'll update the plugin geometry during the next paint in this
|
||||
// presContext (either from nsPresShell::WillPaint or from
|
||||
// nsPresShell::DidPaint, depending on the platform) or on the next
|
||||
// layout flush, whichever comes first. But we may not have anyone
|
||||
// flush layout, and paints might get optimized away if the old
|
||||
// plugin geometry covers the whole canvas, so set a backup timer to
|
||||
// do this too. We want to make sure this won't fire before our
|
||||
// normal paint notifications, if those would update the geometry,
|
||||
// so set it for double the refresh driver interval.
|
||||
mUpdatePluginGeometryTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
if (mUpdatePluginGeometryTimer) {
|
||||
mUpdatePluginGeometryTimer->
|
||||
InitWithFuncCallback(UpdatePluginGeometryCallback, this,
|
||||
nsRefreshDriver::DefaultInterval() * 2,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
mNeedsToUpdatePluginGeometry = true;
|
||||
|
||||
// Dispatch a Gecko event to ensure plugin geometry gets updated
|
||||
// XXX this really should be done through the refresh driver, once
|
||||
// all painting happens in the refresh driver
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethod(this, &nsRootPresContext::SynchronousPluginGeometryUpdate);
|
||||
NS_DispatchToMainThread(event);
|
||||
|
||||
mUpdatePluginGeometryForFrame = aFrame;
|
||||
mUpdatePluginGeometryForFrame->PresContext()->
|
||||
SetContainsUpdatePluginGeometryFrame(true);
|
||||
|
@ -1265,6 +1265,14 @@ public:
|
||||
|
||||
virtual bool IsRoot() { return true; }
|
||||
|
||||
/**
|
||||
* This method is called off an event to force the plugin geometry to
|
||||
* be updated. First we try to paint, since updating plugin geometry
|
||||
* during paint is best for keeping plugins in sync with content.
|
||||
* But we also force geometry updates in case painting doesn't work.
|
||||
*/
|
||||
void SynchronousPluginGeometryUpdate();
|
||||
|
||||
/**
|
||||
* Call this after reflow and scrolling to ensure that the geometry
|
||||
* of any windowed plugins is updated. aFrame is the root of the
|
||||
@ -1337,17 +1345,7 @@ protected:
|
||||
nsRootPresContext* mPresContext;
|
||||
};
|
||||
|
||||
friend class nsPresContext;
|
||||
void CancelUpdatePluginGeometryTimer()
|
||||
{
|
||||
if (mUpdatePluginGeometryTimer) {
|
||||
mUpdatePluginGeometryTimer->Cancel();
|
||||
mUpdatePluginGeometryTimer = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITimer> mNotifyDidPaintTimer;
|
||||
nsCOMPtr<nsITimer> mUpdatePluginGeometryTimer;
|
||||
nsTHashtable<nsPtrHashKey<nsObjectFrame> > mRegisteredPlugins;
|
||||
// if mNeedsToUpdatePluginGeometry is set, then this is the frame to
|
||||
// use as the root of the subtree to search for plugin updates, or
|
||||
|
@ -1268,8 +1268,6 @@ PresShell::Destroy()
|
||||
// before we destroy the frame manager, since apparently frame destruction
|
||||
// sometimes spins the event queue when plug-ins are involved(!).
|
||||
rd->RemoveLayoutFlushObserver(this);
|
||||
rd->RevokeViewManagerFlush();
|
||||
|
||||
mResizeEvent.Revoke();
|
||||
if (mAsyncResizeTimerIsActive) {
|
||||
mAsyncResizeEventTimer->Cancel();
|
||||
@ -2130,6 +2128,8 @@ PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight)
|
||||
|
||||
if (!GetPresContext()->SupressingResizeReflow())
|
||||
{
|
||||
nsIViewManager::UpdateViewBatch batch(mViewManager);
|
||||
|
||||
// Have to make sure that the content notifications are flushed before we
|
||||
// start messing with the frame model; otherwise we can get content doubling.
|
||||
mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
|
||||
@ -2152,7 +2152,6 @@ PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight)
|
||||
|
||||
// Kick off a top-down reflow
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
|
||||
nsIViewManager::AutoDisableRefresh refreshBlocker(mViewManager);
|
||||
|
||||
mDirtyRoots.RemoveElement(rootFrame);
|
||||
DoReflow(rootFrame, true);
|
||||
@ -2160,6 +2159,8 @@ PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight)
|
||||
|
||||
DidDoReflow(true);
|
||||
}
|
||||
|
||||
batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
|
||||
}
|
||||
|
||||
rootFrame = FrameManager()->GetRootFrame();
|
||||
@ -2477,6 +2478,17 @@ PresShell::ScrollLine(bool aForward)
|
||||
scrollFrame->ScrollBy(nsIntPoint(0, aForward ? lineCount : -lineCount),
|
||||
nsIScrollableFrame::LINES,
|
||||
nsIScrollableFrame::SMOOTH);
|
||||
|
||||
//NEW FOR LINES
|
||||
// force the update to happen now, otherwise multiple scrolls can
|
||||
// occur before the update is processed. (bug #7354)
|
||||
|
||||
// I'd use Composite here, but it doesn't always work.
|
||||
// vm->Composite();
|
||||
nsIViewManager* viewManager = GetViewManager();
|
||||
if (viewManager) {
|
||||
viewManager->ForceUpdate();
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -2490,6 +2502,16 @@ PresShell::ScrollHorizontal(bool aLeft)
|
||||
scrollFrame->ScrollBy(nsIntPoint(aLeft ? -1 : 1, 0),
|
||||
nsIScrollableFrame::LINES,
|
||||
nsIScrollableFrame::SMOOTH);
|
||||
//NEW FOR LINES
|
||||
// force the update to happen now, otherwise multiple scrolls can
|
||||
// occur before the update is processed. (bug #7354)
|
||||
|
||||
// I'd use Composite here, but it doesn't always work.
|
||||
// vm->Composite();
|
||||
nsIViewManager* viewManager = GetViewManager();
|
||||
if (viewManager) {
|
||||
viewManager->ForceUpdate();
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -2967,6 +2989,7 @@ PresShell::RecreateFramesFor(nsIContent* aContent)
|
||||
// to keep the number of entrypoints down.
|
||||
|
||||
NS_ASSERTION(mViewManager, "Should have view manager");
|
||||
nsIViewManager::UpdateViewBatch batch(mViewManager);
|
||||
|
||||
// Have to make sure that the content notifications are flushed before we
|
||||
// start messing with the frame model; otherwise we can get content doubling.
|
||||
@ -2982,6 +3005,7 @@ PresShell::RecreateFramesFor(nsIContent* aContent)
|
||||
nsresult rv = mFrameConstructor->ProcessRestyledFrames(changeList);
|
||||
--mChangeNestCount;
|
||||
|
||||
batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -3622,18 +3646,6 @@ nsresult PresShell::GetLinkLocation(nsIDOMNode* aNode, nsAString& aLocationStrin
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
void
|
||||
PresShell::ScheduleViewManagerFlush()
|
||||
{
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
if (presContext) {
|
||||
presContext->RefreshDriver()->ScheduleViewManagerFlush();
|
||||
}
|
||||
if (mDocument) {
|
||||
mDocument->SetNeedLayoutFlush();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PresShell::DispatchSynthMouseMove(nsGUIEvent *aEvent,
|
||||
bool aFlushOnHoverChange)
|
||||
@ -4004,7 +4016,7 @@ PresShell::FlushPendingNotifications(mozFlushType aType)
|
||||
}
|
||||
|
||||
NS_ASSERTION(!isSafeToFlush || mViewManager, "Must have view manager");
|
||||
// Make sure the view manager stays alive.
|
||||
// Make sure the view manager stays alive while batching view updates.
|
||||
nsCOMPtr<nsIViewManager> viewManagerDeathGrip = mViewManager;
|
||||
if (isSafeToFlush && mViewManager) {
|
||||
// Processing pending notifications can kill us, and some callers only
|
||||
@ -4018,6 +4030,11 @@ PresShell::FlushPendingNotifications(mozFlushType aType)
|
||||
}
|
||||
}
|
||||
|
||||
// Style reresolves not in conjunction with reflows can't cause
|
||||
// painting or geometry changes, so don't bother with view update
|
||||
// batching if we only have style reresolve
|
||||
nsIViewManager::UpdateViewBatch batch(mViewManager);
|
||||
|
||||
// We need to make sure external resource documents are flushed too (for
|
||||
// example, svg filters that reference a filter in an external document
|
||||
// need the frames in the external document to be constructed for the
|
||||
@ -4110,11 +4127,15 @@ PresShell::FlushPendingNotifications(mozFlushType aType)
|
||||
if (rootPresContext) {
|
||||
rootPresContext->UpdatePluginGeometry();
|
||||
}
|
||||
|
||||
if (!mIsDestroying) {
|
||||
mViewManager->UpdateWidgetGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
PRUint32 updateFlags = NS_VMREFRESH_NO_SYNC;
|
||||
if (aType >= Flush_Display) {
|
||||
// Flushing paints, so perform the invalidates and drawing
|
||||
// immediately
|
||||
updateFlags = NS_VMREFRESH_IMMEDIATE;
|
||||
}
|
||||
batch.EndUpdateViewBatch(updateFlags);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7371,7 +7392,7 @@ PresShell::DoVerifyReflow()
|
||||
// First synchronously render what we have so far so that we can
|
||||
// see it.
|
||||
nsIView* rootView = mViewManager->GetRootView();
|
||||
mViewManager->InvalidateView(rootView);
|
||||
mViewManager->UpdateView(rootView, NS_VMREFRESH_IMMEDIATE);
|
||||
|
||||
FlushPendingNotifications(Flush_Layout);
|
||||
mInVerifyReflow = true;
|
||||
@ -7418,7 +7439,6 @@ PresShell::ProcessReflowCommands(bool aInterruptible)
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
WillDoReflow();
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
|
||||
nsIViewManager::AutoDisableRefresh refreshBlocker(mViewManager);
|
||||
|
||||
do {
|
||||
// Send an incremental reflow notification to the target frame.
|
||||
@ -7566,6 +7586,7 @@ PresShell::Observe(nsISupports* aSubject,
|
||||
// at interesting times during startup.
|
||||
if (rootFrame) {
|
||||
NS_ASSERTION(mViewManager, "View manager must exist");
|
||||
nsIViewManager::UpdateViewBatch batch(mViewManager);
|
||||
|
||||
nsWeakFrame weakRoot(rootFrame);
|
||||
// Have to make sure that the content notifications are flushed before we
|
||||
@ -7590,6 +7611,7 @@ PresShell::Observe(nsISupports* aSubject,
|
||||
--mChangeNestCount;
|
||||
}
|
||||
}
|
||||
batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -330,7 +330,6 @@ public:
|
||||
virtual bool ShouldIgnoreInvalidation();
|
||||
virtual void WillPaint(bool aWillSendDidPaint);
|
||||
virtual void DidPaint();
|
||||
virtual void ScheduleViewManagerFlush();
|
||||
virtual void DispatchSynthMouseMove(nsGUIEvent *aEvent, bool aFlushOnHoverChange);
|
||||
virtual void ClearMouseCaptureOnView(nsIView* aView);
|
||||
virtual bool IsVisible();
|
||||
|
@ -55,7 +55,6 @@
|
||||
#include "jsapi.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsIViewManager.h"
|
||||
|
||||
using mozilla::TimeStamp;
|
||||
using mozilla::TimeDuration;
|
||||
@ -74,13 +73,6 @@ nsRefreshDriver::InitializeStatics()
|
||||
"layout.frame_rate.precise",
|
||||
false);
|
||||
}
|
||||
|
||||
/* static */ PRInt32
|
||||
nsRefreshDriver::DefaultInterval()
|
||||
{
|
||||
return NSToIntRound(1000.0 / DEFAULT_FRAME_RATE);
|
||||
}
|
||||
|
||||
// Compute the interval to use for the refresh driver timer, in
|
||||
// milliseconds
|
||||
PRInt32
|
||||
@ -120,7 +112,6 @@ nsRefreshDriver::nsRefreshDriver(nsPresContext *aPresContext)
|
||||
mThrottled(false),
|
||||
mTestControllingRefreshes(false),
|
||||
mTimerIsPrecise(false),
|
||||
mViewManagerFlushIsPending(false),
|
||||
mLastTimerInterval(0)
|
||||
{
|
||||
mRequests.Init();
|
||||
@ -279,7 +270,6 @@ nsRefreshDriver::ObserverCount() const
|
||||
sum += mStyleFlushObservers.Length();
|
||||
sum += mLayoutFlushObservers.Length();
|
||||
sum += mFrameRequestCallbackDocs.Length();
|
||||
sum += mViewManagerFlushIsPending;
|
||||
return sum;
|
||||
}
|
||||
|
||||
@ -441,11 +431,6 @@ nsRefreshDriver::Notify(nsITimer *aTimer)
|
||||
EnsureTimerStarted(false);
|
||||
}
|
||||
|
||||
if (mViewManagerFlushIsPending) {
|
||||
mViewManagerFlushIsPending = false;
|
||||
mPresContext->GetPresShell()->GetViewManager()->ProcessPendingUpdates();
|
||||
}
|
||||
|
||||
if (mThrottled ||
|
||||
(mTimerIsPrecise !=
|
||||
(GetRefreshTimerType() == nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP))) {
|
||||
|
@ -176,17 +176,6 @@ public:
|
||||
return mLayoutFlushObservers.Contains(aShell);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remember whether our presshell's view manager needs a flush
|
||||
*/
|
||||
void ScheduleViewManagerFlush() {
|
||||
mViewManagerFlushIsPending = true;
|
||||
EnsureTimerStarted(false);
|
||||
}
|
||||
void RevokeViewManagerFlush() {
|
||||
mViewManagerFlushIsPending = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a document for which we have nsIFrameRequestCallbacks
|
||||
*/
|
||||
@ -238,11 +227,6 @@ public:
|
||||
mozFlushType aFlushType);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Default interval the refresh driver uses, in ms.
|
||||
*/
|
||||
static PRInt32 DefaultInterval();
|
||||
|
||||
private:
|
||||
typedef nsTObserverArray<nsARefreshObserver*> ObserverArray;
|
||||
typedef nsTHashtable<nsISupportsHashKey> RequestTable;
|
||||
@ -281,7 +265,6 @@ private:
|
||||
a precise timer. If mTimer is null, this boolean's value can be
|
||||
anything. */
|
||||
bool mTimerIsPrecise;
|
||||
bool mViewManagerFlushIsPending;
|
||||
|
||||
// separate arrays for each flush type we support
|
||||
ObserverArray mObservers[3];
|
||||
|
@ -387,6 +387,15 @@ nsComboboxControlFrame::SetFocus(bool aOn, bool aRepaint)
|
||||
// rect to be drawn. This is much faster than ReResolvingStyle
|
||||
// Bug 32920
|
||||
Invalidate(nsRect(0,0,mRect.width,mRect.height));
|
||||
|
||||
// Make sure the content area gets updated for where the dropdown was
|
||||
// This is only needed for embedding, the focus may go to
|
||||
// the chrome that is not part of the Gecko system (Bug 83493)
|
||||
// XXX this is rather inefficient
|
||||
nsIViewManager* vm = PresContext()->GetPresShell()->GetViewManager();
|
||||
if (vm) {
|
||||
vm->UpdateAllViews(NS_VMREFRESH_NO_SYNC);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -4642,15 +4642,22 @@ nsIFrame::InvalidateRoot(const nsRect& aDamageRect, PRUint32 aFlags)
|
||||
}
|
||||
}
|
||||
|
||||
PRUint32 flags =
|
||||
(aFlags & INVALIDATE_IMMEDIATE) ? NS_VMREFRESH_IMMEDIATE : NS_VMREFRESH_NO_SYNC;
|
||||
|
||||
nsRect rect = aDamageRect;
|
||||
nsRegion* excludeRegion = static_cast<nsRegion*>
|
||||
(Properties().Get(DeferInvalidatesProperty()));
|
||||
if (excludeRegion && (aFlags & INVALIDATE_EXCLUDE_CURRENT_PAINT)) {
|
||||
nsRegion r;
|
||||
r.Sub(rect, *excludeRegion);
|
||||
if (r.IsEmpty())
|
||||
return;
|
||||
rect = r.GetBounds();
|
||||
if (excludeRegion) {
|
||||
flags = NS_VMREFRESH_DEFERRED;
|
||||
|
||||
if (aFlags & INVALIDATE_EXCLUDE_CURRENT_PAINT) {
|
||||
nsRegion r;
|
||||
r.Sub(rect, *excludeRegion);
|
||||
if (r.IsEmpty())
|
||||
return;
|
||||
rect = r.GetBounds();
|
||||
}
|
||||
}
|
||||
|
||||
if (!(aFlags & INVALIDATE_NO_UPDATE_LAYER_TREE)) {
|
||||
@ -4659,7 +4666,7 @@ nsIFrame::InvalidateRoot(const nsRect& aDamageRect, PRUint32 aFlags)
|
||||
|
||||
nsIView* view = GetView();
|
||||
NS_ASSERTION(view, "This can only be called on frames with views");
|
||||
view->GetViewManager()->InvalidateViewNoSuppression(view, rect);
|
||||
view->GetViewManager()->UpdateViewNoSuppression(view, rect, flags);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1533,6 +1533,19 @@ nsHTMLFramesetFrame::MouseDrag(nsPresContext* aPresContext,
|
||||
ENSURE_TRUE(weakFrame.IsAlive());
|
||||
if (change != 0) {
|
||||
mDrag.Reset(mDragger->mVertical, mDragger->mPrevNeighbor, change, this);
|
||||
nsIFrame* parentFrame = GetParent();
|
||||
if (!parentFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the view immediately (make drag appear snappier)
|
||||
nsIViewManager* vm = aPresContext->GetPresShell()->GetViewManager();
|
||||
if (vm) {
|
||||
nsIView* root = vm->GetRootView();
|
||||
if (root) {
|
||||
vm->UpdateView(root, NS_VMREFRESH_IMMEDIATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -562,7 +562,7 @@ void nsLayoutDebuggingTools::ForceRefresh()
|
||||
return;
|
||||
nsIView* root = vm->GetRootView();
|
||||
if (root) {
|
||||
vm->InvalidateView(root);
|
||||
vm->UpdateView(root, NS_VMREFRESH_IMMEDIATE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -559,6 +559,15 @@ nsListBoxBodyFrame::ScrollByLines(PRInt32 aNumLines)
|
||||
|
||||
ScrollToIndex(scrollIndex);
|
||||
|
||||
// we have to do a sync update for mac because if we scroll too quickly
|
||||
// w/out going back to the main event loop we can easily scroll the wrong
|
||||
// bits and it looks like garbage (bug 63465).
|
||||
// XXXbz is this seriously still needed?
|
||||
|
||||
// I'd use Composite here, but it doesn't always work.
|
||||
// vm->Composite();
|
||||
PresContext()->GetPresShell()->GetViewManager()->ForceUpdate();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -145,24 +145,6 @@ function _parseModifiers(aEvent)
|
||||
* aWindow is optional, and defaults to the current window object.
|
||||
*/
|
||||
function synthesizeMouse(aTarget, aOffsetX, aOffsetY, aEvent, aWindow)
|
||||
{
|
||||
var rect = aTarget.getBoundingClientRect();
|
||||
synthesizeMouseAtPoint(rect.left + aOffsetX, rect.top + aOffsetY,
|
||||
aEvent, aWindow);
|
||||
}
|
||||
|
||||
/*
|
||||
* Synthesize a mouse event at a particular point in aWindow.
|
||||
*
|
||||
* aEvent is an object which may contain the properties:
|
||||
* shiftKey, ctrlKey, altKey, metaKey, accessKey, clickCount, button, type
|
||||
*
|
||||
* If the type is specified, an mouse event of that type is fired. Otherwise,
|
||||
* a mousedown followed by a mouse up is performed.
|
||||
*
|
||||
* aWindow is optional, and defaults to the current window object.
|
||||
*/
|
||||
function synthesizeMouseAtPoint(left, top, aEvent, aWindow)
|
||||
{
|
||||
var utils = _getDOMWindowUtils(aWindow);
|
||||
|
||||
@ -171,6 +153,11 @@ function synthesizeMouseAtPoint(left, top, aEvent, aWindow)
|
||||
var clickCount = aEvent.clickCount || 1;
|
||||
var modifiers = _parseModifiers(aEvent);
|
||||
|
||||
var rect = aTarget.getBoundingClientRect();
|
||||
|
||||
var left = rect.left + aOffsetX;
|
||||
var top = rect.top + aOffsetY;
|
||||
|
||||
if (aEvent.type) {
|
||||
utils.sendMouseEvent(aEvent.type, left, top, button, clickCount, modifiers);
|
||||
}
|
||||
|
@ -48,8 +48,8 @@ class nsRegion;
|
||||
class nsDeviceContext;
|
||||
|
||||
#define NS_IVIEWMANAGER_IID \
|
||||
{ 0x540610a6, 0x4fdd, 0x4ae3, \
|
||||
{ 0x9b, 0xdb, 0xa6, 0x4d, 0x8b, 0xca, 0x02, 0x0f } }
|
||||
{ 0x1262a33f, 0xc19f, 0x4e5b, \
|
||||
{ 0x85, 0x00, 0xab, 0xf3, 0x7d, 0xcf, 0x30, 0x1d } }
|
||||
|
||||
class nsIViewManager : public nsISupports
|
||||
{
|
||||
@ -116,12 +116,23 @@ public:
|
||||
*/
|
||||
NS_IMETHOD FlushDelayedResize(bool aDoReflow) = 0;
|
||||
|
||||
/**
|
||||
* Called to force a redrawing of any dirty areas.
|
||||
*/
|
||||
// XXXbz why is this exposed? Shouldn't update view batches handle this?
|
||||
// It's not like Composite() does what's expected inside a view update batch
|
||||
// anyway, since dirty areas may not have been invalidated on the widget yet
|
||||
// and widget changes may not have been propagated yet. Maybe this should
|
||||
// call FlushPendingInvalidates()?
|
||||
NS_IMETHOD Composite(void) = 0;
|
||||
|
||||
/**
|
||||
* Called to inform the view manager that the entire area of a view
|
||||
* is dirty and needs to be redrawn.
|
||||
* @param aView view to paint. should be root view
|
||||
* @param aUpdateFlags see bottom of nsIViewManager.h for description
|
||||
*/
|
||||
NS_IMETHOD InvalidateView(nsIView *aView) = 0;
|
||||
NS_IMETHOD UpdateView(nsIView *aView, PRUint32 aUpdateFlags) = 0;
|
||||
|
||||
/**
|
||||
* Called to inform the view manager that some portion of a view is dirty and
|
||||
@ -129,13 +140,17 @@ public:
|
||||
* space. Does not check for paint suppression.
|
||||
* @param aView view to paint. should be root view
|
||||
* @param rect rect to mark as damaged
|
||||
* @param aUpdateFlags see bottom of nsIViewManager.h for description
|
||||
*/
|
||||
NS_IMETHOD InvalidateViewNoSuppression(nsIView *aView, const nsRect &aRect) = 0;
|
||||
NS_IMETHOD UpdateViewNoSuppression(nsIView *aView, const nsRect &aRect,
|
||||
PRUint32 aUpdateFlags) = 0;
|
||||
|
||||
/**
|
||||
* Called to inform the view manager that it should invalidate all views.
|
||||
* Called to inform the view manager that it should redraw all views.
|
||||
* @param aView view to paint. should be root view
|
||||
* @param aUpdateFlags see bottom of nsIViewManager.h for description
|
||||
*/
|
||||
NS_IMETHOD InvalidateAllViews() = 0;
|
||||
NS_IMETHOD UpdateAllViews(PRUint32 aUpdateFlags) = 0;
|
||||
|
||||
/**
|
||||
* Called to dispatch an event to the appropriate view. Often called
|
||||
@ -258,42 +273,76 @@ public:
|
||||
*/
|
||||
NS_IMETHOD GetDeviceContext(nsDeviceContext *&aContext) = 0;
|
||||
|
||||
/**
|
||||
* A stack class for disallowing changes that would enter painting. For
|
||||
* example, popup widgets shouldn't be resized during reflow, since doing so
|
||||
* might cause synchronous painting inside reflow which is forbidden.
|
||||
* While refresh is disabled, widget geometry changes are deferred and will
|
||||
* be handled later, either from the refresh driver or from an NS_WILL_PAINT
|
||||
* event.
|
||||
* We don't want to defer widget geometry changes all the time. Resizing a
|
||||
* popup from script doesn't need to be deferred, for example, especially
|
||||
* since popup widget geometry is observable from script and expected to
|
||||
* update synchronously.
|
||||
*/
|
||||
class NS_STACK_CLASS AutoDisableRefresh {
|
||||
class UpdateViewBatch {
|
||||
public:
|
||||
AutoDisableRefresh(nsIViewManager* aVM) {
|
||||
UpdateViewBatch() {}
|
||||
/**
|
||||
* prevents the view manager from refreshing. allows UpdateView()
|
||||
* to notify widgets of damaged regions that should be repainted
|
||||
* when the batch is ended. Call EndUpdateViewBatch on this object
|
||||
* before it is destroyed
|
||||
* @return error status
|
||||
*/
|
||||
UpdateViewBatch(nsIViewManager* aVM) {
|
||||
if (aVM) {
|
||||
mRootVM = aVM->IncrementDisableRefreshCount();
|
||||
mRootVM = aVM->BeginUpdateViewBatch();
|
||||
}
|
||||
}
|
||||
~AutoDisableRefresh() {
|
||||
if (mRootVM) {
|
||||
mRootVM->DecrementDisableRefreshCount();
|
||||
~UpdateViewBatch() {
|
||||
NS_ASSERTION(!mRootVM, "Someone forgot to call EndUpdateViewBatch!");
|
||||
}
|
||||
|
||||
/**
|
||||
* See the constructor, this lets you "fill in" a blank UpdateViewBatch.
|
||||
*/
|
||||
void BeginUpdateViewBatch(nsIViewManager* aVM) {
|
||||
NS_ASSERTION(!mRootVM, "already started a batch!");
|
||||
if (aVM) {
|
||||
mRootVM = aVM->BeginUpdateViewBatch();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* allow the view manager to refresh any damaged areas accumulated
|
||||
* after the BeginUpdateViewBatch() call. this may cause a
|
||||
* synchronous paint to occur inside the call if aUpdateFlags
|
||||
* NS_VMREFRESH_IMMEDIATE is set.
|
||||
*
|
||||
* If this is not the outermost view batch command, then this does
|
||||
* nothing except that the specified flags are remembered. When the
|
||||
* outermost batch finally ends, we merge together all the flags for the
|
||||
* inner batches in the following way:
|
||||
* -- If any batch specified NS_VMREFRESH_IMMEDIATE, then we use that flag
|
||||
* (i.e. there is a synchronous paint under the last EndUpdateViewBatch)
|
||||
* -- Otherwise if any batch specified NS_VMREFERSH_DEFERRED, then we use
|
||||
* that flag (i.e. invalidation is deferred until the processing of an
|
||||
* Invalidate PLEvent)
|
||||
* -- Otherwise all batches specified NS_VMREFRESH_NO_SYNC and we honor
|
||||
* that; all widgets are invalidated normally and will be painted the next
|
||||
* time the toolkit chooses to update them.
|
||||
*
|
||||
* @param aUpdateFlags see bottom of nsIViewManager.h for
|
||||
* description @return error status
|
||||
*/
|
||||
void EndUpdateViewBatch(PRUint32 aUpdateFlags) {
|
||||
if (!mRootVM)
|
||||
return;
|
||||
mRootVM->EndUpdateViewBatch(aUpdateFlags);
|
||||
mRootVM = nsnull;
|
||||
}
|
||||
|
||||
private:
|
||||
AutoDisableRefresh(const AutoDisableRefresh& aOther);
|
||||
const AutoDisableRefresh& operator=(const AutoDisableRefresh& aOther);
|
||||
UpdateViewBatch(const UpdateViewBatch& aOther);
|
||||
const UpdateViewBatch& operator=(const UpdateViewBatch& aOther);
|
||||
|
||||
nsCOMPtr<nsIViewManager> mRootVM;
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
friend class AutoDisableRefresh;
|
||||
friend class UpdateViewBatch;
|
||||
|
||||
virtual nsIViewManager* IncrementDisableRefreshCount() = 0;
|
||||
virtual void DecrementDisableRefreshCount() = 0;
|
||||
virtual nsIViewManager* BeginUpdateViewBatch(void) = 0;
|
||||
NS_IMETHOD EndUpdateViewBatch(PRUint32 aUpdateFlags) = 0;
|
||||
|
||||
public:
|
||||
/**
|
||||
@ -302,6 +351,16 @@ public:
|
||||
*/
|
||||
NS_IMETHOD GetRootWidget(nsIWidget **aWidget) = 0;
|
||||
|
||||
/**
|
||||
* Force update of view manager widget
|
||||
* Callers should use UpdateView(view, NS_VMREFRESH_IMMEDIATE) in most cases instead
|
||||
* @result error status
|
||||
*/
|
||||
// XXXbz Callers seem to be confused about this one... and it doesn't play
|
||||
// right with view update batching at all (will miss updates). Maybe this
|
||||
// should call FlushPendingInvalidates()?
|
||||
NS_IMETHOD ForceUpdate() = 0;
|
||||
|
||||
/**
|
||||
* Indicate whether the viewmanager is currently painting
|
||||
*
|
||||
@ -324,19 +383,25 @@ public:
|
||||
* the nearest enclosing popup or the root view for the root document.
|
||||
*/
|
||||
static nsIView* GetDisplayRootFor(nsIView* aView);
|
||||
|
||||
/**
|
||||
* Flush the accumulated dirty region to the widget and update widget
|
||||
* geometry.
|
||||
*/
|
||||
virtual void ProcessPendingUpdates()=0;
|
||||
|
||||
/**
|
||||
* Just update widget geometry without flushing the dirty region
|
||||
*/
|
||||
virtual void UpdateWidgetGeometry() = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIViewManager, NS_IVIEWMANAGER_IID)
|
||||
|
||||
// Paint timing mode flags
|
||||
|
||||
// intermediate: do no special timing processing; repaint when the
|
||||
// toolkit issues an expose event (which will happen *before* PLEvent
|
||||
// processing). This is essentially the default.
|
||||
#define NS_VMREFRESH_NO_SYNC 0
|
||||
|
||||
// least immediate: we suppress invalidation, storing dirty areas in
|
||||
// views, and post an Invalidate PLEvent. The Invalidate event gets
|
||||
// processed after toolkit events such as window resize events!
|
||||
// This is only usable with EndUpdateViewBatch and EnableRefresh.
|
||||
#define NS_VMREFRESH_DEFERRED 0x0001
|
||||
|
||||
// most immediate: force a call to nsViewManager::Composite, which
|
||||
// synchronously updates the window(s) right away before returning
|
||||
#define NS_VMREFRESH_IMMEDIATE 0x0002
|
||||
|
||||
#endif // nsIViewManager_h___
|
||||
|
@ -351,7 +351,7 @@ void nsView::SetPosition(nscoord aX, nscoord aY)
|
||||
NS_ASSERTION(GetParent() || (aX == 0 && aY == 0),
|
||||
"Don't try to move the root widget to something non-zero");
|
||||
|
||||
ResetWidgetBounds(true, false);
|
||||
ResetWidgetBounds(true, true, false);
|
||||
}
|
||||
|
||||
void nsIView::SetInvalidationDimensions(const nsRect* aRect)
|
||||
@ -359,23 +359,22 @@ void nsIView::SetInvalidationDimensions(const nsRect* aRect)
|
||||
return Impl()->SetInvalidationDimensions(aRect);
|
||||
}
|
||||
|
||||
void nsView::ResetWidgetBounds(bool aRecurse, bool aForceSync)
|
||||
{
|
||||
void nsView::ResetWidgetBounds(bool aRecurse, bool aMoveOnly,
|
||||
bool aInvalidateChangedSize) {
|
||||
if (mWindow) {
|
||||
if (!aForceSync) {
|
||||
// Don't change widget geometry synchronously, since that can
|
||||
// cause synchronous painting.
|
||||
// If our view manager has refresh disabled, then do nothing; the view
|
||||
// manager will set our position when refresh is reenabled. Just let it
|
||||
// know that it has pending updates.
|
||||
if (!mViewManager->IsRefreshEnabled()) {
|
||||
mViewManager->PostPendingUpdate();
|
||||
} else {
|
||||
DoResetWidgetBounds(false, true);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (aRecurse) {
|
||||
DoResetWidgetBounds(aMoveOnly, aInvalidateChangedSize);
|
||||
} else if (aRecurse) {
|
||||
// reposition any widgets under this view
|
||||
for (nsView* v = GetFirstChild(); v; v = v->GetNextSibling()) {
|
||||
v->ResetWidgetBounds(true, aForceSync);
|
||||
v->ResetWidgetBounds(true, aMoveOnly, aInvalidateChangedSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -493,7 +492,7 @@ void nsView::SetDimensions(const nsRect& aRect, bool aPaint, bool aResizeWidget)
|
||||
mDimBounds = dims;
|
||||
|
||||
if (aResizeWidget) {
|
||||
ResetWidgetBounds(false, false);
|
||||
ResetWidgetBounds(false, false, aPaint);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,7 +181,7 @@ public:
|
||||
void SetTopMost(bool aTopMost) { aTopMost ? mVFlags |= NS_VIEW_FLAG_TOPMOST : mVFlags &= ~NS_VIEW_FLAG_TOPMOST; }
|
||||
bool IsTopMost() { return((mVFlags & NS_VIEW_FLAG_TOPMOST) != 0); }
|
||||
|
||||
void ResetWidgetBounds(bool aRecurse, bool aForceSync);
|
||||
void ResetWidgetBounds(bool aRecurse, bool aMoveOnly, bool aInvalidateChangedSize);
|
||||
void AssertNoWindow();
|
||||
|
||||
void NotifyEffectiveVisibilityChanged(bool aEffectivelyVisible);
|
||||
|
@ -80,6 +80,21 @@
|
||||
|
||||
#define NSCOORD_NONE PR_INT32_MIN
|
||||
|
||||
void
|
||||
nsViewManager::PostInvalidateEvent()
|
||||
{
|
||||
NS_ASSERTION(IsRootVM(), "Caller screwed up");
|
||||
|
||||
if (!mInvalidateEvent.IsPending()) {
|
||||
nsRefPtr<nsInvalidateEvent> ev = new nsInvalidateEvent(this);
|
||||
if (NS_FAILED(NS_DispatchToCurrentThread(ev))) {
|
||||
NS_WARNING("failed to dispatch nsInvalidateEvent");
|
||||
} else {
|
||||
mInvalidateEvent = ev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef DEBUG_MOUSE_LOCATION
|
||||
|
||||
PRInt32 nsViewManager::mVMCount = 0;
|
||||
@ -105,8 +120,8 @@ nsViewManager::nsViewManager()
|
||||
// NOTE: we use a zeroing operator new, so all data members are
|
||||
// assumed to be cleared here.
|
||||
mHasPendingUpdates = false;
|
||||
mHasPendingWidgetGeometryChanges = false;
|
||||
mRecursiveRefreshPending = false;
|
||||
mUpdateBatchFlags = 0;
|
||||
}
|
||||
|
||||
nsViewManager::~nsViewManager()
|
||||
@ -117,6 +132,10 @@ nsViewManager::~nsViewManager()
|
||||
mRootView = nsnull;
|
||||
}
|
||||
|
||||
// Make sure to revoke pending events for all viewmanagers, since some events
|
||||
// are posted by a non-root viewmanager.
|
||||
mInvalidateEvent.Revoke();
|
||||
|
||||
if (!IsRootVM()) {
|
||||
// We have a strong ref to mRootViewManager
|
||||
NS_RELEASE(mRootViewManager);
|
||||
@ -342,6 +361,9 @@ void nsViewManager::Refresh(nsView *aView, nsIWidget *aWidget,
|
||||
NS_ASSERTION(aView == nsView::GetViewFor(aWidget), "view widget mismatch");
|
||||
NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
|
||||
|
||||
if (! IsRefreshEnabled())
|
||||
return;
|
||||
|
||||
// damageRegion is the damaged area, in twips, relative to the view origin
|
||||
nsRegion damageRegion = aRegion.ToAppUnits(AppUnitsPerDevPixel());
|
||||
// move region from widget coordinates into view coordinates
|
||||
@ -374,8 +396,10 @@ void nsViewManager::Refresh(nsView *aView, nsIWidget *aWidget,
|
||||
}
|
||||
|
||||
if (RootViewManager()->mRecursiveRefreshPending) {
|
||||
// Unset this flag first, since if aUpdateFlags includes NS_VMREFRESH_IMMEDIATE
|
||||
// we'll reenter this code from the UpdateAllViews call.
|
||||
RootViewManager()->mRecursiveRefreshPending = false;
|
||||
InvalidateAllViews();
|
||||
UpdateAllViews(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -396,8 +420,7 @@ void nsViewManager::RenderViews(nsView *aView, nsIWidget *aWidget,
|
||||
}
|
||||
}
|
||||
|
||||
void nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
|
||||
bool aFlushDirtyRegion)
|
||||
void nsViewManager::ProcessPendingUpdates(nsView* aView, bool aDoInvalidate)
|
||||
{
|
||||
NS_ASSERTION(IsRootVM(), "Updates will be missed");
|
||||
|
||||
@ -407,87 +430,96 @@ void nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
|
||||
}
|
||||
|
||||
if (aView->HasWidget()) {
|
||||
aView->ResetWidgetBounds(false, true);
|
||||
aView->ResetWidgetBounds(false, false, true);
|
||||
}
|
||||
|
||||
// process pending updates in child view.
|
||||
for (nsView* childView = aView->GetFirstChild(); childView;
|
||||
childView = childView->GetNextSibling()) {
|
||||
ProcessPendingUpdatesForView(childView, aFlushDirtyRegion);
|
||||
ProcessPendingUpdates(childView, aDoInvalidate);
|
||||
}
|
||||
|
||||
// Push out updates after we've processed the children; ensures that
|
||||
// damage is applied based on the final widget geometry
|
||||
if (aFlushDirtyRegion) {
|
||||
FlushDirtyRegionToWidget(aView);
|
||||
if (aDoInvalidate && aView->HasNonEmptyDirtyRegion()) {
|
||||
// Push out updates after we've processed the children; ensures that
|
||||
// damage is applied based on the final widget geometry
|
||||
NS_ASSERTION(IsRefreshEnabled(), "Cannot process pending updates with refresh disabled");
|
||||
nsRegion* dirtyRegion = aView->GetDirtyRegion();
|
||||
if (dirtyRegion) {
|
||||
nsView* nearestViewWithWidget = aView;
|
||||
while (!nearestViewWithWidget->HasWidget() &&
|
||||
nearestViewWithWidget->GetParent()) {
|
||||
nearestViewWithWidget = nearestViewWithWidget->GetParent();
|
||||
}
|
||||
nsRegion r =
|
||||
ConvertRegionBetweenViews(*dirtyRegion, aView, nearestViewWithWidget);
|
||||
nsViewManager* widgetVM = nearestViewWithWidget->GetViewManager();
|
||||
widgetVM->
|
||||
UpdateWidgetArea(nearestViewWithWidget,
|
||||
nearestViewWithWidget->GetWidget(), r, nsnull);
|
||||
dirtyRegion->SetEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nsViewManager::FlushDirtyRegionToWidget(nsView* aView)
|
||||
NS_IMETHODIMP nsViewManager::Composite()
|
||||
{
|
||||
if (!aView->HasNonEmptyDirtyRegion())
|
||||
return;
|
||||
|
||||
nsRegion* dirtyRegion = aView->GetDirtyRegion();
|
||||
nsView* nearestViewWithWidget = aView;
|
||||
while (!nearestViewWithWidget->HasWidget() &&
|
||||
nearestViewWithWidget->GetParent()) {
|
||||
nearestViewWithWidget = nearestViewWithWidget->GetParent();
|
||||
if (!IsRootVM()) {
|
||||
return RootViewManager()->Composite();
|
||||
}
|
||||
nsRegion r =
|
||||
ConvertRegionBetweenViews(*dirtyRegion, aView, nearestViewWithWidget);
|
||||
nsViewManager* widgetVM = nearestViewWithWidget->GetViewManager();
|
||||
widgetVM->InvalidateWidgetArea(nearestViewWithWidget, r);
|
||||
dirtyRegion->SetEmpty();
|
||||
ForceUpdate();
|
||||
ClearUpdateCount();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsViewManager::InvalidateView(nsIView *aView)
|
||||
NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, PRUint32 aUpdateFlags)
|
||||
{
|
||||
// Mark the entire view as damaged
|
||||
return InvalidateView(aView, aView->GetDimensions());
|
||||
}
|
||||
|
||||
static void
|
||||
AddDirtyRegion(nsView *aView, const nsRegion &aDamagedRegion)
|
||||
{
|
||||
nsRegion* dirtyRegion = aView->GetDirtyRegion();
|
||||
if (!dirtyRegion)
|
||||
return;
|
||||
|
||||
dirtyRegion->Or(*dirtyRegion, aDamagedRegion);
|
||||
dirtyRegion->SimplifyOutward(8);
|
||||
}
|
||||
|
||||
void
|
||||
nsViewManager::PostPendingUpdate()
|
||||
{
|
||||
nsViewManager* rootVM = RootViewManager();
|
||||
rootVM->mHasPendingUpdates = true;
|
||||
rootVM->mHasPendingWidgetGeometryChanges = true;
|
||||
if (rootVM->mPresShell) {
|
||||
rootVM->mPresShell->ScheduleViewManagerFlush();
|
||||
}
|
||||
return UpdateView(aView, aView->GetDimensions(), aUpdateFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param aWidget the widget for aWidgetView; in some cases the widget
|
||||
* is being managed directly by the frame system, so aWidgetView->GetWidget()
|
||||
* will return null but nsView::GetViewFor(aWidget) returns aWidgetview
|
||||
* @param aDamagedRegion this region, relative to aWidgetView, is invalidated in
|
||||
* every widget child of aWidgetView, plus aWidgetView's own widget
|
||||
* @param aIgnoreWidgetView if non-null, the aIgnoreWidgetView's widget and its
|
||||
* children are not updated.
|
||||
*/
|
||||
void
|
||||
nsViewManager::InvalidateWidgetArea(nsView *aWidgetView,
|
||||
const nsRegion &aDamagedRegion)
|
||||
nsViewManager::UpdateWidgetArea(nsView *aWidgetView, nsIWidget* aWidget,
|
||||
const nsRegion &aDamagedRegion,
|
||||
nsView* aIgnoreWidgetView)
|
||||
{
|
||||
NS_ASSERTION(aWidgetView->GetViewManager() == this,
|
||||
"InvalidateWidgetArea called on view we don't own");
|
||||
nsIWidget* widget = aWidgetView->GetWidget();
|
||||
"UpdateWidgetArea called on view we don't own");
|
||||
|
||||
#if 0
|
||||
nsRect dbgBounds = aDamagedRegion.GetBounds();
|
||||
printf("InvalidateWidgetArea view:%X (%d) widget:%X region: %d, %d, %d, %d\n",
|
||||
printf("UpdateWidgetArea view:%X (%d) widget:%X region: %d, %d, %d, %d\n",
|
||||
aWidgetView, aWidgetView->IsAttachedToTopLevel(),
|
||||
widget, dbgBounds.x, dbgBounds.y, dbgBounds.width, dbgBounds.height);
|
||||
aWidget, dbgBounds.x, dbgBounds.y, dbgBounds.width, dbgBounds.height);
|
||||
#endif
|
||||
|
||||
if (!IsRefreshEnabled()) {
|
||||
// accumulate this rectangle in the view's dirty region, so we can
|
||||
// process it later.
|
||||
nsRegion* dirtyRegion = aWidgetView->GetDirtyRegion();
|
||||
if (!dirtyRegion) return;
|
||||
|
||||
dirtyRegion->Or(*dirtyRegion, aDamagedRegion);
|
||||
// Don't let dirtyRegion grow beyond 8 rects
|
||||
dirtyRegion->SimplifyOutward(8);
|
||||
nsViewManager* rootVM = RootViewManager();
|
||||
rootVM->mHasPendingUpdates = true;
|
||||
rootVM->IncrementUpdateCount();
|
||||
return;
|
||||
// this should only happen at the top level, and this result
|
||||
// should not be consumed by top-level callers, so it doesn't
|
||||
// really matter what we return
|
||||
}
|
||||
|
||||
// If the bounds don't overlap at all, there's nothing to do
|
||||
nsRegion intersection;
|
||||
intersection.And(aWidgetView->GetInvalidationDimensions(), aDamagedRegion);
|
||||
@ -496,14 +528,19 @@ nsViewManager::InvalidateWidgetArea(nsView *aWidgetView,
|
||||
}
|
||||
|
||||
// If the widget is hidden, it don't cover nothing
|
||||
if (widget) {
|
||||
if (aWidget) {
|
||||
bool visible;
|
||||
widget->IsVisible(visible);
|
||||
aWidget->IsVisible(visible);
|
||||
if (!visible)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!widget) {
|
||||
if (aWidgetView == aIgnoreWidgetView) {
|
||||
// the widget for aIgnoreWidgetView (and its children) should be treated as already updated.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aWidget) {
|
||||
// The root view or a scrolling view might not have a widget
|
||||
// (for example, during printing). We get here when we scroll
|
||||
// during printing to show selected options in a listbox, for example.
|
||||
@ -514,8 +551,8 @@ nsViewManager::InvalidateWidgetArea(nsView *aWidgetView,
|
||||
// accumulate the union of all the child widget areas, or at least
|
||||
// some subset of that.
|
||||
nsRegion children;
|
||||
if (widget->GetTransparencyMode() != eTransparencyTransparent) {
|
||||
for (nsIWidget* childWidget = widget->GetFirstChild();
|
||||
if (aWidget->GetTransparencyMode() != eTransparencyTransparent) {
|
||||
for (nsIWidget* childWidget = aWidget->GetFirstChild();
|
||||
childWidget;
|
||||
childWidget = childWidget->GetNextSibling()) {
|
||||
nsView* view = nsView::GetViewFor(childWidget);
|
||||
@ -554,10 +591,12 @@ nsViewManager::InvalidateWidgetArea(nsView *aWidgetView,
|
||||
leftOver.Sub(intersection, children);
|
||||
|
||||
if (!leftOver.IsEmpty()) {
|
||||
NS_ASSERTION(IsRefreshEnabled(), "Can only get here with refresh enabled, I hope");
|
||||
|
||||
const nsRect* r;
|
||||
for (nsRegionRectIterator iter(leftOver); (r = iter.Next());) {
|
||||
nsIntRect bounds = ViewToWidget(aWidgetView, *r);
|
||||
widget->Invalidate(bounds);
|
||||
aWidget->Invalidate(bounds, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -576,7 +615,8 @@ ShouldIgnoreInvalidation(nsViewManager* aVM)
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult nsViewManager::InvalidateView(nsIView *aView, const nsRect &aRect)
|
||||
nsresult nsViewManager::UpdateView(nsIView *aView, const nsRect &aRect,
|
||||
PRUint32 aUpdateFlags)
|
||||
{
|
||||
// If painting is suppressed in the presshell or an ancestor drop all
|
||||
// invalidates, it will invalidate everything when it unsuppresses.
|
||||
@ -584,18 +624,19 @@ nsresult nsViewManager::InvalidateView(nsIView *aView, const nsRect &aRect)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return InvalidateViewNoSuppression(aView, aRect);
|
||||
return UpdateViewNoSuppression(aView, aRect, aUpdateFlags);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsViewManager::InvalidateViewNoSuppression(nsIView *aView,
|
||||
const nsRect &aRect)
|
||||
NS_IMETHODIMP nsViewManager::UpdateViewNoSuppression(nsIView *aView,
|
||||
const nsRect &aRect,
|
||||
PRUint32 aUpdateFlags)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != aView, "null view");
|
||||
|
||||
nsView* view = static_cast<nsView*>(aView);
|
||||
|
||||
NS_ASSERTION(view->GetViewManager() == this,
|
||||
"InvalidateViewNoSuppression called on view we don't own");
|
||||
"UpdateView called on view we don't own");
|
||||
|
||||
nsRect damagedRect(aRect);
|
||||
if (damagedRect.IsEmpty()) {
|
||||
@ -611,36 +652,42 @@ NS_IMETHODIMP nsViewManager::InvalidateViewNoSuppression(nsIView *aView,
|
||||
PRInt32 rootAPD = displayRootVM->AppUnitsPerDevPixel();
|
||||
PRInt32 APD = AppUnitsPerDevPixel();
|
||||
damagedRect = damagedRect.ConvertAppUnitsRoundOut(APD, rootAPD);
|
||||
displayRootVM->UpdateWidgetArea(displayRoot, displayRoot->GetWidget(),
|
||||
nsRegion(damagedRect), nsnull);
|
||||
|
||||
// accumulate this rectangle in the view's dirty region, so we can
|
||||
// process it later.
|
||||
AddDirtyRegion(displayRoot, nsRegion(damagedRect));
|
||||
RootViewManager()->IncrementUpdateCount();
|
||||
|
||||
// Schedule an invalidation flush with the refresh driver.
|
||||
PostPendingUpdate();
|
||||
if (!IsRefreshEnabled()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// See if we should do an immediate refresh or wait
|
||||
if (aUpdateFlags & NS_VMREFRESH_IMMEDIATE) {
|
||||
Composite();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsViewManager::InvalidateAllViews()
|
||||
NS_IMETHODIMP nsViewManager::UpdateAllViews(PRUint32 aUpdateFlags)
|
||||
{
|
||||
if (RootViewManager() != this) {
|
||||
return RootViewManager()->InvalidateAllViews();
|
||||
return RootViewManager()->UpdateAllViews(aUpdateFlags);
|
||||
}
|
||||
|
||||
InvalidateViews(mRootView);
|
||||
UpdateViews(mRootView, aUpdateFlags);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsViewManager::InvalidateViews(nsView *aView)
|
||||
void nsViewManager::UpdateViews(nsView *aView, PRUint32 aUpdateFlags)
|
||||
{
|
||||
// Invalidate this view.
|
||||
InvalidateView(aView);
|
||||
// update this view.
|
||||
UpdateView(aView, aUpdateFlags);
|
||||
|
||||
// Invalidate all children as well.
|
||||
// update all children as well.
|
||||
nsView* childView = aView->GetFirstChild();
|
||||
while (nsnull != childView) {
|
||||
childView->GetViewManager()->InvalidateViews(childView);
|
||||
childView->GetViewManager()->UpdateViews(childView, aUpdateFlags);
|
||||
childView = childView->GetNextSibling();
|
||||
}
|
||||
}
|
||||
@ -753,74 +800,132 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
|
||||
break;
|
||||
|
||||
case NS_WILL_PAINT:
|
||||
case NS_PAINT:
|
||||
{
|
||||
nsPaintEvent *event = static_cast<nsPaintEvent*>(aEvent);
|
||||
|
||||
if (!aView || !mContext)
|
||||
break;
|
||||
|
||||
*aStatus = nsEventStatus_eConsumeNoDefault;
|
||||
|
||||
nsPaintEvent *event = static_cast<nsPaintEvent*>(aEvent);
|
||||
if (aEvent->message == NS_PAINT && event->region.IsEmpty())
|
||||
break;
|
||||
|
||||
NS_ASSERTION(static_cast<nsView*>(aView) ==
|
||||
nsView::GetViewFor(event->widget),
|
||||
"view/widget mismatch");
|
||||
|
||||
// If an ancestor widget was hidden and then shown, we could
|
||||
// have a delayed resize to handle.
|
||||
for (nsViewManager *vm = this; vm;
|
||||
vm = vm->mRootView->GetParent()
|
||||
? vm->mRootView->GetParent()->GetViewManager()
|
||||
: nsnull) {
|
||||
if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
|
||||
vm->mRootView->IsEffectivelyVisible() &&
|
||||
mPresShell && mPresShell->IsVisible()) {
|
||||
vm->FlushDelayedResize(true);
|
||||
vm->InvalidateView(vm->mRootView);
|
||||
// The region is in device units, and it's in the coordinate space of
|
||||
// its associated widget.
|
||||
|
||||
// Refresh the view
|
||||
if (IsRefreshEnabled()) {
|
||||
nsRefPtr<nsViewManager> rootVM = RootViewManager();
|
||||
|
||||
// If an ancestor widget was hidden and then shown, we could
|
||||
// have a delayed resize to handle.
|
||||
bool didResize = false;
|
||||
for (nsViewManager *vm = this; vm;
|
||||
vm = vm->mRootView->GetParent()
|
||||
? vm->mRootView->GetParent()->GetViewManager()
|
||||
: nsnull) {
|
||||
if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
|
||||
vm->mRootView->IsEffectivelyVisible() &&
|
||||
mPresShell && mPresShell->IsVisible()) {
|
||||
vm->FlushDelayedResize(true);
|
||||
|
||||
// Paint later.
|
||||
vm->UpdateView(vm->mRootView, NS_VMREFRESH_NO_SYNC);
|
||||
didResize = true;
|
||||
|
||||
// not sure if it's valid for us to claim that we
|
||||
// ignored this, but we're going to do so anyway, since
|
||||
// we didn't actually paint anything
|
||||
*aStatus = nsEventStatus_eIgnore;
|
||||
}
|
||||
}
|
||||
|
||||
if (!didResize) {
|
||||
//NS_ASSERTION(view->IsEffectivelyVisible(), "painting an invisible view");
|
||||
|
||||
// Notify view observers that we're about to paint.
|
||||
// Make sure to not send WillPaint notifications while scrolling.
|
||||
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
rootVM->GetRootWidget(getter_AddRefs(widget));
|
||||
bool transparentWindow = false;
|
||||
if (widget)
|
||||
transparentWindow = widget->GetTransparencyMode() == eTransparencyTransparent;
|
||||
|
||||
nsView* view = static_cast<nsView*>(aView);
|
||||
if (!transparentWindow) {
|
||||
if (mPresShell) {
|
||||
// Do an update view batch. Make sure not to do it DEFERRED,
|
||||
// since that would effectively delay any invalidates that are
|
||||
// triggered by the WillPaint notification (they'd happen when
|
||||
// the invalid event fires, which is later than the reflow
|
||||
// event would fire and could end up being after some timer
|
||||
// events, leading to frame dropping in DHTML). Note that the
|
||||
// observer may try to reenter this code from inside
|
||||
// WillPaint() by trying to do a synchronous paint, but since
|
||||
// refresh will be disabled it won't be able to do the paint.
|
||||
// We should really sort out the rules on our synch painting
|
||||
// api....
|
||||
UpdateViewBatch batch(this);
|
||||
rootVM->CallWillPaintOnObservers(event->willSendDidPaint);
|
||||
batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
|
||||
|
||||
// Get the view pointer again since the code above might have
|
||||
// destroyed it (bug 378273).
|
||||
view = nsView::GetViewFor(aEvent->widget);
|
||||
}
|
||||
}
|
||||
// Make sure to sync up any widget geometry changes we
|
||||
// have pending before we paint.
|
||||
if (rootVM->mHasPendingUpdates) {
|
||||
rootVM->ProcessPendingUpdates(mRootView, false);
|
||||
}
|
||||
|
||||
if (view && aEvent->message == NS_PAINT) {
|
||||
Refresh(view, event->widget, event->region);
|
||||
}
|
||||
}
|
||||
} else if (aEvent->message == NS_PAINT) {
|
||||
// since we got an NS_PAINT event, we need to
|
||||
// draw something so we don't get blank areas,
|
||||
// unless there's no widget or it's transparent.
|
||||
nsRegion rgn = event->region.ToAppUnits(AppUnitsPerDevPixel());
|
||||
rgn.MoveBy(-aView->ViewToWidgetOffset());
|
||||
RenderViews(static_cast<nsView*>(aView), event->widget, rgn,
|
||||
event->region, true, event->willSendDidPaint);
|
||||
// Clients like the editor can trigger multiple
|
||||
// reflows during what the user perceives as a single
|
||||
// edit operation, so it disables view manager
|
||||
// refreshing until the edit operation is complete
|
||||
// so that users don't see the intermediate steps.
|
||||
//
|
||||
// Unfortunately some of these reflows can trigger
|
||||
// nsScrollPortView and nsScrollingView Scroll() calls
|
||||
// which in most cases force an immediate BitBlt and
|
||||
// synchronous paint to happen even if the view manager's
|
||||
// refresh is disabled. (Bug 97674)
|
||||
//
|
||||
// Calling UpdateView() here, is necessary to add
|
||||
// the exposed region specified in the synchronous paint
|
||||
// event to the view's damaged region so that it gets
|
||||
// painted properly when refresh is enabled.
|
||||
//
|
||||
// Note that calling UpdateView() here was deemed
|
||||
// to have the least impact on performance, since the
|
||||
// other alternative was to make Scroll() post an
|
||||
// async paint event for the *entire* ScrollPort or
|
||||
// ScrollingView's viewable area. (See bug 97674 for this
|
||||
// alternate patch.)
|
||||
|
||||
UpdateView(aView, rgn.GetBounds(), NS_VMREFRESH_NO_SYNC);
|
||||
}
|
||||
|
||||
// Flush things like reflows and plugin widget geometry updates by
|
||||
// calling WillPaint on observer presShells.
|
||||
nsRefPtr<nsViewManager> rootVM = RootViewManager();
|
||||
if (mPresShell) {
|
||||
rootVM->CallWillPaintOnObservers(event->willSendDidPaint);
|
||||
}
|
||||
// Flush view widget geometry updates and invalidations.
|
||||
rootVM->ProcessPendingUpdates();
|
||||
}
|
||||
break;
|
||||
|
||||
case NS_PAINT:
|
||||
{
|
||||
if (!aView || !mContext)
|
||||
break;
|
||||
|
||||
*aStatus = nsEventStatus_eConsumeNoDefault;
|
||||
nsPaintEvent *event = static_cast<nsPaintEvent*>(aEvent);
|
||||
nsView* view = static_cast<nsView*>(aView);
|
||||
NS_ASSERTION(view == nsView::GetViewFor(event->widget),
|
||||
"view/widget mismatch");
|
||||
NS_ASSERTION(IsPaintingAllowed(),
|
||||
"shouldn't be receiving paint events while painting is "
|
||||
"disallowed!");
|
||||
|
||||
if (!event->didSendWillPaint) {
|
||||
// Send NS_WILL_PAINT event ourselves.
|
||||
nsPaintEvent willPaintEvent(true, NS_WILL_PAINT, event->widget);
|
||||
willPaintEvent.willSendDidPaint = event->willSendDidPaint;
|
||||
DispatchEvent(&willPaintEvent, view, aStatus);
|
||||
|
||||
// Get the view pointer again since NS_WILL_PAINT might have
|
||||
// destroyed it during CallWillPaintOnObservers (bug 378273).
|
||||
view = nsView::GetViewFor(event->widget);
|
||||
}
|
||||
|
||||
if (!view || event->region.IsEmpty())
|
||||
break;
|
||||
|
||||
// Paint.
|
||||
Refresh(view, event->widget, event->region);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1071,7 +1176,7 @@ NS_IMETHODIMP nsViewManager::InsertChild(nsIView *aParent, nsIView *aChild, nsIV
|
||||
//and mark this area as dirty if the view is visible...
|
||||
|
||||
if (nsViewVisibility_kHide != child->GetVisibility())
|
||||
child->GetViewManager()->InvalidateView(child);
|
||||
child->GetViewManager()->UpdateView(child, NS_VMREFRESH_NO_SYNC);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1094,7 +1199,7 @@ NS_IMETHODIMP nsViewManager::RemoveChild(nsIView *aChild)
|
||||
if (nsnull != parent) {
|
||||
NS_ASSERTION(child->GetViewManager() == this ||
|
||||
parent->GetViewManager() == this, "wrong view manager");
|
||||
child->GetViewManager()->InvalidateView(child);
|
||||
child->GetViewManager()->UpdateView(child, NS_VMREFRESH_NO_SYNC);
|
||||
parent->RemoveChild(child);
|
||||
}
|
||||
|
||||
@ -1116,8 +1221,9 @@ NS_IMETHODIMP nsViewManager::MoveViewTo(nsIView *aView, nscoord aX, nscoord aY)
|
||||
nsView* parentView = view->GetParent();
|
||||
if (parentView) {
|
||||
nsViewManager* parentVM = parentView->GetViewManager();
|
||||
parentVM->InvalidateView(parentView, oldBounds);
|
||||
parentVM->InvalidateView(parentView, view->GetBoundsInParentUnits());
|
||||
parentVM->UpdateView(parentView, oldBounds, NS_VMREFRESH_NO_SYNC);
|
||||
parentVM->UpdateView(parentView, view->GetBoundsInParentUnits(),
|
||||
NS_VMREFRESH_NO_SYNC);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1125,33 +1231,34 @@ NS_IMETHODIMP nsViewManager::MoveViewTo(nsIView *aView, nscoord aX, nscoord aY)
|
||||
}
|
||||
|
||||
void nsViewManager::InvalidateHorizontalBandDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut,
|
||||
nscoord aY1, nscoord aY2, bool aInCutOut) {
|
||||
PRUint32 aUpdateFlags, nscoord aY1, nscoord aY2, bool aInCutOut) {
|
||||
nscoord height = aY2 - aY1;
|
||||
if (aRect.x < aCutOut.x) {
|
||||
nsRect r(aRect.x, aY1, aCutOut.x - aRect.x, height);
|
||||
InvalidateView(aView, r);
|
||||
UpdateView(aView, r, aUpdateFlags);
|
||||
}
|
||||
if (!aInCutOut && aCutOut.x < aCutOut.XMost()) {
|
||||
nsRect r(aCutOut.x, aY1, aCutOut.width, height);
|
||||
InvalidateView(aView, r);
|
||||
UpdateView(aView, r, aUpdateFlags);
|
||||
}
|
||||
if (aCutOut.XMost() < aRect.XMost()) {
|
||||
nsRect r(aCutOut.XMost(), aY1, aRect.XMost() - aCutOut.XMost(), height);
|
||||
InvalidateView(aView, r);
|
||||
UpdateView(aView, r, aUpdateFlags);
|
||||
}
|
||||
}
|
||||
|
||||
void nsViewManager::InvalidateRectDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut) {
|
||||
void nsViewManager::InvalidateRectDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut,
|
||||
PRUint32 aUpdateFlags) {
|
||||
NS_ASSERTION(aView->GetViewManager() == this,
|
||||
"InvalidateRectDifference called on view we don't own");
|
||||
if (aRect.y < aCutOut.y) {
|
||||
InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aRect.y, aCutOut.y, false);
|
||||
InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aUpdateFlags, aRect.y, aCutOut.y, false);
|
||||
}
|
||||
if (aCutOut.y < aCutOut.YMost()) {
|
||||
InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aCutOut.y, aCutOut.YMost(), true);
|
||||
InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aUpdateFlags, aCutOut.y, aCutOut.YMost(), true);
|
||||
}
|
||||
if (aCutOut.YMost() < aRect.YMost()) {
|
||||
InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aCutOut.YMost(), aRect.YMost(), false);
|
||||
InvalidateHorizontalBandDifference(aView, aRect, aCutOut, aUpdateFlags, aCutOut.YMost(), aRect.YMost(), false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1175,13 +1282,14 @@ NS_IMETHODIMP nsViewManager::ResizeView(nsIView *aView, const nsRect &aRect, boo
|
||||
view->SetDimensions(aRect, true);
|
||||
nsViewManager* parentVM = parentView->GetViewManager();
|
||||
if (!aRepaintExposedAreaOnly) {
|
||||
// Invalidate the union of the old and new size
|
||||
InvalidateView(view, aRect);
|
||||
parentVM->InvalidateView(parentView, oldBounds);
|
||||
//Invalidate the union of the old and new size
|
||||
UpdateView(view, aRect, NS_VMREFRESH_NO_SYNC);
|
||||
parentVM->UpdateView(parentView, oldBounds, NS_VMREFRESH_NO_SYNC);
|
||||
} else {
|
||||
InvalidateRectDifference(view, aRect, oldDimensions);
|
||||
InvalidateRectDifference(view, aRect, oldDimensions, NS_VMREFRESH_NO_SYNC);
|
||||
nsRect newBounds = view->GetBoundsInParentUnits();
|
||||
parentVM->InvalidateRectDifference(parentView, oldBounds, newBounds);
|
||||
parentVM->InvalidateRectDifference(parentView, oldBounds, newBounds,
|
||||
NS_VMREFRESH_NO_SYNC);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1220,11 +1328,12 @@ NS_IMETHODIMP nsViewManager::SetViewVisibility(nsIView *aView, nsViewVisibility
|
||||
nsView* parentView = view->GetParent();
|
||||
if (parentView) {
|
||||
parentView->GetViewManager()->
|
||||
InvalidateView(parentView, view->GetBoundsInParentUnits());
|
||||
UpdateView(parentView, view->GetBoundsInParentUnits(),
|
||||
NS_VMREFRESH_NO_SYNC);
|
||||
}
|
||||
}
|
||||
else {
|
||||
InvalidateView(view);
|
||||
UpdateView(view, NS_VMREFRESH_NO_SYNC);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1232,6 +1341,37 @@ NS_IMETHODIMP nsViewManager::SetViewVisibility(nsIView *aView, nsViewVisibility
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsViewManager::UpdateWidgetsForView(nsView* aView)
|
||||
{
|
||||
NS_PRECONDITION(aView, "Must have view!");
|
||||
|
||||
// No point forcing an update if invalidations have been suppressed.
|
||||
if (!IsRefreshEnabled())
|
||||
return;
|
||||
|
||||
nsWeakView parentWeakView = aView;
|
||||
if (aView->HasWidget()) {
|
||||
aView->GetWidget()->Update(); // Flushes Layout!
|
||||
if (!parentWeakView.IsAlive()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsView* childView = aView->GetFirstChild();
|
||||
while (childView) {
|
||||
nsWeakView childWeakView = childView;
|
||||
UpdateWidgetsForView(childView);
|
||||
if (NS_LIKELY(childWeakView.IsAlive())) {
|
||||
childView = childView->GetNextSibling();
|
||||
}
|
||||
else {
|
||||
// The current view was destroyed - restart at the first child if the
|
||||
// parent is still alive.
|
||||
childView = parentWeakView.IsAlive() ? aView->GetFirstChild() : nsnull;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool nsViewManager::IsViewInserted(nsView *aView)
|
||||
{
|
||||
if (mRootView == aView) {
|
||||
@ -1275,7 +1415,7 @@ NS_IMETHODIMP nsViewManager::SetViewZIndex(nsIView *aView, bool aAutoZIndex, PRI
|
||||
|
||||
if (oldidx != aZIndex || oldTopMost != aTopMost ||
|
||||
oldIsAuto != aAutoZIndex) {
|
||||
InvalidateView(view);
|
||||
UpdateView(view, NS_VMREFRESH_NO_SYNC);
|
||||
}
|
||||
|
||||
return rv;
|
||||
@ -1288,24 +1428,68 @@ NS_IMETHODIMP nsViewManager::GetDeviceContext(nsDeviceContext *&aContext)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIViewManager*
|
||||
nsViewManager::IncrementDisableRefreshCount()
|
||||
void nsViewManager::TriggerRefresh(PRUint32 aUpdateFlags)
|
||||
{
|
||||
if (!IsRootVM()) {
|
||||
return RootViewManager()->IncrementDisableRefreshCount();
|
||||
RootViewManager()->TriggerRefresh(aUpdateFlags);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mUpdateBatchCnt > 0)
|
||||
return;
|
||||
|
||||
// nested batching can combine IMMEDIATE with DEFERRED. Favour
|
||||
// IMMEDIATE over DEFERRED and DEFERRED over NO_SYNC. We need to
|
||||
// check for IMMEDIATE before checking mHasPendingUpdates, because
|
||||
// the latter might be false as far as gecko is concerned but the OS
|
||||
// might still have queued up expose events that it hasn't sent yet.
|
||||
if (aUpdateFlags & NS_VMREFRESH_IMMEDIATE) {
|
||||
FlushPendingInvalidates();
|
||||
Composite();
|
||||
} else if (!mHasPendingUpdates) {
|
||||
// Nothing to do
|
||||
} else if (aUpdateFlags & NS_VMREFRESH_DEFERRED) {
|
||||
PostInvalidateEvent();
|
||||
} else { // NO_SYNC
|
||||
FlushPendingInvalidates();
|
||||
}
|
||||
}
|
||||
|
||||
nsIViewManager* nsViewManager::BeginUpdateViewBatch(void)
|
||||
{
|
||||
if (!IsRootVM()) {
|
||||
return RootViewManager()->BeginUpdateViewBatch();
|
||||
}
|
||||
|
||||
if (mUpdateBatchCnt == 0) {
|
||||
mUpdateBatchFlags = 0;
|
||||
}
|
||||
|
||||
++mRefreshDisableCount;
|
||||
++mUpdateBatchCnt;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
void
|
||||
nsViewManager::DecrementDisableRefreshCount()
|
||||
NS_IMETHODIMP nsViewManager::EndUpdateViewBatch(PRUint32 aUpdateFlags)
|
||||
{
|
||||
NS_ASSERTION(IsRootVM(), "Should only be called on root");
|
||||
--mRefreshDisableCount;
|
||||
NS_ASSERTION(mRefreshDisableCount >= 0, "Invalid refresh disable count!");
|
||||
|
||||
--mUpdateBatchCnt;
|
||||
|
||||
NS_ASSERTION(mUpdateBatchCnt >= 0, "Invalid batch count!");
|
||||
|
||||
if (mUpdateBatchCnt < 0)
|
||||
{
|
||||
mUpdateBatchCnt = 0;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mUpdateBatchFlags |= aUpdateFlags;
|
||||
if (mUpdateBatchCnt == 0) {
|
||||
TriggerRefresh(mUpdateBatchFlags);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsViewManager::GetRootWidget(nsIWidget **aWidget)
|
||||
@ -1325,6 +1509,20 @@ NS_IMETHODIMP nsViewManager::GetRootWidget(nsIWidget **aWidget)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsViewManager::ForceUpdate()
|
||||
{
|
||||
if (!IsRootVM()) {
|
||||
return RootViewManager()->ForceUpdate();
|
||||
}
|
||||
|
||||
// Walk the view tree looking for widgets, and call Update() on each one
|
||||
if (mRootView) {
|
||||
UpdateWidgetsForView(mRootView);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIntRect nsViewManager::ViewToWidget(nsView *aView, const nsRect &aRect) const
|
||||
{
|
||||
NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
|
||||
@ -1349,38 +1547,26 @@ nsViewManager::IsPainting(bool& aIsPainting)
|
||||
}
|
||||
|
||||
void
|
||||
nsViewManager::ProcessPendingUpdates()
|
||||
nsViewManager::FlushPendingInvalidates()
|
||||
{
|
||||
if (!IsRootVM()) {
|
||||
RootViewManager()->ProcessPendingUpdates();
|
||||
return;
|
||||
}
|
||||
NS_ASSERTION(IsRootVM(), "Must be root VM for this to be called!");
|
||||
NS_ASSERTION(mUpdateBatchCnt == 0, "Must not be in an update batch!");
|
||||
|
||||
if (mHasPendingUpdates) {
|
||||
ProcessPendingUpdatesForView(mRootView, true);
|
||||
ProcessPendingUpdates(mRootView, true);
|
||||
mHasPendingUpdates = false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsViewManager::UpdateWidgetGeometry()
|
||||
{
|
||||
if (!IsRootVM()) {
|
||||
RootViewManager()->UpdateWidgetGeometry();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mHasPendingWidgetGeometryChanges) {
|
||||
ProcessPendingUpdatesForView(mRootView, false);
|
||||
mHasPendingWidgetGeometryChanges = false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsViewManager::CallWillPaintOnObservers(bool aWillSendDidPaint)
|
||||
{
|
||||
NS_PRECONDITION(IsRootVM(), "Must be root VM for this to be called!");
|
||||
NS_PRECONDITION(mUpdateBatchCnt > 0, "Must be in an update batch!");
|
||||
|
||||
#ifdef DEBUG
|
||||
PRInt32 savedUpdateBatchCnt = mUpdateBatchCnt;
|
||||
#endif
|
||||
PRInt32 index;
|
||||
for (index = 0; index < mVMCount; index++) {
|
||||
nsViewManager* vm = (nsViewManager*)gViewManagers->ElementAt(index);
|
||||
@ -1390,6 +1576,8 @@ nsViewManager::CallWillPaintOnObservers(bool aWillSendDidPaint)
|
||||
nsCOMPtr<nsIPresShell> shell = vm->GetPresShell();
|
||||
if (shell) {
|
||||
shell->WillPaint(aWillSendDidPaint);
|
||||
NS_ASSERTION(mUpdateBatchCnt == savedUpdateBatchCnt,
|
||||
"Observer did not end view batch?");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1416,6 +1604,24 @@ nsViewManager::CallDidPaintOnObservers()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsViewManager::ProcessInvalidateEvent()
|
||||
{
|
||||
NS_ASSERTION(IsRootVM(),
|
||||
"Incorrectly targeted invalidate event");
|
||||
// If we're in the middle of an update batch, just repost the event,
|
||||
// to be processed when the batch ends.
|
||||
bool processEvent = (mUpdateBatchCnt == 0);
|
||||
if (processEvent) {
|
||||
FlushPendingInvalidates();
|
||||
}
|
||||
mInvalidateEvent.Forget();
|
||||
if (!processEvent) {
|
||||
// We didn't actually process this event... post a new one
|
||||
PostInvalidateEvent();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsViewManager::GetLastUserEventTime(PRUint32& aTime)
|
||||
{
|
||||
|
@ -53,27 +53,36 @@
|
||||
/**
|
||||
Invalidation model:
|
||||
|
||||
1) Callers call into the view manager and ask it to invalidate a view.
|
||||
1) Callers call into the view manager and ask it to update a view.
|
||||
|
||||
2) The view manager finds the "right" widget for the view, henceforth called
|
||||
the root widget.
|
||||
|
||||
3) The view manager traverses descendants of the root widget and for each
|
||||
one that needs invalidation stores the rect to invalidate on the widget's
|
||||
view (batching).
|
||||
one that needs invalidation either
|
||||
|
||||
4) The dirty region is flushed to the right widget when
|
||||
ProcessPendingUpdates is called from the RefreshDriver.
|
||||
a) Calls Invalidate() on the widget (no batching)
|
||||
or
|
||||
b) Stores the rect to invalidate on the widget's view (batching)
|
||||
|
||||
// XXXbz we want to change this a bit. See bug 243726
|
||||
|
||||
4) When batching, the call to end the batch either processes the pending
|
||||
Invalidate() calls on the widgets or posts an event to do so.
|
||||
|
||||
It's important to note that widgets associated to views outside this view
|
||||
manager can end up being invalidated during step 3. Therefore, the end of a
|
||||
view update batch really needs to traverse the entire view tree, to ensure
|
||||
that those invalidates happen.
|
||||
|
||||
To cope with this, invalidation processing and should only happen on the
|
||||
root viewmanager.
|
||||
To cope with this, invalidate event processing and view update batch
|
||||
handling should only happen on the root viewmanager. This means the root
|
||||
view manager is the only thing keeping track of mUpdateCnt. As a result,
|
||||
Composite() calls should also be forwarded to the root view manager.
|
||||
*/
|
||||
|
||||
class nsInvalidateEvent;
|
||||
|
||||
class nsViewManager : public nsIViewManager {
|
||||
public:
|
||||
nsViewManager();
|
||||
@ -95,9 +104,12 @@ public:
|
||||
NS_IMETHOD SetWindowDimensions(nscoord width, nscoord height);
|
||||
NS_IMETHOD FlushDelayedResize(bool aDoReflow);
|
||||
|
||||
NS_IMETHOD InvalidateView(nsIView *aView);
|
||||
NS_IMETHOD InvalidateViewNoSuppression(nsIView *aView, const nsRect &aRect);
|
||||
NS_IMETHOD InvalidateAllViews();
|
||||
NS_IMETHOD Composite(void);
|
||||
|
||||
NS_IMETHOD UpdateView(nsIView *aView, PRUint32 aUpdateFlags);
|
||||
NS_IMETHOD UpdateViewNoSuppression(nsIView *aView, const nsRect &aRect,
|
||||
PRUint32 aUpdateFlags);
|
||||
NS_IMETHOD UpdateAllViews(PRUint32 aUpdateFlags);
|
||||
|
||||
NS_IMETHOD DispatchEvent(nsGUIEvent *aEvent,
|
||||
nsIView* aTargetView, nsEventStatus* aStatus);
|
||||
@ -125,30 +137,27 @@ public:
|
||||
|
||||
NS_IMETHOD GetDeviceContext(nsDeviceContext *&aContext);
|
||||
|
||||
virtual nsIViewManager* IncrementDisableRefreshCount();
|
||||
virtual void DecrementDisableRefreshCount();
|
||||
virtual nsIViewManager* BeginUpdateViewBatch(void);
|
||||
NS_IMETHOD EndUpdateViewBatch(PRUint32 aUpdateFlags);
|
||||
|
||||
NS_IMETHOD GetRootWidget(nsIWidget **aWidget);
|
||||
NS_IMETHOD ForceUpdate();
|
||||
|
||||
NS_IMETHOD IsPainting(bool& aIsPainting);
|
||||
NS_IMETHOD GetLastUserEventTime(PRUint32& aTime);
|
||||
void ProcessInvalidateEvent();
|
||||
static PRUint32 gLastUserEventTime;
|
||||
|
||||
/* Update the cached RootViewManager pointer on this view manager. */
|
||||
void InvalidateHierarchy();
|
||||
|
||||
virtual void ProcessPendingUpdates();
|
||||
virtual void UpdateWidgetGeometry();
|
||||
|
||||
protected:
|
||||
virtual ~nsViewManager();
|
||||
|
||||
private:
|
||||
|
||||
void FlushPendingInvalidates();
|
||||
void ProcessPendingUpdatesForView(nsView *aView,
|
||||
bool aFlushDirtyRegion = true);
|
||||
void FlushDirtyRegionToWidget(nsView* aView);
|
||||
void ProcessPendingUpdates(nsView *aView, bool aDoInvalidate);
|
||||
/**
|
||||
* Call WillPaint() on all view observers under this vm root.
|
||||
*/
|
||||
@ -156,9 +165,13 @@ private:
|
||||
void CallDidPaintOnObservers();
|
||||
void ReparentChildWidgets(nsIView* aView, nsIWidget *aNewWidget);
|
||||
void ReparentWidgets(nsIView* aView, nsIView *aParent);
|
||||
void InvalidateWidgetArea(nsView *aWidgetView, const nsRegion &aDamagedRegion);
|
||||
void UpdateWidgetArea(nsView *aWidgetView, nsIWidget* aWidget,
|
||||
const nsRegion &aDamagedRegion,
|
||||
nsView* aIgnoreWidgetView);
|
||||
|
||||
void InvalidateViews(nsView *aView);
|
||||
void UpdateViews(nsView *aView, PRUint32 aUpdateFlags);
|
||||
|
||||
void TriggerRefresh(PRUint32 aUpdateFlags);
|
||||
|
||||
// aView is the view for aWidget and aRegion is relative to aWidget.
|
||||
void Refresh(nsView *aView, nsIWidget *aWidget, const nsIntRegion& aRegion);
|
||||
@ -168,14 +181,20 @@ private:
|
||||
const nsRegion& aRegion, const nsIntRegion& aIntRegion,
|
||||
bool aPaintDefaultBackground, bool aWillSendDidPaint);
|
||||
|
||||
void InvalidateRectDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut);
|
||||
void InvalidateRectDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut, PRUint32 aUpdateFlags);
|
||||
void InvalidateHorizontalBandDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut,
|
||||
nscoord aY1, nscoord aY2, bool aInCutOut);
|
||||
PRUint32 aUpdateFlags, nscoord aY1, nscoord aY2, bool aInCutOut);
|
||||
|
||||
// Utilities
|
||||
|
||||
bool IsViewInserted(nsView *aView);
|
||||
|
||||
/**
|
||||
* Function to recursively call Update() on all widgets belonging to
|
||||
* a view or its kids.
|
||||
*/
|
||||
void UpdateWidgetsForView(nsView* aView);
|
||||
|
||||
/**
|
||||
* Intersects aRect with aView's bounds and then transforms it from aView's
|
||||
* coordinate system to the coordinate system of the widget attached to
|
||||
@ -185,6 +204,31 @@ private:
|
||||
|
||||
void DoSetWindowDimensions(nscoord aWidth, nscoord aHeight);
|
||||
|
||||
// Safety helpers
|
||||
void IncrementUpdateCount() {
|
||||
NS_ASSERTION(IsRootVM(),
|
||||
"IncrementUpdateCount called on non-root viewmanager");
|
||||
++mUpdateCnt;
|
||||
}
|
||||
|
||||
void DecrementUpdateCount() {
|
||||
NS_ASSERTION(IsRootVM(),
|
||||
"DecrementUpdateCount called on non-root viewmanager");
|
||||
--mUpdateCnt;
|
||||
}
|
||||
|
||||
PRInt32 UpdateCount() const {
|
||||
NS_ASSERTION(IsRootVM(),
|
||||
"DecrementUpdateCount called on non-root viewmanager");
|
||||
return mUpdateCnt;
|
||||
}
|
||||
|
||||
void ClearUpdateCount() {
|
||||
NS_ASSERTION(IsRootVM(),
|
||||
"DecrementUpdateCount called on non-root viewmanager");
|
||||
mUpdateCnt = 0;
|
||||
}
|
||||
|
||||
bool IsPainting() const {
|
||||
return RootViewManager()->mPainting;
|
||||
}
|
||||
@ -193,21 +237,18 @@ private:
|
||||
RootViewManager()->mPainting = aPainting;
|
||||
}
|
||||
|
||||
nsresult InvalidateView(nsIView *aView, const nsRect &aRect);
|
||||
nsresult UpdateView(nsIView *aView, const nsRect &aRect, PRUint32 aUpdateFlags);
|
||||
|
||||
public: // NOT in nsIViewManager, so private to the view module
|
||||
nsView* GetRootViewImpl() const { return mRootView; }
|
||||
nsViewManager* RootViewManager() const { return mRootViewManager; }
|
||||
bool IsRootVM() const { return this == RootViewManager(); }
|
||||
|
||||
// Whether synchronous painting is allowed at the moment. For example,
|
||||
// widget geometry changes can cause synchronous painting, so they need to
|
||||
// be deferred while refresh is disabled.
|
||||
bool IsPaintingAllowed() { return RootViewManager()->mRefreshDisableCount == 0; }
|
||||
bool IsRefreshEnabled() { return RootViewManager()->mUpdateBatchCnt == 0; }
|
||||
|
||||
// Call this when you need to let the viewmanager know that it now has
|
||||
// pending updates.
|
||||
void PostPendingUpdate();
|
||||
void PostPendingUpdate() { RootViewManager()->mHasPendingUpdates = true; }
|
||||
|
||||
PRUint32 AppUnitsPerDevPixel() const
|
||||
{
|
||||
@ -227,16 +268,21 @@ private:
|
||||
// never null (if we have no ancestors, it will be |this|).
|
||||
nsViewManager *mRootViewManager;
|
||||
|
||||
nsRevocableEventPtr<nsInvalidateEvent> mInvalidateEvent;
|
||||
|
||||
// The following members should not be accessed directly except by
|
||||
// the root view manager. Some have accessor functions to enforce
|
||||
// this, as noted.
|
||||
|
||||
PRInt32 mRefreshDisableCount;
|
||||
// Use IncrementUpdateCount(), DecrementUpdateCount(), UpdateCount(),
|
||||
// ClearUpdateCount() on the root viewmanager to access mUpdateCnt.
|
||||
PRInt32 mUpdateCnt;
|
||||
PRInt32 mUpdateBatchCnt;
|
||||
PRUint32 mUpdateBatchFlags;
|
||||
// Use IsPainting() and SetPainting() to access mPainting.
|
||||
bool mPainting;
|
||||
bool mRecursiveRefreshPending;
|
||||
bool mHasPendingUpdates;
|
||||
bool mHasPendingWidgetGeometryChanges;
|
||||
bool mInScroll;
|
||||
|
||||
//from here to public should be static and locked... MMP
|
||||
@ -244,6 +290,24 @@ private:
|
||||
|
||||
//list of view managers
|
||||
static nsVoidArray *gViewManagers;
|
||||
|
||||
void PostInvalidateEvent();
|
||||
};
|
||||
|
||||
class nsInvalidateEvent : public nsRunnable {
|
||||
public:
|
||||
nsInvalidateEvent(class nsViewManager *vm) : mViewManager(vm) {
|
||||
NS_ASSERTION(mViewManager, "null parameter");
|
||||
}
|
||||
void Revoke() { mViewManager = nsnull; }
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
if (mViewManager)
|
||||
mViewManager->ProcessInvalidateEvent();
|
||||
return NS_OK;
|
||||
}
|
||||
protected:
|
||||
class nsViewManager *mViewManager;
|
||||
};
|
||||
|
||||
#endif /* nsViewManager_h___ */
|
||||
|
@ -737,15 +737,13 @@ class nsPaintEvent : public nsGUIEvent
|
||||
public:
|
||||
nsPaintEvent(bool isTrusted, PRUint32 msg, nsIWidget *w)
|
||||
: nsGUIEvent(isTrusted, msg, w, NS_PAINT_EVENT),
|
||||
willSendDidPaint(false),
|
||||
didSendWillPaint(false)
|
||||
willSendDidPaint(false)
|
||||
{
|
||||
}
|
||||
|
||||
// area that needs repainting
|
||||
nsIntRegion region;
|
||||
bool willSendDidPaint;
|
||||
bool didSendWillPaint;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -118,8 +118,8 @@ typedef nsEventStatus (* EVENT_CALLBACK)(nsGUIEvent *event);
|
||||
#endif
|
||||
|
||||
#define NS_IWIDGET_IID \
|
||||
{ 0xba20ac65, 0xb2a6, 0x4052, \
|
||||
{ 0xa4, 0xcb, 0x65, 0x40, 0xf8, 0x87, 0x9c, 0x55 } }
|
||||
{ 0x6ca77c11, 0xade7, 0x4715, \
|
||||
{ 0x82, 0xe0, 0xfe, 0xae, 0x42, 0xca, 0x5b, 0x1f } }
|
||||
/*
|
||||
* Window shadow styles
|
||||
* Also used for the -moz-window-shadow CSS property
|
||||
@ -1021,10 +1021,21 @@ class nsIWidget : public nsISupports {
|
||||
NS_IMETHOD MakeFullScreen(bool aFullScreen) = 0;
|
||||
|
||||
/**
|
||||
* Invalidate a specified rect for a widget so that it will be repainted
|
||||
* later.
|
||||
* Invalidate a specified rect for a widget and repaints it.
|
||||
*
|
||||
* @param aIsSynchronouse true then repaint synchronously. If false repaint later.
|
||||
* @see #Update()
|
||||
*/
|
||||
NS_IMETHOD Invalidate(const nsIntRect & aRect) = 0;
|
||||
|
||||
NS_IMETHOD Invalidate(const nsIntRect & aRect, bool aIsSynchronous) = 0;
|
||||
|
||||
/**
|
||||
* Force a synchronous repaint of the window if there are dirty rects.
|
||||
*
|
||||
* @see Invalidate()
|
||||
*/
|
||||
|
||||
NS_IMETHOD Update() = 0;
|
||||
|
||||
enum LayerManagerPersistence
|
||||
{
|
||||
|
@ -589,13 +589,20 @@ nsWindow::IsEnabled(bool *aState)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindow::Invalidate(const nsIntRect &aRect)
|
||||
nsWindow::Invalidate(const nsIntRect &aRect,
|
||||
bool aIsSynchronous)
|
||||
{
|
||||
AndroidGeckoEvent *event = new AndroidGeckoEvent(AndroidGeckoEvent::DRAW, aRect);
|
||||
nsAppShell::gAppShell->PostEvent(event);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindow::Update()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsWindow*
|
||||
nsWindow::FindTopLevel()
|
||||
{
|
||||
|
@ -120,7 +120,9 @@ public:
|
||||
NS_IMETHOD SetSizeMode(PRInt32 aMode);
|
||||
NS_IMETHOD Enable(bool aState);
|
||||
NS_IMETHOD IsEnabled(bool *aState);
|
||||
NS_IMETHOD Invalidate(const nsIntRect &aRect);
|
||||
NS_IMETHOD Invalidate(const nsIntRect &aRect,
|
||||
bool aIsSynchronous);
|
||||
NS_IMETHOD Update();
|
||||
NS_IMETHOD SetFocus(bool aRaise = false);
|
||||
NS_IMETHOD GetScreenBounds(nsIntRect &aRect);
|
||||
virtual nsIntPoint WidgetToScreenOffset();
|
||||
|
@ -418,7 +418,7 @@ public:
|
||||
NS_IMETHOD SetFocus(bool aRaise);
|
||||
NS_IMETHOD GetBounds(nsIntRect &aRect);
|
||||
|
||||
NS_IMETHOD Invalidate(const nsIntRect &aRect);
|
||||
NS_IMETHOD Invalidate(const nsIntRect &aRect, bool aIsSynchronous);
|
||||
|
||||
virtual void* GetNativeData(PRUint32 aDataType);
|
||||
virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations);
|
||||
@ -429,6 +429,7 @@ public:
|
||||
{ return aStatus == nsEventStatus_eConsumeNoDefault; }
|
||||
NS_IMETHOD DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus);
|
||||
|
||||
NS_IMETHOD Update();
|
||||
virtual bool GetShouldAccelerate();
|
||||
|
||||
NS_IMETHOD SetCursor(nsCursor aCursor);
|
||||
|
@ -1398,7 +1398,7 @@ static void blinkRgn(RgnHandle rgn)
|
||||
#endif
|
||||
|
||||
// Invalidate this component's visible area
|
||||
NS_IMETHODIMP nsChildView::Invalidate(const nsIntRect &aRect)
|
||||
NS_IMETHODIMP nsChildView::Invalidate(const nsIntRect &aRect, bool aIsSynchronous)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
@ -1408,7 +1408,10 @@ NS_IMETHODIMP nsChildView::Invalidate(const nsIntRect &aRect)
|
||||
NSRect r;
|
||||
nsCocoaUtils::GeckoRectToNSRect(aRect, r);
|
||||
|
||||
if ([NSView focusView]) {
|
||||
if (aIsSynchronous) {
|
||||
[mView displayRect:r];
|
||||
}
|
||||
else if ([NSView focusView]) {
|
||||
// if a view is focussed (i.e. being drawn), then postpone the invalidate so that we
|
||||
// don't lose it.
|
||||
[mView setNeedsPendingDisplayInRect:r];
|
||||
@ -1439,6 +1442,15 @@ inline PRUint16 COLOR8TOCOLOR16(PRUint8 color8)
|
||||
return (color8 << 8) | color8; /* (color8 * 257) == (color8 * 0x0101) */
|
||||
}
|
||||
|
||||
// The OS manages repaints well enough on its own, so we don't have to
|
||||
// flush them out here. In other words, the OS will automatically call
|
||||
// displayIfNeeded at the appropriate times, so we don't need to do it
|
||||
// ourselves. See bmo bug 459319.
|
||||
NS_IMETHODIMP nsChildView::Update()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
nsresult nsChildView::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
|
||||
@ -2508,7 +2520,6 @@ NSEvent* gLastDragMouseDownEvent = nil;
|
||||
#endif
|
||||
// Create the event so we can fill in its region
|
||||
nsPaintEvent paintEvent(true, NS_PAINT, mGeckoChild);
|
||||
paintEvent.didSendWillPaint = true;
|
||||
|
||||
nsIntRect boundingRect =
|
||||
nsIntRect(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height);
|
||||
|
@ -252,7 +252,8 @@ public:
|
||||
|
||||
NS_IMETHOD SetTitle(const nsAString& aTitle);
|
||||
|
||||
NS_IMETHOD Invalidate(const nsIntRect &aRect);
|
||||
NS_IMETHOD Invalidate(const nsIntRect &aRect, bool aIsSynchronous);
|
||||
NS_IMETHOD Update();
|
||||
virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations);
|
||||
virtual LayerManager* GetLayerManager(PLayersChild* aShadowManager = nsnull,
|
||||
LayersBackend aBackendHint = LayerManager::LAYERS_NONE,
|
||||
|
@ -1279,10 +1279,18 @@ NS_IMETHODIMP nsCocoaWindow::SetTitle(const nsAString& aTitle)
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsCocoaWindow::Invalidate(const nsIntRect & aRect)
|
||||
NS_IMETHODIMP nsCocoaWindow::Invalidate(const nsIntRect & aRect, bool aIsSynchronous)
|
||||
{
|
||||
if (mPopupContentView)
|
||||
return mPopupContentView->Invalidate(aRect);
|
||||
return mPopupContentView->Invalidate(aRect, aIsSynchronous);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsCocoaWindow::Update()
|
||||
{
|
||||
if (mPopupContentView)
|
||||
return mPopupContentView->Update();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ nsNativeThemeGTK::RefreshWidgetWindow(nsIFrame* aFrame)
|
||||
if (!vm)
|
||||
return;
|
||||
|
||||
vm->InvalidateAllViews();
|
||||
vm->UpdateAllViews(NS_VMREFRESH_NO_SYNC);
|
||||
}
|
||||
|
||||
static bool IsFrameContentNodeInNamespace(nsIFrame *aFrame, PRUint32 aNamespace)
|
||||
|
@ -1736,7 +1736,8 @@ nsWindow::SetCursor(imgIContainer* aCursor,
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindow::Invalidate(const nsIntRect &aRect)
|
||||
nsWindow::Invalidate(const nsIntRect &aRect,
|
||||
bool aIsSynchronous)
|
||||
{
|
||||
if (!mGdkWindow)
|
||||
return NS_OK;
|
||||
@ -1747,14 +1748,30 @@ nsWindow::Invalidate(const nsIntRect &aRect)
|
||||
rect.width = aRect.width;
|
||||
rect.height = aRect.height;
|
||||
|
||||
LOGDRAW(("Invalidate (rect) [%p]: %d %d %d %d\n", (void *)this,
|
||||
rect.x, rect.y, rect.width, rect.height));
|
||||
LOGDRAW(("Invalidate (rect) [%p]: %d %d %d %d (sync: %d)\n", (void *)this,
|
||||
rect.x, rect.y, rect.width, rect.height, aIsSynchronous));
|
||||
|
||||
gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
|
||||
if (aIsSynchronous)
|
||||
gdk_window_process_updates(mGdkWindow, FALSE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindow::Update()
|
||||
{
|
||||
if (!mGdkWindow)
|
||||
return NS_OK;
|
||||
|
||||
LOGDRAW(("Update [%p] %p\n", this, mGdkWindow));
|
||||
|
||||
gdk_window_process_updates(mGdkWindow, FALSE);
|
||||
// Send the updates to the server.
|
||||
gdk_display_flush(gdk_window_get_display(mGdkWindow));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void*
|
||||
nsWindow::GetNativeData(PRUint32 aDataType)
|
||||
{
|
||||
|
@ -177,7 +177,9 @@ public:
|
||||
NS_IMETHOD SetCursor(nsCursor aCursor);
|
||||
NS_IMETHOD SetCursor(imgIContainer* aCursor,
|
||||
PRUint32 aHotspotX, PRUint32 aHotspotY);
|
||||
NS_IMETHOD Invalidate(const nsIntRect &aRect);
|
||||
NS_IMETHOD Invalidate(const nsIntRect &aRect,
|
||||
bool aIsSynchronous);
|
||||
NS_IMETHOD Update();
|
||||
virtual void* GetNativeData(PRUint32 aDataType);
|
||||
NS_IMETHOD SetTitle(const nsAString& aTitle);
|
||||
NS_IMETHOD SetIcon(const nsAString& aIconSpec);
|
||||
|
@ -617,12 +617,28 @@ NS_METHOD nsWindow::SetFocus(bool aRaise)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_METHOD nsWindow::Invalidate(const nsIntRect& aRect)
|
||||
NS_METHOD nsWindow::Invalidate(const nsIntRect& aRect, bool aIsSynchronous)
|
||||
{
|
||||
if (mWnd) {
|
||||
RECTL rcl = {aRect.x, aRect.y, aRect.x + aRect.width, aRect.y + aRect.height};
|
||||
NS2PM(rcl);
|
||||
WinInvalidateRect(mWnd, &rcl, false);
|
||||
#if 0
|
||||
if (aIsSynchronous) {
|
||||
Update();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Force a synchronous repaint of the window.
|
||||
|
||||
NS_IMETHODIMP nsWindow::Update()
|
||||
{
|
||||
if (mWnd) {
|
||||
WinUpdateWindow(mWnd);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -175,7 +175,9 @@ public:
|
||||
NS_IMETHOD Show(bool aState);
|
||||
NS_IMETHOD IsVisible(bool& aState);
|
||||
NS_IMETHOD SetFocus(bool aRaise);
|
||||
NS_IMETHOD Invalidate(const nsIntRect& aRect);
|
||||
NS_IMETHOD Invalidate(const nsIntRect& aRect,
|
||||
bool aIsSynchronous);
|
||||
NS_IMETHOD Update();
|
||||
gfxASurface* GetThebesSurface();
|
||||
virtual void* GetNativeData(PRUint32 aDataType);
|
||||
virtual void FreeNativeData(void* aDatum, PRUint32 aDataType);
|
||||
|
@ -751,10 +751,11 @@ nsWindow::SetCursor(imgIContainer* aCursor,
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindow::Invalidate(const nsIntRect &aRect)
|
||||
nsWindow::Invalidate(const nsIntRect &aRect,
|
||||
bool aIsSynchronous)
|
||||
{
|
||||
LOGDRAW(("Invalidate (rect) [%p,%p]: %d %d %d %d\n", (void *)this,
|
||||
(void*)mWidget,aRect.x, aRect.y, aRect.width, aRect.height));
|
||||
LOGDRAW(("Invalidate (rect) [%p,%p]: %d %d %d %d (sync: %d)\n", (void *)this,
|
||||
(void*)mWidget,aRect.x, aRect.y, aRect.width, aRect.height, aIsSynchronous));
|
||||
|
||||
if (!mWidget)
|
||||
return NS_OK;
|
||||
@ -763,6 +764,19 @@ nsWindow::Invalidate(const nsIntRect &aRect)
|
||||
|
||||
mWidget->update(aRect.x, aRect.y, aRect.width, aRect.height);
|
||||
|
||||
// QGraphicsItems cannot trigger a repaint themselves, so we start it on the view
|
||||
if (aIsSynchronous) {
|
||||
QWidget *widget = GetViewWidget();
|
||||
if (widget)
|
||||
widget->repaint();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindow::Update()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -173,7 +173,9 @@ public:
|
||||
NS_IMETHOD GetHasTransparentBackground(bool& aTransparent);
|
||||
NS_IMETHOD HideWindowChrome(bool aShouldHide);
|
||||
NS_IMETHOD MakeFullScreen(bool aFullScreen);
|
||||
NS_IMETHOD Invalidate(const nsIntRect &aRect);
|
||||
NS_IMETHOD Invalidate(const nsIntRect &aRect,
|
||||
bool aIsSynchronous);
|
||||
NS_IMETHOD Update();
|
||||
|
||||
virtual void* GetNativeData(PRUint32 aDataType);
|
||||
NS_IMETHOD SetTitle(const nsAString& aTitle);
|
||||
|
@ -1280,12 +1280,8 @@ NS_METHOD nsWindow::Show(bool bState)
|
||||
}
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
if (!wasVisible && bState) {
|
||||
Invalidate();
|
||||
if (syncInvalidate) {
|
||||
::UpdateWindow(mWnd);
|
||||
}
|
||||
}
|
||||
if (!wasVisible && bState)
|
||||
Invalidate(syncInvalidate);
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
@ -1491,7 +1487,7 @@ NS_METHOD nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, bool aRepaint)
|
||||
}
|
||||
|
||||
if (aRepaint)
|
||||
Invalidate();
|
||||
Invalidate(false);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1530,7 +1526,7 @@ NS_METHOD nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeig
|
||||
}
|
||||
|
||||
if (aRepaint)
|
||||
Invalidate();
|
||||
Invalidate(false);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -2021,7 +2017,7 @@ nsWindow::ResetLayout()
|
||||
OnResize(evRect);
|
||||
|
||||
// Invalidate and update
|
||||
Invalidate();
|
||||
Invalidate(false);
|
||||
}
|
||||
|
||||
// Internally track the caption status via a window property. Required
|
||||
@ -2657,7 +2653,8 @@ NS_IMETHODIMP nsWindow::HideWindowChrome(bool aShouldHide)
|
||||
**************************************************************/
|
||||
|
||||
// Invalidate this component visible area
|
||||
NS_METHOD nsWindow::Invalidate(bool aEraseBackground,
|
||||
NS_METHOD nsWindow::Invalidate(bool aIsSynchronous,
|
||||
bool aEraseBackground,
|
||||
bool aUpdateNCArea,
|
||||
bool aIncludeChildren)
|
||||
{
|
||||
@ -2669,6 +2666,7 @@ NS_METHOD nsWindow::Invalidate(bool aEraseBackground,
|
||||
debug_DumpInvalidate(stdout,
|
||||
this,
|
||||
nsnull,
|
||||
aIsSynchronous,
|
||||
nsCAutoString("noname"),
|
||||
(PRInt32) mWnd);
|
||||
#endif // WIDGET_DEBUG_OUTPUT
|
||||
@ -2677,6 +2675,9 @@ NS_METHOD nsWindow::Invalidate(bool aEraseBackground,
|
||||
if (aEraseBackground) {
|
||||
flags |= RDW_ERASE;
|
||||
}
|
||||
if (aIsSynchronous) {
|
||||
flags |= RDW_UPDATENOW;
|
||||
}
|
||||
if (aUpdateNCArea) {
|
||||
flags |= RDW_FRAME;
|
||||
}
|
||||
@ -2689,7 +2690,7 @@ NS_METHOD nsWindow::Invalidate(bool aEraseBackground,
|
||||
}
|
||||
|
||||
// Invalidate this component visible area
|
||||
NS_METHOD nsWindow::Invalidate(const nsIntRect & aRect)
|
||||
NS_METHOD nsWindow::Invalidate(const nsIntRect & aRect, bool aIsSynchronous)
|
||||
{
|
||||
if (mWnd)
|
||||
{
|
||||
@ -2697,6 +2698,7 @@ NS_METHOD nsWindow::Invalidate(const nsIntRect & aRect)
|
||||
debug_DumpInvalidate(stdout,
|
||||
this,
|
||||
&aRect,
|
||||
aIsSynchronous,
|
||||
nsCAutoString("noname"),
|
||||
(PRInt32) mWnd);
|
||||
#endif // WIDGET_DEBUG_OUTPUT
|
||||
@ -2709,6 +2711,10 @@ NS_METHOD nsWindow::Invalidate(const nsIntRect & aRect)
|
||||
rect.bottom = aRect.y + aRect.height;
|
||||
|
||||
VERIFY(::InvalidateRect(mWnd, &rect, FALSE));
|
||||
|
||||
if (aIsSynchronous) {
|
||||
VERIFY(::UpdateWindow(mWnd));
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -2748,7 +2754,7 @@ nsWindow::MakeFullScreen(bool aFullScreen)
|
||||
|
||||
if (visible) {
|
||||
Show(true);
|
||||
Invalidate();
|
||||
Invalidate(false);
|
||||
}
|
||||
|
||||
// Notify the taskbar that we have exited full screen mode.
|
||||
@ -2765,6 +2771,26 @@ nsWindow::MakeFullScreen(bool aFullScreen)
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* SECTION: nsIWidget::Update
|
||||
*
|
||||
* Force a synchronous repaint of the window.
|
||||
*
|
||||
**************************************************************/
|
||||
|
||||
NS_IMETHODIMP nsWindow::Update()
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// updates can come through for windows no longer holding an mWnd during
|
||||
// deletes triggered by JavaScript in buttons with mouse feedback
|
||||
if (mWnd)
|
||||
VERIFY(::UpdateWindow(mWnd));
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* SECTION: Native data storage
|
||||
@ -4655,7 +4681,7 @@ bool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
|
||||
|
||||
// Invalidate the window so that the repaint will
|
||||
// pick up the new theme.
|
||||
Invalidate(true, true, true);
|
||||
Invalidate(true, true, true, true);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -5334,7 +5360,7 @@ bool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
|
||||
BroadcastMsg(mWnd, WM_DWMCOMPOSITIONCHANGED);
|
||||
DispatchStandardEvent(NS_THEMECHANGED);
|
||||
UpdateGlass();
|
||||
Invalidate(true, true, true);
|
||||
Invalidate(true, true, true, true);
|
||||
break;
|
||||
#endif
|
||||
|
||||
@ -7210,7 +7236,7 @@ nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
|
||||
r.Sub(bounds, configuration.mBounds);
|
||||
r.MoveBy(-bounds.x,
|
||||
-bounds.y);
|
||||
w->Invalidate(r.GetBounds());
|
||||
w->Invalidate(r.GetBounds(), false);
|
||||
}
|
||||
}
|
||||
rv = w->SetWindowClipRegion(configuration.mClipRegion, false);
|
||||
@ -7430,7 +7456,7 @@ bool nsWindow::OnResize(nsIntRect &aWindowRect)
|
||||
#ifdef CAIRO_HAS_D2D_SURFACE
|
||||
if (mD2DWindowSurface) {
|
||||
mD2DWindowSurface = NULL;
|
||||
Invalidate();
|
||||
Invalidate(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -142,10 +142,12 @@ public:
|
||||
virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations);
|
||||
NS_IMETHOD MakeFullScreen(bool aFullScreen);
|
||||
NS_IMETHOD HideWindowChrome(bool aShouldHide);
|
||||
NS_IMETHOD Invalidate(bool aEraseBackground = false,
|
||||
NS_IMETHOD Invalidate(bool aIsSynchronous,
|
||||
bool aEraseBackground = false,
|
||||
bool aUpdateNCArea = false,
|
||||
bool aIncludeChildren = false);
|
||||
NS_IMETHOD Invalidate(const nsIntRect & aRect);
|
||||
NS_IMETHOD Invalidate(const nsIntRect & aRect, bool aIsSynchronous);
|
||||
NS_IMETHOD Update();
|
||||
virtual void* GetNativeData(PRUint32 aDataType);
|
||||
virtual void FreeNativeData(void * data, PRUint32 aDataType);
|
||||
NS_IMETHOD SetTitle(const nsAString& aTitle);
|
||||
|
@ -310,7 +310,6 @@ bool nsWindow::OnPaint(HDC aDC, PRUint32 aNestingLevel)
|
||||
#endif
|
||||
event.region = GetRegionToPaint(forceRepaint, ps, hDC);
|
||||
event.willSendDidPaint = true;
|
||||
event.didSendWillPaint = true;
|
||||
|
||||
if (!event.region.IsEmpty() && mEventCallback)
|
||||
{
|
||||
@ -575,7 +574,7 @@ bool nsWindow::OnPaint(HDC aDC, PRUint32 aNestingLevel)
|
||||
// When our device was removed, we should have gfxWindowsPlatform
|
||||
// check if its render mode is up to date!
|
||||
gfxWindowsPlatform::GetPlatform()->UpdateRenderMode();
|
||||
Invalidate();
|
||||
Invalidate(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -586,7 +585,7 @@ bool nsWindow::OnPaint(HDC aDC, PRUint32 aNestingLevel)
|
||||
gfxWindowsPlatform::GetPlatform()->UpdateRenderMode();
|
||||
LayerManagerD3D10 *layerManagerD3D10 = static_cast<mozilla::layers::LayerManagerD3D10*>(GetLayerManager());
|
||||
if (layerManagerD3D10->device() != gfxWindowsPlatform::GetPlatform()->GetD3D10Device()) {
|
||||
Invalidate();
|
||||
Invalidate(false);
|
||||
} else {
|
||||
result = DispatchWindowEvent(&event, eventStatus);
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ InvalidateRegion(nsIWidget* aWidget, const nsIntRegion& aRegion)
|
||||
{
|
||||
nsIntRegionRectIterator it(aRegion);
|
||||
while(const nsIntRect* r = it.Next()) {
|
||||
aWidget->Invalidate(*r);
|
||||
aWidget->Invalidate(*r, false/*async*/);
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,20 +228,25 @@ PuppetWidget::SetFocus(bool aRaise)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PuppetWidget::Invalidate(const nsIntRect& aRect)
|
||||
PuppetWidget::Invalidate(const nsIntRect& aRect, bool aIsSynchronous)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
debug_DumpInvalidate(stderr, this, &aRect,
|
||||
debug_DumpInvalidate(stderr, this, &aRect, aIsSynchronous,
|
||||
nsCAutoString("PuppetWidget"), nsnull);
|
||||
#endif
|
||||
|
||||
if (mChild) {
|
||||
return mChild->Invalidate(aRect);
|
||||
return mChild->Invalidate(aRect, aIsSynchronous);
|
||||
}
|
||||
|
||||
mDirtyRegion.Or(mDirtyRegion, aRect);
|
||||
|
||||
if (!mDirtyRegion.IsEmpty() && !mPaintTask.IsPending()) {
|
||||
if (mDirtyRegion.IsEmpty()) {
|
||||
return NS_OK;
|
||||
} else if (aIsSynchronous) {
|
||||
DispatchPaintEvent();
|
||||
return NS_OK;
|
||||
} else if (!mPaintTask.IsPending()) {
|
||||
mPaintTask = new PaintTask(this);
|
||||
return NS_DispatchToCurrentThread(mPaintTask.get());
|
||||
}
|
||||
@ -249,6 +254,19 @@ PuppetWidget::Invalidate(const nsIntRect& aRect)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PuppetWidget::Update()
|
||||
{
|
||||
if (mChild) {
|
||||
return mChild->Update();
|
||||
}
|
||||
|
||||
if (mDirtyRegion.IsEmpty()) {
|
||||
return NS_OK;
|
||||
}
|
||||
return DispatchPaintEvent();
|
||||
}
|
||||
|
||||
void
|
||||
PuppetWidget::InitEvent(nsGUIEvent& event, nsIntPoint* aPoint)
|
||||
{
|
||||
|
@ -123,7 +123,9 @@ public:
|
||||
virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
|
||||
{ return NS_OK; }
|
||||
|
||||
NS_IMETHOD Invalidate(const nsIntRect& aRect);
|
||||
NS_IMETHOD Invalidate(const nsIntRect& aRect, bool aIsSynchronous);
|
||||
|
||||
NS_IMETHOD Update();
|
||||
|
||||
// This API is going away, steer clear.
|
||||
virtual void Scroll(const nsIntPoint& aDelta,
|
||||
|
@ -1469,6 +1469,7 @@ nsBaseWidget::debug_DumpPaintEvent(FILE * aFileOut,
|
||||
nsBaseWidget::debug_DumpInvalidate(FILE * aFileOut,
|
||||
nsIWidget * aWidget,
|
||||
const nsIntRect * aRect,
|
||||
bool aIsSynchronous,
|
||||
const nsCAutoString & aWidgetName,
|
||||
PRInt32 aWindowID)
|
||||
{
|
||||
@ -1500,6 +1501,10 @@ nsBaseWidget::debug_DumpInvalidate(FILE * aFileOut,
|
||||
" rect=%-15s",
|
||||
"none");
|
||||
}
|
||||
|
||||
fprintf(aFileOut,
|
||||
" sync=%s",
|
||||
(const char *) (aIsSynchronous ? "yes" : "no "));
|
||||
|
||||
fprintf(aFileOut,"\n");
|
||||
}
|
||||
|
@ -297,6 +297,7 @@ protected:
|
||||
static void debug_DumpInvalidate(FILE * aFileOut,
|
||||
nsIWidget * aWidget,
|
||||
const nsIntRect * aRect,
|
||||
bool aIsSynchronous,
|
||||
const nsCAutoString & aWidgetName,
|
||||
PRInt32 aWindowID);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user