mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1168263 - Add nsDisplayPerspective and build separate layers for perspective. r=roc
This commit is contained in:
parent
c66ea2a1c2
commit
a957c40d8f
@ -867,10 +867,10 @@ Factory::CreateWrappingDataSourceSurface(uint8_t *aData, int32_t aStride,
|
||||
const IntSize &aSize,
|
||||
SurfaceFormat aFormat)
|
||||
{
|
||||
MOZ_ASSERT(aData);
|
||||
if (aSize.width <= 0 || aSize.height <= 0) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(aData);
|
||||
|
||||
RefPtr<SourceSurfaceRawData> newSurf = new SourceSurfaceRawData();
|
||||
|
||||
|
@ -504,7 +504,7 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer,
|
||||
|
||||
static void
|
||||
SampleValue(float aPortion, Animation& aAnimation, StyleAnimationValue& aStart,
|
||||
StyleAnimationValue& aEnd, Animatable* aValue)
|
||||
StyleAnimationValue& aEnd, Animatable* aValue, Layer* aLayer)
|
||||
{
|
||||
StyleAnimationValue interpolatedValue;
|
||||
NS_ASSERTION(aStart.GetUnit() == aEnd.GetUnit() ||
|
||||
@ -525,16 +525,21 @@ SampleValue(float aPortion, Animation& aAnimation, StyleAnimationValue& aStart,
|
||||
nsPoint origin = data.origin();
|
||||
// we expect all our transform data to arrive in device pixels
|
||||
Point3D transformOrigin = data.transformOrigin();
|
||||
Point3D perspectiveOrigin = data.perspectiveOrigin();
|
||||
nsDisplayTransform::FrameTransformProperties props(interpolatedList,
|
||||
transformOrigin,
|
||||
perspectiveOrigin,
|
||||
data.perspective());
|
||||
transformOrigin);
|
||||
|
||||
// If our parent layer is a perspective layer, then the offset into reference
|
||||
// frame coordinates is already on that layer. If not, then we need to ask
|
||||
// for it to be added here.
|
||||
uint32_t flags = 0;
|
||||
if (!aLayer->GetParent() || !aLayer->GetParent()->GetTransformIsPerspective()) {
|
||||
flags = nsDisplayTransform::OFFSET_BY_ORIGIN;
|
||||
}
|
||||
|
||||
Matrix4x4 transform =
|
||||
nsDisplayTransform::GetResultingTransformMatrix(props, origin,
|
||||
data.appUnitsPerDevPixel(),
|
||||
nsDisplayTransform::OFFSET_BY_ORIGIN,
|
||||
&data.bounds());
|
||||
flags, &data.bounds());
|
||||
|
||||
InfallibleTArray<TransformFunction> functions;
|
||||
functions.AppendElement(TransformMatrix(transform));
|
||||
@ -612,7 +617,7 @@ SampleAnimations(Layer* aLayer, TimeStamp aPoint)
|
||||
// interpolate the property
|
||||
Animatable interpolatedValue;
|
||||
SampleValue(portion, animation, animData.mStartValues[segmentIndex],
|
||||
animData.mEndValues[segmentIndex], &interpolatedValue);
|
||||
animData.mEndValues[segmentIndex], &interpolatedValue, aLayer);
|
||||
LayerComposite* layerComposite = aLayer->AsLayerComposite();
|
||||
switch (animation.property()) {
|
||||
case eCSSProperty_opacity:
|
||||
|
@ -744,7 +744,12 @@ LayerTransactionParent::RecvGetAnimationTransform(PLayerParent* aParent,
|
||||
}
|
||||
}
|
||||
|
||||
transform.PostTranslate(-scaledOrigin.x, -scaledOrigin.y, -scaledOrigin.z);
|
||||
// If our parent isn't a perspective layer, then the offset into reference
|
||||
// frame coordinates will have been applied to us. Add an inverse translation
|
||||
// to cancel it out.
|
||||
if (!layer->GetParent() || !layer->GetParent()->GetTransformIsPerspective()) {
|
||||
transform.PostTranslate(-scaledOrigin.x, -scaledOrigin.y, -scaledOrigin.z);
|
||||
}
|
||||
|
||||
// Undo the rebasing applied by
|
||||
// nsDisplayTransform::GetResultingTransformMatrixInternal
|
||||
|
@ -164,10 +164,7 @@ struct TransformData {
|
||||
nsPoint origin;
|
||||
// the transform-origin property for the transform in device pixels
|
||||
Point3D transformOrigin;
|
||||
// the perspective-origin property for the transform in device pixels
|
||||
Point3D perspectiveOrigin;
|
||||
nsRect bounds;
|
||||
nscoord perspective;
|
||||
int32_t appUnitsPerDevPixel;
|
||||
};
|
||||
|
||||
|
@ -675,6 +675,7 @@ struct NewLayerEntry {
|
||||
, mPropagateComponentAlphaFlattening(true)
|
||||
, mUntransformedVisibleRegion(false)
|
||||
, mIsCaret(false)
|
||||
, mIsPerspectiveItem(false)
|
||||
{}
|
||||
// mLayer is null if the previous entry is for a PaintedLayer that hasn't
|
||||
// been optimized to some other form (yet).
|
||||
@ -716,6 +717,7 @@ struct NewLayerEntry {
|
||||
// transform.
|
||||
bool mUntransformedVisibleRegion;
|
||||
bool mIsCaret;
|
||||
bool mIsPerspectiveItem;
|
||||
};
|
||||
|
||||
class PaintedLayerDataTree;
|
||||
@ -4116,6 +4118,9 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
|
||||
newLayerEntry->mAnimatedGeometryRoot = animatedGeometryRoot;
|
||||
newLayerEntry->mAnimatedGeometryRootForScrollMetadata = animatedGeometryRootForScrollMetadata;
|
||||
newLayerEntry->mFixedPosFrameForLayerData = fixedPosFrame;
|
||||
if (itemType == nsDisplayItem::TYPE_PERSPECTIVE) {
|
||||
newLayerEntry->mIsPerspectiveItem = true;
|
||||
}
|
||||
|
||||
// Don't attempt to flatten compnent alpha layers that are within
|
||||
// a forced active layer, or an active transform;
|
||||
@ -4132,9 +4137,11 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
|
||||
"Transform items must set layerContentsVisibleRect!");
|
||||
if (mLayerBuilder->IsBuildingRetainedLayers()) {
|
||||
newLayerEntry->mLayerContentsVisibleRect = layerContentsVisibleRect;
|
||||
if (itemType == nsDisplayItem::TYPE_TRANSFORM &&
|
||||
(item->Frame()->Extend3DContext() ||
|
||||
item->Frame()->Combines3DTransformWithAncestors())) {
|
||||
if (itemType == nsDisplayItem::TYPE_PERSPECTIVE ||
|
||||
(itemType == nsDisplayItem::TYPE_TRANSFORM &&
|
||||
(item->Frame()->Extend3DContext() ||
|
||||
item->Frame()->Combines3DTransformWithAncestors() ||
|
||||
item->Frame()->HasPerspective()))) {
|
||||
// Give untransformed visible region as outer visible region
|
||||
// to avoid failure caused by singular transforms.
|
||||
newLayerEntry->mUntransformedVisibleRegion = true;
|
||||
@ -5093,7 +5100,9 @@ ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
|
||||
bool canDraw2D = transform.CanDraw2D(&transform2d);
|
||||
gfxSize scale;
|
||||
// XXX Should we do something for 3D transforms?
|
||||
if (canDraw2D && !aContainerFrame->Combines3DTransformWithAncestors()) {
|
||||
if (canDraw2D &&
|
||||
!aContainerFrame->Combines3DTransformWithAncestors() &&
|
||||
!aContainerFrame->HasPerspective()) {
|
||||
// If the container's transform is animated off main thread, fix a suitable scale size
|
||||
// for animation
|
||||
if (aContainerItem &&
|
||||
|
@ -64,6 +64,7 @@ DECLARE_DISPLAY_ITEM_TYPE(TEXT_DECORATION)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(TEXT_OVERFLOW)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(TEXT_SHADOW)
|
||||
DECLARE_DISPLAY_ITEM_TYPE_FLAGS(TRANSFORM,TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE_FLAGS(PERSPECTIVE,TYPE_RENDERS_NO_IMAGES)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(VIDEO)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(WRAP_LIST)
|
||||
DECLARE_DISPLAY_ITEM_TYPE(ZOOM)
|
||||
|
@ -567,16 +567,6 @@ nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer,
|
||||
float scale = devPixelsToAppUnits;
|
||||
Point3D offsetToTransformOrigin =
|
||||
nsDisplayTransform::GetDeltaToTransformOrigin(aFrame, scale, &bounds);
|
||||
Point3D offsetToPerspectiveOrigin =
|
||||
nsDisplayTransform::GetDeltaToPerspectiveOrigin(aFrame, scale);
|
||||
nscoord perspective = 0.0;
|
||||
nsStyleContext* parentStyleContext = aFrame->StyleContext()->GetParent();
|
||||
if (parentStyleContext) {
|
||||
const nsStyleDisplay* disp = parentStyleContext->StyleDisplay();
|
||||
if (disp && disp->mChildPerspective.GetUnit() == eStyleUnit_Coord) {
|
||||
perspective = disp->mChildPerspective.GetCoordValue();
|
||||
}
|
||||
}
|
||||
nsPoint origin;
|
||||
if (aItem) {
|
||||
// This branch is for display items to leverage the cache of
|
||||
@ -594,8 +584,7 @@ nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer,
|
||||
}
|
||||
|
||||
data = TransformData(origin, offsetToTransformOrigin,
|
||||
offsetToPerspectiveOrigin, bounds, perspective,
|
||||
devPixelsToAppUnits);
|
||||
bounds, devPixelsToAppUnits);
|
||||
} else if (aProperty == eCSSProperty_opacity) {
|
||||
data = null_t();
|
||||
}
|
||||
@ -631,6 +620,7 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
||||
mCurrentScrollParentId(FrameMetrics::NULL_SCROLL_ID),
|
||||
mCurrentScrollbarTarget(FrameMetrics::NULL_SCROLL_ID),
|
||||
mCurrentScrollbarFlags(0),
|
||||
mPerspectiveItemIndex(0),
|
||||
mIsBuildingScrollbar(false),
|
||||
mCurrentScrollbarWillHaveLayer(false),
|
||||
mBuildCaret(aBuildCaret),
|
||||
@ -5072,51 +5062,61 @@ nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame,
|
||||
aAppUnitsPerPixel));
|
||||
}
|
||||
|
||||
/* Returns the delta specified by the -moz-perspective-origin property.
|
||||
* This is a positive delta, meaning that it indicates the direction to move
|
||||
* to get from (0, 0) of the frame to the perspective origin. This function is
|
||||
* called off the main thread.
|
||||
*/
|
||||
/* static */ Point3D
|
||||
nsDisplayTransform::GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame,
|
||||
float aAppUnitsPerPixel)
|
||||
/* static */ bool
|
||||
nsDisplayTransform::ComputePerspectiveMatrix(const nsIFrame* aFrame,
|
||||
float aAppUnitsPerPixel,
|
||||
Matrix4x4& aOutMatrix)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "Can't get delta for a null frame!");
|
||||
NS_PRECONDITION(aFrame->IsTransformed() ||
|
||||
aFrame->StyleDisplay()->BackfaceIsHidden() ||
|
||||
aFrame->Combines3DTransformWithAncestors(),
|
||||
"Shouldn't get a delta for an untransformed frame!");
|
||||
NS_PRECONDITION(aOutMatrix.IsIdentity(), "Must have a blank output matrix");
|
||||
|
||||
if (!aFrame->IsTransformed()) {
|
||||
return Point3D();
|
||||
return false;
|
||||
}
|
||||
|
||||
/* For both of the coordinates, if the value of -moz-perspective-origin is a
|
||||
* percentage, it's relative to the size of the frame. Otherwise, if it's
|
||||
* a distance, it's already computed for us!
|
||||
/* Find our containing block, which is the element that provides the
|
||||
* value for perspective we need to use
|
||||
*/
|
||||
|
||||
//TODO: Should this be using our bounds or the parent's bounds?
|
||||
// How do we handle aBoundsOverride in the latter case?
|
||||
//TODO: Is it possible that the cbFrame's bounds haven't been set correctly yet
|
||||
// (similar to the aBoundsOverride case for GetResultingTransformMatrix)?
|
||||
nsIFrame* cbFrame = aFrame->GetContainingBlock(nsIFrame::SKIP_SCROLLED_FRAME);
|
||||
if (!cbFrame) {
|
||||
return Point3D();
|
||||
return false;
|
||||
}
|
||||
const nsStyleDisplay* display = cbFrame->StyleDisplay();
|
||||
|
||||
/* Grab the values for perspective and perspective-origin (if present) */
|
||||
|
||||
const nsStyleDisplay* cbDisplay = cbFrame->StyleDisplay();
|
||||
if (cbDisplay->mChildPerspective.GetUnit() != eStyleUnit_Coord) {
|
||||
return false;
|
||||
}
|
||||
nscoord perspective = cbDisplay->mChildPerspective.GetCoordValue();
|
||||
if (perspective <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TransformReferenceBox refBox(cbFrame);
|
||||
|
||||
/* Allows us to access named variables by index. */
|
||||
Point3D result;
|
||||
result.z = 0.0f;
|
||||
gfx::Float* coords[2] = {&result.x, &result.y};
|
||||
Point3D perspectiveOrigin;
|
||||
gfx::Float* coords[2] = {&perspectiveOrigin.x, &perspectiveOrigin.y};
|
||||
TransformReferenceBox::DimensionGetter dimensionGetter[] =
|
||||
{ &TransformReferenceBox::Width, &TransformReferenceBox::Height };
|
||||
|
||||
/* For both of the coordinates, if the value of perspective-origin is a
|
||||
* percentage, it's relative to the size of the frame. Otherwise, if it's
|
||||
* a distance, it's already computed for us!
|
||||
*/
|
||||
for (uint8_t index = 0; index < 2; ++index) {
|
||||
/* If the transform-origin specifies a percentage, take the percentage
|
||||
/* If the -transform-origin specifies a percentage, take the percentage
|
||||
* of the size of the box.
|
||||
*/
|
||||
const nsStyleCoord &coord = display->mPerspectiveOrigin[index];
|
||||
const nsStyleCoord &coord = cbDisplay->mPerspectiveOrigin[index];
|
||||
if (coord.GetUnit() == eStyleUnit_Calc) {
|
||||
const nsStyleCoord::Calc *calc = coord.GetCalcValue();
|
||||
*coords[index] =
|
||||
@ -5144,7 +5144,15 @@ nsDisplayTransform::GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame,
|
||||
NSAppUnitsToFloatPixels(frameToCbOffset.y, aAppUnitsPerPixel),
|
||||
0.0f);
|
||||
|
||||
return result + frameToCbGfxOffset;
|
||||
/* Move the perspective origin to be relative to aFrame, instead of relative
|
||||
* to the containing block which is how it was specified in the style system.
|
||||
*/
|
||||
perspectiveOrigin += frameToCbGfxOffset;
|
||||
|
||||
aOutMatrix._34 =
|
||||
-1.0 / NSAppUnitsToFloatPixels(perspective, aAppUnitsPerPixel);
|
||||
aOutMatrix.ChangeBasis(perspectiveOrigin);
|
||||
return true;
|
||||
}
|
||||
|
||||
nsDisplayTransform::FrameTransformProperties::FrameTransformProperties(const nsIFrame* aFrame,
|
||||
@ -5153,20 +5161,7 @@ nsDisplayTransform::FrameTransformProperties::FrameTransformProperties(const nsI
|
||||
: mFrame(aFrame)
|
||||
, mTransformList(aFrame->StyleDisplay()->mSpecifiedTransform)
|
||||
, mToTransformOrigin(GetDeltaToTransformOrigin(aFrame, aAppUnitsPerPixel, aBoundsOverride))
|
||||
, mChildPerspective(0)
|
||||
{
|
||||
nsIFrame* cbFrame = aFrame->GetContainingBlock(nsIFrame::SKIP_SCROLLED_FRAME);
|
||||
if (cbFrame) {
|
||||
const nsStyleDisplay* display = cbFrame->StyleDisplay();
|
||||
if (display->mChildPerspective.GetUnit() == eStyleUnit_Coord) {
|
||||
mChildPerspective = display->mChildPerspective.GetCoordValue();
|
||||
// Calling GetDeltaToPerspectiveOrigin can be expensive, so we avoid
|
||||
// calling it unnecessarily.
|
||||
if (mChildPerspective > 0.0) {
|
||||
mToPerspectiveOrigin = GetDeltaToPerspectiveOrigin(aFrame, aAppUnitsPerPixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Wraps up the transform matrix in a change-of-basis matrix pair that
|
||||
@ -5210,6 +5205,7 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp
|
||||
nsIFrame** aOutAncestor)
|
||||
{
|
||||
const nsIFrame *frame = aProperties.mFrame;
|
||||
NS_ASSERTION(frame || !(aFlags & INCLUDE_PERSPECTIVE), "Must have a frame to compute perspective!");
|
||||
|
||||
if (aOutAncestor) {
|
||||
*aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(frame);
|
||||
@ -5264,7 +5260,12 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp
|
||||
hasSVGTransforms ? newOrigin.y : NS_round(newOrigin.y),
|
||||
0);
|
||||
|
||||
bool hasPerspective = aProperties.mChildPerspective > 0.0;
|
||||
Matrix4x4 perspectiveMatrix;
|
||||
bool hasPerspective = aFlags & INCLUDE_PERSPECTIVE;
|
||||
if (hasPerspective) {
|
||||
hasPerspective = ComputePerspectiveMatrix(frame, aAppUnitsPerPixel,
|
||||
perspectiveMatrix);
|
||||
}
|
||||
|
||||
if (!hasSVGTransforms || !hasTransformFromSVGParent) {
|
||||
// This is a simplification of the following |else| block, the
|
||||
@ -5314,12 +5315,7 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp
|
||||
}
|
||||
|
||||
if (hasPerspective) {
|
||||
Matrix4x4 perspective;
|
||||
perspective._34 =
|
||||
-1.0 / NSAppUnitsToFloatPixels(aProperties.mChildPerspective, aAppUnitsPerPixel);
|
||||
|
||||
perspective.ChangeBasis(aProperties.GetToPerspectiveOrigin());
|
||||
result = result * perspective;
|
||||
result = result * perspectiveMatrix;
|
||||
|
||||
if (aFlags & OFFSET_BY_ORIGIN) {
|
||||
result.PostTranslate(roundedOrigin);
|
||||
@ -5341,7 +5337,7 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp
|
||||
// then we're not a reference frame so no offset to origin will be added. Our
|
||||
// parent transform however *is* the reference frame, so we pass
|
||||
// OFFSET_BY_ORIGIN to convert into the correct coordinate space.
|
||||
uint32_t flags = aFlags & (INCLUDE_PRESERVE3D_ANCESTORS);
|
||||
uint32_t flags = aFlags & (INCLUDE_PRESERVE3D_ANCESTORS|INCLUDE_PERSPECTIVE);
|
||||
if (!frame->IsTransformed()) {
|
||||
flags |= OFFSET_BY_ORIGIN;
|
||||
}
|
||||
@ -5493,7 +5489,7 @@ nsDisplayTransform::GetTransform()
|
||||
bool isReference =
|
||||
mFrame->IsTransformed() ||
|
||||
mFrame->Combines3DTransformWithAncestors() || mFrame->Extend3DContext();
|
||||
uint32_t flags = 0;
|
||||
uint32_t flags = INCLUDE_PERSPECTIVE;
|
||||
if (isReference) {
|
||||
flags |= OFFSET_BY_ORIGIN;
|
||||
}
|
||||
@ -5504,6 +5500,20 @@ nsDisplayTransform::GetTransform()
|
||||
return mTransform;
|
||||
}
|
||||
|
||||
Matrix4x4
|
||||
nsDisplayTransform::GetTransformForRendering()
|
||||
{
|
||||
if (!mFrame->HasPerspective() || mTransformGetter || mIsTransformSeparator) {
|
||||
return GetTransform();
|
||||
}
|
||||
MOZ_ASSERT(!mTransformGetter);
|
||||
|
||||
float scale = mFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
// Don't include perspective transform, or the offset to origin, since
|
||||
// nsDisplayPerspective will handle both of those.
|
||||
return GetResultingTransformMatrix(mFrame, ToReferenceFrame(), scale, 0);
|
||||
}
|
||||
|
||||
const Matrix4x4&
|
||||
nsDisplayTransform::GetAccumulatedPreserved3DTransform(nsDisplayListBuilder* aBuilder)
|
||||
{
|
||||
@ -5527,7 +5537,7 @@ nsDisplayTransform::GetAccumulatedPreserved3DTransform(nsDisplayListBuilder* aBu
|
||||
|
||||
nsPoint offset = mFrame->GetOffsetToCrossDoc(establisherReference);
|
||||
float scale = mFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
uint32_t flags = INCLUDE_PRESERVE3D_ANCESTORS|OFFSET_BY_ORIGIN;
|
||||
uint32_t flags = INCLUDE_PRESERVE3D_ANCESTORS|INCLUDE_PERSPECTIVE|OFFSET_BY_ORIGIN;
|
||||
mTransformPreserves3D =
|
||||
GetResultingTransformMatrix(mFrame, offset, scale, flags);
|
||||
}
|
||||
@ -5551,7 +5561,7 @@ already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBu
|
||||
* backface hidden here. But, it would be removed by the init
|
||||
* function of nsDisplayTransform.
|
||||
*/
|
||||
const Matrix4x4& newTransformMatrix = GetTransform();
|
||||
const Matrix4x4& newTransformMatrix = GetTransformForRendering();
|
||||
|
||||
uint32_t flags = ShouldPrerender(aBuilder) ?
|
||||
FrameLayerBuilder::CONTAINER_NOT_CLIPPED_BY_ANCESTORS : 0;
|
||||
@ -5956,7 +5966,7 @@ nsRect nsDisplayTransform::TransformRect(const nsRect &aUntransformedBounds,
|
||||
|
||||
float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
|
||||
uint32_t flags = 0;
|
||||
uint32_t flags = INCLUDE_PERSPECTIVE;
|
||||
if (aPreserves3D) {
|
||||
flags |= INCLUDE_PRESERVE3D_ANCESTORS;
|
||||
}
|
||||
@ -5977,7 +5987,7 @@ bool nsDisplayTransform::UntransformRect(const nsRect &aTransformedBounds,
|
||||
|
||||
float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
|
||||
uint32_t flags = 0;
|
||||
uint32_t flags = INCLUDE_PERSPECTIVE;
|
||||
if (aPreserves3D) {
|
||||
flags |= INCLUDE_PRESERVE3D_ANCESTORS;
|
||||
}
|
||||
@ -6037,6 +6047,71 @@ nsDisplayTransform::WriteDebugInfo(std::stringstream& aStream)
|
||||
AppendToString(aStream, GetTransform());
|
||||
}
|
||||
|
||||
nsDisplayPerspective::nsDisplayPerspective(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aTransformFrame,
|
||||
nsIFrame* aPerspectiveFrame,
|
||||
nsDisplayList* aList)
|
||||
: nsDisplayItem(aBuilder, aPerspectiveFrame)
|
||||
, mList(aBuilder, aPerspectiveFrame, aList)
|
||||
, mTransformFrame(aTransformFrame)
|
||||
, mIndex(aBuilder->AllocatePerspectiveItemIndex())
|
||||
{}
|
||||
|
||||
already_AddRefed<Layer>
|
||||
nsDisplayPerspective::BuildLayer(nsDisplayListBuilder *aBuilder,
|
||||
LayerManager *aManager,
|
||||
const ContainerLayerParameters& aContainerParameters)
|
||||
{
|
||||
float appUnitsPerPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
|
||||
Matrix4x4 perspectiveMatrix;
|
||||
DebugOnly<bool> hasPerspective =
|
||||
nsDisplayTransform::ComputePerspectiveMatrix(mTransformFrame, appUnitsPerPixel,
|
||||
perspectiveMatrix);
|
||||
MOZ_ASSERT(hasPerspective, "Why did we create nsDisplayPerspective?");
|
||||
|
||||
/*
|
||||
* The resulting matrix is still in the coordinate space of the transformed
|
||||
* frame. Append a translation to the reference frame coordinates.
|
||||
*/
|
||||
nsDisplayTransform* transform =
|
||||
static_cast<nsDisplayTransform*>(mList.GetChildren()->GetTop());
|
||||
|
||||
Point3D newOrigin =
|
||||
Point3D(NSAppUnitsToFloatPixels(transform->ToReferenceFrame().x, appUnitsPerPixel),
|
||||
NSAppUnitsToFloatPixels(transform->ToReferenceFrame().y, appUnitsPerPixel),
|
||||
0.0f);
|
||||
Point3D roundedOrigin(NS_round(newOrigin.x),
|
||||
NS_round(newOrigin.y),
|
||||
0);
|
||||
|
||||
perspectiveMatrix.PostTranslate(roundedOrigin);
|
||||
|
||||
RefPtr<ContainerLayer> container = aManager->GetLayerBuilder()->
|
||||
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList.GetChildren(),
|
||||
aContainerParameters, &perspectiveMatrix, 0);
|
||||
|
||||
if (!container) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Sort of a lie, but we want to pretend that the perspective layer extends a 3d context
|
||||
// so that it gets its transform combined with children. Might need a better name that reflects
|
||||
// this use case and isn't specific to preserve-3d.
|
||||
container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_EXTEND_3D_CONTEXT);
|
||||
container->SetTransformIsPerspective(true);
|
||||
|
||||
return container.forget();
|
||||
}
|
||||
|
||||
LayerState
|
||||
nsDisplayPerspective::GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aParameters)
|
||||
{
|
||||
return LAYER_ACTIVE;
|
||||
}
|
||||
|
||||
nsDisplayItemGeometry*
|
||||
nsCharClipDisplayItem::AllocateGeometry(nsDisplayListBuilder* aBuilder)
|
||||
{
|
||||
|
@ -743,6 +743,32 @@ public:
|
||||
bool mOldValue;
|
||||
};
|
||||
|
||||
class AutoSaveRestorePerspectiveIndex;
|
||||
friend class AutoSaveRestorePerspectiveIndex;
|
||||
class AutoSaveRestorePerspectiveIndex {
|
||||
public:
|
||||
AutoSaveRestorePerspectiveIndex(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
|
||||
: mBuilder(nullptr)
|
||||
{
|
||||
if (aFrame->ChildrenHavePerspective()) {
|
||||
mBuilder = aBuilder;
|
||||
mCachedItemIndex = aBuilder->mPerspectiveItemIndex;
|
||||
aBuilder->mPerspectiveItemIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
~AutoSaveRestorePerspectiveIndex()
|
||||
{
|
||||
if (mBuilder) {
|
||||
mBuilder->mPerspectiveItemIndex = mCachedItemIndex;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsDisplayListBuilder* mBuilder;
|
||||
uint32_t mCachedItemIndex;
|
||||
};
|
||||
|
||||
/**
|
||||
* A helper class to temporarily set the value of mCurrentScrollParentId.
|
||||
*/
|
||||
@ -995,6 +1021,8 @@ public:
|
||||
return mContainedBlendModes;
|
||||
}
|
||||
|
||||
uint32_t AllocatePerspectiveItemIndex() { return mPerspectiveItemIndex++; }
|
||||
|
||||
DisplayListClipState& ClipState() { return mClipState; }
|
||||
|
||||
/**
|
||||
@ -1199,6 +1227,7 @@ private:
|
||||
uint32_t mCurrentScrollbarFlags;
|
||||
BlendModeSet mContainedBlendModes;
|
||||
Preserves3DContext mPreserves3DCtx;
|
||||
uint32_t mPerspectiveItemIndex;
|
||||
bool mIsBuildingScrollbar;
|
||||
bool mCurrentScrollbarWillHaveLayer;
|
||||
bool mBuildCaret;
|
||||
@ -3815,7 +3844,15 @@ public:
|
||||
INDEX_MAX = UINT32_MAX >> nsDisplayItem::TYPE_BITS
|
||||
};
|
||||
|
||||
/**
|
||||
* We include the perspective matrix from our containing block for the
|
||||
* purposes of visibility calculations, but we exclude it from the transform
|
||||
* we set on the layer (for rendering), since there will be an
|
||||
* nsDisplayPerspective created for that.
|
||||
*/
|
||||
const Matrix4x4& GetTransform();
|
||||
Matrix4x4 GetTransformForRendering();
|
||||
|
||||
/**
|
||||
* Return the transform that is aggregation of all transform on the
|
||||
* preserves3d chain.
|
||||
@ -3865,8 +3902,18 @@ public:
|
||||
float aAppUnitsPerPixel,
|
||||
const nsRect* aBoundsOverride);
|
||||
|
||||
static Point3D GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame,
|
||||
float aAppUnitsPerPixel);
|
||||
/*
|
||||
* Returns true if aFrame has perspective applied from its containing
|
||||
* block.
|
||||
* Returns the matrix to append to apply the persective (taking
|
||||
* perspective-origin into account), relative to aFrames coordinate
|
||||
* space).
|
||||
* aOutMatrix is assumed to be the identity matrix, and isn't explicitly
|
||||
* cleared.
|
||||
*/
|
||||
static bool ComputePerspectiveMatrix(const nsIFrame* aFrame,
|
||||
float aAppUnitsPerPixel,
|
||||
Matrix4x4& aOutMatrix);
|
||||
|
||||
struct FrameTransformProperties
|
||||
{
|
||||
@ -3874,30 +3921,15 @@ public:
|
||||
float aAppUnitsPerPixel,
|
||||
const nsRect* aBoundsOverride);
|
||||
FrameTransformProperties(nsCSSValueSharedList* aTransformList,
|
||||
const Point3D& aToTransformOrigin,
|
||||
const Point3D& aToPerspectiveOrigin,
|
||||
nscoord aChildPerspective)
|
||||
const Point3D& aToTransformOrigin)
|
||||
: mFrame(nullptr)
|
||||
, mTransformList(aTransformList)
|
||||
, mToTransformOrigin(aToTransformOrigin)
|
||||
, mChildPerspective(aChildPerspective)
|
||||
, mToPerspectiveOrigin(aToPerspectiveOrigin)
|
||||
{}
|
||||
|
||||
const Point3D& GetToPerspectiveOrigin() const
|
||||
{
|
||||
MOZ_ASSERT(mChildPerspective > 0, "Only valid with mChildPerspective > 0");
|
||||
return mToPerspectiveOrigin;
|
||||
}
|
||||
|
||||
const nsIFrame* mFrame;
|
||||
RefPtr<nsCSSValueSharedList> mTransformList;
|
||||
const Point3D mToTransformOrigin;
|
||||
nscoord mChildPerspective;
|
||||
|
||||
private:
|
||||
// mToPerspectiveOrigin is only valid if mChildPerspective > 0.
|
||||
Point3D mToPerspectiveOrigin;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -3917,10 +3949,13 @@ public:
|
||||
* @param aFlags INCLUDE_PRESERVE3D_ANCESTORS The computed transform will
|
||||
* include the transform of any ancestors participating in the same
|
||||
* 3d rendering context.
|
||||
* @param aFlags INCLUDE_PERSPECTIVE The resulting matrix will include the
|
||||
* perspective transform from the containing block if applicable.
|
||||
*/
|
||||
enum {
|
||||
OFFSET_BY_ORIGIN = 1 << 0,
|
||||
INCLUDE_PRESERVE3D_ANCESTORS = 1 << 1,
|
||||
INCLUDE_PERSPECTIVE = 1 << 2,
|
||||
};
|
||||
static Matrix4x4 GetResultingTransformMatrix(const nsIFrame* aFrame,
|
||||
const nsPoint& aOrigin,
|
||||
@ -4046,6 +4081,85 @@ private:
|
||||
bool mTransformPreserves3DInited;
|
||||
};
|
||||
|
||||
/* A display item that applies a perspective transformation to a single
|
||||
* nsDisplayTransform child item. We keep this as a separate item since the
|
||||
* perspective-origin is relative to an ancestor of the transformed frame, and
|
||||
* APZ can scroll the child separately.
|
||||
*/
|
||||
class nsDisplayPerspective : public nsDisplayItem
|
||||
{
|
||||
typedef mozilla::gfx::Point3D Point3D;
|
||||
|
||||
public:
|
||||
NS_DISPLAY_DECL_NAME("nsDisplayPerspective", TYPE_PERSPECTIVE)
|
||||
|
||||
nsDisplayPerspective(nsDisplayListBuilder* aBuilder, nsIFrame* aTransformFrame,
|
||||
nsIFrame* aPerspectiveFrame,
|
||||
nsDisplayList* aList);
|
||||
|
||||
virtual uint32_t GetPerFrameKey() override { return (mIndex << nsDisplayItem::TYPE_BITS) | nsDisplayItem::GetPerFrameKey(); }
|
||||
|
||||
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
|
||||
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) override
|
||||
{
|
||||
return mList.HitTest(aBuilder, aRect, aState, aOutFrames);
|
||||
}
|
||||
|
||||
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override
|
||||
{
|
||||
return mList.GetBounds(aBuilder, aSnap);
|
||||
}
|
||||
|
||||
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
|
||||
const nsDisplayItemGeometry* aGeometry,
|
||||
nsRegion* aInvalidRegion) override
|
||||
{}
|
||||
|
||||
virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
|
||||
bool* aSnap) override
|
||||
{
|
||||
return mList.GetOpaqueRegion(aBuilder, aSnap);
|
||||
}
|
||||
|
||||
virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) override
|
||||
{
|
||||
return mList.IsUniform(aBuilder, aColor);
|
||||
}
|
||||
|
||||
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aParameters) override;
|
||||
|
||||
virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) override
|
||||
{
|
||||
return mList.ShouldBuildLayerEvenIfInvisible(aBuilder);
|
||||
}
|
||||
|
||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aContainerParameters) override;
|
||||
|
||||
virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
||||
nsRegion* aVisibleRegion) override
|
||||
{
|
||||
mList.RecomputeVisibility(aBuilder, aVisibleRegion);
|
||||
return true;
|
||||
}
|
||||
virtual nsDisplayList* GetSameCoordinateSystemChildren() override { return mList.GetChildren(); }
|
||||
virtual nsDisplayList* GetChildren() override { return mList.GetChildren(); }
|
||||
virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) override
|
||||
{
|
||||
return mList.GetComponentAlphaBounds(aBuilder);
|
||||
}
|
||||
|
||||
nsIFrame* TransformFrame() { return mTransformFrame; }
|
||||
|
||||
private:
|
||||
nsDisplayWrapList mList;
|
||||
nsIFrame* mTransformFrame;
|
||||
uint32_t mIndex;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class adds basic support for limiting the rendering (in the inline axis
|
||||
* of the writing mode) to the part inside the specified edges. It's a base
|
||||
|
@ -1895,7 +1895,7 @@ CheckForApzAwareEventHandlers(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
|
||||
* True if aDescendant participates the context aAncestor participating.
|
||||
*/
|
||||
static bool
|
||||
Participate3DContextFrame(nsIFrame* aAncestor, nsIFrame* aDescendant) {
|
||||
FrameParticipatesIn3DContext(nsIFrame* aAncestor, nsIFrame* aDescendant) {
|
||||
MOZ_ASSERT(aAncestor != aDescendant);
|
||||
MOZ_ASSERT(aAncestor->Extend3DContext());
|
||||
nsIFrame* frame;
|
||||
@ -1910,6 +1910,20 @@ Participate3DContextFrame(nsIFrame* aAncestor, nsIFrame* aDescendant) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ItemParticipatesIn3DContext(nsIFrame* aAncestor, nsDisplayItem* aItem)
|
||||
{
|
||||
nsIFrame* transformFrame;
|
||||
if (aItem->GetType() == nsDisplayItem::TYPE_TRANSFORM) {
|
||||
transformFrame = aItem->Frame();
|
||||
} else if (aItem->GetType() == nsDisplayItem::TYPE_PERSPECTIVE) {
|
||||
transformFrame = static_cast<nsDisplayPerspective*>(aItem)->TransformFrame();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return FrameParticipatesIn3DContext(aAncestor, transformFrame);
|
||||
}
|
||||
|
||||
static void
|
||||
WrapSeparatorTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
|
||||
nsRect& aDirtyRect,
|
||||
@ -2035,6 +2049,8 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
|
||||
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
|
||||
|
||||
nsDisplayListBuilder::AutoSaveRestorePerspectiveIndex perspectiveIndex(aBuilder, this);
|
||||
|
||||
if (isTransformed || useBlendMode || usingSVGEffects || useStickyPosition) {
|
||||
// We don't need to pass ancestor clipping down to our children;
|
||||
// everything goes inside a display item's child list, and the display
|
||||
@ -2190,8 +2206,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
int index = 1;
|
||||
|
||||
while (nsDisplayItem* item = resultList.RemoveBottom()) {
|
||||
if (item->GetType() == nsDisplayItem::TYPE_TRANSFORM &&
|
||||
Participate3DContextFrame(this, item->Frame())) {
|
||||
if (ItemParticipatesIn3DContext(this, item)) {
|
||||
// The frame of this item participates the same 3D context.
|
||||
WrapSeparatorTransform(aBuilder, this, dirtyRect,
|
||||
&nonparticipants, &participants, index++);
|
||||
@ -2213,7 +2228,9 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
}
|
||||
|
||||
// Restore clip state now so nsDisplayTransform is clipped properly.
|
||||
clipState.Restore();
|
||||
if (!HasPerspective()) {
|
||||
clipState.Restore();
|
||||
}
|
||||
// Revert to the dirtyrect coming in from the parent, without our transform
|
||||
// taken into account.
|
||||
buildingDisplayList.SetDirtyRect(dirtyRectOutsideTransform);
|
||||
@ -2228,6 +2245,15 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
nsDisplayTransform *transformItem =
|
||||
new (aBuilder) nsDisplayTransform(aBuilder, this, &resultList, dirtyRect);
|
||||
resultList.AppendNewToTop(transformItem);
|
||||
|
||||
if (HasPerspective()) {
|
||||
clipState.Restore();
|
||||
resultList.AppendNewToTop(
|
||||
new (aBuilder) nsDisplayPerspective(
|
||||
aBuilder, this,
|
||||
GetContainingBlock()->GetContent()->GetPrimaryFrame(), &resultList));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* If we're doing VR rendering, then we need to wrap everything in a nsDisplayVR
|
||||
@ -2287,7 +2313,8 @@ WrapInWrapList(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame, nsDisplayList* aList)
|
||||
{
|
||||
nsDisplayItem* item = aList->GetBottom();
|
||||
if (!item || item->GetAbove() || item->Frame() != aFrame) {
|
||||
if (!item || item->GetAbove() ||
|
||||
(item->Frame() != aFrame && item->GetType() != nsDisplayItem::TYPE_PERSPECTIVE)) {
|
||||
return new (aBuilder) nsDisplayWrapList(aBuilder, aFrame, aList);
|
||||
}
|
||||
aList->RemoveBottom();
|
||||
@ -5027,7 +5054,7 @@ nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor,
|
||||
int32_t scaleFactor = PresContext()->AppUnitsPerDevPixel();
|
||||
|
||||
Matrix4x4 result = nsDisplayTransform::GetResultingTransformMatrix(this,
|
||||
nsPoint(0, 0), scaleFactor, 0,
|
||||
nsPoint(0, 0), scaleFactor, nsDisplayTransform::INCLUDE_PERSPECTIVE,
|
||||
nullptr, aOutAncestor);
|
||||
// XXXjwatt: seems like this will double count offsets in the face of preserve-3d:
|
||||
nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
|
||||
|
Loading…
Reference in New Issue
Block a user