Bug 1095754 - In the chrome process, combine content side plugin widget geometry with chrome layer clipping and transform data, and apply this to native plugin widgets when we compose. r=roc

This commit is contained in:
Jim Mathies 2015-01-29 13:41:55 -06:00
parent 3a91f3de77
commit 464ba3bc8d
5 changed files with 189 additions and 2 deletions

View File

@ -22,6 +22,10 @@
#include "FrameLayerBuilder.h"
#include "mozilla/dom/TabChild.h"
#include "mozilla/unused.h"
#include "mozilla/DebugOnly.h"
#if defined(XP_WIN)
#include "WinUtils.h"
#endif
using mozilla::layers::LayerTransactionChild;
using mozilla::dom::TabChildBase;
@ -135,6 +139,118 @@ CompositorChild::RecvInvalidateAll()
return true;
}
#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
static void CalculatePluginClip(const nsIntRect& aBounds,
const nsTArray<nsIntRect>& aPluginClipRects,
const nsIntPoint& aContentOffset,
const nsIntRegion& aParentLayerVisibleRegion,
nsTArray<nsIntRect>& aResult,
nsIntRect& aVisibleBounds,
bool& aPluginIsVisible)
{
aPluginIsVisible = true;
// aBounds (content origin)
nsIntRegion contentVisibleRegion(aBounds);
// aPluginClipRects (plugin widget origin)
for (uint32_t idx = 0; idx < aPluginClipRects.Length(); idx++) {
nsIntRect rect = aPluginClipRects[idx];
// shift to content origin
rect.MoveBy(aBounds.x, aBounds.y);
contentVisibleRegion.AndWith(rect);
}
// apply layers clip (window origin)
nsIntRegion region = aParentLayerVisibleRegion;
region.MoveBy(-aContentOffset.x, -aContentOffset.y);
contentVisibleRegion.AndWith(region);
if (contentVisibleRegion.IsEmpty()) {
aPluginIsVisible = false;
return;
}
// shift to plugin widget origin
contentVisibleRegion.MoveBy(-aBounds.x, -aBounds.y);
nsIntRegionRectIterator iter(contentVisibleRegion);
for (const nsIntRect* rgnRect = iter.Next(); rgnRect; rgnRect = iter.Next()) {
aResult.AppendElement(*rgnRect);
aVisibleBounds.UnionRect(aVisibleBounds, *rgnRect);
}
}
#endif
bool
CompositorChild::RecvUpdatePluginConfigurations(const nsIntPoint& aContentOffset,
const nsIntRegion& aParentLayerVisibleRegion,
nsTArray<PluginWindowData>&& aPlugins)
{
#if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
NS_NOTREACHED("CompositorChild::RecvUpdatePluginConfigurations calls "
"unexpected on this platform.");
return false;
#else
// Now that we are on the main thread, update plugin widget config.
// This should happen a little before we paint to the screen assuming
// the main thread is running freely.
DebugOnly<nsresult> rv;
MOZ_ASSERT(NS_IsMainThread());
// Tracks visible plugins we update, so we can hide any plugins we don't.
nsTArray<uintptr_t> visiblePluginIds;
for (uint32_t pluginsIdx = 0; pluginsIdx < aPlugins.Length(); pluginsIdx++) {
nsIWidget* widget = nsIWidget::LookupRegisteredPluginWindow(aPlugins[pluginsIdx].windowId());
bool isVisible = aPlugins[pluginsIdx].visible();
if (widget && !widget->Destroyed()) {
nsIntRect bounds;
nsIntRect visibleBounds;
// If the plugin is visible update it's geometry.
if (isVisible) {
// bounds (content origin) - don't pass true to Resize, it triggers a
// sync paint update to the plugin process on Windows, which happens
// prior to clipping information being applied.
bounds = aPlugins[pluginsIdx].bounds();
rv = widget->Resize(aContentOffset.x + bounds.x,
aContentOffset.y + bounds.y,
bounds.width, bounds.height, false);
NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure");
nsTArray<nsIntRect> rectsOut;
CalculatePluginClip(bounds, aPlugins[pluginsIdx].clip(),
aContentOffset, aParentLayerVisibleRegion,
rectsOut, visibleBounds, isVisible);
if (isVisible) {
// content clipping region (widget origin)
rv = widget->SetWindowClipRegion(rectsOut, false);
NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure");
}
}
// visible state - updated after clipping, prior to invalidating
rv = widget->Show(isVisible);
NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure");
// Handle invalidation, this can be costly, avoid if it is not needed.
if (isVisible) {
// invalidate region (widget origin)
nsIntRect bounds = aPlugins[pluginsIdx].bounds();
nsIntRect rect(0, 0, bounds.width, bounds.height);
#if defined(XP_WIN)
// Work around for flash's crummy sandbox. See bug 762948. This call
// digs down into the window hirearchy, invalidating regions on
// windows owned by other processes.
mozilla::widget::WinUtils::InvalidatePluginAsWorkaround(widget, visibleBounds);
#else
rv = widget->Invalidate(visibleBounds);
NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure");
#endif
visiblePluginIds.AppendElement(aPlugins[pluginsIdx].windowId());
}
}
}
// Any plugins we didn't update need to be hidden, as they are
// not associated with visible content.
nsIWidget::UpdateRegisteredPluginWindowVisibility(visiblePluginIds);
return true;
#endif // !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
}
bool
CompositorChild::RecvDidComposite(const uint64_t& aId, const uint64_t& aTransactionId)
{

View File

@ -70,6 +70,11 @@ public:
virtual bool RecvDidComposite(const uint64_t& aId, const uint64_t& aTransactionId) MOZ_OVERRIDE;
virtual bool
RecvUpdatePluginConfigurations(const nsIntPoint& aContentOffset,
const nsIntRegion& aVisibleRegion,
nsTArray<PluginWindowData>&& aPlugins) MOZ_OVERRIDE;
/**
* Request that the parent tell us when graphics are ready on GPU.
* When we get that message, we bounce it to the TabParent via

View File

@ -84,6 +84,7 @@ CompositorParent::LayerTreeState::LayerTreeState()
, mLayerManager(nullptr)
, mCrossProcessParent(nullptr)
, mLayerTree(nullptr)
, mUpdatedPluginDataAvailable(false)
{
}
@ -1695,6 +1696,7 @@ CrossProcessCompositorParent::ShadowLayersUpdated(
LayerTransactionParent* aLayerTree,
const uint64_t& aTransactionId,
const TargetConfig& aTargetConfig,
const InfallibleTArray<PluginWindowData>& aPlugins,
bool aIsFirstPaint,
bool aScheduleComposite,
uint32_t aPaintSequenceNumber,
@ -1704,7 +1706,7 @@ CrossProcessCompositorParent::ShadowLayersUpdated(
MOZ_ASSERT(id != 0);
const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(id);
CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(id);
if (!state) {
return;
}
@ -1717,6 +1719,10 @@ CrossProcessCompositorParent::ShadowLayersUpdated(
}
UpdateIndirectTree(id, shadowRoot, aTargetConfig);
// Cache the plugin data for this remote layer tree
state->mPluginData = aPlugins;
state->mUpdatedPluginDataAvailable = !!state->mPluginData.Length();
state->mParent->NotifyShadowTreeTransaction(id, aIsFirstPaint, aScheduleComposite,
aPaintSequenceNumber, aIsRepeatTransaction);
@ -1729,6 +1735,62 @@ CrossProcessCompositorParent::ShadowLayersUpdated(
aLayerTree->SetPendingTransactionId(aTransactionId);
}
// Sends plugin window state changes to the main thread
static void
UpdatePluginWindowState(uint64_t aId)
{
CompositorParent::LayerTreeState& lts = sIndirectLayerTrees[aId];
if (!lts.mPluginData.Length()) {
return;
}
bool shouldComposePlugin = !!lts.mRoot &&
!!lts.mRoot->GetParent() &&
lts.mUpdatedPluginDataAvailable;
bool shouldHidePlugin = (!lts.mRoot ||
!lts.mRoot->GetParent()) &&
!lts.mUpdatedPluginDataAvailable;
if (shouldComposePlugin) {
// Retrieve the offset and visible region of the layer that hosts
// the plugins, CompositorChild needs these in calculating proper
// plugin clipping.
LayerTransactionParent* layerTree = lts.mLayerTree;
Layer* contentRoot = layerTree->GetRoot();
if (contentRoot) {
nsIntPoint offset;
nsIntRegion visibleRegion;
if (contentRoot->GetVisibleRegionRelativeToRootLayer(visibleRegion,
&offset)) {
unused <<
lts.mParent->SendUpdatePluginConfigurations(offset, visibleRegion,
lts.mPluginData);
lts.mUpdatedPluginDataAvailable = false;
} else {
shouldHidePlugin = true;
}
}
}
// Hide all plugins, this remote layer tree is no longer active
if (shouldHidePlugin) {
// hide all the plugins
for (uint32_t pluginsIdx = 0; pluginsIdx < lts.mPluginData.Length();
pluginsIdx++) {
lts.mPluginData[pluginsIdx].visible() = false;
}
nsIntPoint offset;
nsIntRegion region;
unused << lts.mParent->SendUpdatePluginConfigurations(offset,
region,
lts.mPluginData);
// Clear because there's no recovering from this until we receive
// new shadow layer plugin data in ShadowLayersUpdated.
lts.mPluginData.Clear();
}
}
void
CrossProcessCompositorParent::DidComposite(uint64_t aId)
{
@ -1738,6 +1800,7 @@ CrossProcessCompositorParent::DidComposite(uint64_t aId)
unused << SendDidComposite(aId, layerTree->GetPendingTransactionId());
layerTree->SetPendingTransactionId(0);
}
UpdatePluginWindowState(aId);
}
void

View File

@ -303,6 +303,7 @@ public:
APZTestData mApzTestData;
LayerTransactionParent* mLayerTree;
nsTArray<PluginWindowData> mPluginData;
bool mUpdatedPluginDataAvailable;
};
/**

View File

@ -62,7 +62,9 @@ child:
* application on the widgets. Used on Windows and Linux in managing
* plugin widgets.
*/
async UpdatePluginConfigurations(PluginWindowData[] plugins);
async UpdatePluginConfigurations(nsIntPoint aContentOffset,
nsIntRegion aVisibleRegion,
PluginWindowData[] aPlugins);
parent:
// Child sends the parent a request for fill ratio numbers.