mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 14:52:16 +00:00
Bug 449156 - Implement HTMLVideoElement.poster, with correct reftests. r+=doublec,jst, sr+=roc
This commit is contained in:
parent
d4c3dad091
commit
21a86f06aa
@ -64,7 +64,7 @@ interface nsIURI;
|
||||
* sufficient, when combined with the imageBlockingStatus information.)
|
||||
*/
|
||||
|
||||
[scriptable, uuid(7744c6d3-5c60-4b7b-a526-4fe9d5ac7e97)]
|
||||
[scriptable, uuid(e036857e-3417-4812-a5f2-89668a616781)]
|
||||
interface nsIImageLoadingContent : imgIDecoderObserver
|
||||
{
|
||||
/**
|
||||
@ -167,4 +167,12 @@ interface nsIImageLoadingContent : imgIDecoderObserver
|
||||
* @throws NS_ERROR_NOT_AVAILABLE if there is no current URI to reload
|
||||
*/
|
||||
void forceReload();
|
||||
|
||||
/**
|
||||
* Enables/disables image state forcing. When |aForce| is PR_TRUE, we force
|
||||
* nsImageLoadingContent::ImageState() to return |aState|. Call again with |aForce|
|
||||
* as PR_FALSE to revert ImageState() to its original behaviour.
|
||||
*/
|
||||
void forceImageState(in boolean aForce, in long aState);
|
||||
|
||||
};
|
||||
|
@ -109,7 +109,8 @@ nsImageLoadingContent::nsImageLoadingContent()
|
||||
// mBroken starts out true, since an image without a URI is broken....
|
||||
mBroken(PR_TRUE),
|
||||
mUserDisabled(PR_FALSE),
|
||||
mSuppressed(PR_FALSE)
|
||||
mSuppressed(PR_FALSE),
|
||||
mIsImageStateForced(PR_FALSE)
|
||||
{
|
||||
if (!nsContentUtils::GetImgLoader()) {
|
||||
mLoadingEnabled = PR_FALSE;
|
||||
@ -617,10 +618,18 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsImageLoadingContent::ForceImageState(PRBool aForce, PRInt32 aState)
|
||||
{
|
||||
mIsImageStateForced = aForce;
|
||||
mForcedImageState = aState;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRInt32
|
||||
nsImageLoadingContent::ImageState() const
|
||||
{
|
||||
return
|
||||
return mIsImageStateForced ? mForcedImageState :
|
||||
(mBroken * NS_EVENT_STATE_BROKEN) |
|
||||
(mUserDisabled * NS_EVENT_STATE_USERDISABLED) |
|
||||
(mSuppressed * NS_EVENT_STATE_SUPPRESSED) |
|
||||
|
@ -260,10 +260,21 @@ private:
|
||||
*/
|
||||
ImageObserver mObserverList;
|
||||
|
||||
/**
|
||||
* When mIsImageStateForced is true, this holds the ImageState that we'll
|
||||
* return in ImageState().
|
||||
*/
|
||||
PRInt32 mForcedImageState;
|
||||
|
||||
PRInt16 mImageBlockingStatus;
|
||||
PRPackedBool mLoadingEnabled : 1;
|
||||
PRPackedBool mStartingLoad : 1;
|
||||
|
||||
/**
|
||||
* When true, we return mForcedImageState from ImageState().
|
||||
*/
|
||||
PRPackedBool mIsImageStateForced : 1;
|
||||
|
||||
/**
|
||||
* The state we had the last time we checked whether we needed to notify the
|
||||
* document of a state change. These are maintained by UpdateImageState.
|
||||
|
@ -256,11 +256,24 @@ public:
|
||||
*/
|
||||
already_AddRefed<nsILoadGroup> GetDocumentLoadGroup();
|
||||
|
||||
/**
|
||||
* Returns PR_TRUE if the media has played or completed a seek.
|
||||
* Used by video frame to determine whether to paint the poster.
|
||||
*/
|
||||
PRBool GetPlayedOrSeeked() { return mHasPlayedOrSeeked; }
|
||||
|
||||
protected:
|
||||
class MediaLoadListener;
|
||||
class LoadNextSourceEvent;
|
||||
class SelectResourceEvent;
|
||||
|
||||
/**
|
||||
* Changes mHasPlayedOrSeeked to aValue. If mHasPlayedOrSeeked changes
|
||||
* we'll force a reflow so that the video frame gets reflowed to reflect
|
||||
* the poster hiding or showing immediately.
|
||||
*/
|
||||
void SetPlayedOrSeeked(PRBool aValue);
|
||||
|
||||
/**
|
||||
* Create a decoder for the given aMIMEType. Returns false if we
|
||||
* were unable to create the decoder.
|
||||
@ -469,4 +482,8 @@ protected:
|
||||
// PR_TRUE if we are allowed to suspend the decoder because we were paused,
|
||||
// autobuffer and autoplay were not set, and we loaded the first frame.
|
||||
PRPackedBool mAllowSuspendAfterFirstFrame;
|
||||
|
||||
// PR_TRUE if we've played or completed a seek. We use this to determine
|
||||
// when the poster frame should be shown.
|
||||
PRPackedBool mHasPlayedOrSeeked;
|
||||
};
|
||||
|
@ -413,6 +413,7 @@ NS_IMETHODIMP nsHTMLMediaElement::Load()
|
||||
{
|
||||
if (mIsRunningLoadMethod)
|
||||
return NS_OK;
|
||||
SetPlayedOrSeeked(PR_FALSE);
|
||||
mIsRunningLoadMethod = PR_TRUE;
|
||||
AbortExistingLoads();
|
||||
QueueSelectResourceTask();
|
||||
@ -784,7 +785,8 @@ nsHTMLMediaElement::nsHTMLMediaElement(nsINodeInfo *aNodeInfo, PRBool aFromParse
|
||||
mDelayingLoadEvent(PR_FALSE),
|
||||
mIsRunningSelectResource(PR_FALSE),
|
||||
mSuspendedAfterFirstFrame(PR_FALSE),
|
||||
mAllowSuspendAfterFirstFrame(PR_TRUE)
|
||||
mAllowSuspendAfterFirstFrame(PR_TRUE),
|
||||
mHasPlayedOrSeeked(PR_FALSE)
|
||||
{
|
||||
RegisterFreezableElement();
|
||||
}
|
||||
@ -813,9 +815,29 @@ void nsHTMLMediaElement::StopSuspendingAfterFirstFrame()
|
||||
}
|
||||
}
|
||||
|
||||
void nsHTMLMediaElement::SetPlayedOrSeeked(PRBool aValue)
|
||||
{
|
||||
if (aValue == mHasPlayedOrSeeked)
|
||||
return;
|
||||
|
||||
mHasPlayedOrSeeked = aValue;
|
||||
|
||||
// Force a reflow so that the poster frame hides or shows immediately.
|
||||
nsIDocument *doc = GetDocument();
|
||||
if (!doc) return;
|
||||
nsIPresShell *presShell = doc->GetPrimaryShell();
|
||||
if (!presShell) return;
|
||||
nsIFrame* frame = presShell->GetPrimaryFrameFor(this);
|
||||
if (!frame) return;
|
||||
presShell->FrameNeedsReflow(frame,
|
||||
nsIPresShell::eTreeChange,
|
||||
NS_FRAME_IS_DIRTY);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsHTMLMediaElement::Play()
|
||||
{
|
||||
StopSuspendingAfterFirstFrame();
|
||||
SetPlayedOrSeeked(PR_TRUE);
|
||||
|
||||
if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_EMPTY) {
|
||||
nsresult rv = Load();
|
||||
@ -1204,6 +1226,7 @@ nsresult nsHTMLMediaElement::InitializeDecoderForChannel(nsIChannel *aChannel,
|
||||
mDecoder->SetVolume(mMuted ? 0.0 : mVolume);
|
||||
|
||||
if (!mPaused) {
|
||||
SetPlayedOrSeeked(PR_TRUE);
|
||||
rv = mDecoder->Play();
|
||||
}
|
||||
|
||||
@ -1301,6 +1324,7 @@ void nsHTMLMediaElement::SeekStarted()
|
||||
void nsHTMLMediaElement::SeekCompleted()
|
||||
{
|
||||
mPlayingBeforeSeek = PR_FALSE;
|
||||
SetPlayedOrSeeked(PR_TRUE);
|
||||
DispatchAsyncSimpleEvent(NS_LITERAL_STRING("seeked"));
|
||||
}
|
||||
|
||||
@ -1454,6 +1478,7 @@ void nsHTMLMediaElement::NotifyAutoplayDataReady()
|
||||
mAutoplayEnabled) {
|
||||
mPaused = PR_FALSE;
|
||||
if (mDecoder) {
|
||||
SetPlayedOrSeeked(PR_TRUE);
|
||||
mDecoder->Play();
|
||||
}
|
||||
DispatchAsyncSimpleEvent(NS_LITERAL_STRING("play"));
|
||||
|
@ -158,3 +158,5 @@ nsHTMLVideoElement::GetAttributeMappingFunction() const
|
||||
{
|
||||
return &MapAttributesIntoRule;
|
||||
}
|
||||
|
||||
NS_IMPL_URI_ATTR(nsHTMLVideoElement, Poster, poster)
|
||||
|
@ -48,12 +48,13 @@
|
||||
* @status UNDER_DEVELOPMENT
|
||||
*/
|
||||
|
||||
[scriptable, uuid(4e3f05a5-ca9b-4576-af7f-b1d4038e6eb3)]
|
||||
[scriptable, uuid(edf468dc-42eb-4494-920b-56a315172640)]
|
||||
interface nsIDOMHTMLVideoElement : nsIDOMHTMLMediaElement
|
||||
{
|
||||
attribute long width;
|
||||
attribute long height;
|
||||
readonly attribute unsigned long videoWidth;
|
||||
readonly attribute unsigned long videoHeight;
|
||||
attribute DOMString poster;
|
||||
};
|
||||
|
||||
|
@ -55,6 +55,8 @@
|
||||
#include "nsContentCreatorFunctions.h"
|
||||
#include "nsBoxLayoutState.h"
|
||||
#include "nsBoxFrame.h"
|
||||
#include "nsImageFrame.h"
|
||||
#include "nsIImageLoadingContent.h"
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
#include "nsIServiceManager.h"
|
||||
@ -87,20 +89,50 @@ NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
|
||||
nsresult
|
||||
nsVideoFrame::CreateAnonymousContent(nsTArray<nsIContent*>& aElements)
|
||||
{
|
||||
nsNodeInfoManager *nodeInfoManager = GetContent()->GetCurrentDoc()->NodeInfoManager();
|
||||
nsCOMPtr<nsINodeInfo> nodeInfo;
|
||||
if (HasVideoElement()) {
|
||||
// Create an anonymous image element as a child to hold the poster
|
||||
// image. We may not have a poster image now, but one could be added
|
||||
// before we load, or on a subsequent load.
|
||||
nodeInfo = nodeInfoManager->GetNodeInfo(nsGkAtoms::img,
|
||||
nsnull,
|
||||
kNameSpaceID_None);
|
||||
NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
|
||||
mPosterImage = NS_NewHTMLImageElement(nodeInfo);
|
||||
NS_ENSURE_TRUE(mPosterImage, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
// Set the nsImageLoadingContent::ImageState() to 0. This means that the
|
||||
// image will always report its state as 0, so it will never be reframed
|
||||
// to show frames for loading or the broken image icon. This is important,
|
||||
// as the image is native anonymous, and so can't be reframed (currently).
|
||||
nsCOMPtr<nsIImageLoadingContent> imgContent = do_QueryInterface(mPosterImage);
|
||||
NS_ENSURE_TRUE(imgContent, NS_ERROR_FAILURE);
|
||||
|
||||
imgContent->ForceImageState(PR_TRUE, 0);
|
||||
|
||||
nsresult res = UpdatePosterSource(PR_FALSE);
|
||||
NS_ENSURE_SUCCESS(res,res);
|
||||
|
||||
if (!aElements.AppendElement(mPosterImage))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Set up "videocontrols" XUL element which will be XBL-bound to the
|
||||
// actual controls.
|
||||
nsPresContext* presContext = PresContext();
|
||||
nsNodeInfoManager *nodeInfoManager =
|
||||
presContext->Document()->NodeInfoManager();
|
||||
nsCOMPtr<nsINodeInfo> nodeInfo;
|
||||
nodeInfo = nodeInfoManager->GetNodeInfo(nsGkAtoms::videocontrols, nsnull,
|
||||
nodeInfo = nodeInfoManager->GetNodeInfo(nsGkAtoms::videocontrols,
|
||||
nsnull,
|
||||
kNameSpaceID_XUL);
|
||||
NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsresult rv = NS_NewElement(getter_AddRefs(mVideoControls), kNameSpaceID_XUL, nodeInfo, PR_FALSE);
|
||||
nsresult rv = NS_NewElement(getter_AddRefs(mVideoControls),
|
||||
kNameSpaceID_XUL,
|
||||
nodeInfo,
|
||||
PR_FALSE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!aElements.AppendElement(mVideoControls))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -108,6 +140,7 @@ void
|
||||
nsVideoFrame::Destroy()
|
||||
{
|
||||
nsContentUtils::DestroyAnonymousContent(&mVideoControls);
|
||||
nsContentUtils::DestroyAnonymousContent(&mPosterImage);
|
||||
nsContainerFrame::Destroy();
|
||||
}
|
||||
|
||||
@ -179,16 +212,46 @@ nsVideoFrame::Reflow(nsPresContext* aPresContext,
|
||||
aMetrics.width += mBorderPadding.left + mBorderPadding.right;
|
||||
aMetrics.height += mBorderPadding.top + mBorderPadding.bottom;
|
||||
|
||||
nsIFrame* child = mFrames.FirstChild();
|
||||
if (child) {
|
||||
NS_ASSERTION(child->GetContent() == mVideoControls,
|
||||
"What is this child doing here?");
|
||||
nsBoxLayoutState boxState(PresContext(), aReflowState.rendContext);
|
||||
nsBoxFrame::LayoutChildAt(boxState, child,
|
||||
nsRect(mBorderPadding.left, mBorderPadding.top,
|
||||
aReflowState.ComputedWidth(), aReflowState.ComputedHeight()));
|
||||
// Reflow the child frames. We may have up to two, an image frame
|
||||
// which is the poster, and a box frame, which is the video controls.
|
||||
for (nsIFrame *child = mFrames.FirstChild();
|
||||
child;
|
||||
child = child->GetNextSibling()) {
|
||||
if (child->GetType() == nsGkAtoms::imageFrame) {
|
||||
// Reflow the poster frame.
|
||||
nsImageFrame* imageFrame = static_cast<nsImageFrame*>(child);
|
||||
nsHTMLReflowMetrics kidDesiredSize;
|
||||
nsSize availableSize = nsSize(aReflowState.availableWidth,
|
||||
aReflowState.availableHeight);
|
||||
nsHTMLReflowState kidReflowState(aPresContext,
|
||||
aReflowState,
|
||||
imageFrame,
|
||||
availableSize,
|
||||
aMetrics.width,
|
||||
aMetrics.height);
|
||||
if (ShouldDisplayPoster()) {
|
||||
kidReflowState.SetComputedWidth(aReflowState.ComputedWidth());
|
||||
kidReflowState.SetComputedHeight(aReflowState.ComputedHeight());
|
||||
} else {
|
||||
kidReflowState.SetComputedWidth(0);
|
||||
kidReflowState.SetComputedHeight(0);
|
||||
}
|
||||
ReflowChild(imageFrame, aPresContext, kidDesiredSize, kidReflowState,
|
||||
mBorderPadding.left, mBorderPadding.top, 0, aStatus);
|
||||
FinishReflowChild(imageFrame, aPresContext,
|
||||
&kidReflowState, kidDesiredSize,
|
||||
mBorderPadding.left, mBorderPadding.top, 0);
|
||||
} else if (child->GetType() == nsGkAtoms::boxFrame) {
|
||||
// Reflow the video controls frame.
|
||||
nsBoxLayoutState boxState(PresContext(), aReflowState.rendContext);
|
||||
nsBoxFrame::LayoutChildAt(boxState,
|
||||
child,
|
||||
nsRect(mBorderPadding.left,
|
||||
mBorderPadding.top,
|
||||
aReflowState.ComputedWidth(),
|
||||
aReflowState.ComputedHeight()));
|
||||
}
|
||||
}
|
||||
|
||||
aMetrics.mOverflowArea.SetRect(0, 0, aMetrics.width, aMetrics.height);
|
||||
|
||||
FinishAndStoreOverflow(&aMetrics);
|
||||
@ -233,16 +296,30 @@ nsVideoFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (HasVideoData()) {
|
||||
if (!ShouldDisplayPoster() && HasVideoData()) {
|
||||
rv = aLists.Content()->AppendNewToTop(new (aBuilder) nsDisplayGeneric(this, ::PaintVideo, "Video"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
nsIFrame *kid = mFrames.FirstChild();
|
||||
if (kid) {
|
||||
rv = kid->BuildDisplayListForStackingContext(aBuilder, aDirtyRect - kid->GetOffsetTo(this), aLists.Content());
|
||||
// Add child frames to display list. We expect up to two children, an image
|
||||
// frame for the poster, and the box frame for the video controls.
|
||||
for (nsIFrame *child = mFrames.FirstChild();
|
||||
child;
|
||||
child = child->GetNextSibling()) {
|
||||
if (child->GetType() == nsGkAtoms::imageFrame && ShouldDisplayPoster()) {
|
||||
rv = child->BuildDisplayListForStackingContext(aBuilder,
|
||||
aDirtyRect - child->GetOffsetTo(this),
|
||||
aLists.Content());
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
} else if (child->GetType() == nsGkAtoms::boxFrame) {
|
||||
rv = child->BuildDisplayListForStackingContext(aBuilder,
|
||||
aDirtyRect - child->GetOffsetTo(this),
|
||||
aLists.Content());
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIAtom*
|
||||
@ -317,11 +394,49 @@ nsSize nsVideoFrame::GetIntrinsicRatio()
|
||||
return GetIntrinsicSize(nsnull);
|
||||
}
|
||||
|
||||
PRBool nsVideoFrame::ShouldDisplayPoster()
|
||||
{
|
||||
if (!HasVideoElement())
|
||||
return PR_FALSE;
|
||||
|
||||
nsHTMLVideoElement* element = static_cast<nsHTMLVideoElement*>(GetContent());
|
||||
if (element->GetPlayedOrSeeked() && HasVideoData())
|
||||
return PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIImageLoadingContent> imgContent = do_QueryInterface(mPosterImage);
|
||||
NS_ENSURE_TRUE(imgContent, PR_FALSE);
|
||||
|
||||
nsCOMPtr<imgIRequest> request;
|
||||
nsresult res = imgContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
|
||||
getter_AddRefs(request));
|
||||
if (NS_FAILED(res) || !request) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRUint32 status = 0;
|
||||
res = request->GetImageStatus(&status);
|
||||
if (NS_FAILED(res) || (status & imgIRequest::STATUS_ERROR))
|
||||
return PR_FALSE;
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsSize nsVideoFrame::GetIntrinsicSize(nsIRenderingContext *aRenderingContext)
|
||||
{
|
||||
// Defaulting size to 300x150 if no size given.
|
||||
nsIntSize size(300,150);
|
||||
|
||||
if (ShouldDisplayPoster()) {
|
||||
// Use the poster image frame's size.
|
||||
nsIFrame *child = mFrames.FirstChild();
|
||||
if (child && child->GetType() == nsGkAtoms::imageFrame) {
|
||||
nsImageFrame* imageFrame = static_cast<nsImageFrame*>(child);
|
||||
nsSize imgsize;
|
||||
imageFrame->GetIntrinsicImageSize(imgsize);
|
||||
return imgsize;
|
||||
}
|
||||
}
|
||||
|
||||
if (!HasVideoData()) {
|
||||
if (!aRenderingContext || !mFrames.FirstChild()) {
|
||||
// We just want our intrinsic ratio, but audio elements need no
|
||||
@ -332,21 +447,57 @@ nsSize nsVideoFrame::GetIntrinsicSize(nsIRenderingContext *aRenderingContext)
|
||||
|
||||
// Ask the controls frame what its preferred height is
|
||||
nsBoxLayoutState boxState(PresContext(), aRenderingContext, 0);
|
||||
nscoord prefHeight = mFrames.FirstChild()->GetPrefSize(boxState).height;
|
||||
nscoord prefHeight = mFrames.LastChild()->GetPrefSize(boxState).height;
|
||||
return nsSize(nsPresContext::CSSPixelsToAppUnits(size.width), prefHeight);
|
||||
}
|
||||
|
||||
nsHTMLVideoElement* element = static_cast<nsHTMLVideoElement*>(GetContent());
|
||||
if (element) {
|
||||
size = element->GetVideoSize(size);
|
||||
}
|
||||
size = element->GetVideoSize(size);
|
||||
|
||||
return nsSize(nsPresContext::CSSPixelsToAppUnits(size.width),
|
||||
nsPresContext::CSSPixelsToAppUnits(size.height));
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsVideoFrame::UpdatePosterSource(PRBool aNotify)
|
||||
{
|
||||
NS_ASSERTION(HasVideoElement(), "Only call this on <video> elements.");
|
||||
nsHTMLVideoElement* element = static_cast<nsHTMLVideoElement*>(GetContent());
|
||||
|
||||
nsAutoString posterStr;
|
||||
element->GetPoster(posterStr);
|
||||
nsresult res = mPosterImage->SetAttr(kNameSpaceID_None,
|
||||
nsGkAtoms::src,
|
||||
posterStr,
|
||||
aNotify);
|
||||
NS_ENSURE_SUCCESS(res,res);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsVideoFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
PRInt32 aModType)
|
||||
{
|
||||
if (aAttribute == nsGkAtoms::poster) {
|
||||
nsresult res = UpdatePosterSource(PR_TRUE);
|
||||
NS_ENSURE_SUCCESS(res,res);
|
||||
}
|
||||
return nsContainerFrame::AttributeChanged(aNameSpaceID,
|
||||
aAttribute,
|
||||
aModType);
|
||||
}
|
||||
|
||||
PRBool nsVideoFrame::HasVideoElement() {
|
||||
nsCOMPtr<nsIDOMHTMLVideoElement> videoDomElement = do_QueryInterface(mContent);
|
||||
return videoDomElement != nsnull;
|
||||
}
|
||||
|
||||
PRBool nsVideoFrame::HasVideoData()
|
||||
{
|
||||
nsCOMPtr<nsIDOMHTMLVideoElement> videoElem = do_QueryInterface(mContent);
|
||||
return videoElem != nsnull;
|
||||
if (!HasVideoElement())
|
||||
return PR_FALSE;
|
||||
nsHTMLVideoElement* element = static_cast<nsHTMLVideoElement*>(GetContent());
|
||||
nsIntSize size = element->GetVideoSize(nsIntSize(0,0));
|
||||
return size != nsIntSize(0,0);
|
||||
}
|
||||
|
@ -63,6 +63,10 @@ public:
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists);
|
||||
|
||||
NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
PRInt32 aModType);
|
||||
|
||||
void PaintVideo(nsIRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect, nsPoint aPt);
|
||||
|
||||
@ -101,14 +105,33 @@ public:
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// Returns true if there is video data to render. Can return false
|
||||
// when we're the frame for an audio element.
|
||||
|
||||
// Returns PR_TRUE if we're rendering for a video element. We still create
|
||||
// nsVideoFrame to render controls for an audio element.
|
||||
PRBool HasVideoElement();
|
||||
|
||||
// Returns PR_TRUE if there is video data to render. Can return false
|
||||
// when we're the frame for an audio element, or we've created a video
|
||||
// element for a media which is audio-only.
|
||||
PRBool HasVideoData();
|
||||
|
||||
// Returns PR_TRUE if we should display the poster. Note that once we show
|
||||
// a video frame, the poster will never be displayed again.
|
||||
PRBool ShouldDisplayPoster();
|
||||
|
||||
// Sets the mPosterImage's src attribute to be the video's poster attribute,
|
||||
// if we're the frame for a video element.
|
||||
nsresult UpdatePosterSource(PRBool aNotify);
|
||||
|
||||
virtual ~nsVideoFrame();
|
||||
|
||||
nsMargin mBorderPadding;
|
||||
|
||||
// Anonymous child which is bound via XBL to the video controls.
|
||||
nsCOMPtr<nsIContent> mVideoControls;
|
||||
|
||||
// Anonymous child which is the image element of the poster frame.
|
||||
nsCOMPtr<nsIContent> mPosterImage;
|
||||
};
|
||||
|
||||
#endif /* nsVideoFrame_h___ */
|
||||
|
BIN
layout/reftests/ogg-video/blue250x200.png
Normal file
BIN
layout/reftests/ogg-video/blue250x200.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
BIN
layout/reftests/ogg-video/green70x30.png
Normal file
BIN
layout/reftests/ogg-video/green70x30.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 224 B |
7
layout/reftests/ogg-video/poster-1.html
Normal file
7
layout/reftests/ogg-video/poster-1.html
Normal file
@ -0,0 +1,7 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body style="background:white;">
|
||||
<!-- Test if poster frame displays correctly when poster is different size. -->
|
||||
<video src="black140x100.ogv" poster="blue250x200.png"></video>
|
||||
</body>
|
||||
</html>
|
18
layout/reftests/ogg-video/poster-10.html
Normal file
18
layout/reftests/ogg-video/poster-10.html
Normal file
@ -0,0 +1,18 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<!-- Test: Create video, add poster, load. Should display poster. -->
|
||||
<script>
|
||||
function runTest() {
|
||||
var v = document.createElement('video');
|
||||
v.addEventListener('loadeddata', function(){setTimeout(function(){document.documentElement.className = '';}, 0);}, false);
|
||||
v.id = 'v';
|
||||
v.src = "black140x100.ogv";
|
||||
v.poster = "blue250x200.png";
|
||||
v.autobuffer = true;
|
||||
document.body.appendChild(v);
|
||||
}
|
||||
|
||||
</script>
|
||||
<body style="background:white;" onload="runTest();">
|
||||
</body>
|
||||
</html>
|
29
layout/reftests/ogg-video/poster-11.html
Normal file
29
layout/reftests/ogg-video/poster-11.html
Normal file
@ -0,0 +1,29 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<!-- Test: Create video, load. Add poster frame, load again, poster should show. -->
|
||||
<script>
|
||||
function runTest() {
|
||||
var v = document.createElement('video');
|
||||
|
||||
var endTest = function() {
|
||||
setTimeout(function(){document.documentElement.className = '';}, 0);
|
||||
};
|
||||
|
||||
var addPoster = function() {
|
||||
v.removeEventListener('loadeddata', addPoster, false);
|
||||
v.poster = "blue250x200.png";
|
||||
v.addEventListener('loadeddata', endTest, false);
|
||||
v.load();
|
||||
};
|
||||
|
||||
v.addEventListener('loadeddata', addPoster, false);
|
||||
v.id = 'v';
|
||||
v.src = "black140x100.ogv";
|
||||
v.autobuffer = true;
|
||||
document.body.appendChild(v);
|
||||
}
|
||||
|
||||
</script>
|
||||
<body style="background:white;" onload="runTest();">
|
||||
</body>
|
||||
</html>
|
40
layout/reftests/ogg-video/poster-12.html
Normal file
40
layout/reftests/ogg-video/poster-12.html
Normal file
@ -0,0 +1,40 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<!-- Test: Create video, load, play. Add poster frame, load again, poster should show. -->
|
||||
<script>
|
||||
function runTest() {
|
||||
var v = document.createElement('video');
|
||||
|
||||
var endTest = function() {
|
||||
setTimeout(function(){document.documentElement.className = '';}, 0);
|
||||
};
|
||||
|
||||
var play =
|
||||
function() {
|
||||
v.removeEventListener('loadeddata', play, false);
|
||||
v.play();
|
||||
}
|
||||
|
||||
var addPoster = function() {
|
||||
v.removeEventListener('playing', addPoster,false);
|
||||
v.poster = "blue250x200.png";
|
||||
v.addEventListener('loadeddata', endTest, false);
|
||||
v.load();
|
||||
};
|
||||
|
||||
v.addEventListener('loadeddata',
|
||||
play,
|
||||
false);
|
||||
v.addEventListener('playing',
|
||||
addPoster,
|
||||
false);
|
||||
v.id = 'v';
|
||||
v.src = "black140x100.ogv";
|
||||
v.autobuffer = true;
|
||||
document.body.appendChild(v);
|
||||
}
|
||||
|
||||
</script>
|
||||
<body style="background:white;" onload="runTest();">
|
||||
</body>
|
||||
</html>
|
8
layout/reftests/ogg-video/poster-13.html
Normal file
8
layout/reftests/ogg-video/poster-13.html
Normal file
@ -0,0 +1,8 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body style="background:white;">
|
||||
<!-- Test that poster is stretched by css styling. -->
|
||||
<video src="black140x100.ogv" poster="blue250x200.png" style="width: 400px; height: 300px;"></video>
|
||||
|
||||
</body>
|
||||
</html>
|
28
layout/reftests/ogg-video/poster-14.html
Normal file
28
layout/reftests/ogg-video/poster-14.html
Normal file
@ -0,0 +1,28 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<!-- Test: Create video, load, wait for video frame to show, add poster
|
||||
attribute, poster should show. -->
|
||||
<script>
|
||||
function runTest() {
|
||||
var v = document.createElement('video');
|
||||
|
||||
var loadeddata =
|
||||
function() {
|
||||
setTimeout(function() {v.poster = "blue250x200.png";}, 100);
|
||||
setTimeout(function() {document.documentElement.className = '';}, 150);
|
||||
};
|
||||
|
||||
v.addEventListener('loadeddata',
|
||||
loadeddata,
|
||||
false);
|
||||
v.id = 'v';
|
||||
v.src = "black140x100.ogv";
|
||||
v.autobuffer = true;
|
||||
document.body.appendChild(v);
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
<body style="background:white;" onload="runTest();">
|
||||
</body>
|
||||
</html>
|
13
layout/reftests/ogg-video/poster-15.html
Normal file
13
layout/reftests/ogg-video/poster-15.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!-- Test that poster is correctly laid out inside borders. Also test that
|
||||
poster frames smaller than video don't have the video frame drawn behind
|
||||
them etc. -->
|
||||
<body style="background:white;">
|
||||
<video src="black140x100.ogv"
|
||||
poster="green70x30.png"
|
||||
autobuffer
|
||||
style="border: solid blue 2px;">
|
||||
</video>
|
||||
</body>
|
||||
</html>
|
7
layout/reftests/ogg-video/poster-2.html
Normal file
7
layout/reftests/ogg-video/poster-2.html
Normal file
@ -0,0 +1,7 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body style="background:white;">
|
||||
<!-- Test if poster frame with invalid poster displays video frame. -->
|
||||
<video src="black140x100.ogv" poster="not-a-valid-file"></video>
|
||||
</body>
|
||||
</html>
|
11
layout/reftests/ogg-video/poster-3.html
Normal file
11
layout/reftests/ogg-video/poster-3.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<body style="background:white;">
|
||||
<!-- Test if poster hides after playing with autoplay. -->
|
||||
<video src="black140x100.ogv"
|
||||
poster="blue250x200.png"
|
||||
autobuffer
|
||||
autoplay
|
||||
onplaying="setTimeout(function(){document.documentElement.className = '';},0);"></video>
|
||||
</body>
|
||||
</html>
|
11
layout/reftests/ogg-video/poster-4.html
Normal file
11
layout/reftests/ogg-video/poster-4.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<body style="background:white;">
|
||||
<!-- Test if we show video frame after removing valid poster. -->
|
||||
<video src="black140x100.ogv"
|
||||
autobuffer
|
||||
id="v"
|
||||
onload="document.getElementById('v').poster = ''; setTimeout(function(){document.documentElement.className = '';}, 0);"
|
||||
poster="blue250x200.png"></video>
|
||||
</body>
|
||||
</html>
|
13
layout/reftests/ogg-video/poster-5.html
Normal file
13
layout/reftests/ogg-video/poster-5.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<body style="background:white;">
|
||||
<!-- Test to ensure that changing the poster after video has painted its first
|
||||
frame doesn't render the poster. The video frame should not change to the
|
||||
poster, since it's already painted its first video frame. -->
|
||||
<video src="black140x100.ogv"
|
||||
autobuffer
|
||||
id="v"
|
||||
autoplay
|
||||
onended="document.getElementById('v').poster = 'blue250x200.png'; setTimeout(function(){document.documentElement.className = '';},0);"></video>
|
||||
</body>
|
||||
</html>
|
12
layout/reftests/ogg-video/poster-6.html
Normal file
12
layout/reftests/ogg-video/poster-6.html
Normal file
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<body style="background:white;">
|
||||
<!-- Test that poster frame should hide after completing a seek. -->
|
||||
<video src="black140x100.ogv"
|
||||
autobuffer
|
||||
id="v"
|
||||
onloadeddata="var v = document.getElementById('v'); v.currentTime = v.duration;"
|
||||
onseeked="setTimeout(function(){document.documentElement.className = '';}, 0);"
|
||||
poster="blue250x200.png"></video>
|
||||
</body>
|
||||
</html>
|
11
layout/reftests/ogg-video/poster-7.html
Normal file
11
layout/reftests/ogg-video/poster-7.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<body style="background:white;">
|
||||
<!-- Test that poster frame changes when you change the poster attribute. -->
|
||||
<video src="black140x100.ogv"
|
||||
autobuffer
|
||||
id="v"
|
||||
onload="document.getElementById('v').poster = 'red160x120.png'; setTimeout(function(){document.documentElement.className = '';}, 0);"
|
||||
poster="blue250x200.png"></video>
|
||||
</body>
|
||||
</html>
|
12
layout/reftests/ogg-video/poster-8.html
Normal file
12
layout/reftests/ogg-video/poster-8.html
Normal file
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<body style="background:white;">
|
||||
<!-- Test if poster hides after playing with play() call. -->
|
||||
<video src="black140x100.ogv"
|
||||
poster="blue250x200.png"
|
||||
id="v"
|
||||
autobuffer
|
||||
onloadeddata="document.getElementById('v').play();"
|
||||
onplaying="setTimeout(function(){document.documentElement.className = '';}, 0);"></video>
|
||||
</body>
|
||||
</html>
|
13
layout/reftests/ogg-video/poster-9.html
Normal file
13
layout/reftests/ogg-video/poster-9.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<body style="background:white;" >
|
||||
<!-- Test that poster displays all the time when <video> is showing an audio-only media. -->
|
||||
<video src="../../../content/media/test/bug461281.ogg"
|
||||
poster="blue250x200.png"
|
||||
id="v"
|
||||
autobuffer
|
||||
autoplay
|
||||
onended="setTimeout(function(){document.documentElement.className = '';},0);">
|
||||
</video>
|
||||
</body>
|
||||
</html>
|
6
layout/reftests/ogg-video/poster-ref-black140x100.html
Normal file
6
layout/reftests/ogg-video/poster-ref-black140x100.html
Normal file
@ -0,0 +1,6 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body style="background:white;">
|
||||
<video src="black140x100.ogv" autobuffer></video>
|
||||
</body>
|
||||
</html>
|
6
layout/reftests/ogg-video/poster-ref-blue250x200.html
Normal file
6
layout/reftests/ogg-video/poster-ref-blue250x200.html
Normal file
@ -0,0 +1,6 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body style="background:white;">
|
||||
<img src="blue250x200.png" alt="poster">
|
||||
</body>
|
||||
</html>
|
8
layout/reftests/ogg-video/poster-ref-blue400x300.html
Normal file
8
layout/reftests/ogg-video/poster-ref-blue400x300.html
Normal file
@ -0,0 +1,8 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body style="background:white;">
|
||||
<img src="blue250x200.png" style="width: 400px; height: 300px;">
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
6
layout/reftests/ogg-video/poster-ref-green70x30.html
Normal file
6
layout/reftests/ogg-video/poster-ref-green70x30.html
Normal file
@ -0,0 +1,6 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body style="background:white;">
|
||||
<img src="green70x30.png" alt="poster" style="border: solid blue 2px;">
|
||||
</body>
|
||||
</html>
|
6
layout/reftests/ogg-video/poster-ref-red160x120.html
Normal file
6
layout/reftests/ogg-video/poster-ref-red160x120.html
Normal file
@ -0,0 +1,6 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body style="background:white;">
|
||||
<img src="red160x120.png" alt="poster">
|
||||
</body>
|
||||
</html>
|
BIN
layout/reftests/ogg-video/red160x120.png
Normal file
BIN
layout/reftests/ogg-video/red160x120.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 720 B |
@ -15,3 +15,18 @@ HTTP(..) == offset-1.xhtml offset-1-ref.html
|
||||
random HTTP(..) == object-aspect-ratio-2a.xhtml aspect-ratio-2-ref.html
|
||||
random HTTP(..) == object-aspect-ratio-2b.xhtml aspect-ratio-2-ref.html
|
||||
skip-if(MOZ_WIDGET_TOOLKIT=="gtk2") HTTP(..) == zoomed-1.xhtml zoomed-1-ref.html
|
||||
== poster-1.html poster-ref-blue250x200.html
|
||||
== poster-2.html poster-ref-black140x100.html
|
||||
== poster-3.html poster-ref-black140x100.html
|
||||
== poster-4.html poster-ref-black140x100.html
|
||||
== poster-5.html poster-ref-black140x100.html
|
||||
== poster-6.html poster-ref-black140x100.html
|
||||
== poster-7.html poster-ref-red160x120.html
|
||||
== poster-8.html poster-ref-black140x100.html
|
||||
== poster-9.html poster-ref-blue250x200.html
|
||||
== poster-10.html poster-ref-blue250x200.html
|
||||
== poster-11.html poster-ref-blue250x200.html
|
||||
== poster-12.html poster-ref-blue250x200.html
|
||||
== poster-13.html poster-ref-blue400x300.html
|
||||
== poster-14.html poster-ref-blue250x200.html
|
||||
== poster-15.html poster-ref-green70x30.html
|
||||
|
Loading…
Reference in New Issue
Block a user