Bug 1076241 - Add an API for setting a resolution on a document and scaling it by that amount. r=kats,tn

This commit is contained in:
Botond Ballo 2015-01-02 20:06:14 -05:00
parent 27a7c7b513
commit 2e46796a0f
15 changed files with 186 additions and 25 deletions

View File

@ -510,6 +510,27 @@ nsDOMWindowUtils::SetResolution(float aXResolution, float aYResolution)
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SetResolutionAndScaleTo(float aXResolution, float aYResolution)
{
if (!nsContentUtils::IsCallerChrome()) {
return NS_ERROR_DOM_SECURITY_ERR;
}
nsIPresShell* presShell = GetPresShell();
if (!presShell) {
return NS_ERROR_FAILURE;
}
nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
if (sf) {
sf->SetResolutionAndScaleTo(gfxSize(aXResolution, aYResolution));
presShell->SetResolutionAndScaleTo(aXResolution, aYResolution);
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetResolution(float* aXResolution, float* aYResolution)
{

View File

@ -51,7 +51,7 @@ interface nsITranslationNodeList;
interface nsIJSRAIIHelper;
interface nsIContentPermissionRequest;
[scriptable, uuid(9621eb05-b498-4e87-a012-95d817987624)]
[scriptable, uuid(4922a706-a17e-48e0-ab6f-9fe1bbe4e5f7)]
interface nsIDOMWindowUtils : nsISupports {
/**
@ -199,24 +199,16 @@ interface nsIDOMWindowUtils : nsISupports {
/**
* Get/set the resolution at which rescalable web content is drawn.
* Currently this is only (some) thebes content.
*
* Setting a new resolution does *not* trigger reflow. This API is
* entirely separate from textZoom and fullZoom; a resolution scale
* can be applied together with both textZoom and fullZoom.
*
* The effect of is API for gfx code to allocate more or fewer
* The effect of this API is for gfx code to allocate more or fewer
* pixels for rescalable content by a factor of |resolution| in
* either or both dimensions. setResolution() together with
* setDisplayport() can be used to implement a non-reflowing
* scale-zoom in concert with another entity that can draw with a
* scale. For example, to scale a content |window| inside a
* <browser> by a factor of 2.0
*
* window.setDisplayport(x, y, oldW / 2.0, oldH / 2.0);
* window.setResolution(2.0, 2.0);
* // elsewhere
* browser.setViewportScale(2.0, 2.0);
* either or both dimensions. The scale at which the content is
* displayed does not change; if that is desired, use
* setResolutionAndScaleTo() instead.
*
* The caller of this method must have chrome privileges.
*/
@ -224,6 +216,19 @@ interface nsIDOMWindowUtils : nsISupports {
void getResolution(out float aXResolution, out float aYResolution);
/**
* Similar to setResolution(), but also scales the content by the
* amount of the resolution, so that it is displayed at a
* correspondingly larger or smaller size, without the need for
* the caller to set an additional transform.
*
* This can be used to implement a non-reflowing scale-zoom, e.g.
* for pinch-zoom on mobile platforms.
*
* The caller of this method must have chrome privileges.
*/
void setResolutionAndScaleTo(in float aXResolution, in float aYResolution);
/**
* Whether the resolution has been set by the user.
* This gives a way to check whether the provided resolution is the default

View File

@ -737,7 +737,7 @@ const Matrix4x4
Layer::GetTransform() const
{
Matrix4x4 transform = mTransform;
transform.PostScale(mPostXScale, mPostYScale, 1.0f);
transform.PostScale(GetPostXScale(), GetPostYScale(), 1.0f);
if (const ContainerLayer* c = AsContainerLayer()) {
transform.PreScale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
}
@ -753,7 +753,7 @@ Layer::GetLocalTransform()
else
transform = mTransform;
transform.PostScale(mPostXScale, mPostYScale, 1.0f);
transform.PostScale(GetPostXScale(), GetPostYScale(), 1.0f);
if (ContainerLayer* c = AsContainerLayer()) {
transform.PreScale(c->GetPreXScale(), c->GetPreYScale(), 1.0f);
}
@ -858,6 +858,8 @@ ContainerLayer::ContainerLayer(LayerManager* aManager, void* aImplData)
mPreYScale(1.0f),
mInheritedXScale(1.0f),
mInheritedYScale(1.0f),
mPresShellResolution(1.0f),
mScaleToResolution(false),
mUseIntermediateSurface(false),
mSupportsComponentAlphaChildren(false),
mMayHaveReadbackChild(false),
@ -1017,6 +1019,7 @@ ContainerLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
{
aAttrs = ContainerLayerAttributes(mPreXScale, mPreYScale,
mInheritedXScale, mInheritedYScale,
mPresShellResolution, mScaleToResolution,
reinterpret_cast<uint64_t>(mHMDInfo.get()));
}
@ -1681,6 +1684,9 @@ ContainerLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
if (1.0 != mPreXScale || 1.0 != mPreYScale) {
aStream << nsPrintfCString(" [preScale=%g, %g]", mPreXScale, mPreYScale).get();
}
if (mScaleToResolution) {
aStream << nsPrintfCString(" [presShellResolution=%g]", mPresShellResolution).get();
}
if (mHMDInfo) {
aStream << nsPrintfCString(" [hmd=%p]", mHMDInfo.get()).get();
}

View File

@ -1226,8 +1226,9 @@ public:
virtual Layer* GetLastChild() const { return nullptr; }
const gfx::Matrix4x4 GetTransform() const;
const gfx::Matrix4x4& GetBaseTransform() const { return mTransform; }
float GetPostXScale() const { return mPostXScale; }
float GetPostYScale() const { return mPostYScale; }
// Note: these are virtual because ContainerLayerComposite overrides them.
virtual float GetPostXScale() const { return mPostXScale; }
virtual float GetPostYScale() const { return mPostYScale; }
bool GetIsFixedPosition() { return mIsFixedPosition; }
bool GetIsStickyPosition() { return mStickyPositionData; }
LayerPoint GetFixedPositionAnchor() { return mAnchor; }
@ -1855,6 +1856,18 @@ public:
Mutated();
}
void SetScaleToResolution(bool aScaleToResolution, float aResolution)
{
if (mScaleToResolution == aScaleToResolution && mPresShellResolution == aResolution) {
return;
}
MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ScaleToResolution", this));
mScaleToResolution = aScaleToResolution;
mPresShellResolution = aResolution;
Mutated();
}
virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs) MOZ_OVERRIDE;
void SortChildrenBy3DZOrder(nsTArray<Layer*>& aArray);
@ -1870,6 +1883,8 @@ public:
float GetPreYScale() const { return mPreYScale; }
float GetInheritedXScale() const { return mInheritedXScale; }
float GetInheritedYScale() const { return mInheritedYScale; }
float GetPresShellResolution() const { return mPresShellResolution; }
bool ScaleToResolution() const { return mScaleToResolution; }
MOZ_LAYER_DECL_NAME("ContainerLayer", TYPE_CONTAINER)
@ -1968,6 +1983,11 @@ protected:
// be part of mTransform.
float mInheritedXScale;
float mInheritedYScale;
// For layers corresponding to an nsDisplayResolution, the resolution of the
// associated pres shell; for other layers, 1.0.
float mPresShellResolution;
// Whether the compositor should scale to mPresShellResolution.
bool mScaleToResolution;
bool mUseIntermediateSurface;
bool mSupportsComponentAlphaChildren;
bool mMayHaveReadbackChild;

View File

@ -92,6 +92,24 @@ public:
// container layers don't use a compositable
CompositableHost* GetCompositableHost() MOZ_OVERRIDE { return nullptr; }
// If the layer is marked as scale-to-resolution, add a post-scale
// to the layer's transform equal to the pres shell resolution we're
// scaling to. This cancels out the post scale of '1 / resolution'
// added by Layout. TODO: It would be nice to get rid of both of these
// post-scales.
virtual float GetPostXScale() const MOZ_OVERRIDE {
if (mScaleToResolution) {
return mPostXScale * mPresShellResolution;
}
return mPostXScale;
}
virtual float GetPostYScale() const MOZ_OVERRIDE {
if (mScaleToResolution) {
return mPostYScale * mPresShellResolution;
}
return mPostYScale;
}
virtual const char* Name() const MOZ_OVERRIDE { return "ContainerLayerComposite"; }
UniquePtr<PreparedData> mPrepared;

View File

@ -382,6 +382,8 @@ LayerTransactionParent::RecvUpdate(const InfallibleTArray<Edit>& cset,
specific.get_ContainerLayerAttributes();
containerLayer->SetPreScale(attrs.preXScale(), attrs.preYScale());
containerLayer->SetInheritedScale(attrs.inheritedXScale(), attrs.inheritedYScale());
containerLayer->SetScaleToResolution(attrs.scaleToResolution(),
attrs.presShellResolution());
if (attrs.hmdInfo()) {
if (!IsSameProcess()) {

View File

@ -232,6 +232,8 @@ struct ContainerLayerAttributes {
float preYScale;
float inheritedXScale;
float inheritedYScale;
float presShellResolution;
bool scaleToResolution;
// This is a bare pointer; LayerTransactionParent::RecvUpdate prevents this
// from being used when !IsSameProcess(), but we should make this truly
// cross process at some point by passing the HMDConfig

View File

@ -1579,6 +1579,8 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB
// Root is being scaled up by the X/Y resolution. Scale it back down.
root->SetPostScale(1.0f/containerParameters.mXScale,
1.0f/containerParameters.mYScale);
root->SetScaleToResolution(presShell->ScaleToResolution(),
containerParameters.mXScale);
if (gfxPrefs::LayoutUseContainersForRootFrames()) {
bool isRoot = presContext->IsRootContentDocument();
@ -4153,6 +4155,8 @@ nsDisplayResolution::BuildLayer(nsDisplayListBuilder* aBuilder,
aBuilder, aManager, containerParameters);
layer->SetPostScale(1.0f / presShell->GetXResolution(),
1.0f / presShell->GetYResolution());
layer->AsContainerLayer()->SetScaleToResolution(
presShell->ScaleToResolution(), presShell->GetXResolution());
return layer.forget();
}

View File

@ -139,10 +139,10 @@ typedef struct CapturingContentInfo {
nsIContent* mContent;
} CapturingContentInfo;
// 79c0f49f-77f1-4cc5-80d1-6552e85ccb0c
// 9d010f90-2d90-471c-b640-038cc350c187
#define NS_IPRESSHELL_IID \
{ 0xa0a4b515, 0x0b91, 0x4f13, \
{ 0xa0, 0x60, 0x4b, 0xfb, 0x35, 0x00, 0xdc, 0x00 } }
{ 0x9d010f90, 0x2d90, 0x471c, \
{ 0xb6, 0x40, 0x03, 0x8c, 0xc3, 0x50, 0xc1, 0x87 } }
// debug VerifyReflow flags
#define VERIFY_REFLOW_ON 0x01
@ -1402,6 +1402,19 @@ public:
float GetYResolution() { return mYResolution; }
virtual gfxSize GetCumulativeResolution() = 0;
/**
* Similar to SetResolution() but also increases the scale of the content
* by the same amount.
*/
virtual nsresult SetResolutionAndScaleTo(float aXResolution, float aYResolution) = 0;
/**
* Return whether we are scaling to the set resolution.
* This is initially false; it's set to true by a call to
* SetResolutionAndScaleTo(), and set to false by a call to SetResolution().
*/
virtual bool ScaleToResolution() const = 0;
/**
* Returns whether we are in a DrawWindow() call that used the
* DRAWWINDOW_DO_NOT_FLUSH flag.

View File

@ -5545,7 +5545,7 @@ void PresShell::SetIgnoreViewportScrolling(bool aIgnore)
SetRenderingState(state);
}
nsresult PresShell::SetResolution(float aXResolution, float aYResolution)
nsresult PresShell::SetResolutionImpl(float aXResolution, float aYResolution, bool aScaleToResolution)
{
if (!(aXResolution > 0.0 && aYResolution > 0.0)) {
return NS_ERROR_ILLEGAL_VALUE;
@ -5557,9 +5557,16 @@ nsresult PresShell::SetResolution(float aXResolution, float aYResolution)
state.mXResolution = aXResolution;
state.mYResolution = aYResolution;
SetRenderingState(state);
mScaleToResolution = aScaleToResolution;
return NS_OK;
}
bool PresShell::ScaleToResolution() const
{
return mScaleToResolution;
}
gfxSize PresShell::GetCumulativeResolution()
{
gfxSize resolution = GetResolution();

View File

@ -197,7 +197,13 @@ public:
virtual void SetIgnoreViewportScrolling(bool aIgnore) MOZ_OVERRIDE;
virtual nsresult SetResolution(float aXResolution, float aYResolution) MOZ_OVERRIDE;
virtual nsresult SetResolution(float aXResolution, float aYResolution) MOZ_OVERRIDE {
return SetResolutionImpl(aXResolution, aYResolution, /* aScaleToResolution = */ false);
}
virtual nsresult SetResolutionAndScaleTo(float aXResolution, float aYResolution) MOZ_OVERRIDE {
return SetResolutionImpl(aXResolution, aYResolution, /* aScaleToResolution = */ true);
}
virtual bool ScaleToResolution() const MOZ_OVERRIDE;
virtual gfxSize GetCumulativeResolution() MOZ_OVERRIDE;
//nsIViewObserver interface
@ -753,6 +759,8 @@ protected:
// A list of images that are visible or almost visible.
nsTHashtable< nsRefPtrHashKey<nsIImageLoadingContent> > mVisibleImages;
nsresult SetResolutionImpl(float aXResolution, float aYResolution, bool aScaleToResolution);
#ifdef DEBUG
// The reflow root under which we're currently reflowing. Null when
// not in reflow.
@ -855,6 +863,11 @@ protected:
bool mHasCSSBackgroundColor : 1;
// Whether content should be scaled by the resolution amount. If this is
// not set, a transform that scales by the inverse of the resolution is
// applied to rendered layers.
bool mScaleToResolution : 1;
static bool sDisableNonTestMouseEvents;
};

View File

@ -22,6 +22,7 @@ public:
: mContentData(nullptr)
, mScrollState(0, 0)
, mResolution(1.0, 1.0)
, mScaleToResolution(false)
, mDisabledSet(false)
, mDisabled(false)
{}
@ -46,6 +47,16 @@ public:
return mResolution;
}
void SetScaleToResolution(bool aScaleToResolution)
{
mScaleToResolution = aScaleToResolution;
}
bool GetScaleToResolution() const
{
return mScaleToResolution;
}
void ClearNonScrollState()
{
mContentData = nullptr;
@ -83,6 +94,7 @@ protected:
nsCOMPtr<nsISupports> mContentData;
nsPoint mScrollState;
gfxSize mResolution;
bool mScaleToResolution;
bool mDisabledSet;
bool mDisabled;
};

View File

@ -1895,6 +1895,7 @@ ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter,
, mShouldBuildScrollableLayer(false)
, mHasBeenScrolled(false)
, mIsResolutionSet(false)
, mScaleToResolution(false)
{
if (LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0) {
mScrollbarActivity = new ScrollbarActivity(do_QueryFrame(aOuter));
@ -3264,6 +3265,16 @@ ScrollFrameHelper::SetResolution(const gfxSize& aResolution)
{
mResolution = aResolution;
mIsResolutionSet = true;
mScaleToResolution = false;
}
void
ScrollFrameHelper::SetResolutionAndScaleTo(const gfxSize& aResolution)
{
MOZ_ASSERT(mIsRoot); // This API should only be called on root scroll frames.
mResolution = aResolution;
mIsResolutionSet = true;
mScaleToResolution = true;
}
static void
@ -5061,6 +5072,7 @@ ScrollFrameHelper::SaveState() const
}
state->SetScrollState(pt);
state->SetResolution(mResolution);
state->SetScaleToResolution(mScaleToResolution);
return state;
}
@ -5072,9 +5084,18 @@ ScrollFrameHelper::RestoreState(nsPresState* aState)
mLastPos = mScrolledFrame ? GetLogicalScrollPosition() : nsPoint(0,0);
mResolution = aState->GetResolution();
mIsResolutionSet = true;
mScaleToResolution = aState->GetScaleToResolution();
// Scaling-to-resolution should only be used on root scroll frames.
MOZ_ASSERT(mIsRoot || !mScaleToResolution);
if (mIsRoot) {
mOuter->PresContext()->PresShell()->SetResolution(mResolution.width, mResolution.height);
nsIPresShell* presShell = mOuter->PresContext()->PresShell();
if (mScaleToResolution) {
presShell->SetResolutionAndScaleTo(mResolution.width, mResolution.height);
} else {
presShell->SetResolution(mResolution.width, mResolution.height);
}
}
}

View File

@ -177,6 +177,7 @@ public:
nsSize GetScrollPositionClampingScrollPortSize() const;
gfxSize GetResolution() const;
void SetResolution(const gfxSize& aResolution);
void SetResolutionAndScaleTo(const gfxSize& aResolution);
protected:
nsRect GetScrollRangeForClamping() const;
@ -457,10 +458,14 @@ public:
// True if this frame has been scrolled at least once
bool mHasBeenScrolled:1;
// True if the frame's resolution has been set via SetResolution or restored
// via RestoreState.
// True if the frame's resolution has been set via SetResolution or
// SetResolutionAndScaleTo or restored via RestoreState.
bool mIsResolutionSet:1;
// True if the frame's resolution has been set via SetResolutionAndScaleTo.
// Only meaningful for root scroll frames.
bool mScaleToResolution:1;
protected:
/**
* @note This method might destroy the frame, pres shell and other objects.
@ -643,6 +648,9 @@ public:
virtual void SetResolution(const gfxSize& aResolution) MOZ_OVERRIDE {
return mHelper.SetResolution(aResolution);
}
virtual void SetResolutionAndScaleTo(const gfxSize& aResolution) MOZ_OVERRIDE {
return mHelper.SetResolutionAndScaleTo(aResolution);
}
virtual nsSize GetLineScrollAmount() const MOZ_OVERRIDE {
return mHelper.GetLineScrollAmount();
}
@ -1004,6 +1012,9 @@ public:
virtual void SetResolution(const gfxSize& aResolution) MOZ_OVERRIDE {
return mHelper.SetResolution(aResolution);
}
virtual void SetResolutionAndScaleTo(const gfxSize& aResolution) MOZ_OVERRIDE {
return mHelper.SetResolutionAndScaleTo(aResolution);
}
virtual nsSize GetLineScrollAmount() const MOZ_OVERRIDE {
return mHelper.GetLineScrollAmount();
}

View File

@ -153,6 +153,12 @@ public:
* Set the element resolution.
*/
virtual void SetResolution(const gfxSize& aResolution) = 0;
/**
* Set the element resolution and specify that content should be scaled by
* the amount of the resolution. This is only meaningful for root scroll
* frames. See nsIDOMWindowUtils.setResolutionAndScaleTo().
*/
virtual void SetResolutionAndScaleTo(const gfxSize& aResolution) = 0;
/**
* Return how much we would try to scroll by in each direction if
* asked to scroll by one "line" vertically and horizontally.