Bug 339548. Part 9: Create nsRootPresContext::UpdatePluginGeometry, and use it. Make nsObjectFrame manage its widget directly.

This commit is contained in:
Robert O'Callahan 2009-07-22 12:45:00 +12:00
parent 3da1f8631b
commit dce2b0d98a
17 changed files with 554 additions and 72 deletions

View File

@ -95,7 +95,6 @@
#include "nsIWebNavigation.h"
#include "nsIContentViewer.h"
#include "nsIPrefBranch2.h"
#include "nsIObjectFrame.h"
#ifdef MOZ_XUL
#include "nsXULPopupManager.h"
#endif

View File

@ -1534,9 +1534,7 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
nsIFrame* contentFrame = presShell->GetPrimaryFrameFor(aContent);
nsIObjectFrame* objectFrame = do_QueryFrame(contentFrame);
if (objectFrame) {
nsIView* view = contentFrame->GetViewExternal();
NS_ASSERTION(view, "Object frames must have views");
nsCOMPtr<nsIWidget> widget = view->GetWidget();
nsIWidget* widget = objectFrame->GetWidget();
if (widget)
widget->SetFocus(PR_TRUE);
}

View File

@ -7712,7 +7712,8 @@ nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
// processing restyles
BeginUpdate();
nsPropertyTable *propTable = mPresShell->GetPresContext()->PropertyTable();
nsPresContext* presContext = mPresShell->GetPresContext();
nsPropertyTable *propTable = presContext->PropertyTable();
// Mark frames so that we skip frames that die along the way, bug 123049.
// A frame can be in the list multiple times with different hints. Further
@ -7730,6 +7731,9 @@ nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
}
index = count;
PRBool didInvalidate = PR_FALSE;
PRBool didReflow = PR_FALSE;
while (0 <= --index) {
nsIFrame* frame;
nsIContent* content;
@ -7765,9 +7769,11 @@ nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
#endif
if (hint & nsChangeHint_ReflowFrame) {
StyleChangeReflow(frame);
didReflow = PR_TRUE;
}
if (hint & (nsChangeHint_RepaintFrame | nsChangeHint_SyncFrameView)) {
ApplyRenderingChangeToTree(mPresShell->GetPresContext(), frame, hint);
ApplyRenderingChangeToTree(presContext, frame, hint);
didInvalidate = PR_TRUE;
}
if (hint & nsChangeHint_UpdateCursor) {
nsIViewManager* viewMgr = mPresShell->GetViewManager();
@ -7778,7 +7784,15 @@ nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
}
EndUpdate();
if (didInvalidate && !didReflow) {
// RepaintFrame changes can indicate changes in opacity etc which
// can require plugin clipping to change. If we requested a reflow,
// we don't need to do this since the reflow will do it for us.
nsIFrame* rootFrame = mPresShell->FrameManager()->GetRootFrame();
presContext->RootPresContext()->UpdatePluginGeometry(rootFrame);
}
// cleanup references and verify the style tree. Note that the latter needs
// to happen once we've processed the whole list, since until then the tree
// is not in fact in a consistent state.

View File

@ -389,15 +389,17 @@ public:
*/
enum Type {
TYPE_GENERIC,
TYPE_OUTLINE,
TYPE_BORDER,
TYPE_CLIP,
TYPE_OPACITY,
TYPE_OUTLINE,
TYPE_PLUGIN,
#ifdef MOZ_SVG
TYPE_SVG_EFFECTS,
#endif
TYPE_WRAPLIST,
TYPE_TRANSFORM,
TYPE_BORDER
TYPE_WRAPLIST
};
struct HitTestState {

View File

@ -93,6 +93,7 @@
#include "prenv.h"
#include "nsIPrivateDOMEvent.h"
#include "nsIDOMEventTarget.h"
#include "nsObjectFrame.h"
#ifdef MOZ_SMIL
#include "nsSMILAnimationController.h"
@ -2156,4 +2157,176 @@ nsRootPresContext::nsRootPresContext(nsIDocument* aDocument,
nsPresContextType aType)
: nsPresContext(aDocument, aType)
{
mRegisteredPlugins.Init();
}
nsRootPresContext::~nsRootPresContext()
{
NS_ASSERTION(mRegisteredPlugins.Count() == 0,
"All plugins should have been unregistered");
}
void
nsRootPresContext::RegisterPluginForGeometryUpdates(nsObjectFrame* aPlugin)
{
mRegisteredPlugins.PutEntry(aPlugin);
}
void
nsRootPresContext::UnregisterPluginForGeometryUpdates(nsObjectFrame* aPlugin)
{
mRegisteredPlugins.RemoveEntry(aPlugin);
}
struct PluginGeometryClosure {
nsIFrame* mRootFrame;
nsIFrame* mChangedSubtree;
nsRect mChangedRect;
nsTHashtable<nsPtrHashKey<nsObjectFrame> > mAffectedPlugins;
nsRect mAffectedPluginBounds;
nsTArray<nsIWidget::Configuration>* mOutputConfigurations;
};
static PLDHashOperator
PluginBoundsEnumerator(nsPtrHashKey<nsObjectFrame>* aEntry, void* userArg)
{
PluginGeometryClosure* closure = static_cast<PluginGeometryClosure*>(userArg);
nsObjectFrame* f = aEntry->GetKey();
nsRect fBounds = f->GetContentRect() +
f->GetParent()->GetOffsetTo(closure->mRootFrame);
// We're identifying the plugins that may have been affected by changes
// to the frame subtree rooted at aChangedRoot. Any plugin that overlaps
// the overflow area of aChangedRoot could have its clip region affected
// because it might be covered (or uncovered) by changes to the subtree.
// Plugins in the subtree might have changed position and/or size, and
// they might not be in aChangedRoot's overflow area (because they're
// being clipped by an ancestor in the subtree).
if (fBounds.Intersects(closure->mChangedRect) ||
nsLayoutUtils::IsAncestorFrameCrossDoc(closure->mChangedSubtree, f)) {
closure->mAffectedPluginBounds.UnionRect(
closure->mAffectedPluginBounds, fBounds);
closure->mAffectedPlugins.PutEntry(f);
}
return PL_DHASH_NEXT;
}
static PLDHashOperator
PluginHideEnumerator(nsPtrHashKey<nsObjectFrame>* aEntry, void* userArg)
{
PluginGeometryClosure* closure = static_cast<PluginGeometryClosure*>(userArg);
nsObjectFrame* f = aEntry->GetKey();
f->GetEmptyClipConfiguration(closure->mOutputConfigurations);
return PL_DHASH_NEXT;
}
static void
RecoverPluginGeometry(nsDisplayListBuilder* aBuilder,
nsDisplayList* aList, PluginGeometryClosure* aClosure)
{
for (nsDisplayItem* i = aList->GetBottom(); i; i = i->GetAbove()) {
switch (i->GetType()) {
case nsDisplayItem::TYPE_PLUGIN: {
nsDisplayPlugin* displayPlugin = static_cast<nsDisplayPlugin*>(i);
nsObjectFrame* f = static_cast<nsObjectFrame*>(
displayPlugin->GetUnderlyingFrame());
// Ignore plugins which aren't supposed to be affected by this
// operation --- their bounds will not have been included in the
// display list computations so the visible region computed for them
// would be incorrect
nsPtrHashKey<nsObjectFrame>* entry =
aClosure->mAffectedPlugins.GetEntry(f);
if (entry) {
displayPlugin->GetWidgetConfiguration(aBuilder,
aClosure->mOutputConfigurations);
// we've dealt with this plugin now
aClosure->mAffectedPlugins.RawRemoveEntry(entry);
}
break;
}
default: {
nsDisplayList* sublist = i->GetList();
if (sublist) {
RecoverPluginGeometry(aBuilder, sublist, aClosure);
}
break;
}
}
}
}
#ifdef DEBUG
#include <stdio.h>
static PRBool gDumpPluginList = PR_FALSE;
#endif
void
nsRootPresContext::GetPluginGeometryUpdates(nsIFrame* aChangedSubtree,
nsTArray<nsIWidget::Configuration>* aConfigurations)
{
if (mRegisteredPlugins.Count() == 0)
return;
PluginGeometryClosure closure;
closure.mRootFrame = mShell->FrameManager()->GetRootFrame();
closure.mChangedSubtree = aChangedSubtree;
closure.mChangedRect = aChangedSubtree->GetOverflowRect() +
aChangedSubtree->GetOffsetTo(closure.mRootFrame);
closure.mAffectedPlugins.Init();
closure.mOutputConfigurations = aConfigurations;
// Fill in closure.mAffectedPlugins and closure.mAffectedPluginBounds
mRegisteredPlugins.EnumerateEntries(PluginBoundsEnumerator, &closure);
nsRect bounds;
if (bounds.IntersectRect(closure.mAffectedPluginBounds,
closure.mRootFrame->GetRect())) {
// It's OK to disable GetUsedX assertions because after a reflow,
// any changed geometry will cause UpdatePluginGeometry to happen
// again.
nsAutoDisableGetUsedXAssertions disableAssertions;
nsDisplayListBuilder builder(closure.mRootFrame, PR_FALSE, PR_FALSE);
builder.SetAccurateVisibleRegions();
nsDisplayList list;
builder.EnterPresShell(closure.mRootFrame, bounds);
closure.mRootFrame->BuildDisplayListForStackingContext(
&builder, bounds, &list);
builder.LeavePresShell(closure.mRootFrame, bounds);
#ifdef DEBUG
if (gDumpPluginList) {
fprintf(stderr, "Plugins --- before optimization (bounds %d,%d,%d,%d):\n",
bounds.x, bounds.y, bounds.width, bounds.height);
nsIFrameDebug::PrintDisplayList(&builder, list);
}
#endif
nsRegion visibleRegion(bounds);
list.OptimizeVisibility(&builder, &visibleRegion);
#ifdef DEBUG
if (gDumpPluginList) {
fprintf(stderr, "Plugins --- after optimization:\n");
nsIFrameDebug::PrintDisplayList(&builder, list);
}
#endif
RecoverPluginGeometry(&builder, &list, &closure);
list.DeleteAll();
}
// Plugins that we didn't find in the display list are not visible
closure.mAffectedPlugins.EnumerateEntries(PluginHideEnumerator, &closure);
}
void
nsRootPresContext::UpdatePluginGeometry(nsIFrame* aChangedSubtree)
{
nsTArray<nsIWidget::Configuration> configurations;
GetPluginGeometryUpdates(aChangedSubtree, &configurations);
if (configurations.IsEmpty())
return;
nsIWidget* widget = configurations[0].mChild->GetParent();
NS_ASSERTION(widget, "Plugin must have a parent");
widget->ConfigureChildren(configurations);
}

View File

@ -70,6 +70,7 @@
#include "nsAutoPtr.h"
#include "nsThreadUtils.h"
#include "nsContentUtils.h"
#include "nsIWidget.h"
class nsImageLoader;
#ifdef IBMBIDI
@ -98,6 +99,7 @@ class nsIRunnable;
class gfxUserFontSet;
class nsUserFontSet;
struct nsFontFaceRuleContainer;
class nsObjectFrame;
#ifdef MOZ_REFLOW_PERF
class nsIRenderingContext;
@ -1066,6 +1068,42 @@ public:
class nsRootPresContext : public nsPresContext {
public:
nsRootPresContext(nsIDocument* aDocument, nsPresContextType aType) NS_HIDDEN;
virtual ~nsRootPresContext();
/**
* Registers a plugin to receive geometry updates (position and clip
* region) so it can update its widget.
* Callers must call UnregisterPluginForGeometryUpdates before
* the aPlugin frame is destroyed.
*/
void RegisterPluginForGeometryUpdates(nsObjectFrame* aPlugin);
/**
* Stops a plugin receiving geometry updates (position and clip
* region). If the plugin was not already registered, this does
* nothing.
*/
void UnregisterPluginForGeometryUpdates(nsObjectFrame* aPlugin);
/**
* Iterate through all plugins that are registered for geometry updates
* and update their position and clip region to match the current frame
* tree. Only frames at or under aChangedRoot can have changed their
* geometry.
*/
void UpdatePluginGeometry(nsIFrame* aChangedRoot);
/**
* Iterate through all plugins that are registered for geometry updates
* and compute their position and clip region according to the
* current frame tree. Only frames at or under aChangedRoot can have
* changed their geometry. The computed positions and clip regions are
* appended to aConfigurations.
*/
void GetPluginGeometryUpdates(nsIFrame* aChangedRoot,
nsTArray<nsIWidget::Configuration>* aConfigurations);
private:
nsTHashtable<nsPtrHashKey<nsObjectFrame> > mRegisteredPlugins;
};
#ifdef DEBUG

View File

@ -4629,6 +4629,8 @@ PresShell::UnsuppressAndInvalidate()
rootFrame->Invalidate(rect);
}
mPresContext->RootPresContext()->UpdatePluginGeometry(rootFrame);
// now that painting is unsuppressed, focus may be set on the document
nsPIDOMWindow *win = mDocument->GetWindow();
if (win)
@ -7229,6 +7231,8 @@ PresShell::DoReflow(nsIFrame* target, PRBool aInterruptible)
PostReflowEvent();
}
mPresContext->RootPresContext()->UpdatePluginGeometry(target);
return !interrupted;
}

View File

@ -1816,6 +1816,9 @@ nsGfxScrollFrameInner::ScrollPositionDidChange(nsIScrollableView* aScrollable, n
// Notify that the display has changed
mOuter->InvalidateWithFlags(nsRect(nsPoint(0, 0), mOuter->GetSize()),
nsIFrame::INVALIDATE_NOTIFY_ONLY);
mOuter->PresContext()->RootPresContext()->UpdatePluginGeometry(mOuter);
return NS_OK;
}

View File

@ -1579,6 +1579,8 @@ public:
*
* This function is fastest when aOther is an ancestor of |this|.
*
* This function works across document boundaries.
*
* NOTE: this actually returns the offset from aOther to |this|, but
* that offset is added to transform _coordinates_ from |this| to
* aOther.

View File

@ -89,6 +89,11 @@ public:
* is currently active in this frame.
*/
virtual void StopPlugin() = 0;
/**
* Get the native widget for the plugin, if any.
*/
virtual nsIWidget* GetWidget() = 0;
};
#endif /* nsIObjectFrame_h___ */

View File

@ -116,6 +116,8 @@
#include "nsDOMClassInfo.h"
#include "nsFocusManager.h"
#include "nsLayoutUtils.h"
#include "nsFrameManager.h"
#include "nsComponentManagerUtils.h"
// headers for plugin scriptability
#include "nsIScriptGlobalObject.h"
@ -597,10 +599,19 @@ nsObjectFrame::Destroy()
(mContent && mContent->GetCurrentDoc()->GetDisplayDocument()),
"about to crash due to bug 136927");
PresContext()->RootPresContext()->UnregisterPluginForGeometryUpdates(this);
// we need to finish with the plugin before native window is destroyed
// doing this in the destructor is too late.
StopPluginInternal(PR_TRUE);
// StopPluginInternal might have disowned the widget; if it has,
// mWidget will be null.
if (mWidget) {
GetView()->DetachWidgetEventHandler(mWidget);
mWidget->Destroy();
}
nsObjectFrameSuper::Destroy();
}
@ -640,6 +651,8 @@ nsObjectFrame::CreateWidgetForView(nsIView* aView)
// Bug 179822: Create widget and allow non-unicode SubClass
nsWidgetInitData initData;
initData.mUnicode = PR_FALSE;
initData.clipChildren = PR_TRUE;
initData.clipSiblings = PR_TRUE;
return aView->CreateWidget(kWidgetCID, &initData);
}
@ -659,6 +672,11 @@ nsObjectFrame::CreateWidget(nscoord aWidth,
// XXX is the above comment correct?
viewMan->SetViewVisibility(view, nsViewVisibility_kHide);
PRBool usewidgets;
nsCOMPtr<nsIDeviceContext> dx;
viewMan->GetDeviceContext(*getter_AddRefs(dx));
dx->SupportsNativeWidgets(usewidgets);
//this is ugly. it was ripped off from didreflow(). MMP
// Position and size view relative to its parent, not relative to our
// parent frame (our parent frame may not have a view).
@ -671,14 +689,38 @@ nsObjectFrame::CreateWidget(nscoord aWidth,
viewMan->ResizeView(view, r);
viewMan->MoveViewTo(view, origin.x, origin.y);
if (!aViewOnly && !view->HasWidget()) {
nsresult rv = CreateWidgetForView(view);
if (NS_FAILED(rv)) {
return NS_OK; //XXX why OK? MMP
}
if (!aViewOnly && !mWidget && usewidgets) {
nsresult rv;
mWidget = do_CreateInstance(kWidgetCID, &rv);
if (NS_FAILED(rv))
return rv;
nsRootPresContext* rpc = PresContext()->RootPresContext();
// XXX this breaks plugins in popups ... do we care?
nsIWidget* parentWidget =
rpc->PresShell()->FrameManager()->GetRootFrame()->GetWindow();
nsWidgetInitData initData;
initData.mUnicode = PR_FALSE;
initData.clipChildren = PR_TRUE;
initData.clipSiblings = PR_TRUE;
// We want mWidget to be able to deliver events to us, especially on
// Mac where events to the plugin are routed through Gecko. So we
// allow the view to attach its event handler to mWidget even though
// mWidget isn't the view's designated widget.
EVENT_CALLBACK eventHandler = view->AttachWidgetEventHandler(mWidget);
mWidget->Create(parentWidget, nsIntRect(0,0,0,0),
eventHandler, dx, nsnull, nsnull, &initData);
mWidget->EnableDragDrop(PR_TRUE);
rpc->RegisterPluginForGeometryUpdates(this);
rpc->UpdatePluginGeometry(this);
mWidget->Show(PR_TRUE);
}
{
if (mWidget) {
// Here we set the background color for this widget because some plugins will use
// the child window background color when painting. If it's not set, it may default to gray
// Sometimes, a frame doesn't have a background color or is transparent. In this
@ -686,13 +728,10 @@ nsObjectFrame::CreateWidget(nscoord aWidth,
for (nsIFrame* frame = this; frame; frame = frame->GetParent()) {
const nsStyleBackground* background = frame->GetStyleBackground();
if (!background->IsTransparent()) { // make sure we got an actual color
nsIWidget* win = view->GetWidget();
if (win)
win->SetBackgroundColor(background->mBackgroundColor);
mWidget->SetBackgroundColor(background->mBackgroundColor);
break;
}
}
}
if (!IsHidden()) {
@ -1071,11 +1110,97 @@ nsObjectFrame::PaintPrintPlugin(nsIFrame* aFrame, nsIRenderingContext* aCtx,
static_cast<nsObjectFrame*>(aFrame)->PrintPlugin(*aCtx, aDirtyRect);
}
/*static */ void
nsObjectFrame::PaintPlugin(nsIFrame* aFrame, nsIRenderingContext* aCtx,
const nsRect& aDirtyRect, nsPoint aPt)
nsRect
nsDisplayPlugin::GetBounds(nsDisplayListBuilder* aBuilder)
{
static_cast<nsObjectFrame*>(aFrame)->PaintPlugin(*aCtx, aDirtyRect, aPt);
return mFrame->GetContentRect() +
aBuilder->ToReferenceFrame(mFrame->GetParent());
}
void
nsDisplayPlugin::Paint(nsDisplayListBuilder* aBuilder,
nsIRenderingContext* aCtx,
const nsRect& aDirtyRect)
{
nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
f->PaintPlugin(*aCtx, aDirtyRect, GetBounds(aBuilder).TopLeft());
}
PRBool
nsDisplayPlugin::OptimizeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion)
{
mVisibleRegion.And(*aVisibleRegion, GetBounds(aBuilder));
return nsDisplayItem::OptimizeVisibility(aBuilder, aVisibleRegion);
}
PRBool
nsDisplayPlugin::IsOpaque(nsDisplayListBuilder* aBuilder)
{
nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
return f->IsOpaque();
}
void
nsDisplayPlugin::GetWidgetConfiguration(nsDisplayListBuilder* aBuilder,
nsTArray<nsIWidget::Configuration>* aConfigurations)
{
nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
f->ComputeWidgetGeometry(mVisibleRegion, aBuilder->ToReferenceFrame(mFrame),
aConfigurations);
}
void
nsObjectFrame::ComputeWidgetGeometry(const nsRegion& aRegion,
const nsPoint& aPluginOrigin,
nsTArray<nsIWidget::Configuration>* aConfigurations)
{
if (!mWidget)
return;
nsIWidget::Configuration* configuration =
aConfigurations->AppendElement();
if (!configuration)
return;
configuration->mChild = mWidget;
nsPresContext* presContext = PresContext();
PRInt32 appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
nsIFrame* rootFrame =
presContext->RootPresContext()->PresShell()->FrameManager()->GetRootFrame();
nsRect bounds = GetContentRect() + GetParent()->GetOffsetTo(rootFrame);
configuration->mBounds = bounds.ToNearestPixels(appUnitsPerDevPixel);
nsRegionRectIterator iter(aRegion);
nsIntPoint pluginOrigin = aPluginOrigin.ToNearestPixels(appUnitsPerDevPixel);
for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
// Snap *r to pixels while it's relative to the painted widget, to
// improve consistency with rectangle and image drawing
nsIntRect pixRect =
r->ToNearestPixels(appUnitsPerDevPixel) - pluginOrigin;
if (!pixRect.IsEmpty()) {
configuration->mClipRegion.AppendElement(pixRect);
}
}
}
PRBool
nsObjectFrame::IsOpaque() const
{
#if defined(XP_MACOSX)
return PR_FALSE;
#else
if (mInstanceOwner) {
nsPluginWindow * window;
mInstanceOwner->GetWindow(window);
if (window->type == nsPluginWindowType_Drawable) {
// XXX we possibly should call nsPluginInstanceVariable_TransparentBool
// here to optimize for windowless but opaque plugins
return PR_FALSE;
}
}
return PR_TRUE;
#endif
}
NS_IMETHODIMP
@ -1104,7 +1229,7 @@ nsObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
nsDisplayGeneric(this, PaintPrintPlugin, "PrintPlugin"));
return aLists.Content()->AppendNewToTop(new (aBuilder)
nsDisplayGeneric(this, PaintPlugin, "Plugin"));
nsDisplayPlugin(this));
}
void
@ -2122,17 +2247,12 @@ nsObjectFrame::StopPluginInternal(PRBool aDelayedStop)
nsWeakFrame weakFrame(this);
#if defined(XP_WIN) || defined(MOZ_X11)
if (aDelayedStop) {
if (aDelayedStop && mWidget) {
// If we're asked to do a delayed stop it means we're stopping the
// plugin because we're destroying the frame. In that case, tell
// the view to disown the widget (i.e. leave it up to us to
// destroy it).
// Disown the view while we still know it's safe to do so.
nsIView *view = GetView();
if (view) {
view->DisownWidget();
}
// plugin because we're destroying the frame. In that case, disown
// the widget.
GetView()->DetachWidgetEventHandler(mWidget);
mWidget = nsnull;
}
#endif
@ -4855,11 +4975,7 @@ NS_IMETHODIMP nsPluginInstanceOwner::CreateWidget(void)
context->DevPixelsToAppUnits(mPluginWindow->height),
windowless);
if (NS_OK == rv) {
view = mOwner->GetView();
if (view) {
mWidget = view->GetWidget();
}
mWidget = mOwner->GetWidget();
if (PR_TRUE == windowless) {
mPluginWindow->type = nsPluginWindowType_Drawable;
@ -4938,23 +5054,16 @@ WindowRef nsPluginInstanceOwner::FixUpPluginWindow(PRInt32 inPaintState)
if (!pluginPort)
return nsnull;
// first, check our view for CSS visibility style
PRBool isVisible =
mOwner->GetView()->GetVisibility() == nsViewVisibility_kShow;
nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
nsIntPoint pluginOrigin;
nsIntRect widgetClip;
PRBool widgetVisible;
pluginWidget->GetPluginClipRect(widgetClip, pluginOrigin, widgetVisible);
mWidgetVisible = widgetVisible;
// printf("GetPluginClipRect returning visible %d\n", widgetVisible);
isVisible &= widgetVisible;
if (!isVisible)
widgetClip.Empty();
#ifndef NP_NO_QUICKDRAW
// set the port coordinates
if (drawingModel == NPDrawingModelQuickDraw) {
@ -4985,8 +5094,6 @@ WindowRef nsPluginInstanceOwner::FixUpPluginWindow(PRInt32 inPaintState)
mPluginWindow->clipRect.top = widgetClip.y;
mPluginWindow->clipRect.left = widgetClip.x;
mWidgetVisible = isVisible;
if (!mWidgetVisible || inPaintState == ePluginPaintDisable) {
mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top;
mPluginWindow->clipRect.right = mPluginWindow->clipRect.left;

View File

@ -46,6 +46,8 @@
#include "nsIObjectFrame.h"
#include "nsFrame.h"
#include "nsRegion.h"
#include "nsDisplayList.h"
#ifdef ACCESSIBILITY
class nsIAccessible;
@ -55,6 +57,7 @@ class nsPluginInstanceOwner;
class nsIPluginHost;
class nsIPluginInstance;
class nsPresContext;
class nsDisplayPlugin;
#define nsObjectFrameSuper nsFrame
@ -123,6 +126,18 @@ public:
return NS_ERROR_NOT_IMPLEMENTED;
}
// Compute the desired position of the plugin's widget, on the assumption
// that it is not visible (clipped out or covered by opaque content).
// This will only be called for plugins which have been registered
// with the root pres context for geometry updates.
// The widget, its new position, size and (empty) clip region are appended
// as a Configuration record to aConfigurations.
// If there is no widget associated with the plugin, this
// simply does nothing.
void GetEmptyClipConfiguration(nsTArray<nsIWidget::Configuration>* aConfigurations) {
ComputeWidgetGeometry(nsRegion(), nsPoint(0,0), aConfigurations);
}
// accessibility support
#ifdef ACCESSIBILITY
NS_IMETHOD GetAccessible(nsIAccessible** aAccessible);
@ -168,6 +183,8 @@ protected:
// check attributes and optionally CSS to see if we should display anything
PRBool IsHidden(PRBool aCheckVisibilityStyle = PR_TRUE) const;
PRBool IsOpaque() const;
void NotifyContentObjectWrapper();
nsIntPoint GetWindowOriginInPixels(PRBool aWindowless);
@ -189,9 +206,27 @@ protected:
*/
NS_HIDDEN_(nsresult) PrepareInstanceOwner();
/**
* Get the widget geometry for the plugin. aRegion is in some appunits
* coordinate system whose origin is device-pixel-aligned (if possible),
* and aPluginOrigin gives the top-left of the plugin in that coordinate
* system. It doesn't matter what that coordinate system actually is,
* as long as aRegion and aPluginOrigin are consistent.
* This will append a Configuration object to aConfigurations
* containing the widget, its desired position, size and clip region.
*/
void ComputeWidgetGeometry(const nsRegion& aRegion,
const nsPoint& aPluginOrigin,
nsTArray<nsIWidget::Configuration>* aConfigurations);
nsIWidget* GetWidget() { return mWidget; }
friend class nsPluginInstanceOwner;
friend class nsDisplayPlugin;
private:
nsRefPtr<nsPluginInstanceOwner> mInstanceOwner;
nsCOMPtr<nsIWidget> mWidget;
nsIntRect mWindowlessRect;
// For assertions that make it easier to determine if a crash is due
@ -200,5 +235,41 @@ private:
PRBool mPreventInstantiation;
};
class nsDisplayPlugin : public nsDisplayItem {
public:
nsDisplayPlugin(nsIFrame* aFrame)
: nsDisplayItem(aFrame)
{
MOZ_COUNT_CTOR(nsDisplayPlugin);
}
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplayPlugin() {
MOZ_COUNT_DTOR(nsDisplayPlugin);
}
#endif
virtual Type GetType() { return TYPE_PLUGIN; }
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
virtual PRBool IsOpaque(nsDisplayListBuilder* aBuilder);
virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx,
const nsRect& aDirtyRect);
virtual PRBool OptimizeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion);
NS_DISPLAY_DECL_NAME("Plugin")
// Compute the desired position and clip region of the plugin's widget.
// This will only be called for plugins which have been registered
// with the root pres context for geometry updates.
// The widget, its new position, size and clip region are appended as
// a Configuration record to aConfigurations.
// If there is no widget associated with the plugin, this
// simply does nothing.
void GetWidgetConfiguration(nsDisplayListBuilder* aBuilder,
nsTArray<nsIWidget::Configuration>* aConfigurations);
private:
nsRegion mVisibleRegion;
};
#endif /* nsObjectFrame_h___ */

View File

@ -43,6 +43,7 @@
#include "nsRect.h"
#include "nsPoint.h"
#include "nsNativeWidget.h"
#include "nsIWidget.h"
#include "nsWidgetInitData.h"
class nsIViewManager;
@ -323,6 +324,17 @@ public:
mVFlags |= NS_VIEW_DISOWNS_WIDGET;
}
/**
* Make aWidget direct its events to this view.
* The caller must call DetachWidgetEventHandler before this view
* is destroyed.
*/
EVENT_CALLBACK AttachWidgetEventHandler(nsIWidget* aWidget);
/**
* Stop aWidget directing its events to this view.
*/
void DetachWidgetEventHandler(nsIWidget* aWidget);
/**
* If called, will make the view invalidate its frame instead of BitBlitting
* it when there's a scroll.

View File

@ -730,6 +730,31 @@ nsresult nsView::LoadWidget(const nsCID &aClassIID)
return rv;
}
EVENT_CALLBACK nsIView::AttachWidgetEventHandler(nsIWidget* aWidget)
{
#ifdef DEBUG
void* data = nsnull;
aWidget->GetClientData(data);
NS_ASSERTION(!data, "Already got client data");
#endif
nsView* v = static_cast<nsView*>(this);
ViewWrapper* wrapper = new ViewWrapper(v);
if (!wrapper)
return nsnull;
NS_ADDREF(wrapper); // Will be released in DetachWidgetEventHandler
aWidget->SetClientData(wrapper);
return ::HandleEvent;
}
void nsIView::DetachWidgetEventHandler(nsIWidget* aWidget)
{
ViewWrapper* wrapper = GetWrapperFor(aWidget);
NS_ASSERTION(!wrapper || wrapper->GetView() == this, "Wrong view");
NS_IF_RELEASE(wrapper);
aWidget->SetClientData(nsnull);
}
#ifdef DEBUG
void nsIView::List(FILE* out, PRInt32 aIndent) const
{

View File

@ -63,6 +63,7 @@
#include "nsThreadUtils.h"
#include "nsContentUtils.h"
#include "gfxContext.h"
#include "nsIPluginWidget.h"
static NS_DEFINE_IID(kBlenderCID, NS_BLENDER_CID);
static NS_DEFINE_IID(kRegionCID, NS_REGION_CID);
@ -469,8 +470,6 @@ void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext,
SetPainting(PR_TRUE);
nsCOMPtr<nsIRenderingContext> localcx;
NS_ASSERTION(aView->GetWidget(),
"Must have a widget to calculate coordinates correctly");
if (nsnull == aContext)
{
localcx = CreateRenderingContext(*aView);
@ -568,7 +567,16 @@ void nsViewManager::ProcessPendingUpdates(nsView* aView, PRBool aDoInvalidate)
NS_ASSERTION(mRefreshEnabled, "Cannot process pending updates with refresh disabled");
nsRegion* dirtyRegion = aView->GetDirtyRegion();
if (dirtyRegion) {
UpdateWidgetArea(aView, *dirtyRegion, nsnull);
nsView* nearestViewWithWidget = aView;
while (!nearestViewWithWidget->HasWidget() &&
nearestViewWithWidget->GetParent()) {
nearestViewWithWidget =
static_cast<nsView*>(nearestViewWithWidget->GetParent());
}
nsRegion r = *dirtyRegion;
r.MoveBy(aView->GetOffsetTo(nearestViewWithWidget));
UpdateWidgetArea(nearestViewWithWidget,
nearestViewWithWidget->GetNearestWidget(nsnull), r, nsnull);
dirtyRegion->SetEmpty();
}
}
@ -675,13 +683,15 @@ nsViewManager::UpdateViewAfterScroll(nsView *aView, const nsRegion& aUpdateRegio
nsPoint offset = aView->GetOffsetTo(displayRoot);
damageRect.MoveBy(offset);
UpdateWidgetArea(displayRoot, nsRegion(damageRect), aView);
UpdateWidgetArea(displayRoot, displayRoot->GetNearestWidget(nsnull),
nsRegion(damageRect), aView);
if (!aUpdateRegion.IsEmpty()) {
// XXX We should update the region, not the bounds rect, but that requires
// a little more work. Fix this when we reshuffle this code.
nsRegion update(aUpdateRegion);
update.MoveBy(offset);
UpdateWidgetArea(displayRoot, update, nsnull);
UpdateWidgetArea(displayRoot, displayRoot->GetNearestWidget(nsnull),
update, nsnull);
// FlushPendingInvalidates();
}
@ -689,14 +699,32 @@ nsViewManager::UpdateViewAfterScroll(nsView *aView, const nsRegion& aUpdateRegio
--RootViewManager()->mScrollCnt;
}
static PRBool
IsWidgetDrawnByPlugin(nsIWidget* aWidget, nsIView* aView)
{
if (aView->GetWidget() == aWidget)
return PR_FALSE;
nsCOMPtr<nsIPluginWidget> pw = do_QueryInterface(aWidget);
if (pw) {
// It's a plugin widget, but one that we are responsible for painting
// (i.e., a Mac widget)
return PR_FALSE;
}
return PR_TRUE;
}
/**
* @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::UpdateWidgetArea(nsView *aWidgetView, const nsRegion &aDamagedRegion,
nsViewManager::UpdateWidgetArea(nsView *aWidgetView, nsIWidget* aWidget,
const nsRegion &aDamagedRegion,
nsView* aIgnoreWidgetView)
{
if (!IsRefreshEnabled()) {
@ -727,11 +755,9 @@ nsViewManager::UpdateWidgetArea(nsView *aWidgetView, const nsRegion &aDamagedReg
// If the widget is hidden, it don't cover nothing
if (nsViewVisibility_kHide == aWidgetView->GetVisibility()) {
#ifdef DEBUG
// Assert if view is hidden but widget is visible
nsIWidget* widget = aWidgetView->GetNearestWidget(nsnull);
if (widget) {
if (aWidget) {
PRBool visible;
widget->IsVisible(visible);
aWidget->IsVisible(visible);
NS_ASSERTION(!visible, "View is hidden but widget is visible!");
}
#endif
@ -743,8 +769,7 @@ nsViewManager::UpdateWidgetArea(nsView *aWidgetView, const nsRegion &aDamagedReg
return;
}
nsIWidget* widget = aWidgetView->GetNearestWidget(nsnull);
if (!widget) {
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.
@ -755,13 +780,15 @@ nsViewManager::UpdateWidgetArea(nsView *aWidgetView, const nsRegion &aDamagedReg
// 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);
NS_ASSERTION(view != aWidgetView, "will recur infinitely");
if (view && view->GetVisibility() == nsViewVisibility_kShow) {
PRBool visible;
childWidget->IsVisible(visible);
if (view && visible && !IsWidgetDrawnByPlugin(childWidget, view)) {
// Don't mess with views that are in completely different view
// manager trees
if (view->GetViewManager()->RootViewManager() == RootViewManager()) {
@ -769,7 +796,7 @@ nsViewManager::UpdateWidgetArea(nsView *aWidgetView, const nsRegion &aDamagedReg
nsRegion damage = intersection;
nsPoint offset = view->GetOffsetTo(aWidgetView);
damage.MoveBy(-offset);
UpdateWidgetArea(view, damage, aIgnoreWidgetView);
UpdateWidgetArea(view, childWidget, damage, aIgnoreWidgetView);
nsIntRect bounds;
childWidget->GetBounds(bounds);
@ -795,7 +822,7 @@ nsViewManager::UpdateWidgetArea(nsView *aWidgetView, const nsRegion &aDamagedReg
const nsRect* r;
for (nsRegionRectIterator iter(leftOver); (r = iter.Next());) {
nsIntRect bounds = ViewToWidget(aWidgetView, aWidgetView, *r);
widget->Invalidate(bounds, PR_FALSE);
aWidget->Invalidate(bounds, PR_FALSE);
}
}
}
@ -824,7 +851,8 @@ NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, const nsRect &aRect, PRU
// can overlap each other and be translucent. So we have to possibly
// invalidate our rect in each of the widgets we have lying about.
damagedRect.MoveBy(view->GetOffsetTo(displayRoot));
UpdateWidgetArea(displayRoot, nsRegion(damagedRect), nsnull);
UpdateWidgetArea(displayRoot, displayRoot->GetNearestWidget(nsnull),
nsRegion(damagedRect), nsnull);
RootViewManager()->IncrementUpdateCount();

View File

@ -210,7 +210,8 @@ private:
void ReparentChildWidgets(nsIView* aView, nsIWidget *aNewWidget);
void ReparentWidgets(nsIView* aView, nsIView *aParent);
already_AddRefed<nsIRenderingContext> CreateRenderingContext(nsView &aView);
void UpdateWidgetArea(nsView *aWidgetView, const nsRegion &aDamagedRegion,
void UpdateWidgetArea(nsView *aWidgetView, nsIWidget* aWidget,
const nsRegion &aDamagedRegion,
nsView* aIgnoreWidgetView);
void UpdateViews(nsView *aView, PRUint32 aUpdateFlags);

View File

@ -44,8 +44,8 @@
{0xd530ce43, 0x8f6e, 0x45c5, \
{ 0xa9, 0x84, 0x35, 0xc4, 0x3d, 0xa1, 0x90, 0x73 }}
struct nsRect;
struct nsPoint;
struct nsIntPoint;
class nsIPluginInstanceOwner;
class NS_NO_VTABLE nsIPluginWidget : public nsISupports
{