зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1653166 - Add rotation support to computed reference frames and use them for <video>. r=aosmond
Differential Revision: https://phabricator.services.mozilla.com/D85104
This commit is contained in:
Родитель
ba116b41d6
Коммит
72cda2d18d
|
@ -33,6 +33,7 @@
|
|||
#include "nsDataHashtable.h"
|
||||
#include "mozilla/EnumeratedArray.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "MediaInfo.h"
|
||||
|
||||
#ifndef XPCOM_GLUE_AVOID_NSPR
|
||||
/**
|
||||
|
@ -536,6 +537,10 @@ class ImageContainer final : public SupportsWeakPtr {
|
|||
|
||||
const gfx::Matrix& GetTransformHint() const { return mTransformHint; }
|
||||
|
||||
void SetRotation(VideoInfo::Rotation aRotation) { mRotation = aRotation; }
|
||||
|
||||
VideoInfo::Rotation GetRotation() const { return mRotation; }
|
||||
|
||||
void SetImageFactory(ImageFactory* aFactory) {
|
||||
RecursiveMutexAutoLock lock(mRecursiveMutex);
|
||||
mImageFactory = aFactory ? aFactory : new ImageFactory();
|
||||
|
@ -660,6 +665,8 @@ class ImageContainer final : public SupportsWeakPtr {
|
|||
|
||||
gfx::Matrix mTransformHint;
|
||||
|
||||
VideoInfo::Rotation mRotation = VideoInfo::Rotation::kDegree_0;
|
||||
|
||||
RefPtr<BufferRecycleBin> mRecycleBin;
|
||||
|
||||
// This member points to an ImageClient if this ImageContainer was
|
||||
|
|
|
@ -29,6 +29,7 @@ using mozilla::LayoutDeviceRect from "Units.h";
|
|||
using mozilla::LayoutDeviceSize from "Units.h";
|
||||
using mozilla::ImageIntRect from "Units.h";
|
||||
using mozilla::gfx::Rect from "mozilla/gfx/Rect.h";
|
||||
using mozilla::VideoInfo::Rotation from "MediaInfo.h";
|
||||
using class mozilla::gfx::Matrix4x4 from "mozilla/gfx/Matrix.h";
|
||||
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
|
||||
|
||||
|
@ -80,6 +81,7 @@ struct OpUpdateAsyncImagePipeline {
|
|||
LayoutDeviceRect scBounds;
|
||||
Matrix4x4 scTransform;
|
||||
MaybeIntSize scaleToSize;
|
||||
Rotation rotation;
|
||||
ImageRendering filter;
|
||||
MixBlendMode mixBlendMode;
|
||||
LayoutDeviceSize scaleFromSize;
|
||||
|
|
|
@ -181,7 +181,8 @@ void AsyncImagePipelineManager::RemoveAsyncImagePipeline(
|
|||
void AsyncImagePipelineManager::UpdateAsyncImagePipeline(
|
||||
const wr::PipelineId& aPipelineId, const LayoutDeviceRect& aScBounds,
|
||||
const gfx::Matrix4x4& aScTransform, const gfx::MaybeIntSize& aScaleToSize,
|
||||
const wr::ImageRendering& aFilter, const wr::MixBlendMode& aMixBlendMode,
|
||||
const VideoInfo::Rotation aRotation, const wr::ImageRendering& aFilter,
|
||||
const wr::MixBlendMode& aMixBlendMode,
|
||||
const LayoutDeviceSize& aScaleFromSize) {
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
|
@ -192,7 +193,7 @@ void AsyncImagePipelineManager::UpdateAsyncImagePipeline(
|
|||
return;
|
||||
}
|
||||
pipeline->mInitialised = true;
|
||||
pipeline->Update(aScBounds, aScTransform, aScaleToSize, aFilter,
|
||||
pipeline->Update(aScBounds, aScTransform, aScaleToSize, aRotation, aFilter,
|
||||
aMixBlendMode, aScaleFromSize);
|
||||
}
|
||||
|
||||
|
@ -333,6 +334,20 @@ void AsyncImagePipelineManager::ApplyAsyncImagesOfImageBridge(
|
|||
}
|
||||
}
|
||||
|
||||
wr::WrRotation ToWrRotation(VideoInfo::Rotation aRotation) {
|
||||
switch (aRotation) {
|
||||
case VideoInfo::Rotation::kDegree_0:
|
||||
return wr::WrRotation::Degree0;
|
||||
case VideoInfo::Rotation::kDegree_90:
|
||||
return wr::WrRotation::Degree90;
|
||||
case VideoInfo::Rotation::kDegree_180:
|
||||
return wr::WrRotation::Degree180;
|
||||
case VideoInfo::Rotation::kDegree_270:
|
||||
return wr::WrRotation::Degree270;
|
||||
}
|
||||
return wr::WrRotation::Degree0;
|
||||
}
|
||||
|
||||
void AsyncImagePipelineManager::ApplyAsyncImageForPipeline(
|
||||
const wr::Epoch& aEpoch, const wr::PipelineId& aPipelineId,
|
||||
AsyncImagePipeline* aPipeline, wr::TransactionBuilder& aSceneBuilderTxn,
|
||||
|
@ -372,11 +387,13 @@ void AsyncImagePipelineManager::ApplyAsyncImageForPipeline(
|
|||
params.mix_blend_mode = aPipeline->mMixBlendMode;
|
||||
|
||||
wr::WrComputedTransformData computedTransform;
|
||||
if (!aPipeline->mScaleFromSize.IsEmpty()) {
|
||||
if (!aPipeline->mScaleFromSize.IsEmpty() ||
|
||||
aPipeline->mRotation != VideoInfo::Rotation::kDegree_0) {
|
||||
MOZ_ASSERT(scTransform.IsIdentity());
|
||||
computedTransform.vertical_flip =
|
||||
aPipeline->mCurrentTexture && aPipeline->mCurrentTexture->NeedsYFlip();
|
||||
computedTransform.scale_from = wr::ToLayoutSize(aPipeline->mScaleFromSize);
|
||||
computedTransform.rotation = ToWrRotation(aPipeline->mRotation);
|
||||
params.computed_transform = &computedTransform;
|
||||
} else {
|
||||
if (aPipeline->mCurrentTexture &&
|
||||
|
|
|
@ -103,6 +103,7 @@ class AsyncImagePipelineManager final {
|
|||
const LayoutDeviceRect& aScBounds,
|
||||
const gfx::Matrix4x4& aScTransform,
|
||||
const gfx::MaybeIntSize& aScaleToSize,
|
||||
VideoInfo::Rotation aRotation,
|
||||
const wr::ImageRendering& aFilter,
|
||||
const wr::MixBlendMode& aMixBlendMode,
|
||||
const LayoutDeviceSize& aScaleFromSize);
|
||||
|
@ -182,16 +183,19 @@ class AsyncImagePipelineManager final {
|
|||
void Update(const LayoutDeviceRect& aScBounds,
|
||||
const gfx::Matrix4x4& aScTransform,
|
||||
const gfx::MaybeIntSize& aScaleToSize,
|
||||
VideoInfo::Rotation aRotation,
|
||||
const wr::ImageRendering& aFilter,
|
||||
const wr::MixBlendMode& aMixBlendMode,
|
||||
const LayoutDeviceSize& aScaleFromSize) {
|
||||
mIsChanged |=
|
||||
!mScBounds.IsEqualEdges(aScBounds) || mScTransform != aScTransform ||
|
||||
mScaleToSize != aScaleToSize || mFilter != aFilter ||
|
||||
mMixBlendMode != aMixBlendMode || mScaleFromSize != aScaleFromSize;
|
||||
mIsChanged |= !mScBounds.IsEqualEdges(aScBounds) ||
|
||||
mScTransform != aScTransform ||
|
||||
mScaleToSize != aScaleToSize || mRotation != aRotation ||
|
||||
mFilter != aFilter || mMixBlendMode != aMixBlendMode ||
|
||||
mScaleFromSize != aScaleFromSize;
|
||||
mScBounds = aScBounds;
|
||||
mScTransform = aScTransform;
|
||||
mScaleToSize = aScaleToSize;
|
||||
mRotation = aRotation;
|
||||
mFilter = aFilter;
|
||||
mMixBlendMode = aMixBlendMode;
|
||||
mScaleFromSize = aScaleFromSize;
|
||||
|
@ -204,6 +208,7 @@ class AsyncImagePipelineManager final {
|
|||
LayoutDeviceSize mScaleFromSize;
|
||||
gfx::Matrix4x4 mScTransform;
|
||||
gfx::MaybeIntSize mScaleToSize;
|
||||
VideoInfo::Rotation mRotation;
|
||||
wr::ImageRendering mFilter;
|
||||
wr::MixBlendMode mMixBlendMode;
|
||||
RefPtr<WebRenderImageHost> mImageHost;
|
||||
|
|
|
@ -1353,7 +1353,7 @@ bool WebRenderBridgeParent::ProcessWebRenderParentCommands(
|
|||
cmd.get_OpUpdateAsyncImagePipeline();
|
||||
mAsyncImageManager->UpdateAsyncImagePipeline(
|
||||
op.pipelineId(), op.scBounds(), op.scTransform(), op.scaleToSize(),
|
||||
op.filter(), op.mixBlendMode(), op.scaleFromSize());
|
||||
op.rotation(), op.filter(), op.mixBlendMode(), op.scaleFromSize());
|
||||
mAsyncImageManager->ApplyAsyncImageForPipeline(op.pipelineId(), aTxn,
|
||||
txnForImageBridge);
|
||||
break;
|
||||
|
|
|
@ -1856,18 +1856,14 @@ Maybe<wr::ImageKey> WebRenderCommandBuilder::CreateImageKey(
|
|||
|
||||
LayoutDeviceRect rect = aAsyncImageBounds.value();
|
||||
LayoutDeviceRect scBounds(LayoutDevicePoint(0, 0), rect.Size());
|
||||
gfx::MaybeIntSize scaleToSize;
|
||||
if (!aContainer->GetScaleHint().IsEmpty()) {
|
||||
scaleToSize = Some(aContainer->GetScaleHint());
|
||||
}
|
||||
gfx::Matrix4x4 transform =
|
||||
gfx::Matrix4x4::From2D(aContainer->GetTransformHint());
|
||||
gfx::Matrix4x4 transform;
|
||||
// TODO!
|
||||
// We appear to be using the image bridge for a lot (most/all?) of
|
||||
// layers-free image handling and that breaks frame consistency.
|
||||
imageData->CreateAsyncImageWebRenderCommands(
|
||||
aBuilder, aContainer, aSc, rect, scBounds, transform, scaleToSize,
|
||||
aRendering, wr::MixBlendMode::Normal, !aItem->BackfaceIsHidden());
|
||||
aBuilder, aContainer, aSc, rect, scBounds, transform,
|
||||
gfx::MaybeIntSize(), aContainer->GetRotation(), aRendering,
|
||||
wr::MixBlendMode::Normal, !aItem->BackfaceIsHidden());
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "ipc/IPCMessageUtils.h"
|
||||
#include "mozilla/webrender/webrender_ffi.h"
|
||||
#include "mozilla/webrender/WebRenderTypes.h"
|
||||
#include "mozilla/dom/MediaIPCUtils.h"
|
||||
|
||||
namespace IPC {
|
||||
|
||||
|
|
|
@ -232,8 +232,9 @@ void WebRenderImageData::CreateAsyncImageWebRenderCommands(
|
|||
mozilla::wr::DisplayListBuilder& aBuilder, ImageContainer* aContainer,
|
||||
const StackingContextHelper& aSc, const LayoutDeviceRect& aBounds,
|
||||
const LayoutDeviceRect& aSCBounds, const gfx::Matrix4x4& aSCTransform,
|
||||
const gfx::MaybeIntSize& aScaleToSize, const wr::ImageRendering& aFilter,
|
||||
const wr::MixBlendMode& aMixBlendMode, bool aIsBackfaceVisible) {
|
||||
const gfx::MaybeIntSize& aScaleToSize, VideoInfo::Rotation aRotation,
|
||||
const wr::ImageRendering& aFilter, const wr::MixBlendMode& aMixBlendMode,
|
||||
bool aIsBackfaceVisible) {
|
||||
MOZ_ASSERT(aContainer->IsAsync());
|
||||
|
||||
if (mPipelineId.isSome() && mContainer != aContainer) {
|
||||
|
@ -253,6 +254,14 @@ void WebRenderImageData::CreateAsyncImageWebRenderCommands(
|
|||
}
|
||||
MOZ_ASSERT(!mImageClient);
|
||||
|
||||
LayoutDeviceSize scaleFromSize;
|
||||
AutoLockImage autoLock(aContainer);
|
||||
if (autoLock.HasImage()) {
|
||||
mozilla::layers::Image* image = autoLock.GetImage();
|
||||
gfx::IntSize size = image->GetSize();
|
||||
scaleFromSize = LayoutDeviceSize(size.width, size.height);
|
||||
}
|
||||
|
||||
// Push IFrame for async image pipeline.
|
||||
//
|
||||
// We don't push a stacking context for this async image pipeline here.
|
||||
|
@ -266,8 +275,8 @@ void WebRenderImageData::CreateAsyncImageWebRenderCommands(
|
|||
/*ignoreMissingPipelines*/ false);
|
||||
|
||||
WrBridge()->AddWebRenderParentCommand(OpUpdateAsyncImagePipeline(
|
||||
mPipelineId.value(), aSCBounds, aSCTransform, aScaleToSize, aFilter,
|
||||
aMixBlendMode, LayoutDeviceSize()));
|
||||
mPipelineId.value(), aSCBounds, aSCTransform, aScaleToSize, aRotation,
|
||||
aFilter, aMixBlendMode, scaleFromSize));
|
||||
}
|
||||
|
||||
void WebRenderImageData::CreateImageClientIfNeeded() {
|
||||
|
|
|
@ -158,8 +158,9 @@ class WebRenderImageData : public WebRenderUserData {
|
|||
mozilla::wr::DisplayListBuilder& aBuilder, ImageContainer* aContainer,
|
||||
const StackingContextHelper& aSc, const LayoutDeviceRect& aBounds,
|
||||
const LayoutDeviceRect& aSCBounds, const gfx::Matrix4x4& aSCTransform,
|
||||
const gfx::MaybeIntSize& aScaleToSize, const wr::ImageRendering& aFilter,
|
||||
const wr::MixBlendMode& aMixBlendMode, bool aIsBackfaceVisible);
|
||||
const gfx::MaybeIntSize& aScaleToSize, VideoInfo::Rotation aRotation,
|
||||
const wr::ImageRendering& aFilter, const wr::MixBlendMode& aMixBlendMode,
|
||||
bool aIsBackfaceVisible);
|
||||
|
||||
void CreateImageClientIfNeeded();
|
||||
|
||||
|
|
|
@ -490,6 +490,7 @@ pub struct WrWindowId(u64);
|
|||
pub struct WrComputedTransformData {
|
||||
pub scale_from: LayoutSize,
|
||||
pub vertical_flip: bool,
|
||||
pub rotation: WrRotation,
|
||||
}
|
||||
|
||||
fn get_proc_address(glcontext_ptr: *mut c_void, name: &str) -> *const c_void {
|
||||
|
@ -2317,6 +2318,15 @@ pub enum WrReferenceFrameKind {
|
|||
Zoom,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub enum WrRotation {
|
||||
Degree0,
|
||||
Degree90,
|
||||
Degree180,
|
||||
Degree270,
|
||||
}
|
||||
|
||||
/// IMPORTANT: If you add fields to this struct, you need to also add initializers
|
||||
/// for those fields in WebRenderAPI.h.
|
||||
#[repr(C)]
|
||||
|
@ -2444,11 +2454,18 @@ pub extern "C" fn wr_dp_push_stacking_context(
|
|||
result.id = wr_spatial_id.0;
|
||||
assert_ne!(wr_spatial_id.0, 0);
|
||||
} else if let Some(data) = computed_ref {
|
||||
let rotation = match data.rotation {
|
||||
WrRotation::Degree0 => Rotation::Degree0,
|
||||
WrRotation::Degree90 => Rotation::Degree90,
|
||||
WrRotation::Degree180 => Rotation::Degree180,
|
||||
WrRotation::Degree270 => Rotation::Degree270,
|
||||
};
|
||||
wr_spatial_id = state.frame_builder.dl_builder.push_computed_frame(
|
||||
bounds.origin,
|
||||
wr_spatial_id,
|
||||
Some(data.scale_from),
|
||||
data.vertical_flip,
|
||||
rotation,
|
||||
);
|
||||
|
||||
bounds.origin = LayoutPoint::zero();
|
||||
|
|
|
@ -11,7 +11,7 @@ use api::{LineOrientation, LineStyle, NinePatchBorderSource, PipelineId, MixBlen
|
|||
use api::{PropertyBinding, ReferenceFrameKind, ScrollFrameDisplayItem, ScrollSensitivity};
|
||||
use api::{Shadow, SpaceAndClipInfo, SpatialId, StickyFrameDisplayItem, ImageMask};
|
||||
use api::{ClipMode, PrimitiveKeyKind, TransformStyle, YuvColorSpace, ColorRange, YuvData, TempFilterData};
|
||||
use api::{ReferenceTransformBinding};
|
||||
use api::{ReferenceTransformBinding, Rotation};
|
||||
use api::image_tiling::simplify_repeated_primitive;
|
||||
use api::units::*;
|
||||
use crate::clip::{ClipChainId, ClipRegion, ClipItemKey, ClipStore, ClipItemKeyKind};
|
||||
|
@ -482,14 +482,32 @@ impl<'a> SceneBuilder<'a> {
|
|||
|
||||
let transform = match info.reference_frame.transform {
|
||||
ReferenceTransformBinding::Static { binding } => binding,
|
||||
ReferenceTransformBinding::Computed { scale_from, vertical_flip } => {
|
||||
ReferenceTransformBinding::Computed { scale_from, vertical_flip, rotation } => {
|
||||
let content_size = &self.iframe_size.last().unwrap();
|
||||
|
||||
let mut transform = if let Some(scale_from) = scale_from {
|
||||
let content_size = &self.iframe_size.last().unwrap();
|
||||
LayoutTransform::create_scale(
|
||||
content_size.width / scale_from.width,
|
||||
content_size.height / scale_from.height,
|
||||
1.0
|
||||
)
|
||||
// If we have a 90/270 degree rotation, then scale_from
|
||||
// and content_size are in different coordinate spaces and
|
||||
// we need to swap width/height for them to be correct.
|
||||
match rotation {
|
||||
Rotation::Degree0 |
|
||||
Rotation::Degree180 => {
|
||||
LayoutTransform::create_scale(
|
||||
content_size.width / scale_from.width,
|
||||
content_size.height / scale_from.height,
|
||||
1.0
|
||||
)
|
||||
},
|
||||
Rotation::Degree90 |
|
||||
Rotation::Degree270 => {
|
||||
LayoutTransform::create_scale(
|
||||
content_size.height / scale_from.width,
|
||||
content_size.width / scale_from.height,
|
||||
1.0
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LayoutTransform::identity()
|
||||
};
|
||||
|
@ -501,6 +519,9 @@ impl<'a> SceneBuilder<'a> {
|
|||
.pre_scale(1.0, -1.0, 1.0);
|
||||
}
|
||||
|
||||
let rotate = rotation.to_matrix(**content_size);
|
||||
let transform = transform.post_transform(&rotate);
|
||||
|
||||
PropertyBinding::Value(transform)
|
||||
},
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use euclid::SideOffsets2D;
|
||||
use euclid::{SideOffsets2D, Angle};
|
||||
use peek_poke::PeekPoke;
|
||||
use std::ops::Not;
|
||||
// local imports
|
||||
|
@ -721,6 +721,41 @@ pub enum ReferenceFrameKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum Rotation {
|
||||
Degree0,
|
||||
Degree90,
|
||||
Degree180,
|
||||
Degree270,
|
||||
}
|
||||
|
||||
impl Rotation {
|
||||
pub fn to_matrix(
|
||||
&self,
|
||||
size: LayoutSize,
|
||||
) -> LayoutTransform {
|
||||
let (shift_center_to_origin, angle) = match self {
|
||||
Rotation::Degree0 => {
|
||||
(LayoutTransform::create_translation(-size.width / 2., -size.height / 2., 0.), Angle::degrees(0.))
|
||||
},
|
||||
Rotation::Degree90 => {
|
||||
(LayoutTransform::create_translation(-size.height / 2., -size.width / 2., 0.), Angle::degrees(90.))
|
||||
},
|
||||
Rotation::Degree180 => {
|
||||
(LayoutTransform::create_translation(-size.width / 2., -size.height / 2., 0.), Angle::degrees(180.))
|
||||
},
|
||||
Rotation::Degree270 => {
|
||||
(LayoutTransform::create_translation(-size.height / 2., -size.width / 2., 0.), Angle::degrees(270.))
|
||||
},
|
||||
};
|
||||
let shift_origin_to_center = LayoutTransform::create_translation(size.width / 2., size.height / 2., 0.);
|
||||
|
||||
LayoutTransform::create_rotation(0., 0., -1.0, angle)
|
||||
.pre_transform(&shift_center_to_origin)
|
||||
.post_transform(&shift_origin_to_center)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum ReferenceTransformBinding {
|
||||
/// Standard reference frame which contains a precomputed transform.
|
||||
|
@ -733,6 +768,7 @@ pub enum ReferenceTransformBinding {
|
|||
Computed {
|
||||
scale_from: Option<LayoutSize>,
|
||||
vertical_flip: bool,
|
||||
rotation: Rotation,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -1598,6 +1634,7 @@ impl_default_for_enums! {
|
|||
ClipMode => Clip,
|
||||
ClipId => ClipId::invalid(),
|
||||
ReferenceFrameKind => Transform,
|
||||
Rotation => Degree0,
|
||||
TransformStyle => Flat,
|
||||
RasterSpace => Local(f32::default()),
|
||||
MixBlendMode => Normal,
|
||||
|
|
|
@ -1545,6 +1545,7 @@ impl DisplayListBuilder {
|
|||
parent_spatial_id: di::SpatialId,
|
||||
scale_from: Option<LayoutSize>,
|
||||
vertical_flip: bool,
|
||||
rotation: di::Rotation,
|
||||
) -> di::SpatialId {
|
||||
let id = self.generate_spatial_index();
|
||||
|
||||
|
@ -1555,7 +1556,8 @@ impl DisplayListBuilder {
|
|||
transform_style: di::TransformStyle::Flat,
|
||||
transform: di::ReferenceTransformBinding::Computed {
|
||||
scale_from,
|
||||
vertical_flip
|
||||
vertical_flip,
|
||||
rotation,
|
||||
},
|
||||
kind: di::ReferenceFrameKind::Transform,
|
||||
id,
|
||||
|
|
|
@ -174,7 +174,8 @@ class nsDisplayCanvas final : public nsPaintedDisplayItem {
|
|||
aManager->WrBridge()->AddWebRenderParentCommand(
|
||||
OpUpdateAsyncImagePipeline(
|
||||
data->GetPipelineId().value(), scBounds, scTransform,
|
||||
scaleToSize, filter, mixBlendMode,
|
||||
scaleToSize, VideoInfo::Rotation::kDegree_0, filter,
|
||||
mixBlendMode,
|
||||
LayoutDeviceSize(canvasSizeInPx.width, canvasSizeInPx.height)));
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -461,19 +461,7 @@ class nsDisplayVideo : public nsPaintedDisplayItem {
|
|||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
Matrix transformHint;
|
||||
if (rotationDeg != VideoInfo::Rotation::kDegree_0) {
|
||||
transformHint = ComputeRotationMatrix(destGFXRect.Width(),
|
||||
destGFXRect.Height(), rotationDeg);
|
||||
}
|
||||
container->SetTransformHint(transformHint);
|
||||
container->SetRotation(element->RotationDegrees());
|
||||
|
||||
// If the image container is empty, we don't want to fallback. Any other
|
||||
// failure will be due to resource constraints and fallback is unlikely to
|
||||
|
|
Загрузка…
Ссылка в новой задаче