Skip to content

Commit

Permalink
Bug 1783069 - Make aspect-ratio work on <video> properly. r=boris,Ori…
Browse files Browse the repository at this point in the history
…ol,layout-reviewers

See w3c/csswg-drafts#7524 for discussion. This
matches what we do for images.

Differential Revision: https://phabricator.services.mozilla.com/D153664
  • Loading branch information
emilio committed Aug 16, 2022
1 parent a5d1294 commit c94712a
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 29 deletions.
61 changes: 37 additions & 24 deletions layout/generic/nsVideoFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ nscoord nsVideoFrame::GetMinISize(gfxContext* aRenderingContext) {
// therefore must match the function's return value.
DISPLAY_MIN_INLINE_SIZE(this, result);
// This call handles size-containment
nsSize size = GetVideoIntrinsicSize();
nsSize size = GetIntrinsicSize().ToSize().valueOr(nsSize());
result = GetWritingMode().IsVertical() ? size.height : size.width;
return result;
}
Expand All @@ -424,7 +424,7 @@ AspectRatio nsVideoFrame::GetIntrinsicRatio() const {
return AspectRatio();
}

HTMLVideoElement* element = static_cast<HTMLVideoElement*>(GetContent());
auto* element = static_cast<HTMLVideoElement*>(GetContent());
if (Maybe<CSSIntSize> size = element->GetVideoSize()) {
return AspectRatio::FromSize(*size);
}
Expand All @@ -435,14 +435,22 @@ AspectRatio nsVideoFrame::GetIntrinsicRatio() const {
}
}

if (StylePosition()->mAspectRatio.HasRatio()) {
return AspectRatio();
}

return AspectRatio::FromSize(kFallbackIntrinsicSizeInPixels);
}

bool nsVideoFrame::ShouldDisplayPoster() const {
if (!HasVideoElement()) return false;
if (!HasVideoElement()) {
return false;
}

HTMLVideoElement* element = static_cast<HTMLVideoElement*>(GetContent());
if (element->GetPlayedOrSeeked() && HasVideoData()) return false;
auto* element = static_cast<HTMLVideoElement*>(GetContent());
if (element->GetPlayedOrSeeked() && HasVideoData()) {
return false;
}

nsCOMPtr<nsIImageLoadingContent> imgContent = do_QueryInterface(mPosterImage);
NS_ENSURE_TRUE(imgContent, false);
Expand All @@ -461,48 +469,53 @@ bool nsVideoFrame::ShouldDisplayPoster() const {
return true;
}

nsSize nsVideoFrame::GetVideoIntrinsicSize() const {
IntrinsicSize nsVideoFrame::GetIntrinsicSize() {
const auto containAxes = StyleDisplay()->GetContainSizeAxes();
const auto isVideo = HasVideoElement();
// Intrinsic size will be given by contain-intrinsic-size if the element is
// size-contained. If both axes have containment, ContainSize() will ignore
// the fallback size argument, so we can just pass 0,0 or whatever.
// size-contained. If both axes have containment, ContainIntrinsicSize() will
// ignore the fallback size argument, so we can just pass no intrinsic size,
// or whatever.
if (containAxes.IsBoth()) {
return containAxes.ContainSize({}, *this);
}

// An audio element with no "controls" attribute, distinguished by the last
// and only child being the control, falls back to 0,0.
if (!isVideo && !mFrames.LastChild()) {
return containAxes.ContainSize({}, *this);
return containAxes.ContainIntrinsicSize({}, *this);
}

if (!isVideo) {
return containAxes.ContainSize(kFallbackIntrinsicSize, *this);
// An audio element with no "controls" attribute, distinguished by the last
// and only child being the control, falls back to no intrinsic size.
if (!mFrames.LastChild()) {
return containAxes.ContainIntrinsicSize({}, *this);
}

return containAxes.ContainIntrinsicSize(
IntrinsicSize(kFallbackIntrinsicSize), *this);
}

HTMLVideoElement* element = static_cast<HTMLVideoElement*>(GetContent());
auto* element = static_cast<HTMLVideoElement*>(GetContent());
if (Maybe<CSSIntSize> size = element->GetVideoSize()) {
return containAxes.ContainSize(CSSPixel::ToAppUnits(*size), *this);
return containAxes.ContainIntrinsicSize(
IntrinsicSize(CSSPixel::ToAppUnits(*size)), *this);
}

if (ShouldDisplayPoster()) {
if (Maybe<nsSize> imgSize = PosterImageSize()) {
return containAxes.ContainSize(*imgSize, *this);
return containAxes.ContainIntrinsicSize(IntrinsicSize(*imgSize), *this);
}
}
return containAxes.ContainSize(kFallbackIntrinsicSize, *this);
}

IntrinsicSize nsVideoFrame::GetIntrinsicSize() {
return IntrinsicSize(GetVideoIntrinsicSize());
if (StylePosition()->mAspectRatio.HasRatio()) {
return {};
}

return containAxes.ContainIntrinsicSize(IntrinsicSize(kFallbackIntrinsicSize),
*this);
}

void nsVideoFrame::UpdatePosterSource(bool aNotify) {
NS_ASSERTION(HasVideoElement(), "Only call this on <video> elements.");
HTMLVideoElement* element = static_cast<HTMLVideoElement*>(GetContent());

if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::poster) &&
if (element->HasAttr(nsGkAtoms::poster) &&
!element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::poster,
nsGkAtoms::_empty, eIgnoreCase)) {
nsAutoString posterStr;
Expand Down
1 change: 0 additions & 1 deletion layout/generic/nsVideoFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ class nsVideoFrame final : public nsContainerFrame,
const Maybe<OnNonvisible>& aNonvisibleAction = Nothing()) override;

/* get the size of the video's display */
nsSize GetVideoIntrinsicSize() const;
mozilla::IntrinsicSize GetIntrinsicSize() override;
mozilla::AspectRatio GetIntrinsicRatio() const override;
SizeComputationResult ComputeSize(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,30 @@
video.setAttribute("height", "100");
video.src = getVideoURI('/media/2x2-green');
document.body.appendChild(video);
// Videos default to a size of 300x150px and calculate their aspect ratio
// based on that before the video is loaded. So this should be 2, ignoring
// the 2.5 that it would be based on the attributes.
assert_ratio(video, 2);
assert_ratio(video, 2.5);

video.onloadeddata = t.step_func_done(function() {
// When loaded this video is square.
assert_ratio(video, 1);
});
}, "aspect ratio for regular video");

// Same but with auto width.
t.step(function() {
video = document.createElement("video");
video.setAttribute("width", "250");
video.setAttribute("height", "100");
video.style.width = "auto";
video.src = getVideoURI('/media/2x2-green');
document.body.appendChild(video);
assert_ratio(video, 2.5);

video.onloadeddata = t.step_func_done(function() {
// When loaded this video is square.
assert_ratio(video, 1);
});
}, "aspect ratio for regular video with width: auto and height: auto");

test_computed_style("10", "20", "auto 10 / 20");
test_computed_style("0.5", "1.5", "auto 0.5 / 1.5");
test_computed_style("0", "1", "auto 0 / 1");
Expand Down

0 comments on commit c94712a

Please sign in to comment.