/* static */ already_AddRefed<ImageBitmap> ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLVideoElement& aVideoEl, const Maybe<IntRect>& aCropRect, ErrorResult& aRv) { // Check network state. if (aVideoEl.NetworkState() == HTMLMediaElement::NETWORK_EMPTY) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } // Check ready state. // Cannot be HTMLMediaElement::HAVE_NOTHING or HTMLMediaElement::HAVE_METADATA. if (aVideoEl.ReadyState() <= HTMLMediaElement::HAVE_METADATA) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } // Check security. nsCOMPtr<nsIPrincipal> principal = aVideoEl.GetCurrentPrincipal(); bool CORSUsed = aVideoEl.GetCORSMode() != CORS_NONE; if (!CheckSecurityForHTMLElements(false, CORSUsed, principal)) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return nullptr; } // Create ImageBitmap. ImageContainer *container = aVideoEl.GetImageContainer(); if (!container) { aRv.Throw(NS_ERROR_NOT_AVAILABLE); return nullptr; } AutoLockImage lockImage(container); layers::Image* data = lockImage.GetImage(); RefPtr<ImageBitmap> ret = new ImageBitmap(aGlobal, data); // Set the picture rectangle. if (ret && aCropRect.isSome()) { ret->SetPictureRect(aCropRect.ref(), aRv); } return ret.forget(); }
already_AddRefed<Layer> nsVideoFrame::BuildLayer(nsDisplayListBuilder* aBuilder, LayerManager* aManager, nsDisplayItem* aItem, const ContainerLayerParameters& aContainerParameters) { nsRect area = GetContentRect() - GetPosition() + aItem->ToReferenceFrame(); HTMLVideoElement* element = static_cast<HTMLVideoElement*>(GetContent()); nsIntSize videoSize; if (NS_FAILED(element->GetVideoSize(&videoSize)) || area.IsEmpty()) { return nullptr; } nsRefPtr<ImageContainer> container = element->GetImageContainer(); if (!container) return nullptr; // Retrieve the size of the decoded video frame, before being scaled // by pixel aspect ratio. mozilla::gfx::IntSize frameSize = container->GetCurrentSize(); if (frameSize.width == 0 || frameSize.height == 0) { // No image, or zero-sized image. No point creating a layer. 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()) { return nullptr; } IntSize scaleHint(static_cast<int32_t>(r.Width()), static_cast<int32_t>(r.Height())); container->SetScaleHint(scaleHint); nsRefPtr<ImageLayer> layer = static_cast<ImageLayer*> (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem)); if (!layer) { layer = aManager->CreateImageLayer(); if (!layer) return nullptr; } layer->SetContainer(container); layer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this)); layer->SetContentFlags(Layer::CONTENT_OPAQUE); // Set a transform on the layer to draw the video in the right place gfx::Matrix transform; gfxPoint p = r.TopLeft() + aContainerParameters.mOffset; transform.Translate(p.x, p.y); transform.Scale(r.Width()/frameSize.width, r.Height()/frameSize.height); layer->SetBaseTransform(gfx::Matrix4x4::From2D(transform)); layer->SetVisibleRegion(nsIntRect(0, 0, frameSize.width, frameSize.height)); nsRefPtr<Layer> result = layer.forget(); return result.forget(); }
already_AddRefed<Layer> nsVideoFrame::BuildLayer(nsDisplayListBuilder* aBuilder, LayerManager* aManager, nsDisplayItem* aItem, const ContainerLayerParameters& aContainerParameters) { nsRect area = GetContentRectRelativeToSelf() + aItem->ToReferenceFrame(); HTMLVideoElement* element = static_cast<HTMLVideoElement*>(GetContent()); nsIntSize videoSizeInPx; if (NS_FAILED(element->GetVideoSize(&videoSizeInPx)) || area.IsEmpty()) { return nullptr; } RefPtr<ImageContainer> container = element->GetImageContainer(); if (!container) return nullptr; // Retrieve the size of the decoded video frame, before being scaled // by pixel aspect ratio. mozilla::gfx::IntSize frameSize = container->GetCurrentSize(); if (frameSize.width == 0 || frameSize.height == 0) { // No image, or zero-sized image. No point creating a layer. return nullptr; } // 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 dest = nsLayoutUtils::ComputeObjectDestRect(area, intrinsicSize, aspectRatio, StylePosition()); gfxRect destGFXRect = PresContext()->AppUnitsToGfxUnits(dest); destGFXRect.Round(); if (destGFXRect.IsEmpty()) { return nullptr; } VideoInfo::Rotation rotationDeg = element->RotationDegrees(); IntSize scaleHint(static_cast<int32_t>(destGFXRect.Width()), static_cast<int32_t>(destGFXRect.Height())); // scaleHint is set regardless of rotation, so swap w/h if needed. SwapScaleWidthHeightForRotation(scaleHint, rotationDeg); container->SetScaleHint(scaleHint); RefPtr<ImageLayer> layer = static_cast<ImageLayer*> (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem)); if (!layer) { layer = aManager->CreateImageLayer(); if (!layer) return nullptr; } layer->SetContainer(container); layer->SetSamplingFilter(nsLayoutUtils::GetSamplingFilterForFrame(this)); // Set a transform on the layer to draw the video in the right place gfxPoint p = destGFXRect.TopLeft() + aContainerParameters.mOffset; Matrix preTransform = ComputeRotationMatrix(destGFXRect.Width(), destGFXRect.Height(), rotationDeg); Matrix transform = preTransform * Matrix::Translation(p.x, p.y); layer->SetBaseTransform(gfx::Matrix4x4::From2D(transform)); layer->SetScaleToSize(scaleHint, ScaleMode::STRETCH); RefPtr<Layer> result = layer.forget(); return result.forget(); }