Bumping manifests a=b2g-bump
[gecko.git] / layout / generic / nsVideoFrame.cpp
blob74a7198cff1701518f2f6d338efe30121f7da9a9
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"
11 #include "nsCOMPtr.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"
28 #include <algorithm>
30 using namespace mozilla;
31 using namespace mozilla::layers;
32 using namespace mozilla::dom;
33 using namespace mozilla::gfx;
35 nsIFrame*
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)
57 nsresult
58 nsVideoFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
60 nsNodeInfoManager *nodeInfoManager = GetContent()->GetCurrentDoc()->NodeInfoManager();
61 nsRefPtr<NodeInfo> nodeInfo;
62 Element *element;
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,
69 nullptr,
70 kNameSpaceID_XHTML,
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,
95 nullptr,
96 kNameSpaceID_XHTML,
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
109 // actual controls.
110 nodeInfo = nodeInfoManager->GetNodeInfo(nsGkAtoms::videocontrols,
111 nullptr,
112 kNameSpaceID_XUL,
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;
120 return NS_OK;
123 void
124 nsVideoFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
125 uint32_t aFliter)
127 if (mPosterImage) {
128 aElements.AppendElement(mPosterImage);
131 if (mVideoControls) {
132 aElements.AppendElement(mVideoControls);
135 if (mCaptionDiv) {
136 aElements.AppendElement(mCaptionDiv);
140 void
141 nsVideoFrame::DestroyFrom(nsIFrame* aDestructRoot)
143 nsContentUtils::DestroyAnonymousContent(&mCaptionDiv);
144 nsContentUtils::DestroyAnonymousContent(&mVideoControls);
145 nsContentUtils::DestroyAnonymousContent(&mPosterImage);
146 nsContainerFrame::DestroyFrom(aDestructRoot);
149 bool
150 nsVideoFrame::IsLeaf() const
152 return true;
155 // Return the largest rectangle that fits in aRect and has the
156 // same aspect ratio as aRatio, centered at the center of aRect
157 static gfxRect
158 CorrectForAspectRatio(const gfxRect& aRect, const nsIntSize& aRatio)
160 NS_ASSERTION(aRatio.width > 0 && aRatio.height > 0 && !aRect.IsEmpty(),
161 "Nothing to draw");
162 // Choose scale factor that scales aRatio to just fit into aRect
163 gfxFloat scale =
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());
179 nsIntSize videoSize;
180 if (NS_FAILED(element->GetVideoSize(&videoSize)) || area.IsEmpty()) {
181 return nullptr;
184 nsRefPtr<ImageContainer> container = element->GetImageContainer();
185 if (!container)
186 return nullptr;
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.
193 return nullptr;
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);
205 r.Round();
206 if (r.IsEmpty()) {
207 return nullptr;
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));
215 if (!layer) {
216 layer = aManager->CreateImageLayer();
217 if (!layer)
218 return nullptr;
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
235 public:
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"),
241 false, false);
242 return NS_OK;
244 nsCOMPtr<nsIContent> mContent;
247 void
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();
275 child;
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,
284 aReflowState,
285 imageFrame,
286 availableSize,
287 aMetrics.Width(),
288 aMetrics.Height());
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);
296 if (!posterImage) {
297 return;
299 posterImage->GetNaturalHeight(&posterHeight);
300 posterImage->GetNaturalWidth(&posterWidth);
302 if (ShouldDisplayPoster() && posterHeight && posterWidth) {
303 gfxFloat scale =
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,
324 child,
325 nsRect(mBorderPadding.left,
326 mBorderPadding.top,
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,
339 aReflowState,
340 child,
341 availableSize,
342 aMetrics.Width(),
343 aMetrics.Height());
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 {
369 public:
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);
379 #endif
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
393 *aSnap = true;
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).
416 return LAYER_ACTIVE;
418 HTMLMediaElement* elem =
419 static_cast<HTMLMediaElement*>(mFrame->GetContent());
420 return elem->IsPotentiallyPlaying() ? LAYER_ACTIVE_FORCE : LAYER_INACTIVE;
424 void
425 nsVideoFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
426 const nsRect& aDirtyRect,
427 const nsDisplayListSet& aLists)
429 if (!IsVisibleForPainting(aBuilder))
430 return;
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();
448 child;
449 child = child->GetNextSibling()) {
450 if (child->GetContent() != mPosterImage || ShouldDisplayPoster()) {
451 child->BuildDisplayListForStackingContext(aBuilder,
452 aDirtyRect - child->GetOffsetTo(this),
453 aLists.Content());
454 } else if (child->GetType() == nsGkAtoms::boxFrame) {
455 child->BuildDisplayListForStackingContext(aBuilder,
456 aDirtyRect - child->GetOffsetTo(this),
457 aLists.Content());
462 nsIAtom*
463 nsVideoFrame::GetType() const
465 return nsGkAtoms::HTMLVideoFrame;
468 #ifdef ACCESSIBILITY
469 a11y::AccType
470 nsVideoFrame::AccessibleType()
472 return a11y::eHTMLMediaType;
474 #endif
476 #ifdef DEBUG_FRAME_DUMP
477 nsresult
478 nsVideoFrame::GetFrameName(nsAString& aResult) const
480 return MakeFrameName(NS_LITERAL_STRING("HTMLVideo"), aResult);
482 #endif
484 LogicalSize
485 nsVideoFrame::ComputeSize(nsRenderingContext *aRenderingContext,
486 WritingMode aWM,
487 const LogicalSize& aCBSize,
488 nscoord aAvailableISize,
489 const LogicalSize& aMargin,
490 const LogicalSize& aBorder,
491 const LogicalSize& aPadding,
492 uint32_t aFlags)
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,
504 this,
505 intrinsicSize,
506 intrinsicRatio,
507 aCBSize,
508 aMargin,
509 aBorder,
510 aPadding);
513 nscoord nsVideoFrame::GetMinISize(nsRenderingContext *aRenderingContext)
515 nscoord result = GetVideoIntrinsicSize(aRenderingContext).width;
516 DISPLAY_MIN_WIDTH(this, result);
517 return result;
520 nscoord nsVideoFrame::GetPrefISize(nsRenderingContext *aRenderingContext)
522 nscoord result = GetVideoIntrinsicSize(aRenderingContext).width;
523 DISPLAY_PREF_WIDTH(this, result);
524 return result;
527 nsSize nsVideoFrame::GetIntrinsicRatio()
529 if (!HasVideoElement()) {
530 // Audio elements have no intrinsic ratio.
531 return nsSize(0, 0);
534 return GetVideoIntrinsicSize(nullptr);
537 bool nsVideoFrame::ShouldDisplayPoster()
539 if (!HasVideoElement())
540 return false;
542 HTMLVideoElement* element = static_cast<HTMLVideoElement*>(GetContent());
543 if (element->GetPlayedOrSeeked() && HasVideoData())
544 return false;
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) {
553 return false;
556 uint32_t status = 0;
557 res = request->GetImageStatus(&status);
558 if (NS_FAILED(res) || (status & imgIRequest::STATUS_ERROR))
559 return false;
561 return true;
564 nsSize
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()) {
572 return nsSize(0, 0);
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);
586 nsSize imgsize;
587 if (NS_SUCCEEDED(imageFrame->GetIntrinsicImageSize(imgsize))) {
588 return imgsize;
592 return nsSize(nsPresContext::CSSPixelsToAppUnits(size.width),
593 nsPresContext::CSSPixelsToAppUnits(size.height));
596 void
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,
606 nsGkAtoms::src,
607 posterStr,
608 aNotify);
609 } else {
610 mPosterImage->UnsetAttr(kNameSpaceID_None, nsGkAtoms::poster, aNotify);
614 nsresult
615 nsVideoFrame::AttributeChanged(int32_t aNameSpaceID,
616 nsIAtom* aAttribute,
617 int32_t aModType)
619 if (aAttribute == nsGkAtoms::poster && HasVideoElement()) {
620 UpdatePosterSource(true);
622 return nsContainerFrame::AttributeChanged(aNameSpaceID,
623 aAttribute,
624 aModType);
627 bool nsVideoFrame::HasVideoElement() {
628 nsCOMPtr<nsIDOMHTMLMediaElement> mediaDomElement = do_QueryInterface(mContent);
629 return mediaDomElement->IsVideo();
632 bool nsVideoFrame::HasVideoData()
634 if (!HasVideoElement())
635 return false;
636 HTMLVideoElement* element = static_cast<HTMLVideoElement*>(GetContent());
637 nsIntSize size(0, 0);
638 element->GetVideoSize(&size);
639 return size != nsIntSize(0,0);