1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* rendering object for the HTML <video> element */
9 #include "nsVideoFrame.h"
12 #include "nsGkAtoms.h"
14 #include "mozilla/dom/HTMLVideoElement.h"
15 #include "nsIDOMHTMLImageElement.h"
16 #include "nsDisplayList.h"
17 #include "nsGenericHTMLElement.h"
18 #include "nsPresContext.h"
19 #include "nsContentCreatorFunctions.h"
20 #include "nsBoxLayoutState.h"
21 #include "nsBoxFrame.h"
22 #include "nsImageFrame.h"
23 #include "nsIImageLoadingContent.h"
24 #include "nsContentUtils.h"
25 #include "ImageContainer.h"
26 #include "ImageLayers.h"
27 #include "nsContentList.h"
30 using namespace mozilla
;
31 using namespace mozilla::layers
;
32 using namespace mozilla::dom
;
33 using namespace mozilla::gfx
;
36 NS_NewHTMLVideoFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
38 return new (aPresShell
) nsVideoFrame(aContext
);
41 NS_IMPL_FRAMEARENA_HELPERS(nsVideoFrame
)
43 nsVideoFrame::nsVideoFrame(nsStyleContext
* aContext
) :
44 nsContainerFrame(aContext
)
48 nsVideoFrame::~nsVideoFrame()
52 NS_QUERYFRAME_HEAD(nsVideoFrame
)
53 NS_QUERYFRAME_ENTRY(nsVideoFrame
)
54 NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator
)
55 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame
)
58 nsVideoFrame::CreateAnonymousContent(nsTArray
<ContentInfo
>& aElements
)
60 nsNodeInfoManager
*nodeInfoManager
= GetContent()->GetCurrentDoc()->NodeInfoManager();
61 nsRefPtr
<NodeInfo
> nodeInfo
;
64 if (HasVideoElement()) {
65 // Create an anonymous image element as a child to hold the poster
66 // image. We may not have a poster image now, but one could be added
67 // before we load, or on a subsequent load.
68 nodeInfo
= nodeInfoManager
->GetNodeInfo(nsGkAtoms::img
,
71 nsIDOMNode::ELEMENT_NODE
);
72 NS_ENSURE_TRUE(nodeInfo
, NS_ERROR_OUT_OF_MEMORY
);
73 element
= NS_NewHTMLImageElement(nodeInfo
.forget());
74 mPosterImage
= element
;
75 NS_ENSURE_TRUE(mPosterImage
, NS_ERROR_OUT_OF_MEMORY
);
77 // Set the nsImageLoadingContent::ImageState() to 0. This means that the
78 // image will always report its state as 0, so it will never be reframed
79 // to show frames for loading or the broken image icon. This is important,
80 // as the image is native anonymous, and so can't be reframed (currently).
81 nsCOMPtr
<nsIImageLoadingContent
> imgContent
= do_QueryInterface(mPosterImage
);
82 NS_ENSURE_TRUE(imgContent
, NS_ERROR_FAILURE
);
84 imgContent
->ForceImageState(true, 0);
85 // And now have it update its internal state
86 element
->UpdateState(false);
88 UpdatePosterSource(false);
90 if (!aElements
.AppendElement(mPosterImage
))
91 return NS_ERROR_OUT_OF_MEMORY
;
93 // Set up the caption overlay div for showing any TextTrack data
94 nodeInfo
= nodeInfoManager
->GetNodeInfo(nsGkAtoms::div
,
97 nsIDOMNode::ELEMENT_NODE
);
98 NS_ENSURE_TRUE(nodeInfo
, NS_ERROR_OUT_OF_MEMORY
);
99 mCaptionDiv
= NS_NewHTMLDivElement(nodeInfo
.forget());
100 NS_ENSURE_TRUE(mCaptionDiv
, NS_ERROR_OUT_OF_MEMORY
);
101 nsGenericHTMLElement
* div
= static_cast<nsGenericHTMLElement
*>(mCaptionDiv
.get());
102 div
->SetClassName(NS_LITERAL_STRING("caption-box"));
104 if (!aElements
.AppendElement(mCaptionDiv
))
105 return NS_ERROR_OUT_OF_MEMORY
;
108 // Set up "videocontrols" XUL element which will be XBL-bound to the
110 nodeInfo
= nodeInfoManager
->GetNodeInfo(nsGkAtoms::videocontrols
,
113 nsIDOMNode::ELEMENT_NODE
);
114 NS_ENSURE_TRUE(nodeInfo
, NS_ERROR_OUT_OF_MEMORY
);
116 NS_TrustedNewXULElement(getter_AddRefs(mVideoControls
), nodeInfo
.forget());
117 if (!aElements
.AppendElement(mVideoControls
))
118 return NS_ERROR_OUT_OF_MEMORY
;
124 nsVideoFrame::AppendAnonymousContentTo(nsTArray
<nsIContent
*>& aElements
,
128 aElements
.AppendElement(mPosterImage
);
131 if (mVideoControls
) {
132 aElements
.AppendElement(mVideoControls
);
136 aElements
.AppendElement(mCaptionDiv
);
141 nsVideoFrame::DestroyFrom(nsIFrame
* aDestructRoot
)
143 nsContentUtils::DestroyAnonymousContent(&mCaptionDiv
);
144 nsContentUtils::DestroyAnonymousContent(&mVideoControls
);
145 nsContentUtils::DestroyAnonymousContent(&mPosterImage
);
146 nsContainerFrame::DestroyFrom(aDestructRoot
);
150 nsVideoFrame::IsLeaf() const
155 // Return the largest rectangle that fits in aRect and has the
156 // same aspect ratio as aRatio, centered at the center of aRect
158 CorrectForAspectRatio(const gfxRect
& aRect
, const nsIntSize
& aRatio
)
160 NS_ASSERTION(aRatio
.width
> 0 && aRatio
.height
> 0 && !aRect
.IsEmpty(),
162 // Choose scale factor that scales aRatio to just fit into aRect
164 std::min(aRect
.Width()/aRatio
.width
, aRect
.Height()/aRatio
.height
);
165 gfxSize
scaledRatio(scale
*aRatio
.width
, scale
*aRatio
.height
);
166 gfxPoint
topLeft((aRect
.Width() - scaledRatio
.width
)/2,
167 (aRect
.Height() - scaledRatio
.height
)/2);
168 return gfxRect(aRect
.TopLeft() + topLeft
, scaledRatio
);
171 already_AddRefed
<Layer
>
172 nsVideoFrame::BuildLayer(nsDisplayListBuilder
* aBuilder
,
173 LayerManager
* aManager
,
174 nsDisplayItem
* aItem
,
175 const ContainerLayerParameters
& aContainerParameters
)
177 nsRect area
= GetContentRect() - GetPosition() + aItem
->ToReferenceFrame();
178 HTMLVideoElement
* element
= static_cast<HTMLVideoElement
*>(GetContent());
180 if (NS_FAILED(element
->GetVideoSize(&videoSize
)) || area
.IsEmpty()) {
184 nsRefPtr
<ImageContainer
> container
= element
->GetImageContainer();
188 // Retrieve the size of the decoded video frame, before being scaled
189 // by pixel aspect ratio.
190 mozilla::gfx::IntSize frameSize
= container
->GetCurrentSize();
191 if (frameSize
.width
== 0 || frameSize
.height
== 0) {
192 // No image, or zero-sized image. No point creating a layer.
196 // Compute the rectangle in which to paint the video. We need to use
197 // the largest rectangle that fills our content-box and has the
198 // correct aspect ratio.
199 nsPresContext
* presContext
= PresContext();
200 gfxRect r
= gfxRect(presContext
->AppUnitsToGfxUnits(area
.x
),
201 presContext
->AppUnitsToGfxUnits(area
.y
),
202 presContext
->AppUnitsToGfxUnits(area
.width
),
203 presContext
->AppUnitsToGfxUnits(area
.height
));
204 r
= CorrectForAspectRatio(r
, videoSize
);
209 IntSize
scaleHint(static_cast<int32_t>(r
.Width()),
210 static_cast<int32_t>(r
.Height()));
211 container
->SetScaleHint(scaleHint
);
213 nsRefPtr
<ImageLayer
> layer
= static_cast<ImageLayer
*>
214 (aManager
->GetLayerBuilder()->GetLeafLayerFor(aBuilder
, aItem
));
216 layer
= aManager
->CreateImageLayer();
221 layer
->SetContainer(container
);
222 layer
->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this));
223 // Set a transform on the layer to draw the video in the right place
224 gfx::Matrix transform
;
225 gfxPoint p
= r
.TopLeft() + aContainerParameters
.mOffset
;
226 transform
.Translate(p
.x
, p
.y
);
227 transform
.Scale(r
.Width()/frameSize
.width
, r
.Height()/frameSize
.height
);
228 layer
->SetBaseTransform(gfx::Matrix4x4::From2D(transform
));
229 nsRefPtr
<Layer
> result
= layer
.forget();
230 return result
.forget();
233 class DispatchResizeToControls
: public nsRunnable
236 explicit DispatchResizeToControls(nsIContent
* aContent
)
237 : mContent(aContent
) {}
238 NS_IMETHOD
Run() MOZ_OVERRIDE
{
239 nsContentUtils::DispatchTrustedEvent(mContent
->OwnerDoc(), mContent
,
240 NS_LITERAL_STRING("resizevideocontrols"),
244 nsCOMPtr
<nsIContent
> mContent
;
248 nsVideoFrame::Reflow(nsPresContext
* aPresContext
,
249 nsHTMLReflowMetrics
& aMetrics
,
250 const nsHTMLReflowState
& aReflowState
,
251 nsReflowStatus
& aStatus
)
253 DO_GLOBAL_REFLOW_COUNT("nsVideoFrame");
254 DISPLAY_REFLOW(aPresContext
, this, aReflowState
, aMetrics
, aStatus
);
255 NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS
,
256 ("enter nsVideoFrame::Reflow: availSize=%d,%d",
257 aReflowState
.AvailableWidth(), aReflowState
.AvailableHeight()));
259 NS_PRECONDITION(mState
& NS_FRAME_IN_REFLOW
, "frame is not in reflow");
261 aStatus
= NS_FRAME_COMPLETE
;
263 aMetrics
.Width() = aReflowState
.ComputedWidth();
264 aMetrics
.Height() = aReflowState
.ComputedHeight();
266 // stash this away so we can compute our inner area later
267 mBorderPadding
= aReflowState
.ComputedPhysicalBorderPadding();
269 aMetrics
.Width() += mBorderPadding
.left
+ mBorderPadding
.right
;
270 aMetrics
.Height() += mBorderPadding
.top
+ mBorderPadding
.bottom
;
272 // Reflow the child frames. We may have up to two, an image frame
273 // which is the poster, and a box frame, which is the video controls.
274 for (nsIFrame
*child
= mFrames
.FirstChild();
276 child
= child
->GetNextSibling()) {
277 if (child
->GetContent() == mPosterImage
) {
278 // Reflow the poster frame.
279 nsImageFrame
* imageFrame
= static_cast<nsImageFrame
*>(child
);
280 nsHTMLReflowMetrics
kidDesiredSize(aReflowState
);
281 WritingMode wm
= imageFrame
->GetWritingMode();
282 LogicalSize availableSize
= aReflowState
.AvailableSize(wm
);
283 nsHTMLReflowState
kidReflowState(aPresContext
,
290 uint32_t posterHeight
, posterWidth
;
291 nsSize
scaledPosterSize(0, 0);
292 nsSize
computedArea(aReflowState
.ComputedWidth(), aReflowState
.ComputedHeight());
293 nsPoint
posterTopLeft(0, 0);
295 nsCOMPtr
<nsIDOMHTMLImageElement
> posterImage
= do_QueryInterface(mPosterImage
);
299 posterImage
->GetNaturalHeight(&posterHeight
);
300 posterImage
->GetNaturalWidth(&posterWidth
);
302 if (ShouldDisplayPoster() && posterHeight
&& posterWidth
) {
304 std::min(static_cast<float>(computedArea
.width
)/nsPresContext::CSSPixelsToAppUnits(static_cast<float>(posterWidth
)),
305 static_cast<float>(computedArea
.height
)/nsPresContext::CSSPixelsToAppUnits(static_cast<float>(posterHeight
)));
306 gfxSize scaledRatio
= gfxSize(scale
*posterWidth
, scale
*posterHeight
);
307 scaledPosterSize
.width
= nsPresContext::CSSPixelsToAppUnits(static_cast<float>(scaledRatio
.width
));
308 scaledPosterSize
.height
= nsPresContext::CSSPixelsToAppUnits(static_cast<int32_t>(scaledRatio
.height
));
310 kidReflowState
.SetComputedWidth(scaledPosterSize
.width
);
311 kidReflowState
.SetComputedHeight(scaledPosterSize
.height
);
312 posterTopLeft
.x
= ((computedArea
.width
- scaledPosterSize
.width
) / 2) + mBorderPadding
.left
;
313 posterTopLeft
.y
= ((computedArea
.height
- scaledPosterSize
.height
) / 2) + mBorderPadding
.top
;
315 ReflowChild(imageFrame
, aPresContext
, kidDesiredSize
, kidReflowState
,
316 posterTopLeft
.x
, posterTopLeft
.y
, 0, aStatus
);
317 FinishReflowChild(imageFrame
, aPresContext
, kidDesiredSize
, &kidReflowState
,
318 posterTopLeft
.x
, posterTopLeft
.y
, 0);
319 } else if (child
->GetContent() == mVideoControls
) {
320 // Reflow the video controls frame.
321 nsBoxLayoutState
boxState(PresContext(), aReflowState
.rendContext
);
322 nsSize size
= child
->GetSize();
323 nsBoxFrame::LayoutChildAt(boxState
,
325 nsRect(mBorderPadding
.left
,
327 aReflowState
.ComputedWidth(),
328 aReflowState
.ComputedHeight()));
329 if (child
->GetSize() != size
) {
330 nsRefPtr
<nsRunnable
> event
= new DispatchResizeToControls(child
->GetContent());
331 nsContentUtils::AddScriptRunner(event
);
333 } else if (child
->GetContent() == mCaptionDiv
) {
334 // Reflow to caption div
335 nsHTMLReflowMetrics
kidDesiredSize(aReflowState
);
336 WritingMode wm
= child
->GetWritingMode();
337 LogicalSize availableSize
= aReflowState
.AvailableSize(wm
);
338 nsHTMLReflowState
kidReflowState(aPresContext
,
344 nsSize
size(aReflowState
.ComputedWidth(), aReflowState
.ComputedHeight());
345 size
.width
-= kidReflowState
.ComputedPhysicalBorderPadding().LeftRight();
346 size
.height
-= kidReflowState
.ComputedPhysicalBorderPadding().TopBottom();
348 kidReflowState
.SetComputedWidth(std::max(size
.width
, 0));
349 kidReflowState
.SetComputedHeight(std::max(size
.height
, 0));
351 ReflowChild(child
, aPresContext
, kidDesiredSize
, kidReflowState
,
352 mBorderPadding
.left
, mBorderPadding
.top
, 0, aStatus
);
353 FinishReflowChild(child
, aPresContext
,
354 kidDesiredSize
, &kidReflowState
,
355 mBorderPadding
.left
, mBorderPadding
.top
, 0);
358 aMetrics
.SetOverflowAreasToDesiredBounds();
360 FinishAndStoreOverflow(&aMetrics
);
362 NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS
,
363 ("exit nsVideoFrame::Reflow: size=%d,%d",
364 aMetrics
.Width(), aMetrics
.Height()));
365 NS_FRAME_SET_TRUNCATION(aStatus
, aReflowState
, aMetrics
);
368 class nsDisplayVideo
: public nsDisplayItem
{
370 nsDisplayVideo(nsDisplayListBuilder
* aBuilder
, nsVideoFrame
* aFrame
)
371 : nsDisplayItem(aBuilder
, aFrame
)
373 MOZ_COUNT_CTOR(nsDisplayVideo
);
375 #ifdef NS_BUILD_REFCNT_LOGGING
376 virtual ~nsDisplayVideo() {
377 MOZ_COUNT_DTOR(nsDisplayVideo
);
381 NS_DISPLAY_DECL_NAME("Video", TYPE_VIDEO
)
383 // It would be great if we could override GetOpaqueRegion to return nonempty here,
384 // but it's probably not safe to do so in general. Video frames are
385 // updated asynchronously from decoder threads, and it's possible that
386 // we might have an opaque video frame when GetOpaqueRegion is called, but
387 // when we come to paint, the video frame is transparent or has gone
388 // away completely (e.g. because of a decoder error). The problem would
389 // be especially acute if we have off-main-thread rendering.
391 virtual nsRect
GetBounds(nsDisplayListBuilder
* aBuilder
, bool* aSnap
) MOZ_OVERRIDE
394 nsIFrame
* f
= Frame();
395 return f
->GetContentRect() - f
->GetPosition() + ToReferenceFrame();
398 virtual already_AddRefed
<Layer
> BuildLayer(nsDisplayListBuilder
* aBuilder
,
399 LayerManager
* aManager
,
400 const ContainerLayerParameters
& aContainerParameters
) MOZ_OVERRIDE
402 return static_cast<nsVideoFrame
*>(mFrame
)->BuildLayer(aBuilder
, aManager
, this, aContainerParameters
);
405 virtual LayerState
GetLayerState(nsDisplayListBuilder
* aBuilder
,
406 LayerManager
* aManager
,
407 const ContainerLayerParameters
& aParameters
) MOZ_OVERRIDE
409 if (aManager
->IsCompositingCheap()) {
410 // Since ImageLayers don't require additional memory of the
411 // video frames we have to have anyway, we can't save much by
412 // making layers inactive. Also, for many accelerated layer
413 // managers calling imageContainer->GetCurrentAsSurface can be
414 // very expensive. So just always be active when compositing is
415 // cheap (i.e. hardware accelerated).
418 HTMLMediaElement
* elem
=
419 static_cast<HTMLMediaElement
*>(mFrame
->GetContent());
420 return elem
->IsPotentiallyPlaying() ? LAYER_ACTIVE_FORCE
: LAYER_INACTIVE
;
425 nsVideoFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
426 const nsRect
& aDirtyRect
,
427 const nsDisplayListSet
& aLists
)
429 if (!IsVisibleForPainting(aBuilder
))
432 DO_GLOBAL_REFLOW_COUNT_DSP("nsVideoFrame");
434 DisplayBorderBackgroundOutline(aBuilder
, aLists
);
436 DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox
437 clip(aBuilder
, this, DisplayListClipState::ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT
);
439 if (HasVideoElement() && !ShouldDisplayPoster()) {
440 aLists
.Content()->AppendNewToTop(
441 new (aBuilder
) nsDisplayVideo(aBuilder
, this));
444 // Add child frames to display list. We expect various children,
445 // but only want to draw mPosterImage conditionally. Others we
446 // always add to the display list.
447 for (nsIFrame
*child
= mFrames
.FirstChild();
449 child
= child
->GetNextSibling()) {
450 if (child
->GetContent() != mPosterImage
|| ShouldDisplayPoster()) {
451 child
->BuildDisplayListForStackingContext(aBuilder
,
452 aDirtyRect
- child
->GetOffsetTo(this),
454 } else if (child
->GetType() == nsGkAtoms::boxFrame
) {
455 child
->BuildDisplayListForStackingContext(aBuilder
,
456 aDirtyRect
- child
->GetOffsetTo(this),
463 nsVideoFrame::GetType() const
465 return nsGkAtoms::HTMLVideoFrame
;
470 nsVideoFrame::AccessibleType()
472 return a11y::eHTMLMediaType
;
476 #ifdef DEBUG_FRAME_DUMP
478 nsVideoFrame::GetFrameName(nsAString
& aResult
) const
480 return MakeFrameName(NS_LITERAL_STRING("HTMLVideo"), aResult
);
485 nsVideoFrame::ComputeSize(nsRenderingContext
*aRenderingContext
,
487 const LogicalSize
& aCBSize
,
488 nscoord aAvailableISize
,
489 const LogicalSize
& aMargin
,
490 const LogicalSize
& aBorder
,
491 const LogicalSize
& aPadding
,
494 nsSize size
= GetVideoIntrinsicSize(aRenderingContext
);
496 IntrinsicSize intrinsicSize
;
497 intrinsicSize
.width
.SetCoordValue(size
.width
);
498 intrinsicSize
.height
.SetCoordValue(size
.height
);
500 // Only video elements have an intrinsic ratio.
501 nsSize intrinsicRatio
= HasVideoElement() ? size
: nsSize(0, 0);
503 return nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(aWM
, aRenderingContext
,
513 nscoord
nsVideoFrame::GetMinISize(nsRenderingContext
*aRenderingContext
)
515 nscoord result
= GetVideoIntrinsicSize(aRenderingContext
).width
;
516 DISPLAY_MIN_WIDTH(this, result
);
520 nscoord
nsVideoFrame::GetPrefISize(nsRenderingContext
*aRenderingContext
)
522 nscoord result
= GetVideoIntrinsicSize(aRenderingContext
).width
;
523 DISPLAY_PREF_WIDTH(this, result
);
527 nsSize
nsVideoFrame::GetIntrinsicRatio()
529 if (!HasVideoElement()) {
530 // Audio elements have no intrinsic ratio.
534 return GetVideoIntrinsicSize(nullptr);
537 bool nsVideoFrame::ShouldDisplayPoster()
539 if (!HasVideoElement())
542 HTMLVideoElement
* element
= static_cast<HTMLVideoElement
*>(GetContent());
543 if (element
->GetPlayedOrSeeked() && HasVideoData())
546 nsCOMPtr
<nsIImageLoadingContent
> imgContent
= do_QueryInterface(mPosterImage
);
547 NS_ENSURE_TRUE(imgContent
, false);
549 nsCOMPtr
<imgIRequest
> request
;
550 nsresult res
= imgContent
->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST
,
551 getter_AddRefs(request
));
552 if (NS_FAILED(res
) || !request
) {
557 res
= request
->GetImageStatus(&status
);
558 if (NS_FAILED(res
) || (status
& imgIRequest::STATUS_ERROR
))
565 nsVideoFrame::GetVideoIntrinsicSize(nsRenderingContext
*aRenderingContext
)
567 // Defaulting size to 300x150 if no size given.
568 nsIntSize
size(300, 150);
570 if (!HasVideoElement()) {
571 if (!mFrames
.FirstChild()) {
575 // Ask the controls frame what its preferred height is
576 nsBoxLayoutState
boxState(PresContext(), aRenderingContext
, 0);
577 nscoord prefHeight
= mFrames
.LastChild()->GetPrefSize(boxState
).height
;
578 return nsSize(nsPresContext::CSSPixelsToAppUnits(size
.width
), prefHeight
);
581 HTMLVideoElement
* element
= static_cast<HTMLVideoElement
*>(GetContent());
582 if (NS_FAILED(element
->GetVideoSize(&size
)) && ShouldDisplayPoster()) {
583 // Use the poster image frame's size.
584 nsIFrame
*child
= mPosterImage
->GetPrimaryFrame();
585 nsImageFrame
* imageFrame
= do_QueryFrame(child
);
587 if (NS_SUCCEEDED(imageFrame
->GetIntrinsicImageSize(imgsize
))) {
592 return nsSize(nsPresContext::CSSPixelsToAppUnits(size
.width
),
593 nsPresContext::CSSPixelsToAppUnits(size
.height
));
597 nsVideoFrame::UpdatePosterSource(bool aNotify
)
599 NS_ASSERTION(HasVideoElement(), "Only call this on <video> elements.");
600 HTMLVideoElement
* element
= static_cast<HTMLVideoElement
*>(GetContent());
602 if (element
->HasAttr(kNameSpaceID_None
, nsGkAtoms::poster
)) {
603 nsAutoString posterStr
;
604 element
->GetPoster(posterStr
);
605 mPosterImage
->SetAttr(kNameSpaceID_None
,
610 mPosterImage
->UnsetAttr(kNameSpaceID_None
, nsGkAtoms::poster
, aNotify
);
615 nsVideoFrame::AttributeChanged(int32_t aNameSpaceID
,
619 if (aAttribute
== nsGkAtoms::poster
&& HasVideoElement()) {
620 UpdatePosterSource(true);
622 return nsContainerFrame::AttributeChanged(aNameSpaceID
,
627 bool nsVideoFrame::HasVideoElement() {
628 nsCOMPtr
<nsIDOMHTMLMediaElement
> mediaDomElement
= do_QueryInterface(mContent
);
629 return mediaDomElement
->IsVideo();
632 bool nsVideoFrame::HasVideoData()
634 if (!HasVideoElement())
636 HTMLVideoElement
* element
= static_cast<HTMLVideoElement
*>(GetContent());
637 nsIntSize
size(0, 0);
638 element
->GetVideoSize(&size
);
639 return size
!= nsIntSize(0,0);