mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 624647 part 2: Honor "object-fit" & "object-position" in nsImageFrame, nsSubDocumentFrame, & nsVideoFrame. r=roc
This commit is contained in:
parent
779bb4b2dd
commit
da820542cf
@ -347,25 +347,36 @@ nsImageFrame::UpdateIntrinsicRatio(imgIContainer* aImage)
|
||||
bool
|
||||
nsImageFrame::GetSourceToDestTransform(nsTransform2D& aTransform)
|
||||
{
|
||||
// Set the translation components.
|
||||
// First, figure out destRect (the rect we're rendering into).
|
||||
// NOTE: We use mComputedSize instead of just GetInnerArea()'s own size here,
|
||||
// because GetInnerArea() might be smaller if we're fragmented, whereas
|
||||
// mComputedSize has our full content-box size (which we need for
|
||||
// ComputeObjectDestRect to work correctly).
|
||||
nsRect constraintRect(GetInnerArea().TopLeft(), mComputedSize);
|
||||
constraintRect.y -= GetContinuationOffset();
|
||||
|
||||
nsRect destRect = nsLayoutUtils::ComputeObjectDestRect(constraintRect,
|
||||
mIntrinsicSize,
|
||||
mIntrinsicRatio,
|
||||
StylePosition());
|
||||
// Set the translation components, based on destRect
|
||||
// XXXbz does this introduce rounding errors because of the cast to
|
||||
// float? Should we just manually add that stuff in every time
|
||||
// instead?
|
||||
nsRect innerArea = GetInnerArea();
|
||||
aTransform.SetToTranslate(float(innerArea.x),
|
||||
float(innerArea.y - GetContinuationOffset()));
|
||||
aTransform.SetToTranslate(float(destRect.x),
|
||||
float(destRect.y));
|
||||
|
||||
// Set the scale factors.
|
||||
// Set the scale factors, based on destRect and intrinsic size.
|
||||
if (mIntrinsicSize.width.GetUnit() == eStyleUnit_Coord &&
|
||||
mIntrinsicSize.width.GetCoordValue() != 0 &&
|
||||
mIntrinsicSize.height.GetUnit() == eStyleUnit_Coord &&
|
||||
mIntrinsicSize.height.GetCoordValue() != 0 &&
|
||||
mIntrinsicSize.width.GetCoordValue() != mComputedSize.width &&
|
||||
mIntrinsicSize.height.GetCoordValue() != mComputedSize.height) {
|
||||
mIntrinsicSize.width.GetCoordValue() != destRect.width &&
|
||||
mIntrinsicSize.height.GetCoordValue() != destRect.height) {
|
||||
|
||||
aTransform.SetScale(float(mComputedSize.width) /
|
||||
aTransform.SetScale(float(destRect.width) /
|
||||
float(mIntrinsicSize.width.GetCoordValue()),
|
||||
float(mComputedSize.height) /
|
||||
float(destRect.height) /
|
||||
float(mIntrinsicSize.height.GetCoordValue()));
|
||||
return true;
|
||||
}
|
||||
@ -1489,9 +1500,18 @@ nsImageFrame::PaintImage(nsRenderingContext& aRenderingContext, nsPoint aPt,
|
||||
// Render the image into our content area (the area inside
|
||||
// the borders and padding)
|
||||
NS_ASSERTION(GetInnerArea().width == mComputedSize.width, "bad width");
|
||||
nsRect inner = GetInnerArea() + aPt;
|
||||
nsRect dest(inner.TopLeft(), mComputedSize);
|
||||
dest.y -= GetContinuationOffset();
|
||||
|
||||
// NOTE: We use mComputedSize instead of just GetInnerArea()'s own size here,
|
||||
// because GetInnerArea() might be smaller if we're fragmented, whereas
|
||||
// mComputedSize has our full content-box size (which we need for
|
||||
// ComputeObjectDestRect to work correctly).
|
||||
nsRect constraintRect(aPt + GetInnerArea().TopLeft(), mComputedSize);
|
||||
constraintRect.y -= GetContinuationOffset();
|
||||
|
||||
nsRect dest = nsLayoutUtils::ComputeObjectDestRect(constraintRect,
|
||||
mIntrinsicSize,
|
||||
mIntrinsicRatio,
|
||||
StylePosition());
|
||||
|
||||
nsLayoutUtils::DrawSingleImage(*aRenderingContext.ThebesContext(),
|
||||
PresContext(), aImage,
|
||||
@ -1501,7 +1521,7 @@ nsImageFrame::PaintImage(nsRenderingContext& aRenderingContext, nsPoint aPt,
|
||||
nsImageMap* map = GetImageMap();
|
||||
if (map) {
|
||||
gfxPoint devPixelOffset =
|
||||
nsLayoutUtils::PointToGfxPoint(inner.TopLeft(),
|
||||
nsLayoutUtils::PointToGfxPoint(dest.TopLeft(),
|
||||
PresContext()->AppUnitsPerDevPixel());
|
||||
AutoRestoreTransform autoRestoreTransform(drawTarget);
|
||||
drawTarget->SetTransform(
|
||||
|
@ -273,6 +273,18 @@ nsSubDocumentFrame::GetSubdocumentSize()
|
||||
} else {
|
||||
docSizeAppUnits = GetContentRect().Size();
|
||||
}
|
||||
// Adjust subdocument size, according to 'object-fit' and the
|
||||
// subdocument's intrinsic size and ratio.
|
||||
nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
|
||||
if (subDocRoot) {
|
||||
nsRect destRect =
|
||||
nsLayoutUtils::ComputeObjectDestRect(nsRect(nsPoint(), docSizeAppUnits),
|
||||
subDocRoot->GetIntrinsicSize(),
|
||||
subDocRoot->GetIntrinsicRatio(),
|
||||
StylePosition());
|
||||
docSizeAppUnits = destRect.Size();
|
||||
}
|
||||
|
||||
return nsIntSize(presContext->AppUnitsToDevPixels(docSizeAppUnits.width),
|
||||
presContext->AppUnitsToDevPixels(docSizeAppUnits.height));
|
||||
}
|
||||
@ -756,14 +768,27 @@ nsSubDocumentFrame::Reflow(nsPresContext* aPresContext,
|
||||
nsPoint offset = nsPoint(aReflowState.ComputedPhysicalBorderPadding().left,
|
||||
aReflowState.ComputedPhysicalBorderPadding().top);
|
||||
|
||||
nsSize innerSize(aDesiredSize.Width(), aDesiredSize.Height());
|
||||
innerSize.width -= aReflowState.ComputedPhysicalBorderPadding().LeftRight();
|
||||
innerSize.height -= aReflowState.ComputedPhysicalBorderPadding().TopBottom();
|
||||
|
||||
if (mInnerView) {
|
||||
const nsMargin& bp = aReflowState.ComputedPhysicalBorderPadding();
|
||||
nsSize innerSize(aDesiredSize.Width() - bp.LeftRight(),
|
||||
aDesiredSize.Height() - bp.TopBottom());
|
||||
|
||||
// Size & position the view according to 'object-fit' & 'object-position'.
|
||||
nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
|
||||
IntrinsicSize intrinsSize;
|
||||
nsSize intrinsRatio;
|
||||
if (subDocRoot) {
|
||||
intrinsSize = subDocRoot->GetIntrinsicSize();
|
||||
intrinsRatio = subDocRoot->GetIntrinsicRatio();
|
||||
}
|
||||
nsRect destRect =
|
||||
nsLayoutUtils::ComputeObjectDestRect(nsRect(offset, innerSize),
|
||||
intrinsSize, intrinsRatio,
|
||||
StylePosition());
|
||||
|
||||
nsViewManager* vm = mInnerView->GetViewManager();
|
||||
vm->MoveViewTo(mInnerView, offset.x, offset.y);
|
||||
vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), innerSize), true);
|
||||
vm->MoveViewTo(mInnerView, destRect.x, destRect.y);
|
||||
vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), destRect.Size()), true);
|
||||
}
|
||||
|
||||
aDesiredSize.SetOverflowAreasToDesiredBounds();
|
||||
|
@ -153,32 +153,18 @@ nsVideoFrame::IsLeaf() const
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return the largest rectangle that fits in aRect and has the
|
||||
// same aspect ratio as aRatio, centered at the center of aRect
|
||||
static gfxRect
|
||||
CorrectForAspectRatio(const gfxRect& aRect, const nsIntSize& aRatio)
|
||||
{
|
||||
NS_ASSERTION(aRatio.width > 0 && aRatio.height > 0 && !aRect.IsEmpty(),
|
||||
"Nothing to draw");
|
||||
// Choose scale factor that scales aRatio to just fit into aRect
|
||||
gfxFloat scale =
|
||||
std::min(aRect.Width()/aRatio.width, aRect.Height()/aRatio.height);
|
||||
gfxSize scaledRatio(scale*aRatio.width, scale*aRatio.height);
|
||||
gfxPoint topLeft((aRect.Width() - scaledRatio.width)/2,
|
||||
(aRect.Height() - scaledRatio.height)/2);
|
||||
return gfxRect(aRect.TopLeft() + topLeft, scaledRatio);
|
||||
}
|
||||
|
||||
already_AddRefed<Layer>
|
||||
nsVideoFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
nsDisplayItem* aItem,
|
||||
const ContainerLayerParameters& aContainerParameters)
|
||||
{
|
||||
nsRect area = GetContentRectRelativeToSelf() + aItem->ToReferenceFrame();
|
||||
nsSize contentBoxSize = GetContentRectRelativeToSelf().Size();
|
||||
HTMLVideoElement* element = static_cast<HTMLVideoElement*>(GetContent());
|
||||
nsIntSize videoSize;
|
||||
if (NS_FAILED(element->GetVideoSize(&videoSize)) || area.IsEmpty()) {
|
||||
|
||||
nsIntSize videoSizeInPx;
|
||||
if (NS_FAILED(element->GetVideoSize(&videoSizeInPx)) ||
|
||||
contentBoxSize.IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -194,21 +180,31 @@ nsVideoFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Compute the rectangle in which to paint the video. We need to use
|
||||
// the largest rectangle that fills our content-box and has the
|
||||
// correct aspect ratio.
|
||||
nsPresContext* presContext = PresContext();
|
||||
gfxRect r = gfxRect(presContext->AppUnitsToGfxUnits(area.x),
|
||||
presContext->AppUnitsToGfxUnits(area.y),
|
||||
presContext->AppUnitsToGfxUnits(area.width),
|
||||
presContext->AppUnitsToGfxUnits(area.height));
|
||||
r = CorrectForAspectRatio(r, videoSize);
|
||||
r.Round();
|
||||
if (r.IsEmpty()) {
|
||||
// Convert video size from pixel units into app units, to get an aspect-ratio
|
||||
// (which has to be represented as a nsSize) and an IntrinsicSize that we
|
||||
// can pass to ComputeObjectRenderRect.
|
||||
nsSize aspectRatio(nsPresContext::CSSPixelsToAppUnits(videoSizeInPx.width),
|
||||
nsPresContext::CSSPixelsToAppUnits(videoSizeInPx.height));
|
||||
IntrinsicSize intrinsicSize;
|
||||
intrinsicSize.width.SetCoordValue(aspectRatio.width);
|
||||
intrinsicSize.height.SetCoordValue(aspectRatio.height);
|
||||
|
||||
nsRect contentBoxRect(
|
||||
GetContentRectRelativeToSelf().TopLeft() + aItem->ToReferenceFrame(),
|
||||
contentBoxSize);
|
||||
|
||||
nsRect dest = nsLayoutUtils::ComputeObjectDestRect(contentBoxRect,
|
||||
intrinsicSize,
|
||||
aspectRatio,
|
||||
StylePosition());
|
||||
|
||||
gfxRect destGFXRect = PresContext()->AppUnitsToGfxUnits(dest);
|
||||
destGFXRect.Round();
|
||||
if (destGFXRect.IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
IntSize scaleHint(static_cast<int32_t>(r.Width()),
|
||||
static_cast<int32_t>(r.Height()));
|
||||
IntSize scaleHint(static_cast<int32_t>(destGFXRect.Width()),
|
||||
static_cast<int32_t>(destGFXRect.Height()));
|
||||
container->SetScaleHint(scaleHint);
|
||||
|
||||
nsRefPtr<ImageLayer> layer = static_cast<ImageLayer*>
|
||||
@ -222,10 +218,10 @@ nsVideoFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
layer->SetContainer(container);
|
||||
layer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this));
|
||||
// Set a transform on the layer to draw the video in the right place
|
||||
gfxPoint p = r.TopLeft() + aContainerParameters.mOffset;
|
||||
gfxPoint p = destGFXRect.TopLeft() + aContainerParameters.mOffset;
|
||||
Matrix transform = Matrix::Translation(p.x, p.y);
|
||||
layer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
|
||||
layer->SetScaleToSize(IntSize(r.width, r.height), ScaleMode::STRETCH);
|
||||
layer->SetScaleToSize(scaleHint, ScaleMode::STRETCH);
|
||||
nsRefPtr<Layer> result = layer.forget();
|
||||
return result.forget();
|
||||
}
|
||||
@ -287,35 +283,20 @@ nsVideoFrame::Reflow(nsPresContext* aPresContext,
|
||||
aMetrics.Width(),
|
||||
aMetrics.Height());
|
||||
|
||||
uint32_t posterHeight, posterWidth;
|
||||
nsSize scaledPosterSize(0, 0);
|
||||
nsSize computedArea(aReflowState.ComputedWidth(), aReflowState.ComputedHeight());
|
||||
nsPoint posterTopLeft(0, 0);
|
||||
|
||||
nsCOMPtr<nsIDOMHTMLImageElement> posterImage = do_QueryInterface(mPosterImage);
|
||||
if (!posterImage) {
|
||||
return;
|
||||
nsRect posterRenderRect;
|
||||
if (ShouldDisplayPoster()) {
|
||||
posterRenderRect =
|
||||
nsRect(nsPoint(mBorderPadding.left, mBorderPadding.top),
|
||||
nsSize(aReflowState.ComputedWidth(),
|
||||
aReflowState.ComputedHeight()));
|
||||
}
|
||||
posterImage->GetNaturalHeight(&posterHeight);
|
||||
posterImage->GetNaturalWidth(&posterWidth);
|
||||
|
||||
if (ShouldDisplayPoster() && posterHeight && posterWidth) {
|
||||
gfxFloat scale =
|
||||
std::min(static_cast<float>(computedArea.width)/nsPresContext::CSSPixelsToAppUnits(static_cast<float>(posterWidth)),
|
||||
static_cast<float>(computedArea.height)/nsPresContext::CSSPixelsToAppUnits(static_cast<float>(posterHeight)));
|
||||
gfxSize scaledRatio = gfxSize(scale*posterWidth, scale*posterHeight);
|
||||
scaledPosterSize.width = nsPresContext::CSSPixelsToAppUnits(static_cast<float>(scaledRatio.width));
|
||||
scaledPosterSize.height = nsPresContext::CSSPixelsToAppUnits(static_cast<int32_t>(scaledRatio.height));
|
||||
}
|
||||
kidReflowState.SetComputedWidth(scaledPosterSize.width);
|
||||
kidReflowState.SetComputedHeight(scaledPosterSize.height);
|
||||
posterTopLeft.x = ((computedArea.width - scaledPosterSize.width) / 2) + mBorderPadding.left;
|
||||
posterTopLeft.y = ((computedArea.height - scaledPosterSize.height) / 2) + mBorderPadding.top;
|
||||
|
||||
kidReflowState.SetComputedWidth(posterRenderRect.width);
|
||||
kidReflowState.SetComputedHeight(posterRenderRect.height);
|
||||
ReflowChild(imageFrame, aPresContext, kidDesiredSize, kidReflowState,
|
||||
posterTopLeft.x, posterTopLeft.y, 0, aStatus);
|
||||
FinishReflowChild(imageFrame, aPresContext, kidDesiredSize, &kidReflowState,
|
||||
posterTopLeft.x, posterTopLeft.y, 0);
|
||||
posterRenderRect.x, posterRenderRect.y, 0, aStatus);
|
||||
FinishReflowChild(imageFrame, aPresContext,
|
||||
kidDesiredSize, &kidReflowState,
|
||||
posterRenderRect.x, posterRenderRect.y, 0);
|
||||
} else if (child->GetContent() == mVideoControls) {
|
||||
// Reflow the video controls frame.
|
||||
nsBoxLayoutState boxState(PresContext(), aReflowState.rendContext);
|
||||
|
@ -720,6 +720,13 @@ video {
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
video > img:-moz-native-anonymous {
|
||||
/* Video poster images should render with the video element's "object-fit" &
|
||||
"object-position" properties */
|
||||
object-fit: inherit !important;
|
||||
object-position: inherit !important;
|
||||
}
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user